diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index 0c2b613f2373..8e2c2c405db2 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -227,6 +227,17 @@ Contact: dmaengine@vger.kernel.org Description: Indicate the number of retires for an enqcmds submission on a sharedwq. A max value to set attribute is capped at 64. +What: /sys/bus/dsa/devices/wq./op_config +Date: Sept 14, 2022 +KernelVersion: 6.0.0 +Contact: dmaengine@vger.kernel.org +Description: Shows the operation capability bits displayed in bitmap format + presented by %*pb printk() output format specifier. + The attribute can be configured when the WQ is disabled in + order to configure the WQ to accept specific bits that + correlates to the operations allowed. It's visible only + on platforms that support the capability. + What: /sys/bus/dsa/devices/engine./group_id Date: Oct 25, 2019 KernelVersion: 5.6.0 @@ -255,3 +266,27 @@ Contact: dmaengine@vger.kernel.org Description: Indicates the number of Read Buffers reserved for the use of engines in the group. See DSA spec v1.2 9.2.18 GRPCFG Read Buffers Reserved. + +What: /sys/bus/dsa/devices/group./desc_progress_limit +Date: Sept 14, 2022 +KernelVersion: 6.0.0 +Contact: dmaengine@vger.kernel.org +Description: Allows control of the number of work descriptors that can be + concurrently processed by an engine in the group as a fraction + of the Maximum Work Descriptors in Progress value specified in + the ENGCAP register. The acceptable values are 0 (default), + 1 (1/2 of max value), 2 (1/4 of the max value), and 3 (1/8 of + the max value). It's visible only on platforms that support + the capability. + +What: /sys/bus/dsa/devices/group./batch_progress_limit +Date: Sept 14, 2022 +KernelVersion: 6.0.0 +Contact: dmaengine@vger.kernel.org +Description: Allows control of the number of batch descriptors that can be + concurrently processed by an engine in the group as a fraction + of the Maximum Batch Descriptors in Progress value specified in + the ENGCAP register. The acceptable values are 0 (default), + 1 (1/2 of max value), 2 (1/4 of the max value), and 3 (1/8 of + the max value). It's visible only on platforms that support + the capability. diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index f7570c240ce8..76ab3e1fe374 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -153,7 +153,7 @@ Date: Jan 2020 KernelVersion: 5.5 Contact: Mika Westerberg Description: This attribute reports number of RX lanes the device is - using simultaneusly through its upstream port. + using simultaneously through its upstream port. What: /sys/bus/thunderbolt/devices/.../tx_speed Date: Jan 2020 @@ -167,7 +167,7 @@ Date: Jan 2020 KernelVersion: 5.5 Contact: Mika Westerberg Description: This attribute reports number of TX lanes the device is - using simultaneusly through its upstream port. + using simultaneously through its upstream port. What: /sys/bus/thunderbolt/devices/.../vendor Date: Sep 2017 diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index a89cfa083155..faa22f77847a 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -5,143 +5,115 @@ Dynamic debug Introduction ============ -This document describes how to use the dynamic debug (dyndbg) feature. +Dynamic debug allows you to dynamically enable/disable kernel +debug-print code to obtain additional kernel information. -Dynamic debug is designed to allow you to dynamically enable/disable -kernel code to obtain additional kernel information. Currently, if -``CONFIG_DYNAMIC_DEBUG`` is set, then all ``pr_debug()``/``dev_dbg()`` and -``print_hex_dump_debug()``/``print_hex_dump_bytes()`` calls can be dynamically -enabled per-callsite. +If ``/proc/dynamic_debug/control`` exists, your kernel has dynamic +debug. You'll need root access (sudo su) to use this. -If you do not want to enable dynamic debug globally (i.e. in some embedded -system), you may set ``CONFIG_DYNAMIC_DEBUG_CORE`` as basic support of dynamic -debug and add ``ccflags := -DDYNAMIC_DEBUG_MODULE`` into the Makefile of any -modules which you'd like to dynamically debug later. +Dynamic debug provides: -If ``CONFIG_DYNAMIC_DEBUG`` is not set, ``print_hex_dump_debug()`` is just -shortcut for ``print_hex_dump(KERN_DEBUG)``. + * a Catalog of all *prdbgs* in your kernel. + ``cat /proc/dynamic_debug/control`` to see them. -For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is -its ``prefix_str`` argument, if it is constant string; or ``hexdump`` -in case ``prefix_str`` is built dynamically. - -Dynamic debug has even more useful features: - - * Simple query language allows turning on and off debugging - statements by matching any combination of 0 or 1 of: + * a Simple query/command language to alter *prdbgs* by selecting on + any combination of 0 or 1 of: - source filename - function name - line number (including ranges of line numbers) - module name - format string - - * Provides a debugfs control file: ``/dynamic_debug/control`` - which can be read to display the complete list of known debug - statements, to help guide you - -Controlling dynamic debug Behaviour -=================================== - -The behaviour of ``pr_debug()``/``dev_dbg()`` are controlled via writing to a -control file in the 'debugfs' filesystem. Thus, you must first mount -the debugfs filesystem, in order to make use of this feature. -Subsequently, we refer to the control file as: -``/dynamic_debug/control``. For example, if you want to enable -printing from source file ``svcsock.c``, line 1603 you simply do:: - - nullarbor:~ # echo 'file svcsock.c line 1603 +p' > - /dynamic_debug/control - -If you make a mistake with the syntax, the write will fail thus:: - - nullarbor:~ # echo 'file svcsock.c wtf 1 +p' > - /dynamic_debug/control - -bash: echo: write error: Invalid argument - -Note, for systems without 'debugfs' enabled, the control file can be -found in ``/proc/dynamic_debug/control``. + - class name (as known/declared by each module) Viewing Dynamic Debug Behaviour =============================== -You can view the currently configured behaviour of all the debug -statements via:: +You can view the currently configured behaviour in the *prdbg* catalog:: - nullarbor:~ # cat /dynamic_debug/control + :#> head -n7 /proc/dynamic_debug/control # filename:lineno [module]function flags format - net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012" - net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012" - net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012" - net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012" - ... + init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012 + init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012" + init/main.c:1424 [main]run_init_process =_ " with arguments:\012" + init/main.c:1426 [main]run_init_process =_ " %s\012" + init/main.c:1427 [main]run_init_process =_ " with environment:\012" + init/main.c:1429 [main]run_init_process =_ " %s\012" +The 3rd space-delimited column shows the current flags, preceded by +a ``=`` for easy use with grep/cut. ``=p`` shows enabled callsites. -You can also apply standard Unix text manipulation filters to this -data, e.g.:: +Controlling dynamic debug Behaviour +=================================== - nullarbor:~ # grep -i rdma /dynamic_debug/control | wc -l - 62 +The behaviour of *prdbg* sites are controlled by writing +query/commands to the control file. Example:: - nullarbor:~ # grep -i tcp /dynamic_debug/control | wc -l - 42 + # grease the interface + :#> alias ddcmd='echo $* > /proc/dynamic_debug/control' -The third column shows the currently enabled flags for each debug -statement callsite (see below for definitions of the flags). The -default value, with no flags enabled, is ``=_``. So you can view all -the debug statement callsites with any non-default flags:: + :#> ddcmd '-p; module main func run* +p' + :#> grep =p /proc/dynamic_debug/control + init/main.c:1424 [main]run_init_process =p " with arguments:\012" + init/main.c:1426 [main]run_init_process =p " %s\012" + init/main.c:1427 [main]run_init_process =p " with environment:\012" + init/main.c:1429 [main]run_init_process =p " %s\012" - nullarbor:~ # awk '$3 != "=_"' /dynamic_debug/control - # filename:lineno [module]function flags format - net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012" +Error messages go to console/syslog:: + + :#> ddcmd mode foo +p + dyndbg: unknown keyword "mode" + dyndbg: query parse failed + bash: echo: write error: Invalid argument + +If debugfs is also enabled and mounted, ``dynamic_debug/control`` is +also under the mount-dir, typically ``/sys/kernel/debug/``. Command Language Reference ========================== -At the lexical level, a command comprises a sequence of words separated +At the basic lexical level, a command is a sequence of words separated by spaces or tabs. So these are all equivalent:: - nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > - /dynamic_debug/control - nullarbor:~ # echo -n ' file svcsock.c line 1603 +p ' > - /dynamic_debug/control - nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > - /dynamic_debug/control + :#> ddcmd file svcsock.c line 1603 +p + :#> ddcmd "file svcsock.c line 1603 +p" + :#> ddcmd ' file svcsock.c line 1603 +p ' Command submissions are bounded by a write() system call. Multiple commands can be written together, separated by ``;`` or ``\n``:: - ~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \ - > /dynamic_debug/control + :#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p" + :#> ddcmd <<"EOC" + func pnpacpi_get_resources +p + func pnp_assign_mem +p + EOC + :#> cat query-batch-file > /proc/dynamic_debug/control -If your query set is big, you can batch them too:: +You can also use wildcards in each query term. The match rule supports +``*`` (matches zero or more characters) and ``?`` (matches exactly one +character). For example, you can match all usb drivers:: - ~# cat query-batch-file > /dynamic_debug/control + :#> ddcmd file "drivers/usb/*" +p # "" to suppress shell expansion -Another way is to use wildcards. The match rule supports ``*`` (matches -zero or more characters) and ``?`` (matches exactly one character). For -example, you can match all usb drivers:: - - ~# echo "file drivers/usb/* +p" > /dynamic_debug/control - -At the syntactical level, a command comprises a sequence of match -specifications, followed by a flags change specification:: +Syntactically, a command is pairs of keyword values, followed by a +flags change or setting:: command ::= match-spec* flags-spec -The match-spec's are used to choose a subset of the known pr_debug() -callsites to which to apply the flags-spec. Think of them as a query -with implicit ANDs between each pair. Note that an empty list of -match-specs will select all debug statement callsites. +The match-spec's select *prdbgs* from the catalog, upon which to apply +the flags-spec, all constraints are ANDed together. An absent keyword +is the same as keyword "*". -A match specification comprises a keyword, which controls the -attribute of the callsite to be compared, and a value to compare -against. Possible keywords are::: + +A match specification is a keyword, which selects the attribute of +the callsite to be compared, and a value to compare against. Possible +keywords are::: match-spec ::= 'func' string | 'file' string | 'module' string | 'format' string | + 'class' string | 'line' line-range line-range ::= lineno | @@ -203,6 +175,16 @@ format format "nfsd: SETATTR" // a neater way to match a format with whitespace format 'nfsd: SETATTR' // yet another way to match a format with whitespace +class + The given class_name is validated against each module, which may + have declared a list of known class_names. If the class_name is + found for a module, callsite & class matching and adjustment + proceeds. Examples:: + + class DRM_UT_KMS # a DRM.debug category + class JUNK # silent non-match + // class TLD_* # NOTICE: no wildcard in class names + line The given line number or range of line numbers is compared against the line number of each ``pr_debug()`` callsite. A single @@ -228,17 +210,16 @@ of the characters:: The flags are:: p enables the pr_debug() callsite. - f Include the function name in the printed message - l Include line number in the printed message - m Include module name in the printed message - t Include thread ID in messages not generated from interrupt context - _ No flags are set. (Or'd with others on input) + _ enables no flags. -For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only ``p`` flag -have meaning, other flags ignored. + Decorator flags add to the message-prefix, in order: + t Include thread ID, or + m Include module name + f Include the function name + l Include line number -For display, the flags are preceded by ``=`` -(mnemonic: what the flags are currently equal to). +For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only +the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][flmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-flmpt``. @@ -313,7 +294,7 @@ For ``CONFIG_DYNAMIC_DEBUG`` kernels, any settings given at boot-time (or enabled by ``-DDEBUG`` flag during compilation) can be disabled later via the debugfs interface if the debug messages are no longer needed:: - echo "module module_name -p" > /dynamic_debug/control + echo "module module_name -p" > /proc/dynamic_debug/control Examples ======== @@ -321,37 +302,31 @@ Examples :: // enable the message at line 1603 of file svcsock.c - nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > - /dynamic_debug/control + :#> ddcmd 'file svcsock.c line 1603 +p' // enable all the messages in file svcsock.c - nullarbor:~ # echo -n 'file svcsock.c +p' > - /dynamic_debug/control + :#> ddcmd 'file svcsock.c +p' // enable all the messages in the NFS server module - nullarbor:~ # echo -n 'module nfsd +p' > - /dynamic_debug/control + :#> ddcmd 'module nfsd +p' // enable all 12 messages in the function svc_process() - nullarbor:~ # echo -n 'func svc_process +p' > - /dynamic_debug/control + :#> ddcmd 'func svc_process +p' // disable all 12 messages in the function svc_process() - nullarbor:~ # echo -n 'func svc_process -p' > - /dynamic_debug/control + :#> ddcmd 'func svc_process -p' // enable messages for NFS calls READ, READLINK, READDIR and READDIR+. - nullarbor:~ # echo -n 'format "nfsd: READ" +p' > - /dynamic_debug/control + :#> ddcmd 'format "nfsd: READ" +p' // enable messages in files of which the paths include string "usb" - nullarbor:~ # echo -n 'file *usb* +p' > /dynamic_debug/control + :#> ddcmd 'file *usb* +p' > /proc/dynamic_debug/control // enable all messages - nullarbor:~ # echo -n '+p' > /dynamic_debug/control + :#> ddcmd '+p' > /proc/dynamic_debug/control // add module, function to all enabled messages - nullarbor:~ # echo -n '+mf' > /dynamic_debug/control + :#> ddcmd '+mf' > /proc/dynamic_debug/control // boot-args example, with newlines and comments for readability Kernel command line: ... @@ -364,3 +339,38 @@ Examples dyndbg="file init/* +p #cmt ; func parse_one +p" // enable pr_debugs in 2 functions in a module loaded later pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p" + +Kernel Configuration +==================== + +Dynamic Debug is enabled via kernel config items:: + + CONFIG_DYNAMIC_DEBUG=y # build catalog, enables CORE + CONFIG_DYNAMIC_DEBUG_CORE=y # enable mechanics only, skip catalog + +If you do not want to enable dynamic debug globally (i.e. in some embedded +system), you may set ``CONFIG_DYNAMIC_DEBUG_CORE`` as basic support of dynamic +debug and add ``ccflags := -DDYNAMIC_DEBUG_MODULE`` into the Makefile of any +modules which you'd like to dynamically debug later. + + +Kernel *prdbg* API +================== + +The following functions are cataloged and controllable when dynamic +debug is enabled:: + + pr_debug() + dev_dbg() + print_hex_dump_debug() + print_hex_dump_bytes() + +Otherwise, they are off by default; ``ccflags += -DDEBUG`` or +``#define DEBUG`` in a source file will enable them appropriately. + +If ``CONFIG_DYNAMIC_DEBUG`` is not set, ``print_hex_dump_debug()`` is +just a shortcut for ``print_hex_dump(KERN_DEBUG)``. + +For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is +its ``prefix_str`` argument, if it is constant string; or ``hexdump`` +in case ``prefix_str`` is built dynamically. diff --git a/Documentation/arm/index.rst b/Documentation/arm/index.rst index 495ada7915e1..8c636d4a061f 100644 --- a/Documentation/arm/index.rst +++ b/Documentation/arm/index.rst @@ -59,6 +59,7 @@ SoC-specific documents stm32/stm32f429-overview stm32/stm32mp13-overview stm32/stm32mp157-overview + stm32/stm32-dma-mdma-chaining sunxi diff --git a/Documentation/arm/stm32/stm32-dma-mdma-chaining.rst b/Documentation/arm/stm32/stm32-dma-mdma-chaining.rst new file mode 100644 index 000000000000..2945e0e33104 --- /dev/null +++ b/Documentation/arm/stm32/stm32-dma-mdma-chaining.rst @@ -0,0 +1,415 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================= +STM32 DMA-MDMA chaining +======================= + + +Introduction +------------ + + This document describes the STM32 DMA-MDMA chaining feature. But before going + further, let's introduce the peripherals involved. + + To offload data transfers from the CPU, STM32 microprocessors (MPUs) embed + direct memory access controllers (DMA). + + STM32MP1 SoCs embed both STM32 DMA and STM32 MDMA controllers. STM32 DMA + request routing capabilities are enhanced by a DMA request multiplexer + (STM32 DMAMUX). + + **STM32 DMAMUX** + + STM32 DMAMUX routes any DMA request from a given peripheral to any STM32 DMA + controller (STM32MP1 counts two STM32 DMA controllers) channels. + + **STM32 DMA** + + STM32 DMA is mainly used to implement central data buffer storage (usually in + the system SRAM) for different peripheral. It can access external RAMs but + without the ability to generate convenient burst transfer ensuring the best + load of the AXI. + + **STM32 MDMA** + + STM32 MDMA (Master DMA) is mainly used to manage direct data transfers between + RAM data buffers without CPU intervention. It can also be used in a + hierarchical structure that uses STM32 DMA as first level data buffer + interfaces for AHB peripherals, while the STM32 MDMA acts as a second level + DMA with better performance. As a AXI/AHB master, STM32 MDMA can take control + of the AXI/AHB bus. + + +Principles +---------- + + STM32 DMA-MDMA chaining feature relies on the strengths of STM32 DMA and + STM32 MDMA controllers. + + STM32 DMA has a circular Double Buffer Mode (DBM). At each end of transaction + (when DMA data counter - DMA_SxNDTR - reaches 0), the memory pointers + (configured with DMA_SxSM0AR and DMA_SxM1AR) are swapped and the DMA data + counter is automatically reloaded. This allows the SW or the STM32 MDMA to + process one memory area while the second memory area is being filled/used by + the STM32 DMA transfer. + + With STM32 MDMA linked-list mode, a single request initiates the data array + (collection of nodes) to be transferred until the linked-list pointer for the + channel is null. The channel transfer complete of the last node is the end of + transfer, unless first and last nodes are linked to each other, in such a + case, the linked-list loops on to create a circular MDMA transfer. + + STM32 MDMA has direct connections with STM32 DMA. This enables autonomous + communication and synchronization between peripherals, thus saving CPU + resources and bus congestion. Transfer Complete signal of STM32 DMA channel + can triggers STM32 MDMA transfer. STM32 MDMA can clear the request generated + by the STM32 DMA by writing to its Interrupt Clear register (whose address is + stored in MDMA_CxMAR, and bit mask in MDMA_CxMDR). + + .. table:: STM32 MDMA interconnect table with STM32 DMA + + +--------------+----------------+-----------+------------+ + | STM32 DMAMUX | STM32 DMA | STM32 DMA | STM32 MDMA | + | channels | channels | Transfer | request | + | | | complete | | + | | | signal | | + +==============+================+===========+============+ + | Channel *0* | DMA1 channel 0 | dma1_tcf0 | *0x00* | + +--------------+----------------+-----------+------------+ + | Channel *1* | DMA1 channel 1 | dma1_tcf1 | *0x01* | + +--------------+----------------+-----------+------------+ + | Channel *2* | DMA1 channel 2 | dma1_tcf2 | *0x02* | + +--------------+----------------+-----------+------------+ + | Channel *3* | DMA1 channel 3 | dma1_tcf3 | *0x03* | + +--------------+----------------+-----------+------------+ + | Channel *4* | DMA1 channel 4 | dma1_tcf4 | *0x04* | + +--------------+----------------+-----------+------------+ + | Channel *5* | DMA1 channel 5 | dma1_tcf5 | *0x05* | + +--------------+----------------+-----------+------------+ + | Channel *6* | DMA1 channel 6 | dma1_tcf6 | *0x06* | + +--------------+----------------+-----------+------------+ + | Channel *7* | DMA1 channel 7 | dma1_tcf7 | *0x07* | + +--------------+----------------+-----------+------------+ + | Channel *8* | DMA2 channel 0 | dma2_tcf0 | *0x08* | + +--------------+----------------+-----------+------------+ + | Channel *9* | DMA2 channel 1 | dma2_tcf1 | *0x09* | + +--------------+----------------+-----------+------------+ + | Channel *10* | DMA2 channel 2 | dma2_tcf2 | *0x0A* | + +--------------+----------------+-----------+------------+ + | Channel *11* | DMA2 channel 3 | dma2_tcf3 | *0x0B* | + +--------------+----------------+-----------+------------+ + | Channel *12* | DMA2 channel 4 | dma2_tcf4 | *0x0C* | + +--------------+----------------+-----------+------------+ + | Channel *13* | DMA2 channel 5 | dma2_tcf5 | *0x0D* | + +--------------+----------------+-----------+------------+ + | Channel *14* | DMA2 channel 6 | dma2_tcf6 | *0x0E* | + +--------------+----------------+-----------+------------+ + | Channel *15* | DMA2 channel 7 | dma2_tcf7 | *0x0F* | + +--------------+----------------+-----------+------------+ + + STM32 DMA-MDMA chaining feature then uses a SRAM buffer. STM32MP1 SoCs embed + three fast access static internal RAMs of various size, used for data storage. + Due to STM32 DMA legacy (within microcontrollers), STM32 DMA performances are + bad with DDR, while they are optimal with SRAM. Hence the SRAM buffer used + between STM32 DMA and STM32 MDMA. This buffer is split in two equal periods + and STM32 DMA uses one period while STM32 MDMA uses the other period + simultaneously. + :: + + dma[1:2]-tcf[0:7] + .----------------. + ____________ ' _________ V____________ + | STM32 DMA | / __|>_ \ | STM32 MDMA | + |------------| | / \ | |------------| + | DMA_SxM0AR |<=>| | SRAM | |<=>| []-[]...[] | + | DMA_SxM1AR | | \_____/ | | | + |____________| \___<|____/ |____________| + + STM32 DMA-MDMA chaining uses (struct dma_slave_config).peripheral_config to + exchange the parameters needed to configure MDMA. These parameters are + gathered into a u32 array with three values: + + * the STM32 MDMA request (which is actually the DMAMUX channel ID), + * the address of the STM32 DMA register to clear the Transfer Complete + interrupt flag, + * the mask of the Transfer Complete interrupt flag of the STM32 DMA channel. + +Device Tree updates for STM32 DMA-MDMA chaining support +------------------------------------------------------- + + **1. Allocate a SRAM buffer** + + SRAM device tree node is defined in SoC device tree. You can refer to it in + your board device tree to define your SRAM pool. + :: + + &sram { + my_foo_device_dma_pool: dma-sram@0 { + reg = <0x0 0x1000>; + }; + }; + + Be careful of the start index, in case there are other SRAM consumers. + Define your pool size strategically: to optimise chaining, the idea is that + STM32 DMA and STM32 MDMA can work simultaneously, on each buffer of the + SRAM. + If the SRAM period is greater than the expected DMA transfer, then STM32 DMA + and STM32 MDMA will work sequentially instead of simultaneously. It is not a + functional issue but it is not optimal. + + Don't forget to refer to your SRAM pool in your device node. You need to + define a new property. + :: + + &my_foo_device { + ... + my_dma_pool = &my_foo_device_dma_pool; + }; + + Then get this SRAM pool in your foo driver and allocate your SRAM buffer. + + **2. Allocate a STM32 DMA channel and a STM32 MDMA channel** + + You need to define an extra channel in your device tree node, in addition to + the one you should already have for "classic" DMA operation. + + This new channel must be taken from STM32 MDMA channels, so, the phandle of + the DMA controller to use is the MDMA controller's one. + :: + + &my_foo_device { + [...] + my_dma_pool = &my_foo_device_dma_pool; + dmas = <&dmamux1 ...>, // STM32 DMA channel + <&mdma1 0 0x3 0x1200000a 0 0>; // + STM32 MDMA channel + }; + + Concerning STM32 MDMA bindings: + + 1. The request line number : whatever the value here, it will be overwritten + by MDMA driver with the STM32 DMAMUX channel ID passed through + (struct dma_slave_config).peripheral_config + + 2. The priority level : choose Very High (0x3) so that your channel will + take priority other the other during request arbitration + + 3. A 32bit mask specifying the DMA channel configuration : source and + destination address increment, block transfer with 128 bytes per single + transfer + + 4. The 32bit value specifying the register to be used to acknowledge the + request: it will be overwritten by MDMA driver, with the DMA channel + interrupt flag clear register address passed through + (struct dma_slave_config).peripheral_config + + 5. The 32bit mask specifying the value to be written to acknowledge the + request: it will be overwritten by MDMA driver, with the DMA channel + Transfer Complete flag passed through + (struct dma_slave_config).peripheral_config + +Driver updates for STM32 DMA-MDMA chaining support in foo driver +---------------------------------------------------------------- + + **0. (optional) Refactor the original sg_table if dmaengine_prep_slave_sg()** + + In case of dmaengine_prep_slave_sg(), the original sg_table can't be used as + is. Two new sg_tables must be created from the original one. One for + STM32 DMA transfer (where memory address targets now the SRAM buffer instead + of DDR buffer) and one for STM32 MDMA transfer (where memory address targets + the DDR buffer). + + The new sg_list items must fit SRAM period length. Here is an example for + DMA_DEV_TO_MEM: + :: + + /* + * Assuming sgl and nents, respectively the initial scatterlist and its + * length. + * Assuming sram_dma_buf and sram_period, respectively the memory + * allocated from the pool for DMA usage, and the length of the period, + * which is half of the sram_buf size. + */ + struct sg_table new_dma_sgt, new_mdma_sgt; + struct scatterlist *s, *_sgl; + dma_addr_t ddr_dma_buf; + u32 new_nents = 0, len; + int i; + + /* Count the number of entries needed */ + for_each_sg(sgl, s, nents, i) + if (sg_dma_len(s) > sram_period) + new_nents += DIV_ROUND_UP(sg_dma_len(s), sram_period); + else + new_nents++; + + /* Create sg table for STM32 DMA channel */ + ret = sg_alloc_table(&new_dma_sgt, new_nents, GFP_ATOMIC); + if (ret) + dev_err(dev, "DMA sg table alloc failed\n"); + + for_each_sg(new_dma_sgt.sgl, s, new_dma_sgt.nents, i) { + _sgl = sgl; + sg_dma_len(s) = min(sg_dma_len(_sgl), sram_period); + /* Targets the beginning = first half of the sram_buf */ + s->dma_address = sram_buf; + /* + * Targets the second half of the sram_buf + * for odd indexes of the item of the sg_list + */ + if (i & 1) + s->dma_address += sram_period; + } + + /* Create sg table for STM32 MDMA channel */ + ret = sg_alloc_table(&new_mdma_sgt, new_nents, GFP_ATOMIC); + if (ret) + dev_err(dev, "MDMA sg_table alloc failed\n"); + + _sgl = sgl; + len = sg_dma_len(sgl); + ddr_dma_buf = sg_dma_address(sgl); + for_each_sg(mdma_sgt.sgl, s, mdma_sgt.nents, i) { + size_t bytes = min_t(size_t, len, sram_period); + + sg_dma_len(s) = bytes; + sg_dma_address(s) = ddr_dma_buf; + len -= bytes; + + if (!len && sg_next(_sgl)) { + _sgl = sg_next(_sgl); + len = sg_dma_len(_sgl); + ddr_dma_buf = sg_dma_address(_sgl); + } else { + ddr_dma_buf += bytes; + } + } + + Don't forget to release these new sg_tables after getting the descriptors + with dmaengine_prep_slave_sg(). + + **1. Set controller specific parameters** + + First, use dmaengine_slave_config() with a struct dma_slave_config to + configure STM32 DMA channel. You just have to take care of DMA addresses, + the memory address (depending on the transfer direction) must point on your + SRAM buffer, and set (struct dma_slave_config).peripheral_size != 0. + + STM32 DMA driver will check (struct dma_slave_config).peripheral_size to + determine if chaining is being used or not. If it is used, then STM32 DMA + driver fills (struct dma_slave_config).peripheral_config with an array of + three u32 : the first one containing STM32 DMAMUX channel ID, the second one + the channel interrupt flag clear register address, and the third one the + channel Transfer Complete flag mask. + + Then, use dmaengine_slave_config with another struct dma_slave_config to + configure STM32 MDMA channel. Take care of DMA addresses, the device address + (depending on the transfer direction) must point on your SRAM buffer, and + the memory address must point to the buffer originally used for "classic" + DMA operation. Use the previous (struct dma_slave_config).peripheral_size + and .peripheral_config that have been updated by STM32 DMA driver, to set + (struct dma_slave_config).peripheral_size and .peripheral_config of the + struct dma_slave_config to configure STM32 MDMA channel. + :: + + struct dma_slave_config dma_conf; + struct dma_slave_config mdma_conf; + + memset(&dma_conf, 0, sizeof(dma_conf)); + [...] + config.direction = DMA_DEV_TO_MEM; + config.dst_addr = sram_dma_buf; // SRAM buffer + config.peripheral_size = 1; // peripheral_size != 0 => chaining + + dmaengine_slave_config(dma_chan, &dma_config); + + memset(&mdma_conf, 0, sizeof(mdma_conf)); + config.direction = DMA_DEV_TO_MEM; + mdma_conf.src_addr = sram_dma_buf; // SRAM buffer + mdma_conf.dst_addr = rx_dma_buf; // original memory buffer + mdma_conf.peripheral_size = dma_conf.peripheral_size; // <- dma_conf + mdma_conf.peripheral_config = dma_config.peripheral_config; // <- dma_conf + + dmaengine_slave_config(mdma_chan, &mdma_conf); + + **2. Get a descriptor for STM32 DMA channel transaction** + + In the same way you get your descriptor for your "classic" DMA operation, + you just have to replace the original sg_list (in case of + dmaengine_prep_slave_sg()) with the new sg_list using SRAM buffer, or to + replace the original buffer address, length and period (in case of + dmaengine_prep_dma_cyclic()) with the new SRAM buffer. + + **3. Get a descriptor for STM32 MDMA channel transaction** + + If you previously get descriptor (for STM32 DMA) with + + * dmaengine_prep_slave_sg(), then use dmaengine_prep_slave_sg() for + STM32 MDMA; + * dmaengine_prep_dma_cyclic(), then use dmaengine_prep_dma_cyclic() for + STM32 MDMA. + + Use the new sg_list using SRAM buffer (in case of dmaengine_prep_slave_sg()) + or, depending on the transfer direction, either the original DDR buffer (in + case of DMA_DEV_TO_MEM) or the SRAM buffer (in case of DMA_MEM_TO_DEV), the + source address being previously set with dmaengine_slave_config(). + + **4. Submit both transactions** + + Before submitting your transactions, you may need to define on which + descriptor you want a callback to be called at the end of the transfer + (dmaengine_prep_slave_sg()) or the period (dmaengine_prep_dma_cyclic()). + Depending on the direction, set the callback on the descriptor that finishes + the overal transfer: + + * DMA_DEV_TO_MEM: set the callback on the "MDMA" descriptor + * DMA_MEM_TO_DEV: set the callback on the "DMA" descriptor + + Then, submit the descriptors whatever the order, with dmaengine_tx_submit(). + + **5. Issue pending requests (and wait for callback notification)** + + As STM32 MDMA channel transfer is triggered by STM32 DMA, you must issue + STM32 MDMA channel before STM32 DMA channel. + + If any, your callback will be called to warn you about the end of the overal + transfer or the period completion. + + Don't forget to terminate both channels. STM32 DMA channel is configured in + cyclic Double-Buffer mode so it won't be disabled by HW, you need to terminate + it. STM32 MDMA channel will be stopped by HW in case of sg transfer, but not + in case of cyclic transfer. You can terminate it whatever the kind of transfer. + + **STM32 DMA-MDMA chaining DMA_MEM_TO_DEV special case** + + STM32 DMA-MDMA chaining in DMA_MEM_TO_DEV is a special case. Indeed, the + STM32 MDMA feeds the SRAM buffer with the DDR data, and the STM32 DMA reads + data from SRAM buffer. So some data (the first period) have to be copied in + SRAM buffer when the STM32 DMA starts to read. + + A trick could be pausing the STM32 DMA channel (that will raise a Transfer + Complete signal, triggering the STM32 MDMA channel), but the first data read + by the STM32 DMA could be "wrong". The proper way is to prepare the first SRAM + period with dmaengine_prep_dma_memcpy(). Then this first period should be + "removed" from the sg or the cyclic transfer. + + Due to this complexity, rather use the STM32 DMA-MDMA chaining for + DMA_DEV_TO_MEM and keep the "classic" DMA usage for DMA_MEM_TO_DEV, unless + you're not afraid. + +Resources +--------- + + Application note, datasheet and reference manual are available on ST website + (STM32MP1_). + + Dedicated focus on three application notes (AN5224_, AN4031_ & AN5001_) + dealing with STM32 DMAMUX, STM32 DMA and STM32 MDMA. + +.. _STM32MP1: https://www.st.com/en/microcontrollers-microprocessors/stm32mp1-series.html +.. _AN5224: https://www.st.com/resource/en/application_note/an5224-stm32-dmamux-the-dma-request-router-stmicroelectronics.pdf +.. _AN4031: https://www.st.com/resource/en/application_note/dm00046011-using-the-stm32f2-stm32f4-and-stm32f7-series-dma-controller-stmicroelectronics.pdf +.. _AN5001: https://www.st.com/resource/en/application_note/an5001-stm32cube-expansion-package-for-stm32h7-series-mdma-stmicroelectronics.pdf + +:Authors: + +- Amelie Delaunay \ No newline at end of file diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index bdc8c129c4f5..3b1e667f7ea0 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -49,6 +49,13 @@ properties: in an interrupts-extended list the disconnected positions will contain an empty phandle reference <0>. + iommus: + minItems: 1 + maxItems: 2 + + power-domains: + maxItems: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/dma/arm,pl330.yaml b/Documentation/devicetree/bindings/dma/arm,pl330.yaml index 2bec69b308f8..4a3dd6f5309b 100644 --- a/Documentation/devicetree/bindings/dma/arm,pl330.yaml +++ b/Documentation/devicetree/bindings/dma/arm,pl330.yaml @@ -55,6 +55,12 @@ properties: dma-coherent: true + iommus: + minItems: 1 + maxItems: 9 + description: Up to 1 IOMMU entry per DMA channel for writes and 1 + IOMMU entry for reads. + power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/dma/mediatek,uart-dma.yaml b/Documentation/devicetree/bindings/dma/mediatek,uart-dma.yaml index 19ea8dcbcbce..9ab4d81ead35 100644 --- a/Documentation/devicetree/bindings/dma/mediatek,uart-dma.yaml +++ b/Documentation/devicetree/bindings/dma/mediatek,uart-dma.yaml @@ -22,6 +22,7 @@ properties: - items: - enum: - mediatek,mt2712-uart-dma + - mediatek,mt6795-uart-dma - mediatek,mt8365-uart-dma - mediatek,mt8516-uart-dma - const: mediatek,mt6577-uart-dma diff --git a/Documentation/devicetree/bindings/dma/qcom,adm.yaml b/Documentation/devicetree/bindings/dma/qcom,adm.yaml new file mode 100644 index 000000000000..6a9d7bc74aff --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom,adm.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/qcom,adm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm ADM DMA Controller + +maintainers: + - Christian Marangi + - Bjorn Andersson + +description: | + QCOM ADM DMA controller provides DMA capabilities for + peripheral buses such as NAND and SPI. + +properties: + compatible: + const: qcom,adm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#dma-cells": + const: 1 + + clocks: + items: + - description: phandle to the core clock + - description: phandle to the iface clock + + clock-names: + items: + - const: core + - const: iface + + resets: + items: + - description: phandle to the clk reset + - description: phandle to the pbus reset + - description: phandle to the c0 reset + - description: phandle to the c1 reset + - description: phandle to the c2 reset + + reset-names: + items: + - const: clk + - const: pbus + - const: c0 + - const: c1 + - const: c2 + + qcom,ee: + $ref: /schemas/types.yaml#/definitions/uint32 + description: indicates the security domain identifier used in the secure world. + minimum: 0 + maximum: 255 + +required: + - compatible + - reg + - interrupts + - "#dma-cells" + - clocks + - clock-names + - resets + - reset-names + - qcom,ee + +additionalProperties: false + +examples: + - | + #include + #include + + adm_dma: dma-controller@18300000 { + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; + #dma-cells = <1>; + + clocks = <&gcc ADM0_CLK>, + <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; + + resets = <&gcc ADM0_RESET>, + <&gcc ADM0_PBUS_RESET>, + <&gcc ADM0_C0_RESET>, + <&gcc ADM0_C1_RESET>, + <&gcc ADM0_C2_RESET>; + reset-names = "clk", "pbus", "c0", "c1", "c2"; + qcom,ee = <0>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml index 9bf3a1b164f1..003098caf709 100644 --- a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml @@ -8,7 +8,7 @@ title: Qualcomm Technologies Inc BAM DMA controller maintainers: - Andy Gross - - Bjorn Andersson + - Bjorn Andersson allOf: - $ref: "dma-controller.yaml#" @@ -20,7 +20,7 @@ properties: - qcom,bam-v1.3.0 # MSM8974, APQ8074 and APQ8084 - qcom,bam-v1.4.0 - # MSM8916 + # MSM8916 and SDM845 - qcom,bam-v1.7.0 clocks: @@ -90,8 +90,8 @@ examples: dma-controller@f9944000 { compatible = "qcom,bam-v1.4.0"; - reg = <0xf9944000 0x15000>; - interrupts = ; + reg = <0xf9944000 0x19000>; + interrupts = ; clocks = <&gcc GCC_BLSP2_AHB_CLK>; clock-names = "bam_clk"; #dma-cells = <1>; diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml index 7d2fc4eb5530..eabf8a76d3a0 100644 --- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml @@ -21,6 +21,7 @@ properties: enum: - qcom,sc7280-gpi-dma - qcom,sdm845-gpi-dma + - qcom,sm6350-gpi-dma - qcom,sm8150-gpi-dma - qcom,sm8250-gpi-dma - qcom,sm8350-gpi-dma diff --git a/Documentation/devicetree/bindings/dma/qcom_adm.txt b/Documentation/devicetree/bindings/dma/qcom_adm.txt deleted file mode 100644 index 9d3b2f917b7b..000000000000 --- a/Documentation/devicetree/bindings/dma/qcom_adm.txt +++ /dev/null @@ -1,61 +0,0 @@ -QCOM ADM DMA Controller - -Required properties: -- compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 -- reg: Address range for DMA registers -- interrupts: Should contain one interrupt shared by all channels -- #dma-cells: must be <2>. First cell denotes the channel number. Second cell - denotes CRCI (client rate control interface) flow control assignment. -- clocks: Should contain the core clock and interface clock. -- clock-names: Must contain "core" for the core clock and "iface" for the - interface clock. -- resets: Must contain an entry for each entry in reset names. -- reset-names: Must include the following entries: - - clk - - c0 - - c1 - - c2 -- qcom,ee: indicates the security domain identifier used in the secure world. - -Example: - adm_dma: dma@18300000 { - compatible = "qcom,adm"; - reg = <0x18300000 0x100000>; - interrupts = <0 170 0>; - #dma-cells = <2>; - - clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; - clock-names = "core", "iface"; - - resets = <&gcc ADM0_RESET>, - <&gcc ADM0_C0_RESET>, - <&gcc ADM0_C1_RESET>, - <&gcc ADM0_C2_RESET>; - reset-names = "clk", "c0", "c1", "c2"; - qcom,ee = <0>; - }; - -DMA clients must use the format descripted in the dma.txt file, using a three -cell specifier for each channel. - -Each dmas request consists of 3 cells: - 1. phandle pointing to the DMA controller - 2. channel number - 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. - The CRCI is used for flow control. It identifies the peripheral device that - is the source/destination for the transferred data. - -Example: - - spi4: spi@1a280000 { - spi-max-frequency = <50000000>; - - pinctrl-0 = <&spi_pins>; - pinctrl-names = "default"; - - cs-gpios = <&qcom_pinmux 20 0>; - - dmas = <&adm_dma 6 9>, - <&adm_dma 5 10>; - dma-names = "rx", "tx"; - }; diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml index 7202cd68e759..89b591a05bce 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.yaml @@ -45,6 +45,7 @@ properties: - enum: - renesas,dmac-r8a779a0 # R-Car V3U - renesas,dmac-r8a779f0 # R-Car S4-8 + - renesas,dmac-r8a779g0 # R-Car V4H - const: renesas,rcar-gen4-dmac # R-Car Gen4 reg: true diff --git a/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt index b849a1ed389d..47e477cce6d2 100644 --- a/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt +++ b/Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt @@ -4,7 +4,7 @@ Required properties: - compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar "ti,am335x-edma-crossbar" for AM335x and AM437x - reg: Memory map for accessing module -- #dma-cells: Should be set to to match with the DMA controller's dma-cells +- #dma-cells: Should be set to match with the DMA controller's dma-cells for ti,dra7-dma-crossbar and <3> for ti,am335x-edma-crossbar. - dma-requests: Number of DMA requests the crossbar can receive - dma-masters: phandle pointing to the DMA controller diff --git a/Documentation/devicetree/bindings/mfd/atmel-usart.txt b/Documentation/devicetree/bindings/mfd/atmel-usart.txt deleted file mode 100644 index a09133066aff..000000000000 --- a/Documentation/devicetree/bindings/mfd/atmel-usart.txt +++ /dev/null @@ -1,98 +0,0 @@ -* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) - -Required properties for USART: -- compatible: Should be one of the following: - - "atmel,at91rm9200-usart" - - "atmel,at91sam9260-usart" - - "microchip,sam9x60-usart" - - "atmel,at91rm9200-dbgu", "atmel,at91rm9200-usart" - - "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart" - - "microchip,sam9x60-dbgu", "microchip,sam9x60-usart" -- reg: Should contain registers location and length -- interrupts: Should contain interrupt -- clock-names: tuple listing input clock names. - Required elements: "usart" -- clocks: phandles to input clocks. - -Required properties for USART in SPI mode: -- #size-cells : Must be <0> -- #address-cells : Must be <1> -- cs-gpios: chipselects (internal cs not supported) -- atmel,usart-mode : Must be (found in dt-bindings/mfd/at91-usart.h) - -Optional properties in serial and SPI mode: -- dma bindings for dma transfer: - - dmas: DMA specifier, consisting of a phandle to DMA controller node, - memory peripheral interface and USART DMA channel ID, FIFO configuration. - The order of DMA channels is fixed. The first DMA channel must be TX - associated channel and the second one must be RX associated channel. - Refer to dma.txt and atmel-dma.txt for details. - - dma-names: "tx" for TX channel. - "rx" for RX channel. - The order of dma-names is also fixed. The first name must be "tx" - and the second one must be "rx" as in the examples below. - -Optional properties in serial mode: -- atmel,use-dma-rx: use of PDC or DMA for receiving data -- atmel,use-dma-tx: use of PDC or DMA for transmitting data -- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively. - It will use specified PIO instead of the peripheral function pin for the USART feature. - If unsure, don't specify this property. -- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO - capable USARTs. -- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt - - compatible description: -- at91rm9200: legacy USART support -- at91sam9260: generic USART implementation for SAM9 SoCs - -Example: -- use PDC: - usart0: serial@fff8c000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfff8c000 0x4000>; - interrupts = <7>; - clocks = <&usart0_clk>; - clock-names = "usart"; - atmel,use-dma-rx; - atmel,use-dma-tx; - rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>; - cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>; - dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>; - dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>; - dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>; - rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>; - }; - -- use DMA: - usart0: serial@f001c000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xf001c000 0x100>; - interrupts = <12 4 5>; - clocks = <&usart0_clk>; - clock-names = "usart"; - atmel,use-dma-rx; - atmel,use-dma-tx; - dmas = <&dma0 2 0x3>, - <&dma0 2 0x204>; - dma-names = "tx", "rx"; - atmel,fifo-size = <32>; - }; - -- SPI mode: - #include - - spi0: spi@f001c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "atmel,at91rm9200-usart", "atmel,at91sam9260-usart"; - atmel,usart-mode = ; - reg = <0xf001c000 0x100>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>; - clocks = <&usart0_clk>; - clock-names = "usart"; - dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>, - <&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>; - dma-names = "tx", "rx"; - cs-gpios = <&pioB 3 0>; - }; diff --git a/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml b/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml index 73cffc45e056..782ce2f8a5df 100644 --- a/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml +++ b/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml @@ -54,6 +54,12 @@ patternProperties: description: Clock provider for TI EHRPWM nodes. + "phy@[0-9a-f]+$": + type: object + $ref: /schemas/phy/ti,phy-gmii-sel.yaml# + description: + The phy node corresponding to the ethernet MAC. + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.yaml index 045699c65779..808e90b2465d 100644 --- a/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.yaml @@ -32,6 +32,7 @@ properties: patternProperties: "^pcie-phy@[0-9]+$": type: object + additionalProperties: false description: > PCIe PHY child nodes diff --git a/Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml b/Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml index 07be031d82e6..d24ec47c038e 100644 --- a/Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml +++ b/Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Cadence DPHY Rx Device Tree Bindings maintainers: - - Pratyush Yadav + - Pratyush Yadav properties: compatible: diff --git a/Documentation/devicetree/bindings/phy/cdns,dphy.yaml b/Documentation/devicetree/bindings/phy/cdns,dphy.yaml index f0e9ca8427bb..649e0b953df0 100644 --- a/Documentation/devicetree/bindings/phy/cdns,dphy.yaml +++ b/Documentation/devicetree/bindings/phy/cdns,dphy.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Cadence DPHY Device Tree Bindings maintainers: - - Pratyush Yadav + - Pratyush Yadav properties: compatible: diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index b3e409988c17..e0754fb44451 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -163,6 +163,7 @@ patternProperties: - PHY_TYPE_USB3 - PHY_TYPE_PCIE - PHY_TYPE_SATA + - PHY_TYPE_SGMII nvmem-cells: items: @@ -218,6 +219,16 @@ patternProperties: minimum: 1 maximum: 15 + mediatek,pre-emphasis: + description: + The level of pre-emphasis which used to widen the eye opening and + boost eye swing, the unit step is about 4.16% increment; e.g. the + level 1 means amplitude increases about 4.16%, the level 2 is about + 8.3% etc. (U2 phy) + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 3 + mediatek,bc12: description: Specify the flag to enable BC1.2 if support it diff --git a/Documentation/devicetree/bindings/phy/mscc,vsc7514-serdes.yaml b/Documentation/devicetree/bindings/phy/mscc,vsc7514-serdes.yaml new file mode 100644 index 000000000000..3169b873231e --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mscc,vsc7514-serdes.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/mscc,vsc7514-serdes.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microsemi Ocelot SerDes muxing + +maintainers: + - Alexandre Belloni + - UNGLinuxDriver@microchip.com + +description: | + On Microsemi Ocelot, there is a handful of registers in HSIO address + space for setting up the SerDes to switch port muxing. + + A SerDes X can be "muxed" to work with switch port Y or Z for example. + One specific SerDes can also be used as a PCIe interface. + + Hence, a SerDes represents an interface, be it an Ethernet or a PCIe one. + + There are two kinds of SerDes: SERDES1G supports 10/100Mbps in + half/full-duplex and 1000Mbps in full-duplex mode while SERDES6G supports + 10/100Mbps in half/full-duplex and 1000/2500Mbps in full-duplex mode. + + Also, SERDES6G number (aka "macro") 0 is the only interface supporting + QSGMII. + + This is a child of the HSIO syscon ("mscc,ocelot-hsio", see + Documentation/devicetree/bindings/mips/mscc.txt) on the Microsemi Ocelot. + +properties: + compatible: + enum: + - mscc,vsc7514-serdes + + "#phy-cells": + const: 2 + description: | + The first number defines the input port to use for a given SerDes macro. + The second defines the macro to use. They are defined in + dt-bindings/phy/phy-ocelot-serdes.h + +required: + - compatible + - "#phy-cells" + +additionalProperties: + false + +examples: + - | + serdes: serdes { + compatible = "mscc,vsc7514-serdes"; + #phy-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt index c9e392c64a7c..70c813b0755f 100644 --- a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt @@ -15,10 +15,10 @@ Required properties: - fsl,anatop: phandle for anatop register, it is only for imx6 SoC series Optional properties: -- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable +- fsl,tx-cal-45-dn-ohms: Integer [35-54]. Resistance (in ohms) of switchable high-speed trimming resistor connected in parallel with the 45 ohm resistor that terminates the DN output signal. Default: 45 -- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable +- fsl,tx-cal-45-dp-ohms: Integer [35-54]. Resistance (in ohms) of switchable high-speed trimming resistor connected in parallel with the 45 ohm resistor that terminates the DP output signal. Default: 45 - fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of diff --git a/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt b/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt deleted file mode 100644 index 332219860187..000000000000 --- a/Documentation/devicetree/bindings/phy/phy-ocelot-serdes.txt +++ /dev/null @@ -1,43 +0,0 @@ -Microsemi Ocelot SerDes muxing driver -------------------------------------- - -On Microsemi Ocelot, there is a handful of registers in HSIO address -space for setting up the SerDes to switch port muxing. - -A SerDes X can be "muxed" to work with switch port Y or Z for example. -One specific SerDes can also be used as a PCIe interface. - -Hence, a SerDes represents an interface, be it an Ethernet or a PCIe one. - -There are two kinds of SerDes: SERDES1G supports 10/100Mbps in -half/full-duplex and 1000Mbps in full-duplex mode while SERDES6G supports -10/100Mbps in half/full-duplex and 1000/2500Mbps in full-duplex mode. - -Also, SERDES6G number (aka "macro") 0 is the only interface supporting -QSGMII. - -This is a child of the HSIO syscon ("mscc,ocelot-hsio", see -Documentation/devicetree/bindings/mips/mscc.txt) on the Microsemi Ocelot. - -Required properties: - -- compatible: should be "mscc,vsc7514-serdes" -- #phy-cells : from the generic phy bindings, must be 2. - The first number defines the input port to use for a given - SerDes macro. The second defines the macro to use. They are - defined in dt-bindings/phy/phy-ocelot-serdes.h - -Example: - - serdes: serdes { - compatible = "mscc,vsc7514-serdes"; - #phy-cells = <2>; - }; - - ethernet { - port1 { - phy-handle = <&phy_foo>; - /* Link SERDES1G_5 to port1 */ - phys = <&serdes 1 SERDES1G_5>; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml index 4b75289735eb..f71920082fa3 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.yaml @@ -13,6 +13,7 @@ properties: compatible: enum: - rockchip,px30-usb2phy + - rockchip,rk3128-usb2phy - rockchip,rk3228-usb2phy - rockchip,rk3308-usb2phy - rockchip,rk3328-usb2phy diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml index dc287d428e49..801993813b18 100644 --- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml +++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml @@ -77,6 +77,8 @@ patternProperties: connector: type: object $ref: /schemas/connector/usb-connector.yaml + unevaluatedProperties: false + properties: vbus-supply: true diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index cf9e9b8011cb..1e104ae76ee6 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -19,6 +19,8 @@ properties: enum: - qcom,sc7280-edp-phy - qcom,sc8180x-edp-phy + - qcom,sc8280xp-dp-phy + - qcom,sc8280xp-edp-phy reg: items: diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-pcie-phy.yaml new file mode 100644 index 000000000000..4e710ef75523 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-pcie-phy.yaml @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,msm8996-qmp-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP PHY controller (MSM8996 PCIe) + +maintainers: + - Vinod Koul + +description: + QMP PHY controller supports physical layer functionality for a number of + controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. + +properties: + compatible: + const: qcom,msm8996-qmp-pcie-phy + + reg: + items: + - description: serdes + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + + ranges: true + + clocks: + maxItems: 3 + + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + + resets: + maxItems: 3 + + reset-names: + items: + - const: phy + - const: common + - const: cfg + + vdda-phy-supply: true + + vdda-pll-supply: true + + vddp-ref-clk-supply: true + +patternProperties: + "^phy@[0-9a-f]+$": + type: object + description: one child node per PHY provided by this block + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + + clocks: + items: + - description: PIPE clock + + clock-names: + deprecated: true + items: + - enum: + - pipe0 + - pipe1 + - pipe2 + + resets: + items: + - description: PHY reset + + reset-names: + deprecated: true + items: + - enum: + - lane0 + - lane1 + - lane2 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + + "#phy-cells": + const: 0 + + required: + - reg + - clocks + - resets + - "#clock-cells" + - clock-output-names + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + +additionalProperties: false + +examples: + - | + #include + pcie_phy: phy-wrapper@34000 { + compatible = "qcom,msm8996-qmp-pcie-phy"; + reg = <0x34000 0x488>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x34000 0x4000>; + + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_PHY_CFG_AHB_CLK>, + <&gcc GCC_PCIE_CLKREF_CLK>; + clock-names = "aux", "cfg_ahb", "ref"; + + resets = <&gcc GCC_PCIE_PHY_BCR>, + <&gcc GCC_PCIE_PHY_COM_BCR>, + <&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>; + reset-names = "phy", "common", "cfg"; + + vdda-phy-supply = <&vreg_l28a_0p925>; + vdda-pll-supply = <&vreg_l12a_1p8>; + + pciephy_0: phy@1000 { + reg = <0x1000 0x130>, + <0x1200 0x200>, + <0x1400 0x1dc>; + + clocks = <&gcc GCC_PCIE_0_PIPE_CLK>; + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + + #clock-cells = <0>; + clock-output-names = "pcie_0_pipe_clk_src"; + + #phy-cells = <0>; + }; + + pciephy_1: phy@2000 { + reg = <0x2000 0x130>, + <0x2200 0x200>, + <0x2400 0x1dc>; + + clocks = <&gcc GCC_PCIE_1_PIPE_CLK>; + resets = <&gcc GCC_PCIE_1_PHY_BCR>; + + #clock-cells = <0>; + clock-output-names = "pcie_1_pipe_clk_src"; + + #phy-cells = <0>; + }; + + pciephy_2: phy@3000 { + reg = <0x3000 0x130>, + <0x3200 0x200>, + <0x3400 0x1dc>; + + clocks = <&gcc GCC_PCIE_2_PIPE_CLK>; + resets = <&gcc GCC_PCIE_2_PHY_BCR>; + + #clock-cells = <0>; + clock-output-names = "pcie_2_pipe_clk_src"; + + #phy-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml new file mode 100644 index 000000000000..324ad7d03a38 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-pcie-phy.yaml @@ -0,0 +1,296 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,qmp-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP PHY controller (PCIe) + +maintainers: + - Vinod Koul + +description: + QMP PHY controller supports physical layer functionality for a number of + controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. + +properties: + compatible: + enum: + - qcom,ipq6018-qmp-pcie-phy + - qcom,ipq8074-qmp-gen3-pcie-phy + - qcom,ipq8074-qmp-pcie-phy + - qcom,msm8998-qmp-pcie-phy + - qcom,sc8180x-qmp-pcie-phy + - qcom,sdm845-qhp-pcie-phy + - qcom,sdm845-qmp-pcie-phy + - qcom,sdx55-qmp-pcie-phy + - qcom,sm8250-qmp-gen3x1-pcie-phy + - qcom,sm8250-qmp-gen3x2-pcie-phy + - qcom,sm8250-qmp-modem-pcie-phy + - qcom,sm8450-qmp-gen3x1-pcie-phy + - qcom,sm8450-qmp-gen4x2-pcie-phy + + reg: + items: + - description: serdes + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + + ranges: true + + clocks: + minItems: 2 + maxItems: 4 + + clock-names: + minItems: 2 + maxItems: 4 + + resets: + minItems: 1 + maxItems: 2 + + reset-names: + minItems: 1 + maxItems: 2 + + vdda-phy-supply: true + + vdda-pll-supply: true + + vddp-ref-clk-supply: true + +patternProperties: + "^phy@[0-9a-f]+$": + type: object + description: single PHY-provider child node + properties: + reg: + minItems: 3 + maxItems: 6 + + clocks: + items: + - description: PIPE clock + + clock-names: + deprecated: true + items: + - const: pipe0 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + + "#phy-cells": + const: 0 + + required: + - reg + - clocks + - "#clock-cells" + - clock-output-names + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + - clock-names + - resets + - reset-names + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-pcie-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + required: + - vdda-phy-supply + - vdda-pll-supply + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq6018-qmp-pcie-phy + - qcom,ipq8074-qmp-gen3-pcie-phy + - qcom,ipq8074-qmp-pcie-phy + then: + properties: + clocks: + maxItems: 2 + clock-names: + items: + - const: aux + - const: cfg_ahb + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8180x-qmp-pcie-phy + - qcom,sdm845-qhp-pcie-phy + - qcom,sdm845-qmp-pcie-phy + - qcom,sdx55-qmp-pcie-phy + - qcom,sm8250-qmp-gen3x1-pcie-phy + - qcom,sm8250-qmp-gen3x2-pcie-phy + - qcom,sm8250-qmp-modem-pcie-phy + - qcom,sm8450-qmp-gen3x1-pcie-phy + - qcom,sm8450-qmp-gen4x2-pcie-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + - const: refgen + resets: + maxItems: 1 + reset-names: + items: + - const: phy + required: + - vdda-phy-supply + - vdda-pll-supply + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8250-qmp-gen3x2-pcie-phy + - qcom,sm8250-qmp-modem-pcie-phy + - qcom,sm8450-qmp-gen4x2-pcie-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX lane 1 + - description: RX lane 1 + - description: PCS + - description: TX lane 2 + - description: RX lane 2 + - description: PCS_MISC + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8180x-qmp-pcie-phy + - qcom,sdm845-qmp-pcie-phy + - qcom,sdx55-qmp-pcie-phy + - qcom,sm8250-qmp-gen3x1-pcie-phy + - qcom,sm8450-qmp-gen3x1-pcie-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + - description: PCS_MISC + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq6018-qmp-pcie-phy + - qcom,ipq8074-qmp-pcie-phy + - qcom,msm8998-qmp-pcie-phy + - qcom,sdm845-qhp-pcie-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + +examples: + - | + #include + phy-wrapper@1c0e000 { + compatible = "qcom,sm8250-qmp-gen3x2-pcie-phy"; + reg = <0x01c0e000 0x1c0>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x01c0e000 0x1000>; + + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_WIGIG_CLKREF_EN>, + <&gcc GCC_PCIE1_PHY_REFGEN_CLK>; + clock-names = "aux", "cfg_ahb", "ref", "refgen"; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>; + reset-names = "phy"; + + vdda-phy-supply = <&vreg_l10c_0p88>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + phy@200 { + reg = <0x200 0x170>, + <0x400 0x200>, + <0xa00 0x1f0>, + <0x600 0x170>, + <0x800 0x200>, + <0xe00 0xf4>; + + clocks = <&gcc GCC_PCIE_1_PIPE_CLK>; + + #clock-cells = <0>; + clock-output-names = "pcie_1_pipe_clk"; + + #phy-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml deleted file mode 100644 index 220788ce215f..000000000000 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ /dev/null @@ -1,502 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) - -%YAML 1.2 ---- -$id: "http://devicetree.org/schemas/phy/qcom,qmp-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" - -title: Qualcomm QMP PHY controller - -maintainers: - - Vinod Koul - -description: - QMP phy controller supports physical layer functionality for a number of - controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. - -properties: - compatible: - enum: - - qcom,ipq6018-qmp-pcie-phy - - qcom,ipq6018-qmp-usb3-phy - - qcom,ipq8074-qmp-gen3-pcie-phy - - qcom,ipq8074-qmp-pcie-phy - - qcom,ipq8074-qmp-usb3-phy - - qcom,msm8996-qmp-pcie-phy - - qcom,msm8996-qmp-ufs-phy - - qcom,msm8996-qmp-usb3-phy - - qcom,msm8998-qmp-pcie-phy - - qcom,msm8998-qmp-ufs-phy - - qcom,msm8998-qmp-usb3-phy - - qcom,qcm2290-qmp-usb3-phy - - qcom,sc7180-qmp-usb3-phy - - qcom,sc8180x-qmp-pcie-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sc8180x-qmp-usb3-phy - - qcom,sc8280xp-qmp-ufs-phy - - qcom,sdm845-qhp-pcie-phy - - qcom,sdm845-qmp-pcie-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sdm845-qmp-usb3-phy - - qcom,sdm845-qmp-usb3-uni-phy - - qcom,sm6115-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8150-qmp-usb3-phy - - qcom,sm8150-qmp-usb3-uni-phy - - qcom,sm8250-qmp-ufs-phy - - qcom,sm8250-qmp-gen3x1-pcie-phy - - qcom,sm8250-qmp-gen3x2-pcie-phy - - qcom,sm8250-qmp-modem-pcie-phy - - qcom,sm8250-qmp-usb3-phy - - qcom,sm8250-qmp-usb3-uni-phy - - qcom,sm8350-qmp-ufs-phy - - qcom,sm8350-qmp-usb3-phy - - qcom,sm8350-qmp-usb3-uni-phy - - qcom,sm8450-qmp-gen3x1-pcie-phy - - qcom,sm8450-qmp-gen4x2-pcie-phy - - qcom,sm8450-qmp-ufs-phy - - qcom,sm8450-qmp-usb3-phy - - qcom,sdx55-qmp-pcie-phy - - qcom,sdx55-qmp-usb3-uni-phy - - qcom,sdx65-qmp-usb3-uni-phy - - reg: - minItems: 1 - items: - - description: Address and length of PHY's common serdes block. - - description: Address and length of PHY's DP_COM control block. - - "#clock-cells": - enum: [ 1, 2 ] - - "#address-cells": - enum: [ 1, 2 ] - - "#size-cells": - enum: [ 1, 2 ] - - ranges: true - - clocks: - minItems: 1 - maxItems: 4 - - clock-names: - minItems: 1 - maxItems: 4 - - resets: - minItems: 1 - maxItems: 3 - - reset-names: - minItems: 1 - maxItems: 3 - - vdda-phy-supply: - description: - Phandle to a regulator supply to PHY core block. - - vdda-pll-supply: - description: - Phandle to 1.8V regulator supply to PHY refclk pll block. - - vddp-ref-clk-supply: - description: - Phandle to a regulator supply to any specific refclk pll block. - -#Required nodes: -patternProperties: - "^phy@[0-9a-f]+$": - type: object - description: - Each device node of QMP phy is required to have as many child nodes as - the number of lanes the PHY has. - -required: - - compatible - - reg - - "#clock-cells" - - "#address-cells" - - "#size-cells" - - ranges - - clocks - - clock-names - - resets - - reset-names - -additionalProperties: false - -allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,sdm845-qmp-usb3-uni-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - - description: 19.2 MHz ref clk. - - description: Phy common block aux clock. - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - - const: com_aux - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,sdx55-qmp-usb3-uni-phy - - qcom,sdx65-qmp-usb3-uni-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - - description: 19.2 MHz ref clk. - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-qmp-pcie-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - - description: 19.2 MHz ref clk. - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - - description: phy's ahb cfg block reset. - reset-names: - items: - - const: phy - - const: common - - const: cfg - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,ipq8074-qmp-usb3-phy - - qcom,msm8996-qmp-usb3-phy - - qcom,msm8998-qmp-pcie-phy - - qcom,msm8998-qmp-usb3-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - - description: 19.2 MHz ref clk. - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-qmp-ufs-phy - then: - properties: - clocks: - items: - - description: 19.2 MHz ref clk. - clock-names: - items: - - const: ref - resets: - items: - - description: PHY reset in the UFS controller. - reset-names: - items: - - const: ufsphy - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8998-qmp-ufs-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8250-qmp-ufs-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sc8280xp-qmp-ufs-phy - then: - properties: - clocks: - items: - - description: 19.2 MHz ref clk. - - description: Phy reference aux clock. - clock-names: - items: - - const: ref - - const: ref_aux - resets: - items: - - description: PHY reset in the UFS controller. - reset-names: - items: - - const: ufsphy - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,ipq6018-qmp-pcie-phy - - qcom,ipq8074-qmp-gen3-pcie-phy - - qcom,ipq8074-qmp-pcie-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - clock-names: - items: - - const: aux - - const: cfg_ahb - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - - if: - properties: - compatible: - contains: - enum: - - qcom,sc8180x-qmp-pcie-phy - - qcom,sdm845-qhp-pcie-phy - - qcom,sdm845-qmp-pcie-phy - - qcom,sdx55-qmp-pcie-phy - - qcom,sm8250-qmp-gen3x1-pcie-phy - - qcom,sm8250-qmp-gen3x2-pcie-phy - - qcom,sm8250-qmp-modem-pcie-phy - - qcom,sm8450-qmp-gen3x1-pcie-phy - - qcom,sm8450-qmp-gen4x2-pcie-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: Phy config clock. - - description: 19.2 MHz ref clk. - - description: Phy refgen clk. - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - - const: refgen - resets: - items: - - description: reset of phy block. - reset-names: - items: - - const: phy - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,sm8150-qmp-usb3-phy - - qcom,sm8150-qmp-usb3-uni-phy - - qcom,sm8250-qmp-usb3-uni-phy - - qcom,sm8350-qmp-usb3-uni-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: 19.2 MHz ref clk source. - - description: 19.2 MHz ref clk. - - description: Phy common block aux clock. - clock-names: - items: - - const: aux - - const: ref_clk_src - - const: ref - - const: com_aux - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,sm8250-qmp-usb3-phy - - qcom,sm8350-qmp-usb3-phy - then: - properties: - clocks: - items: - - description: Phy aux clock. - - description: 19.2 MHz ref clk. - - description: Phy common block aux clock. - clock-names: - items: - - const: aux - - const: ref_clk_src - - const: com_aux - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - reset-names: - items: - - const: phy - - const: common - required: - - vdda-phy-supply - - vdda-pll-supply - - if: - properties: - compatible: - contains: - enum: - - qcom,qcm2290-qmp-usb3-phy - then: - properties: - clocks: - items: - - description: Phy config clock. - - description: 19.2 MHz ref clk. - - description: Phy common block aux clock. - clock-names: - items: - - const: cfg_ahb - - const: ref - - const: com_aux - resets: - items: - - description: phy_phy reset. - - description: reset of phy block. - reset-names: - items: - - const: phy_phy - - const: phy - required: - - vdda-phy-supply - - vdda-pll-supply - -examples: - - | - #include - usb_2_qmpphy: phy-wrapper@88eb000 { - compatible = "qcom,sdm845-qmp-usb3-uni-phy"; - reg = <0x088eb000 0x18c>; - #clock-cells = <1>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x088eb000 0x2000>; - - clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK >, - <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_SEC_CLKREF_CLK>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "cfg_ahb", "ref", "com_aux"; - - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; - - vdda-phy-supply = <&vdda_usb2_ss_1p2>; - vdda-pll-supply = <&vdda_usb2_ss_core>; - - usb_2_ssphy: phy@200 { - reg = <0x200 0x128>, - <0x400 0x1fc>, - <0x800 0x218>, - <0x600 0x70>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml new file mode 100644 index 000000000000..815c375d0f7b --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-ufs-phy.yaml @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,qmp-ufs-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP PHY controller (UFS) + +maintainers: + - Vinod Koul + +description: + QMP PHY controller supports physical layer functionality for a number of + controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. + +properties: + compatible: + enum: + - qcom,msm8996-qmp-ufs-phy + - qcom,msm8998-qmp-ufs-phy + - qcom,sc8180x-qmp-ufs-phy + - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + - qcom,sm8350-qmp-ufs-phy + - qcom,sm8450-qmp-ufs-phy + + reg: + items: + - description: serdes + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + + ranges: true + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + items: + - const: ufsphy + + vdda-phy-supply: true + + vdda-pll-supply: true + + vddp-ref-clk-supply: true + +patternProperties: + "^phy@[0-9a-f]+$": + type: object + description: single PHY-provider child node + properties: + reg: + minItems: 3 + maxItems: 6 + + "#phy-cells": + const: 0 + + required: + - reg + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-qmp-ufs-phy + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: ref + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-ufs-phy + - qcom,sc8180x-qmp-ufs-phy + - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + then: + properties: + clocks: + maxItems: 2 + clock-names: + items: + - const: ref + - const: ref_aux + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8450-qmp-ufs-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: ref + - const: ref_aux + - const: qref + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-ufs-phy + - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + - qcom,sm8350-qmp-ufs-phy + - qcom,sm8450-qmp-ufs-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX lane 1 + - description: RX lane 1 + - description: PCS + - description: TX lane 2 + - description: RX lane 2 + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8180x-qmp-ufs-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + - description: PCS_MISC + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + +examples: + - | + #include + #include + phy-wrapper@1d87000 { + compatible = "qcom,sc8280xp-qmp-ufs-phy"; + reg = <0x01d87000 0xe10>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x01d87000 0x1000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + clock-names = "ref", "ref_aux"; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + vdda-phy-supply = <&vreg_l6b>; + vdda-pll-supply = <&vreg_l3b>; + + phy@400 { + reg = <0x400 0x108>, + <0x600 0x1e0>, + <0xc00 0x1dc>, + <0x800 0x108>, + <0xa00 0x1e0>; + #phy-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml new file mode 100644 index 000000000000..7acb4b7de7f9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb-phy.yaml @@ -0,0 +1,401 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/qcom,qmp-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QMP PHY controller (USB) + +maintainers: + - Vinod Koul + +description: + QMP PHY controller supports physical layer functionality for a number of + controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. + +properties: + compatible: + enum: + - qcom,ipq6018-qmp-usb3-phy + - qcom,ipq8074-qmp-usb3-phy + - qcom,msm8996-qmp-usb3-phy + - qcom,msm8998-qmp-usb3-phy + - qcom,qcm2290-qmp-usb3-phy + - qcom,sc7180-qmp-usb3-phy + - qcom,sc8180x-qmp-usb3-phy + - qcom,sc8280xp-qmp-usb3-uni-phy + - qcom,sdm845-qmp-usb3-phy + - qcom,sdm845-qmp-usb3-uni-phy + - qcom,sdx55-qmp-usb3-uni-phy + - qcom,sdx65-qmp-usb3-uni-phy + - qcom,sm8150-qmp-usb3-phy + - qcom,sm8150-qmp-usb3-uni-phy + - qcom,sm8250-qmp-usb3-phy + - qcom,sm8250-qmp-usb3-uni-phy + - qcom,sm8350-qmp-usb3-phy + - qcom,sm8350-qmp-usb3-uni-phy + - qcom,sm8450-qmp-usb3-phy + + reg: + minItems: 1 + items: + - description: serdes + - description: DP_COM + + "#address-cells": + enum: [ 1, 2 ] + + "#size-cells": + enum: [ 1, 2 ] + + ranges: true + + clocks: + minItems: 3 + maxItems: 4 + + clock-names: + minItems: 3 + maxItems: 4 + + power-domains: + maxItems: 1 + + resets: + maxItems: 2 + + reset-names: + maxItems: 2 + + vdda-phy-supply: true + + vdda-pll-supply: true + + vddp-ref-clk-supply: true + +patternProperties: + "^phy@[0-9a-f]+$": + type: object + description: single PHY-provider child node + properties: + reg: + minItems: 3 + maxItems: 6 + + clocks: + items: + - description: PIPE clock + + clock-names: + deprecated: true + items: + - const: pipe0 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + + "#phy-cells": + const: 0 + + required: + - reg + - clocks + - "#clock-cells" + - clock-output-names + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - ranges + - clocks + - clock-names + - resets + - reset-names + - vdda-phy-supply + - vdda-pll-supply + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7180-qmp-usb3-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + - const: com_aux + resets: + maxItems: 1 + reset-names: + items: + - const: phy + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm845-qmp-usb3-uni-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + - const: com_aux + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq8074-qmp-usb3-phy + - qcom,msm8996-qmp-usb3-phy + - qcom,msm8998-qmp-usb3-phy + - qcom,sdx55-qmp-usb3-uni-phy + - qcom,sdx65-qmp-usb3-uni-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: aux + - const: cfg_ahb + - const: ref + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-qmp-usb3-uni-phy + - qcom,sm8150-qmp-usb3-phy + - qcom,sm8150-qmp-usb3-uni-phy + - qcom,sm8250-qmp-usb3-uni-phy + - qcom,sm8350-qmp-usb3-uni-phy + then: + properties: + clocks: + maxItems: 4 + clock-names: + items: + - const: aux + - const: ref_clk_src + - const: ref + - const: com_aux + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8250-qmp-usb3-phy + - qcom,sm8350-qmp-usb3-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: aux + - const: ref_clk_src + - const: com_aux + resets: + maxItems: 2 + reset-names: + items: + - const: phy + - const: common + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcm2290-qmp-usb3-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: cfg_ahb + - const: ref + - const: com_aux + resets: + maxItems: 2 + reset-names: + items: + - const: phy_phy + - const: phy + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-qmp-usb3-uni-phy + then: + required: + - power-domains + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm845-qmp-usb3-phy + - qcom,sm8150-qmp-usb3-phy + - qcom,sm8350-qmp-usb3-phy + - qcom,sm8450-qmp-usb3-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX lane 1 + - description: RX lane 1 + - description: PCS + - description: TX lane 2 + - description: RX lane 2 + - description: PCS_MISC + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-usb3-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX lane 1 + - description: RX lane 1 + - description: PCS + - description: TX lane 2 + - description: RX lane 2 + + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq6018-qmp-usb3-phy + - qcom,ipq8074-qmp-usb3-phy + - qcom,qcm2290-qmp-usb3-phy + - qcom,sc7180-qmp-usb3-phy + - qcom,sc8180x-qmp-usb3-phy + - qcom,sdx55-qmp-usb3-uni-phy + - qcom,sdx65-qmp-usb3-uni-phy + - qcom,sm8150-qmp-usb3-uni-phy + - qcom,sm8250-qmp-usb3-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + - description: PCS_MISC + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-qmp-usb3-phy + - qcom,sc8280xp-qmp-usb3-uni-phy + - qcom,sm8250-qmp-usb3-uni-phy + - qcom,sm8350-qmp-usb3-uni-phy + then: + patternProperties: + "^phy@[0-9a-f]+$": + properties: + reg: + items: + - description: TX + - description: RX + - description: PCS + +examples: + - | + #include + usb_2_qmpphy: phy-wrapper@88eb000 { + compatible = "qcom,sdm845-qmp-usb3-uni-phy"; + reg = <0x088eb000 0x18c>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x088eb000 0x2000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK >, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; + clock-names = "aux", "cfg_ahb", "ref", "com_aux"; + + resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, + <&gcc GCC_USB3_PHY_SEC_BCR>; + reset-names = "phy", "common"; + + vdda-phy-supply = <&vdda_usb2_ss_1p2>; + vdda-pll-supply = <&vdda_usb2_ss_core>; + + usb_2_ssphy: phy@200 { + reg = <0x200 0x128>, + <0x400 0x1fc>, + <0x800 0x218>, + <0x600 0x70>; + + clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + + #clock-cells = <0>; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + + #phy-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml index b078009ed509..97a7ecafbf85 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml @@ -16,6 +16,7 @@ properties: - qcom,sc7180-qmp-usb3-dp-phy - qcom,sc7280-qmp-usb3-dp-phy - qcom,sc8180x-qmp-usb3-dp-phy + - qcom,sc8280xp-qmp-usb43dp-phy - qcom,sdm845-qmp-usb3-dp-phy - qcom,sm8250-qmp-usb3-dp-phy reg: @@ -30,9 +31,6 @@ properties: - const: dp_com - const: dp - "#clock-cells": - enum: [ 1, 2 ] - "#address-cells": enum: [ 1, 2 ] @@ -55,6 +53,9 @@ properties: - const: ref - const: com_aux + power-domains: + maxItems: 1 + resets: items: - description: reset of phy block. @@ -81,6 +82,7 @@ properties: patternProperties: "^usb3-phy@[0-9a-f]+$": type: object + additionalProperties: false description: The USB3 PHY. @@ -99,6 +101,7 @@ patternProperties: - description: pipe clock clock-names: + deprecated: true items: - const: pipe0 @@ -115,12 +118,12 @@ patternProperties: required: - reg - clocks - - clock-names - '#clock-cells' - '#phy-cells' "^dp-phy@[0-9a-f]+$": type: object + additionalProperties: false description: The DP PHY. @@ -147,7 +150,6 @@ patternProperties: required: - compatible - reg - - "#clock-cells" - "#address-cells" - "#size-cells" - ranges @@ -160,6 +162,17 @@ required: additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-qmp-usb43dp-phy + then: + required: + - power-domains + examples: - | #include @@ -169,7 +182,6 @@ examples: <0x088e8000 0x10>, <0x088ea000 0x40>; reg-names = "usb", "dp_com", "dp"; - #clock-cells = <1>; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x088e9000 0x2000>; @@ -197,7 +209,6 @@ examples: #clock-cells = <0>; #phy-cells = <0>; clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; - clock-names = "pipe0"; clock-output-names = "usb3_phy_pipe_clk_src"; }; diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml index d68ab49345b8..636ea430fbff 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml @@ -30,6 +30,7 @@ properties: - items: - enum: - qcom,sc7180-qusb2-phy + - qcom,sdm670-qusb2-phy - qcom,sdm845-qusb2-phy - qcom,sm6350-qusb2-phy - const: qcom,qusb2-v2-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml index 7a0e6a9854da..68e70961beb2 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml @@ -20,6 +20,7 @@ properties: - qcom,sc7280-usb-hs-phy - qcom,sc8180x-usb-hs-phy - qcom,sc8280xp-usb-hs-phy + - qcom,sm6375-usb-hs-phy - qcom,sm8150-usb-hs-phy - qcom,sm8250-usb-hs-phy - qcom,sm8350-usb-hs-phy @@ -53,6 +54,94 @@ properties: vdda33-supply: description: phandle to the regulator 3.3V supply node. + qcom,hs-disconnect-bp: + description: + This adjusts the voltage level for the threshold used to + detect a disconnect event at the host. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -272 + maximum: 2156 + + qcom,squelch-detector-bp: + description: + This adjusts the voltage level for the threshold used to + detect valid high-speed data. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -2090 + maximum: 1590 + + qcom,hs-amplitude-bp: + description: + This adjusts the high-speed DC level voltage. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -660 + maximum: 2670 + + qcom,pre-emphasis-duration-bp: + description: + This signal controls the duration for which the + HS pre-emphasis current is sourced onto DP<#> or DM<#>. + The HS Transmitter pre-emphasis duration is defined in terms of + unit amounts. One unit of pre-emphasis duration is approximately + 650 ps and is defined as 1X pre-emphasis duration. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: 10000 + maximum: 20000 + + qcom,pre-emphasis-amplitude-bp: + description: + This signal controls the amount of current sourced to + DP<#> and DM<#> after a J-to-K or K-to-J transition. + The HS Transmitter pre-emphasis current is defined in terms of unit + amounts. One unit amount is approximately 2 mA and is defined as + 1X pre-emphasis current. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: 10000 + maximum: 40000 + + qcom,hs-rise-fall-time-bp: + description: + This adjusts the rise/fall times of the high-speed waveform. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -4100 + maximum: 5430 + + qcom,hs-crossover-voltage-microvolt: + description: + This adjusts the voltage at which the DP<#> and DM<#> + signals cross while transmitting in HS mode. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -31000 + maximum: 28000 + + qcom,hs-output-impedance-micro-ohms: + description: + In some applications, there can be significant series resistance + on the D+ and D- paths between the transceiver and cable. This adjusts + the driver source impedance to compensate for added series + resistance on the USB. The hardware accepts only discrete values. The + value closest to the provided input will be chosen as the override value + for this param. + minimum: -2300000 + maximum: 6100000 + + qcom,ls-fs-output-impedance-bp: + description: + This adjusts the low- and full-speed single-ended source + impedance while driving high. The following adjustment values are based + on nominal process, voltage, and temperature. + The hardware accepts only discrete values. The value closest to the + provided input will be chosen as the override value for this param. + minimum: -1053 + maximum: 1310 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt deleted file mode 100644 index a3bd1c4499b7..000000000000 --- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt +++ /dev/null @@ -1,112 +0,0 @@ -* Renesas R-Car generation 2 USB PHY - -This file provides information on what the device node for the R-Car generation -2 USB PHY contains. - -Required properties: -- compatible: "renesas,usb-phy-r8a7742" if the device is a part of R8A7742 SoC. - "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC. - "renesas,usb-phy-r8a7744" if the device is a part of R8A7744 SoC. - "renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC. - "renesas,usb-phy-r8a77470" if the device is a part of R8A77470 SoC. - "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. - "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. - "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. - "renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 or - RZ/G1 compatible device. - - When compatible with the generic version, nodes must list the - SoC-specific version corresponding to the platform first - followed by the generic version. - -- reg: offset and length of the register block. -- #address-cells: number of address cells for the USB channel subnodes, must - be <1>. -- #size-cells: number of size cells for the USB channel subnodes, must be <0>. -- clocks: clock phandle and specifier pair. -- clock-names: string, clock input name, must be "usbhs". - -The USB PHY device tree node should have the subnodes corresponding to the USB -channels. These subnodes must contain the following properties: -- reg: the USB controller selector; see the table below for the values. -- #phy-cells: see phy-bindings.txt in the same directory, must be <1>. - -The phandle's argument in the PHY specifier is the USB controller selector for -the USB channel other than r8a77470 SoC; see the selector meanings below: - -+-----------+---------------+---------------+ -|\ Selector | | | -+ --------- + 0 | 1 | -| Channel \| | | -+-----------+---------------+---------------+ -| 0 | PCI EHCI/OHCI | HS-USB | -| 2 | PCI EHCI/OHCI | xHCI | -+-----------+---------------+---------------+ - -For r8a77470 SoC;see the selector meaning below: - -+-----------+---------------+---------------+ -|\ Selector | | | -+ --------- + 0 | 1 | -| Channel \| | | -+-----------+---------------+---------------+ -| 0 | EHCI/OHCI | HS-USB | -+-----------+---------------+---------------+ - -Example (Lager board): - - usb-phy@e6590100 { - compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy"; - reg = <0 0xe6590100 0 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&cpg CPG_MOD 704>; - clock-names = "usbhs"; - power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; - resets = <&cpg 704>; - - usb0: usb-channel@0 { - reg = <0>; - #phy-cells = <1>; - }; - usb2: usb-channel@2 { - reg = <2>; - #phy-cells = <1>; - }; - }; - -Example (iWave RZ/G1C sbc): - - usbphy0: usb-phy0@e6590100 { - compatible = "renesas,usb-phy-r8a77470", - "renesas,rcar-gen2-usb-phy"; - reg = <0 0xe6590100 0 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&cpg CPG_MOD 704>; - clock-names = "usbhs"; - power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; - resets = <&cpg 704>; - - usb0: usb-channel@0 { - reg = <0>; - #phy-cells = <1>; - }; - }; - - usbphy1: usb-phy@e6598100 { - compatible = "renesas,usb-phy-r8a77470", - "renesas,rcar-gen2-usb-phy"; - reg = <0 0xe6598100 0 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&cpg CPG_MOD 706>; - clock-names = "usbhs"; - power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; - resets = <&cpg 706>; - - usb1: usb-channel@0 { - reg = <0>; - #phy-cells = <1>; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/renesas,rcar-gen2-usb-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,rcar-gen2-usb-phy.yaml new file mode 100644 index 000000000000..afc09f39b02b --- /dev/null +++ b/Documentation/devicetree/bindings/phy/renesas,rcar-gen2-usb-phy.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/renesas,rcar-gen2-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car Gen2 USB PHY + +maintainers: + - Yoshihiro Shimoda + +properties: + compatible: + items: + - enum: + - renesas,usb-phy-r8a7742 # RZ/G1H + - renesas,usb-phy-r8a7743 # RZ/G1M + - renesas,usb-phy-r8a7744 # RZ/G1N + - renesas,usb-phy-r8a7745 # RZ/G1E + - renesas,usb-phy-r8a77470 # RZ/G1C + - renesas,usb-phy-r8a7790 # R-Car H2 + - renesas,usb-phy-r8a7791 # R-Car M2-W + - renesas,usb-phy-r8a7794 # R-Car E2 + - const: renesas,rcar-gen2-usb-phy # R-Car Gen2 or RZ/G1 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: usbhs + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +patternProperties: + "^usb-phy@[02]$": + type: object + description: Subnode corresponding to a USB channel. + + properties: + reg: + description: FIXME RZ/G1C supports channel 0 only + enum: [0, 2] + + '#phy-cells': + description: | + The phandle's argument in the PHY specifier is the USB controller + selector for the USB channel. + For RZ/G1C: + - 0 for EHCI/OHCI + - 1 for HS-USB + For all other SoCS: + - 0 for PCI EHCI/OHCI + - 1 for HS-USB (channel 0) or xHCI (channel 2) + const: 1 + + required: + - reg + - '#phy-cells' + + additionalProperties: false + +required: + - compatible + - reg + - '#address-cells' + - '#size-cells' + - clocks + - clock-names + - resets + - power-domains + - usb-phy@0 + +if: + properties: + compatible: + contains: + const: renesas,usb-phy-r8a77470 +then: + properties: + usb-phy@2: false +else: + required: + - usb-phy@2 + +additionalProperties: false + +examples: + - | + #include + #include + usb-phy-controller@e6590100 { + compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy"; + reg = <0xe6590100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cpg CPG_MOD 704>; + clock-names = "usbhs"; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 704>; + + usb0: usb-phy@0 { + reg = <0>; + #phy-cells = <1>; + }; + usb2: usb-phy@2 { + reg = <2>; + #phy-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml new file mode 100644 index 000000000000..9f2d8d2cc7a5 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/rockchip,pcie3-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip PCIe v3 phy + +maintainers: + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,rk3568-pcie3-phy + + reg: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 3 + + clock-names: + items: + - const: refclk_m + - const: refclk_n + - const: pclk + + data-lanes: + description: which lanes (by position) should be mapped to which + controller (value). 0 means lane disabled, higher value means used. + (controller-number +1 ) + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 16 + items: + minimum: 0 + maximum: 16 + + "#phy-cells": + const: 0 + + resets: + maxItems: 1 + + reset-names: + const: phy + + rockchip,phy-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the syscon managing the phy "general register files" + + rockchip,pipe-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to the syscon managing the pipe "general register files" + +required: + - compatible + - reg + - rockchip,phy-grf + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + pcie30phy: phy@fe8c0000 { + compatible = "rockchip,rk3568-pcie3-phy"; + reg = <0xfe8c0000 0x20000>; + #phy-cells = <0>; + clocks = <&pmucru CLK_PCIE30PHY_REF_M>, + <&pmucru CLK_PCIE30PHY_REF_N>, + <&cru PCLK_PCIE30PHY>; + clock-names = "refclk_m", "refclk_n", "pclk"; + resets = <&cru SRST_PCIE30PHY>; + reset-names = "phy"; + rockchip,phy-grf = <&pcie30_phy_grf>; + }; diff --git a/Documentation/devicetree/bindings/phy/rockchip,px30-dsi-dphy.yaml b/Documentation/devicetree/bindings/phy/rockchip,px30-dsi-dphy.yaml index 8a3032a3bd73..5c35e5ceec0b 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,px30-dsi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,px30-dsi-dphy.yaml @@ -18,6 +18,7 @@ properties: - rockchip,px30-dsi-dphy - rockchip,rk3128-dsi-dphy - rockchip,rk3368-dsi-dphy + - rockchip,rk3568-dsi-dphy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml index bb4a2e4b8ab0..810537a0f7dd 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip-inno-csi-dphy.yaml @@ -20,6 +20,7 @@ properties: - rockchip,rk1808-csi-dphy - rockchip,rk3326-csi-dphy - rockchip,rk3368-csi-dphy + - rockchip,rk3568-csi-dphy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml index 8da99461e817..346eb7cf29a5 100644 --- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml @@ -27,18 +27,12 @@ properties: - const: phy-pma clocks: - items: - - description: PLL reference clock - - description: symbol clock for input symbol ( rx0-ch0 symbol clock) - - description: symbol clock for input symbol ( rx1-ch1 symbol clock) - - description: symbol clock for output symbol ( tx0 symbol clock) + minItems: 1 + maxItems: 4 clock-names: - items: - - const: ref_clk - - const: rx1_symbol_clk - - const: rx0_symbol_clk - - const: tx0_symbol_clk + minItems: 1 + maxItems: 4 samsung,pmu-syscon: $ref: '/schemas/types.yaml#/definitions/phandle-array' @@ -62,6 +56,39 @@ required: - clock-names - samsung,pmu-syscon +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos7-ufs-phy + + then: + properties: + clocks: + items: + - description: PLL reference clock + - description: symbol clock for input symbol (rx0-ch0 symbol clock) + - description: symbol clock for input symbol (rx1-ch1 symbol clock) + - description: symbol clock for output symbol (tx0 symbol clock) + + clock-names: + items: + - const: ref_clk + - const: rx1_symbol_clk + - const: rx0_symbol_clk + - const: tx0_symbol_clk + + else: + properties: + clocks: + items: + - description: PLL reference clock + + clock-names: + items: + - const: ref_clk + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml new file mode 100644 index 000000000000..069d422775bb --- /dev/null +++ b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) Sunplus Co., Ltd. 2021 +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/sunplus,sp7021-usb2-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Sunplus SP7021 USB 2.0 PHY Controller + +maintainers: + - Vincent Shih + +properties: + compatible: + const: sunplus,sp7021-usb2-phy + + reg: + items: + - description: UPHY register region + - description: MOON4 register region + + reg-names: + items: + - const: phy + - const: moon4 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + "#phy-cells": + const: 0 + + nvmem-cell-names: + description: names corresponding to the nvmem cells of disconnect voltage + const: disc_vol + + nvmem-cells: + description: nvmem cell address of disconnect voltage + maxItems: 1 + + sunplus,disc-vol-addr-off: + $ref: /schemas/types.yaml#/definitions/uint32 + description: the otp address offset of disconnect voltage + +required: + - compatible + - reg + - reg-names + - clocks + - resets + - "#phy-cells" + - nvmem-cell-names + - nvmem-cells + - sunplus,disc-vol-addr-off + +additionalProperties: false + +examples: + - | + sp_uphy0: usb-phy@9c004a80 { + compatible = "sunplus,sp7021-usb2-phy"; + reg = <0x9c004a80 0x80>, <0x9c000248 0x10>; + reg-names = "phy", "moon4"; + clocks = <&clkc 0x3d>; + resets = <&rstc 0x2d>; + #phy-cells = <0>; + nvmem-cell-names = "disc_vol"; + nvmem-cells = <&disc_vol>; + sunplus,disc-vol-addr-off = <0>; + }; diff --git a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml index ff8a6d9eb153..da7cac537e15 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml @@ -53,12 +53,25 @@ properties: - ti,am43xx-phy-gmii-sel - ti,dm814-phy-gmii-sel - ti,am654-phy-gmii-sel + - ti,j7200-cpsw5g-phy-gmii-sel reg: maxItems: 1 '#phy-cells': true + ti,qsgmii-main-ports: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + Required only for QSGMII mode. Array to select the port for + QSGMII main mode. Rest of the ports are selected as QSGMII_SUB + ports automatically. Any one of the 4 CPSW5G ports can act as the + main port with the rest of them being the QSGMII_SUB ports. + maxItems: 1 + items: + minimum: 1 + maximum: 4 + allOf: - if: properties: @@ -73,6 +86,18 @@ allOf: '#phy-cells': const: 1 description: CPSW port number (starting from 1) + + - if: + not: + properties: + compatible: + contains: + enum: + - ti,j7200-cpsw5g-phy-gmii-sel + then: + properties: + ti,qsgmii-main-ports: false + - if: properties: compatible: @@ -97,7 +122,7 @@ additionalProperties: false examples: - | - phy_gmii_sel: phy-gmii-sel@650 { + phy_gmii_sel: phy@650 { compatible = "ti,am3352-phy-gmii-sel"; reg = <0x650 0x4>; #phy-cells = <2>; diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml index dcd63908aeae..2225925b6dad 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml @@ -16,19 +16,23 @@ properties: - ti,j721e-wiz-16g - ti,j721e-wiz-10g - ti,am64-wiz-10g + - ti,j7200-wiz-10g power-domains: maxItems: 1 clocks: - maxItems: 3 + minItems: 3 + maxItems: 4 description: clock-specifier to represent input to the WIZ clock-names: + minItems: 3 items: - const: fck - const: core_ref_clk - const: ext_ref_clk + - const: core_ref1_clk num-lanes: minimum: 1 @@ -79,10 +83,12 @@ properties: refclk-dig: type: object + additionalProperties: false description: | WIZ node should have subnode for refclk_dig to select the reference clock source for the reference clock used in the PHY and PMA digital logic. + deprecated: true properties: clocks: minItems: 2 @@ -105,12 +111,19 @@ properties: - assigned-clocks - assigned-clock-parents + ti,scm: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + phandle to System Control Module for syscon regmap access. + patternProperties: "^pll[0|1]-refclk$": type: object + additionalProperties: false description: | WIZ node should have subnodes for each of the PLLs present in the SERDES. + deprecated: true properties: clocks: maxItems: 2 @@ -133,9 +146,11 @@ patternProperties: "^cmn-refclk1?-dig-div$": type: object + additionalProperties: false description: WIZ node should have subnodes for each of the PMA common refclock provided by the SERDES. + deprecated: true properties: clocks: maxItems: 1 @@ -170,6 +185,16 @@ required: - "#reset-cells" - ranges +allOf: + - if: + properties: + compatible: + contains: + const: ti,j7200-wiz-10g + then: + required: + - ti,scm + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml new file mode 100644 index 000000000000..30b2131b5860 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml @@ -0,0 +1,190 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/atmel,at91-usart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) + +maintainers: + - Richard Genoud + +properties: + compatible: + oneOf: + - enum: + - atmel,at91rm9200-usart + - atmel,at91sam9260-usart + - microchip,sam9x60-usart + - items: + - const: atmel,at91rm9200-dbgu + - const: atmel,at91rm9200-usart + - items: + - const: atmel,at91sam9260-dbgu + - const: atmel,at91sam9260-usart + - items: + - const: microchip,sam9x60-dbgu + - const: microchip,sam9x60-usart + - const: atmel,at91sam9260-dbgu + - const: atmel,at91sam9260-usart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-names: + minItems: 1 + items: + - const: usart + - const: gclk + + clocks: + minItems: 1 + items: + - description: USART Peripheral Clock + - description: USART Generic Clock + + dmas: + items: + - description: TX DMA Channel + - description: RX DMA Channel + + dma-names: + items: + - const: tx + - const: rx + + atmel,usart-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Must be either for SPI or + for USART (found in dt-bindings/mfd/at91-usart.h). + enum: [ 0, 1 ] + + atmel,use-dma-rx: + type: boolean + description: use of PDC or DMA for receiving data + + atmel,use-dma-tx: + type: boolean + description: use of PDC or DMA for transmitting data + + atmel,fifo-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Maximum number of data the RX and TX FIFOs can store for FIFO + capable USARTS. + enum: [ 16, 32 ] + +required: + - compatible + - reg + - interrupts + - clock-names + - clocks + - atmel,usart-mode + +allOf: + - if: + properties: + atmel,usart-mode: + const: 1 + then: + allOf: + - $ref: /schemas/spi/spi-controller.yaml# + + properties: + atmel,use-dma-rx: false + + atmel,use-dma-tx: false + + atmel,fifo-size: false + + "#size-cells": + const: 0 + + "#address-cells": + const: 1 + + required: + - "#size-cells" + - "#address-cells" + + else: + allOf: + - $ref: /schemas/serial/serial.yaml# + - $ref: /schemas/serial/rs485.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + /* use PDC */ + usart0: serial@fff8c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff8c000 0x4000>; + atmel,usart-mode = ; + interrupts = <7>; + clocks = <&usart0_clk>; + clock-names = "usart"; + atmel,use-dma-rx; + atmel,use-dma-tx; + rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>; + cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>; + dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>; + dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>; + dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>; + rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>; + }; + + - | + #include + #include + #include + #include + + /* use DMA */ + usart1: serial@f001c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf001c000 0x100>; + atmel,usart-mode = ; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&usart0_clk>; + clock-names = "usart"; + atmel,use-dma-rx; + atmel,use-dma-tx; + dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>, + <&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>; + dma-names = "tx", "rx"; + atmel,fifo-size = <32>; + }; + + - | + #include + #include + #include + #include + + /* SPI mode */ + spi0: spi@f001c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf001c000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + atmel,usart-mode = ; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&usart0_clk>; + clock-names = "usart"; + dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>, + <&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>; + dma-names = "tx", "rx"; + cs-gpios = <&pioB 3 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml index 4ff27d6d4d5b..fe098d98af6e 100644 --- a/Documentation/devicetree/bindings/serial/mediatek,uart.yaml +++ b/Documentation/devicetree/bindings/serial/mediatek,uart.yaml @@ -42,6 +42,7 @@ properties: - mediatek,mt8173-uart - mediatek,mt8183-uart - mediatek,mt8186-uart + - mediatek,mt8188-uart - mediatek,mt8192-uart - mediatek,mt8195-uart - mediatek,mt8516-uart diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml index d8aed84abcd3..80af72859876 100644 --- a/Documentation/devicetree/bindings/serial/pl011.yaml +++ b/Documentation/devicetree/bindings/serial/pl011.yaml @@ -94,6 +94,12 @@ properties: resets: maxItems: 1 + reg-io-width: + description: + The size (in bytes) of the IO accesses that should be performed + on the device. + enum: [1, 4] + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 90fe45265fbc..f930e7f1349f 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -76,7 +76,7 @@ properties: - items: - enum: - - renesas,scif-r9a07g043 # RZ/G2UL + - renesas,scif-r9a07g043 # RZ/G2UL and RZ/Five - renesas,scif-r9a07g054 # RZ/V2L - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 41d3b082eb72..8bd88d5cbb11 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -40,7 +40,6 @@ properties: description: | The size (in bytes) of the IO accesses that should be performed on the device. - $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 4 ] clocks: @@ -72,6 +71,9 @@ properties: minItems: 1 maxItems: 2 + power-domains: + maxItems: 1 + samsung,uart-fifosize: description: The fifo size supported by the UART channel. $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index dc74643ae72e..b9c2287c5d1e 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -26,6 +26,7 @@ properties: - rockchip,rk1808-uart - rockchip,rk3036-uart - rockchip,rk3066-uart + - rockchip,rk3128-uart - rockchip,rk3188-uart - rockchip,rk3288-uart - rockchip,rk3308-uart diff --git a/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml b/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml index ee436308e5dc..0e72c08e6566 100644 --- a/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml +++ b/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml @@ -23,6 +23,8 @@ properties: connector: type: object $ref: ../connector/usb-connector.yaml + unevaluatedProperties: false + description: Properties for usb c connector. diff --git a/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml b/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml index 8b019ac05bbe..a86bcd95100e 100644 --- a/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml +++ b/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml @@ -67,6 +67,7 @@ properties: vhub-strings: type: object + additionalProperties: false properties: '#address-cells': @@ -78,6 +79,7 @@ properties: patternProperties: '^string@[0-9a-f]+$': type: object + additionalProperties: false description: string descriptors of the specific language properties: diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index 1bfbc6ef16eb..dc4988c0009c 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -32,6 +32,7 @@ properties: - enum: - rockchip,px30-usb - rockchip,rk3036-usb + - rockchip,rk3128-usb - rockchip,rk3188-usb - rockchip,rk3228-usb - rockchip,rk3288-usb diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.txt b/Documentation/devicetree/bindings/usb/faraday,fotg210.txt deleted file mode 100644 index 06a2286e2054..000000000000 --- a/Documentation/devicetree/bindings/usb/faraday,fotg210.txt +++ /dev/null @@ -1,35 +0,0 @@ -Faraday FOTG Host controller - -This OTG-capable USB host controller is found in Cortina Systems -Gemini and other SoC products. - -Required properties: -- compatible: should be one of: - "faraday,fotg210" - "cortina,gemini-usb", "faraday,fotg210" -- reg: should contain one register range i.e. start and length -- interrupts: description of the interrupt line - -Optional properties: -- clocks: should contain the IP block clock -- clock-names: should be "PCLK" for the IP block clock - -Required properties for "cortina,gemini-usb" compatible: -- syscon: a phandle to the system controller to access PHY registers - -Optional properties for "cortina,gemini-usb" compatible: -- cortina,gemini-mini-b: boolean property that indicates that a Mini-B - OTG connector is in use -- wakeup-source: see power/wakeup-source.txt - -Example for Gemini: - -usb@68000000 { - compatible = "cortina,gemini-usb", "faraday,fotg210"; - reg = <0x68000000 0x1000>; - interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&cc 12>; - clock-names = "PCLK"; - syscon = <&syscon>; - wakeup-source; -}; diff --git a/Documentation/devicetree/bindings/usb/faraday,fotg210.yaml b/Documentation/devicetree/bindings/usb/faraday,fotg210.yaml new file mode 100644 index 000000000000..c69bbfbcf733 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/faraday,fotg210.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2022 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/faraday,fotg210.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Faraday Technology FOTG210 HS OTG USB 2.0 controller Bindings + +maintainers: + - Linus Walleij + +allOf: + - $ref: usb-drd.yaml# + - $ref: usb-hcd.yaml# + +properties: + compatible: + oneOf: + - const: faraday,fotg210 + - items: + - const: cortina,gemini-usb + - const: faraday,fotg210 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: PCLK + + resets: + maxItems: 1 + + syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: a phandle to the global Gemini system controller on + Gemini systems + + dr_mode: true + + phys: + maxItems: 1 + + phy-names: + const: usb2-phy + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + usb0: usb@68000000 { + compatible = "cortina,gemini-usb", "faraday,fotg210"; + reg = <0x68000000 0x1000>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_USB0>; + clocks = <&syscon GEMINI_CLK_GATE_USB0>; + clock-names = "PCLK"; + syscon = <&syscon>; + dr_mode = "host"; + }; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml new file mode 100644 index 000000000000..72f56cc88457 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller + +maintainers: + - ChiYuan Huang + +description: | + MediaTek MT6370 is a multi-functional device. + It integrates charger, ADC, flash, RGB indicators, + regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller. + This document only describes MT6370 Type-C Port Switch and + Power Delivery controller. + +properties: + compatible: + enum: + - mediatek,mt6370-tcpc + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + +additionalProperties: false + +required: + - compatible + - interrupts diff --git a/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt b/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt index 5a0f1f14fbfa..352a0a1e2f76 100644 --- a/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt +++ b/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt @@ -5,7 +5,9 @@ EHCI: ----- Required properties: -- compatible: "nuvoton,npcm750-ehci" +- compatible: should be one of + "nuvoton,npcm750-ehci" + "nuvoton,npcm845-ehci" - interrupts: Should contain the EHCI interrupt - reg: Physical address and length of the register set for the device diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index cd2f7cb6745a..a6e6abb4dfa9 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -26,6 +26,7 @@ properties: - qcom,sc7280-dwc3 - qcom,sc8280xp-dwc3 - qcom,sdm660-dwc3 + - qcom,sdm670-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sdx65-dwc3 @@ -175,6 +176,7 @@ allOf: - qcom,msm8998-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 + - qcom,sdm670-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sm6350-dwc3 @@ -294,6 +296,7 @@ allOf: compatible: contains: enum: + - qcom,sm6115-dwc3 - qcom,sm6125-dwc3 - qcom,sm8150-dwc3 - qcom,sm8250-dwc3 @@ -344,11 +347,11 @@ allOf: - qcom,msm8994-dwc3 - qcom,qcs404-dwc3 - qcom,sc7180-dwc3 + - qcom,sdm670-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sdx65-dwc3 - qcom,sm4250-dwc3 - - qcom,sm6115-dwc3 - qcom,sm6125-dwc3 - qcom,sm6350-dwc3 - qcom,sm8150-dwc3 @@ -380,6 +383,7 @@ allOf: - qcom,msm8953-dwc3 - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 + - qcom,sm6115-dwc3 then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml b/Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml index 9fcf54b10b07..55dfd121b555 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml @@ -11,27 +11,55 @@ maintainers: properties: compatible: - items: - - enum: - - renesas,r8a774a1-usb3-peri # RZ/G2M - - renesas,r8a774b1-usb3-peri # RZ/G2N - - renesas,r8a774c0-usb3-peri # RZ/G2E - - renesas,r8a774e1-usb3-peri # RZ/G2H - - renesas,r8a7795-usb3-peri # R-Car H3 - - renesas,r8a7796-usb3-peri # R-Car M3-W - - renesas,r8a77961-usb3-peri # R-Car M3-W+ - - renesas,r8a77965-usb3-peri # R-Car M3-N - - renesas,r8a77990-usb3-peri # R-Car E3 - - const: renesas,rcar-gen3-usb3-peri + oneOf: + - items: + - enum: + - renesas,r8a774a1-usb3-peri # RZ/G2M + - renesas,r8a774b1-usb3-peri # RZ/G2N + - renesas,r8a774c0-usb3-peri # RZ/G2E + - renesas,r8a774e1-usb3-peri # RZ/G2H + - renesas,r8a7795-usb3-peri # R-Car H3 + - renesas,r8a7796-usb3-peri # R-Car M3-W + - renesas,r8a77961-usb3-peri # R-Car M3-W+ + - renesas,r8a77965-usb3-peri # R-Car M3-N + - renesas,r8a77990-usb3-peri # R-Car E3 + - const: renesas,rcar-gen3-usb3-peri + + - items: + - enum: + - renesas,r9a09g011-usb3-peri # RZ/V2M + - const: renesas,rzv2m-usb3-peri reg: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + items: + - description: Combined interrupt for DMA, SYS and ERR + - description: Dual Role Device (DRD) + - description: Battery Charging + - description: Global Purpose Input + + interrupt-names: + minItems: 1 + items: + - const: all_p + - const: drd + - const: bc + - const: gpi clocks: - maxItems: 1 + minItems: 1 + items: + - description: Main clock + - description: Register access clock + + clock-names: + minItems: 1 + items: + - const: aclk + - const: reg phys: maxItems: 1 @@ -43,7 +71,15 @@ properties: maxItems: 1 resets: - maxItems: 1 + minItems: 1 + items: + - description: Peripheral reset + - description: DRD reset + + reset-names: + items: + - const: aresetn_p + - const: drd_reset usb-role-switch: $ref: /schemas/types.yaml#/definitions/flag @@ -78,6 +114,39 @@ required: - interrupts - clocks +allOf: + - if: + properties: + compatible: + contains: + enum: + - renesas,rzv2m-usb3-peri + then: + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + interrupts: + minItems: 4 + interrupt-names: + minItems: 4 + resets: + minItems: 2 + required: + - clock-names + - interrupt-names + - resets + - reset-names + else: + properties: + clocks: + maxItems: 1 + interrupts: + maxItems: 1 + resets: + maxItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml new file mode 100644 index 000000000000..1999f614c89b --- /dev/null +++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Richtek RT1711H Type-C Port Switch and Power Delivery controller + +maintainers: + - Gene Chen + +description: | + The RT1711H is a USB Type-C controller that complies with the latest + USB Type-C and PD standards. It does the USB Type-C detection including attach + and orientation. It integrates the physical layer of the USB BMC power + delivery protocol to allow up to 100W of power. The BMC PD block enables full + support for alternative interfaces of the Type-C specification. + +properties: + compatible: + enum: + - richtek,rt1711h + - richtek,rt1715 + description: + RT1711H support PD20, RT1715 support PD30 except Fast Role Swap. + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + wakeup-source: + type: boolean + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + description: + Properties for usb c connector. + +additionalProperties: false + +required: + - compatible + - reg + - connector + - interrupts + +examples: + - | + #include + #include + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + rt1711h@4e { + compatible = "richtek,rt1711h"; + reg = <0x4e>; + interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&usb_hs>; + }; + }; + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&usb_ss>; + }; + }; + port@2 { + reg = <2>; + endpoint { + remote-endpoint = <&dp_aux>; + }; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index 1779d08ba1c0..6d78048c4613 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -234,6 +234,18 @@ properties: avoid -EPROTO errors with usbhid on some devices (Hikey 970). type: boolean + snps,gfladj-refclk-lpm-sel-quirk: + description: + When set, run the SOF/ITP counter based on ref_clk. + type: boolean + + snps,resume-hs-terminations: + description: + Fix the issue of HS terminations CRC error on resume by enabling this + quirk. When set, all the termsel, xcvrsel, opmode becomes 0 during end + of resume. This option is to support certain legacy ULPI PHYs. + type: boolean + snps,is-utmi-l1-suspend: description: True when DWC3 asserts output signal utmi_l1_suspend_n, false when diff --git a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml index b5a8c9814dd3..b8974807b666 100644 --- a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml +++ b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml @@ -33,6 +33,7 @@ properties: connector: type: object $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false properties: compatible: @@ -74,9 +75,14 @@ examples: data-role = "dual"; typec-power-opmode = "default"; - port { - typec_con_ep: endpoint { - remote-endpoint = <&usbotg_hs_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + typec_con_ep: endpoint { + remote-endpoint = <&usbotg_hs_ep>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/usb/willsemi,wusb3801.yaml b/Documentation/devicetree/bindings/usb/willsemi,wusb3801.yaml index c2b2243c7892..5aa4ffd67119 100644 --- a/Documentation/devicetree/bindings/usb/willsemi,wusb3801.yaml +++ b/Documentation/devicetree/bindings/usb/willsemi,wusb3801.yaml @@ -28,6 +28,7 @@ properties: connector: type: object $ref: ../connector/usb-connector.yaml# + unevaluatedProperties: false description: The managed USB Type-C connector. Since WUSB3801 does not support Power Delivery, the node should have the "pd-disable" property. diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 5e6de4ab25dc..687adb58048e 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -311,7 +311,6 @@ IOMAP devm_ioremap() devm_ioremap_uc() devm_ioremap_wc() - devm_ioremap_np() devm_ioremap_resource() : checks resource, requests memory region, ioremaps devm_ioremap_resource_wc() devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device diff --git a/Documentation/filesystems/sysfs.rst b/Documentation/filesystems/sysfs.rst index 004d490179f3..8bba676b1365 100644 --- a/Documentation/filesystems/sysfs.rst +++ b/Documentation/filesystems/sysfs.rst @@ -263,7 +263,7 @@ A very simple (and naive) implementation of a device attribute is:: static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name); + return sysfs_emit(buf, "%s\n", dev->name); } static ssize_t store_name(struct device *dev, struct device_attribute *attr, diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index f5ba36e96461..64b5948fc1d4 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -69,86 +69,17 @@ Changelog:: Magic Name Number Structure File ===================== ================ ======================== ========================================== PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` -CMAGIC 0x0111 user ``include/linux/a.out.h`` -MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` -HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` -DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` -FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -PTY_MAGIC 0x5001 ``drivers/char/pty.c`` -PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` -SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c`` -SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h`` -AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h`` -TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h`` -MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` -TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` -FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` -USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` -RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` -USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` -CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` -RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` -NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` -RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h`` -ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h`` -LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c`` -LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c`` -WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h`` -CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c`` -LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h`` -ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h`` -CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c`` -ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h`` -SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c`` -CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c`` -SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c`` -COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c`` -I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c`` -TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c`` -ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9] -SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c`` -GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h`` -RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c`` -EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` -PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` -I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c`` -TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c`` -M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c`` -FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h`` -SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h`` -SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h`` -LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h`` -M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c`` -VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c`` -KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c`` -PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h`` -NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h`` -ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` -HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c`` NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` ===================== ================ ======================== ========================================== - -Note that there are also defined special per-driver magic numbers in sound -memory management. See ``include/sound/sndmagic.h`` for complete list of them. Many -OSS sound drivers have their magic numbers constructed from the soundcard PCI -ID - these are not listed here as well. - -HFS is another larger user of magic numbers - you can find them in -``fs/hfs/hfs.h``. diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index f452fafb1e84..02eb7eb2448e 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -75,87 +75,17 @@ Registro dei cambiamenti:: Nome magico Numero Struttura File ===================== ================ ======================== ========================================== PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` -CMAGIC 0x0111 user ``include/linux/a.out.h`` -MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` -HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` -DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` -FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -PTY_MAGIC 0x5001 ``drivers/char/pty.c`` -PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` -SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c`` -SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h`` -AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h`` -TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h`` -MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` -TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` -FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` -USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` -RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` -USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` -CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` -RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` -NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` -RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h`` -ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h`` -LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c`` -LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c`` -WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h`` -CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c`` -LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h`` -ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h`` -CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c`` -ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h`` -SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c`` -CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c`` -SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c`` -COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c`` -I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c`` -TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c`` -ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9] -SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c`` -GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h`` -RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c`` -EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` -PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` -I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c`` -TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c`` -M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c`` -FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h`` -SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h`` -SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h`` -LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h`` -M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c`` -VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c`` -KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c`` -PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h`` -NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h`` -ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` -HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c`` NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` ===================== ================ ======================== ========================================== - -Da notare che ci sono anche dei numeri magici specifici per driver nel -*sound memory management*. Consultate ``include/sound/sndmagic.h`` per una -lista completa. Molti driver audio OSS hanno i loro numeri magici costruiti a -partire dall'identificativo PCI della scheda audio - nemmeno questi sono -elencati in questo file. - -Il file-system HFS è un altro grande utilizzatore di numeri magici - potete -trovarli qui ``fs/hfs/hfs.h``. diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 42f0635ca70a..0617ce125e12 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -58,87 +58,17 @@ Linux 魔术数 魔术数名 数字 结构 文件 ===================== ================ ======================== ========================================== PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` -CMAGIC 0x0111 user ``include/linux/a.out.h`` -MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` -HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` -DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` -FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -PTY_MAGIC 0x5001 ``drivers/char/pty.c`` -PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` -SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c`` -SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h`` -AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h`` -TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h`` -MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` -TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` -FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` -USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` -RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` -USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` -CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` -GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` -RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` -NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` -RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h`` -ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h`` -LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c`` -LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c`` -WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h`` -CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c`` -LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h`` -ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h`` -CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c`` -ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h`` -SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c`` -CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c`` -SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c`` -COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c`` -I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c`` -TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c`` -ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9] -SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c`` -GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h`` -RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c`` -EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` -PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` -I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c`` -TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c`` -M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c`` -FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h`` -SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h`` -SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h`` -LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h`` -M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c`` -VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c`` -KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c`` -PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h`` -NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h`` -ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h`` YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` -HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c`` NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` ===================== ================ ======================== ========================================== - - -请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。 - -IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。 - -HFS是另外一个比较大的使用魔术值的文件系统-你可以在fs/hfs/hfs.h中找到他们。 diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst index ae321a9aaece..f3f7082e17c6 100644 --- a/Documentation/translations/zh_TW/process/magic-number.rst +++ b/Documentation/translations/zh_TW/process/magic-number.rst @@ -61,88 +61,17 @@ Linux 魔術數 魔術數名 數字 結構 文件 ===================== ================ ======================== ========================================== PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` -CMAGIC 0x0111 user ``include/linux/a.out.h`` -MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` -HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` -DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` -FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -PTY_MAGIC 0x5001 ``drivers/char/pty.c`` -PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` -SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c`` -SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h`` -AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h`` -TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h`` -MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` -TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` -FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` -USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` -RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` -USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` -CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` -GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` -RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` -NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` -RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` -ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h`` -ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h`` -LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c`` -LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c`` -WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h`` -CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c`` -LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h`` -ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h`` -CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c`` -ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h`` -SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c`` -CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c`` -SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c`` -COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c`` -I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c`` -TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c`` -ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9] -SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c`` -GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h`` -RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c`` -EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` -PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` -I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c`` -TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c`` -M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c`` -FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h`` -SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h`` -SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h`` -LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h`` -M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c`` -VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c`` -KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c`` -PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h`` -NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h`` -ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h`` YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` -HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c`` NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` ===================== ================ ======================== ========================================== - - -請注意,在聲音記憶管理中仍然有一些特殊的爲每個驅動定義的魔術值。查看include/sound/sndmagic.h來獲取他們完整的列表信息。很多OSS聲音驅動擁有自己從音效卡PCI ID構建的魔術值-他們也沒有被列在這裡。 - -IrDA子系統也使用了大量的自己的魔術值,查看include/net/irda/irda.h來獲取他們完整的信息。 - -HFS是另外一個比較大的使用魔術值的文件系統-你可以在fs/hfs/hfs.h中找到他們。 - diff --git a/Documentation/usb/usbip_protocol.rst b/Documentation/usb/usbip_protocol.rst index 0b8541fda4d8..adc158967cc6 100644 --- a/Documentation/usb/usbip_protocol.rst +++ b/Documentation/usb/usbip_protocol.rst @@ -340,13 +340,12 @@ USBIP_CMD_SUBMIT: | 0 | 20 | usbip_header_basic, 'command' shall be 0x00000001 | +-----------+--------+---------------------------------------------------+ | 0x14 | 4 | transfer_flags: possible values depend on the | -| | | URB transfer_flags (refer to URB doc in | -| | | Documentation/driver-api/usb/URB.rst) | -| | | but with URB_NO_TRANSFER_DMA_MAP masked. Refer to | -| | | function usbip_pack_cmd_submit and function | -| | | tweak_transfer_flags in drivers/usb/usbip/ | -| | | usbip_common.c. The following fields may also ref | -| | | to function usbip_pack_cmd_submit and URB doc | +| | | USBIP_URB transfer_flags. | +| | | Refer to include/uapi/linux/usbip.h and | +| | | Documentation/driver-api/usb/URB.rst. | +| | | Refer to usbip_pack_cmd_submit() and | +| | | tweak_transfer_flags() in drivers/usb/usbip/ | +| | | usbip_common.c. | +-----------+--------+---------------------------------------------------+ | 0x18 | 4 | transfer_buffer_length: | | | | use URB transfer_buffer_length | diff --git a/MAINTAINERS b/MAINTAINERS index 4683f0dacad4..31cebfa8733c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5921,10 +5921,9 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git F: drivers/usb/dwc2/ DESIGNWARE USB3 DRD IP DRIVER -M: Felipe Balbi +M: Thinh Nguyen L: linux-usb@vger.kernel.org S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git F: drivers/usb/dwc3/ DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER @@ -7236,6 +7235,8 @@ M: Jason Baron S: Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c +M: Jim Cromie +F: lib/test_dynamic_debug.c DYNAMIC INTERRUPT MODERATION M: Tal Gilboa @@ -9157,6 +9158,7 @@ F: net/dsa/tag_hellcreek.c HISILICON DMA DRIVER M: Zhou Wang +M: Jie Hai L: dmaengine@vger.kernel.org S: Maintained F: drivers/dma/hisi_dma.c @@ -13345,7 +13347,7 @@ F: include/dt-bindings/dma/at91.h MICROCHIP AT91 SERIAL DRIVER M: Richard Genoud S: Maintained -F: Documentation/devicetree/bindings/mfd/atmel-usart.txt +F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml F: drivers/tty/serial/atmel_serial.c F: drivers/tty/serial/atmel_serial.h @@ -13353,7 +13355,7 @@ MICROCHIP AT91 USART MFD DRIVER M: Radu Pirea L: linux-kernel@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/mfd/atmel-usart.txt +F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml F: drivers/mfd/at91-usart.c F: include/dt-bindings/mfd/at91-usart.h @@ -13361,7 +13363,7 @@ MICROCHIP AT91 USART SPI DRIVER M: Radu Pirea L: linux-spi@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/mfd/atmel-usart.txt +F: Documentation/devicetree/bindings/serial/atmel,at91-usart.yaml F: drivers/spi/spi-at91-usart.c MICROCHIP AUDIO ASOC DRIVERS @@ -13554,6 +13556,7 @@ M: UNGLinuxDriver@microchip.com L: linux-mips@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/mips/mscc.txt +F: Documentation/devicetree/bindings/phy/mscc,vsc7514-serdes.yaml F: Documentation/devicetree/bindings/power/reset/ocelot-reset.txt F: arch/mips/boot/dts/mscc/ F: arch/mips/configs/generic/board-ocelot.config @@ -19623,6 +19626,15 @@ S: Maintained F: Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml F: drivers/nvmem/sunplus-ocotp.c +SUNPLUS USB2 PHY DRIVER +M: Vincent Shih +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml +F: drivers/phy/sunplus/Kconfig +F: drivers/phy/sunplus/Makefile +F: drivers/phy/sunplus/phy-sunplus-usb2.c + SUNPLUS PWM DRIVER M: Hammer Hsieh S: Maintained diff --git a/arch/alpha/include/asm/termios.h b/arch/alpha/include/asm/termios.h deleted file mode 100644 index b7c77bb1bfd2..000000000000 --- a/arch/alpha/include/asm/termios.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ALPHA_TERMIOS_H -#define _ALPHA_TERMIOS_H - -#include - -/* eof=^D eol=\0 eol2=\0 erase=del - werase=^W kill=^U reprint=^R sxtc=\0 - intr=^C quit=^\ susp=^Z - start=^Q stop=^S lnext=^V discard=^U - vmin=\1 vtime=\0 -*/ -#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ - -#define user_termio_to_kernel_termios(a_termios, u_termio) \ -({ \ - struct ktermios *k_termios = (a_termios); \ - struct termio k_termio; \ - int canon, ret; \ - \ - ret = copy_from_user(&k_termio, u_termio, sizeof(k_termio)); \ - if (!ret) { \ - /* Overwrite only the low bits. */ \ - *(unsigned short *)&k_termios->c_iflag = k_termio.c_iflag; \ - *(unsigned short *)&k_termios->c_oflag = k_termio.c_oflag; \ - *(unsigned short *)&k_termios->c_cflag = k_termio.c_cflag; \ - *(unsigned short *)&k_termios->c_lflag = k_termio.c_lflag; \ - canon = k_termio.c_lflag & ICANON; \ - \ - k_termios->c_cc[VINTR] = k_termio.c_cc[_VINTR]; \ - k_termios->c_cc[VQUIT] = k_termio.c_cc[_VQUIT]; \ - k_termios->c_cc[VERASE] = k_termio.c_cc[_VERASE]; \ - k_termios->c_cc[VKILL] = k_termio.c_cc[_VKILL]; \ - k_termios->c_cc[VEOL2] = k_termio.c_cc[_VEOL2]; \ - k_termios->c_cc[VSWTC] = k_termio.c_cc[_VSWTC]; \ - k_termios->c_cc[canon ? VEOF : VMIN] = k_termio.c_cc[_VEOF]; \ - k_termios->c_cc[canon ? VEOL : VTIME] = k_termio.c_cc[_VEOL]; \ - } \ - ret; \ -}) - -/* - * Translate a "termios" structure into a "termio". Ugh. - * - * Note the "fun" _VMIN overloading. - */ -#define kernel_termios_to_user_termio(u_termio, a_termios) \ -({ \ - struct ktermios *k_termios = (a_termios); \ - struct termio k_termio; \ - int canon; \ - \ - k_termio.c_iflag = k_termios->c_iflag; \ - k_termio.c_oflag = k_termios->c_oflag; \ - k_termio.c_cflag = k_termios->c_cflag; \ - canon = (k_termio.c_lflag = k_termios->c_lflag) & ICANON; \ - \ - k_termio.c_line = k_termios->c_line; \ - k_termio.c_cc[_VINTR] = k_termios->c_cc[VINTR]; \ - k_termio.c_cc[_VQUIT] = k_termios->c_cc[VQUIT]; \ - k_termio.c_cc[_VERASE] = k_termios->c_cc[VERASE]; \ - k_termio.c_cc[_VKILL] = k_termios->c_cc[VKILL]; \ - k_termio.c_cc[_VEOF] = k_termios->c_cc[canon ? VEOF : VMIN]; \ - k_termio.c_cc[_VEOL] = k_termios->c_cc[canon ? VEOL : VTIME]; \ - k_termio.c_cc[_VEOL2] = k_termios->c_cc[VEOL2]; \ - k_termio.c_cc[_VSWTC] = k_termios->c_cc[VSWTC]; \ - \ - copy_to_user(u_termio, &k_termio, sizeof(k_termio)); \ -}) - -#define user_termios_to_kernel_termios(k, u) \ - copy_from_user(k, u, sizeof(struct termios2)) - -#define kernel_termios_to_user_termios(u, k) \ - copy_to_user(u, k, sizeof(struct termios2)) - -#define user_termios_to_kernel_termios_1(k, u) \ - copy_from_user(k, u, sizeof(struct termios)) - -#define kernel_termios_to_user_termios_1(u, k) \ - copy_to_user(u, k, sizeof(struct termios)) - -#endif /* _ALPHA_TERMIOS_H */ diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 6a274c0d53a2..bd82c8a12f0b 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -9,7 +9,7 @@ ccflags-y := -Wno-sign-compare obj-y := entry.o traps.o process.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o \ - systbls.o err_common.o io.o bugs.o + systbls.o err_common.o io.o bugs.o termios.o obj-$(CONFIG_VGA_HOSE) += console.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/alpha/kernel/termios.c b/arch/alpha/kernel/termios.c new file mode 100644 index 000000000000..a4c29a22edf7 --- /dev/null +++ b/arch/alpha/kernel/termios.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +int user_termio_to_kernel_termios(struct ktermios *termios, + struct termio __user *termio) +{ + struct termio v; + bool canon; + + if (copy_from_user(&v, termio, sizeof(struct termio))) + return -EFAULT; + + termios->c_iflag = (0xffff0000 & termios->c_iflag) | v.c_iflag; + termios->c_oflag = (0xffff0000 & termios->c_oflag) | v.c_oflag; + termios->c_cflag = (0xffff0000 & termios->c_cflag) | v.c_cflag; + termios->c_lflag = (0xffff0000 & termios->c_lflag) | v.c_lflag; + termios->c_line = (0xffff0000 & termios->c_lflag) | v.c_line; + + canon = v.c_lflag & ICANON; + termios->c_cc[VINTR] = v.c_cc[_VINTR]; + termios->c_cc[VQUIT] = v.c_cc[_VQUIT]; + termios->c_cc[VERASE] = v.c_cc[_VERASE]; + termios->c_cc[VKILL] = v.c_cc[_VKILL]; + termios->c_cc[VEOL2] = v.c_cc[_VEOL2]; + termios->c_cc[VSWTC] = v.c_cc[_VSWTC]; + termios->c_cc[canon ? VEOF : VMIN] = v.c_cc[_VEOF]; + termios->c_cc[canon ? VEOL : VTIME] = v.c_cc[_VEOL]; + + return 0; +} + +int kernel_termios_to_user_termio(struct termio __user *termio, + struct ktermios *termios) +{ + struct termio v; + bool canon; + + memset(&v, 0, sizeof(struct termio)); + v.c_iflag = termios->c_iflag; + v.c_oflag = termios->c_oflag; + v.c_cflag = termios->c_cflag; + v.c_lflag = termios->c_lflag; + v.c_line = termios->c_line; + + canon = v.c_lflag & ICANON; + v.c_cc[_VINTR] = termios->c_cc[VINTR]; + v.c_cc[_VQUIT] = termios->c_cc[VQUIT]; + v.c_cc[_VERASE] = termios->c_cc[VERASE]; + v.c_cc[_VKILL] = termios->c_cc[VKILL]; + v.c_cc[_VEOF] = termios->c_cc[canon ? VEOF : VMIN]; + v.c_cc[_VEOL] = termios->c_cc[canon ? VEOL : VTIME]; + v.c_cc[_VEOL2] = termios->c_cc[VEOL2]; + v.c_cc[_VSWTC] = termios->c_cc[VSWTC]; + + return copy_to_user(termio, &v, sizeof(struct termio)); +} diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 2d58e273c96d..95e731676cea 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-s3c/mach-gta02.c b/arch/arm/mach-s3c/mach-gta02.c index abfdce765525..d50a81d85ae1 100644 --- a/arch/arm/mach-s3c/mach-gta02.c +++ b/arch/arm/mach-s3c/mach-gta02.c @@ -421,7 +421,14 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = { /* Get PMU to set USB current limit accordingly. */ static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = { .vbus_draw = gta02_udc_vbus_draw, - .pullup_pin = GTA02_GPIO_USB_PULLUP, +}; + +static struct gpiod_lookup_table gta02_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOB", 9, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, }; /* USB */ @@ -555,6 +562,7 @@ static void __init gta02_machine_init(void) s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(>a02_udc_gpio_table); gpiod_add_lookup_table(>a02_audio_gpio_table); gpiod_add_lookup_table(>a02_mmc_gpio_table); platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices)); diff --git a/arch/arm/mach-s3c/mach-h1940.c b/arch/arm/mach-s3c/mach-h1940.c index 032b18837855..83ac6cfdb1d8 100644 --- a/arch/arm/mach-s3c/mach-h1940.c +++ b/arch/arm/mach-s3c/mach-h1940.c @@ -167,9 +167,15 @@ static struct gpio_chip h1940_latch_gpiochip = { }; static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = { - .vbus_pin = S3C2410_GPG(5), - .vbus_pin_inverted = 1, - .pullup_pin = H1940_LATCH_USB_DP, +}; + +static struct gpiod_lookup_table h1940_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("H1940_LATCH", 7, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, }; static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = { @@ -725,6 +731,7 @@ static void __init h1940_init(void) u32 tmp; s3c24xx_fb_set_platdata(&h1940_fb_info); + gpiod_add_lookup_table(&h1940_udc_gpio_table); gpiod_add_lookup_table(&h1940_mmc_gpio_table); gpiod_add_lookup_table(&h1940_audio_gpio_table); gpiod_add_lookup_table(&h1940_bat_gpio_table); diff --git a/arch/arm/mach-s3c/mach-jive.c b/arch/arm/mach-s3c/mach-jive.c index e32773175944..16859bb3bb13 100644 --- a/arch/arm/mach-s3c/mach-jive.c +++ b/arch/arm/mach-s3c/mach-jive.c @@ -493,7 +493,14 @@ static struct platform_device *jive_devices[] __initdata = { }; static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = { - .vbus_pin = S3C2410_GPG(1), /* detect is on GPG1 */ +}; + +static struct gpiod_lookup_table jive_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH), + { }, + }, }; /* Jive power management device */ @@ -669,6 +676,7 @@ static void __init jive_machine_init(void) pm_power_off = jive_power_off; + gpiod_add_lookup_table(&jive_udc_gpio_table); gpiod_add_lookup_table(&jive_lcdspi_gpiod_table); gpiod_add_lookup_table(&jive_wm8750_gpiod_table); platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices)); diff --git a/arch/arm/mach-s3c/mach-mini2440.c b/arch/arm/mach-s3c/mach-mini2440.c index a6d17ffcdba1..283be70ca622 100644 --- a/arch/arm/mach-s3c/mach-mini2440.c +++ b/arch/arm/mach-s3c/mach-mini2440.c @@ -93,9 +93,15 @@ static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = { /* USB device UDC support */ static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = { - .pullup_pin = S3C2410_GPC(5), }; +static struct gpiod_lookup_table mini2440_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOC", 5, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; /* LCD timing and setup */ @@ -755,6 +761,7 @@ static void __init mini2440_init(void) s3c24xx_fb_set_platdata(&mini2440_fb_info); } + gpiod_add_lookup_table(&mini2440_udc_gpio_table); s3c24xx_udc_set_platdata(&mini2440_udc_cfg); gpiod_add_lookup_table(&mini2440_mmc_gpio_table); s3c24xx_mci_set_platdata(&mini2440_mmc_cfg); diff --git a/arch/arm/mach-s3c/mach-n30.c b/arch/arm/mach-s3c/mach-n30.c index 75f5dc6351a1..90122fc6b2aa 100644 --- a/arch/arm/mach-s3c/mach-n30.c +++ b/arch/arm/mach-s3c/mach-n30.c @@ -84,9 +84,15 @@ static struct s3c2410_uartcfg n30_uartcfgs[] = { }; static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = { - .vbus_pin = S3C2410_GPG(1), - .vbus_pin_inverted = 0, - .pullup_pin = S3C2410_GPB(3), +}; + +static struct gpiod_lookup_table n30_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 3, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, }; static struct gpio_keys_button n30_buttons[] = { @@ -595,6 +601,7 @@ static void __init n30_init(void) WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power")); s3c24xx_fb_set_platdata(&n30_fb_info); + gpiod_add_lookup_table(&n30_udc_gpio_table); s3c24xx_udc_set_platdata(&n30_udc_cfg); gpiod_add_lookup_table(&n30_mci_gpio_table); s3c24xx_mci_set_platdata(&n30_mci_cfg); diff --git a/arch/arm/mach-s3c/mach-rx1950.c b/arch/arm/mach-s3c/mach-rx1950.c index 7a3e7c0a6484..d8c49e562660 100644 --- a/arch/arm/mach-s3c/mach-rx1950.c +++ b/arch/arm/mach-s3c/mach-rx1950.c @@ -643,9 +643,15 @@ static struct s3c2410_platform_nand rx1950_nand_info = { }; static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = { - .vbus_pin = S3C2410_GPG(5), - .vbus_pin_inverted = 1, - .pullup_pin = S3C2410_GPJ(5), +}; + +static struct gpiod_lookup_table rx1950_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("GPIOJ", 5, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, }; static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = { @@ -847,6 +853,7 @@ static void __init rx1950_init_machine(void) gpio_direction_output(S3C2410_GPJ(6), 0); pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup)); + gpiod_add_lookup_table(&rx1950_udc_gpio_table); gpiod_add_lookup_table(&rx1950_audio_gpio_table); gpiod_add_lookup_table(&rx1950_bat_gpio_table); /* Configure the I2S pins (GPE0...GPE4) in correct mode */ diff --git a/arch/arm/mach-s3c/mach-smdk2413.c b/arch/arm/mach-s3c/mach-smdk2413.c index f1f0ec174579..2b4e20aaa346 100644 --- a/arch/arm/mach-s3c/mach-smdk2413.c +++ b/arch/arm/mach-s3c/mach-smdk2413.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -74,9 +74,15 @@ static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = { static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = { - .pullup_pin = S3C2410_GPF(2), }; +static struct gpiod_lookup_table smdk2413_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOF", 2, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; static struct platform_device *smdk2413_devices[] __initdata = { &s3c_device_ohci, @@ -115,7 +121,7 @@ static void __init smdk2413_machine_init(void) S3C2410_MISCCR_USBSUSPND0 | S3C2410_MISCCR_USBSUSPND1, 0x0); - + gpiod_add_lookup_table(&smdk2413_udc_gpio_table); s3c24xx_udc_set_platdata(&smdk2413_udc_cfg); s3c_i2c0_set_platdata(NULL); /* Configure the I2S pins (GPE0...GPE4) in correct mode */ diff --git a/arch/arm/mach-versatile/integrator_ap.c b/arch/arm/mach-versatile/integrator_ap.c index e216fac917d0..4bd6712e9f52 100644 --- a/arch/arm/mach-versatile/integrator_ap.c +++ b/arch/arm/mach-versatile/integrator_ap.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 53493dc7d976..bb916a0948a8 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1299,7 +1299,7 @@ interrupts = ; phys = <&usb3_phy0>, <&usb3_phy0>; phy-names = "usb2-phy", "usb3-phy"; - snps,dis-u2-freeclk-exists-quirk; + snps,gfladj-refclk-lpm-sel-quirk; }; }; @@ -1341,7 +1341,7 @@ interrupts = ; phys = <&usb3_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; - snps,dis-u2-freeclk-exists-quirk; + snps,gfladj-refclk-lpm-sel-quirk; }; }; diff --git a/arch/ia64/include/asm/termios.h b/arch/ia64/include/asm/termios.h deleted file mode 100644 index 589c026444cc..000000000000 --- a/arch/ia64/include/asm/termios.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Modified 1999 - * David Mosberger-Tang , Hewlett-Packard Co - * - * 99/01/28 Added N_IRDA and N_SMSBLOCK - */ -#ifndef _ASM_IA64_TERMIOS_H -#define _ASM_IA64_TERMIOS_H - -#include - - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ - unsigned short __tmp; \ - get_user(__tmp,&(termio)->x); \ - *(unsigned short *) &(termios)->x = __tmp; \ -} - -#define user_termio_to_kernel_termios(termios, termio) \ -({ \ - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ - copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ -}) - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -#define kernel_termios_to_user_termio(termio, termios) \ -({ \ - put_user((termios)->c_iflag, &(termio)->c_iflag); \ - put_user((termios)->c_oflag, &(termio)->c_oflag); \ - put_user((termios)->c_cflag, &(termio)->c_cflag); \ - put_user((termios)->c_lflag, &(termio)->c_lflag); \ - put_user((termios)->c_line, &(termio)->c_line); \ - copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ -}) - -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) -#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) - -#endif /* _ASM_IA64_TERMIOS_H */ diff --git a/arch/ia64/include/uapi/asm/termios.h b/arch/ia64/include/uapi/asm/termios.h deleted file mode 100644 index 199742d08f2c..000000000000 --- a/arch/ia64/include/uapi/asm/termios.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Modified 1999 - * David Mosberger-Tang , Hewlett-Packard Co - * - * 99/01/28 Added N_IRDA and N_SMSBLOCK - */ -#ifndef _UAPI_ASM_IA64_TERMIOS_H -#define _UAPI_ASM_IA64_TERMIOS_H - - -#include -#include - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - - -#endif /* _UAPI_ASM_IA64_TERMIOS_H */ diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild index 83bc0681e72b..f2bcfcb4e311 100644 --- a/arch/loongarch/include/asm/Kbuild +++ b/arch/loongarch/include/asm/Kbuild @@ -21,7 +21,6 @@ generic-y += shmbuf.h generic-y += statfs.h generic-y += socket.h generic-y += sockios.h -generic-y += termios.h generic-y += termbits.h generic-y += poll.h generic-y += param.h diff --git a/arch/mips/include/asm/sn/gda.h b/arch/mips/include/asm/sn/gda.h index d52f81620661..5b8c96d5b587 100644 --- a/arch/mips/include/asm/sn/gda.h +++ b/arch/mips/include/asm/sn/gda.h @@ -16,8 +16,6 @@ #include -#define GDA_MAGIC 0x58464552 - /* * GDA Version History * diff --git a/arch/mips/include/asm/termios.h b/arch/mips/include/asm/termios.h deleted file mode 100644 index bc29eeacc55a..000000000000 --- a/arch/mips/include/asm/termios.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995, 1996, 2000, 2001 by Ralf Baechle - * Copyright (C) 2000, 2001 Silicon Graphics, Inc. - */ -#ifndef _ASM_TERMIOS_H -#define _ASM_TERMIOS_H - -#include -#include - -/* - * intr=^C quit=^\ erase=del kill=^U - * vmin=\1 vtime=\0 eol2=\0 swtc=\0 - * start=^Q stop=^S susp=^Z vdsusp= - * reprint=^R discard=^U werase=^W lnext=^V - * eof=^D eol=\0 - */ -#define INIT_C_CC "\003\034\177\025\1\0\0\0\021\023\032\0\022\017\027\026\004\0" - -#include - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -static inline int user_termio_to_kernel_termios(struct ktermios *termios, - struct termio __user *termio) -{ - unsigned short iflag, oflag, cflag, lflag; - unsigned int err; - - if (!access_ok(termio, sizeof(struct termio))) - return -EFAULT; - - err = __get_user(iflag, &termio->c_iflag); - termios->c_iflag = (termios->c_iflag & 0xffff0000) | iflag; - err |=__get_user(oflag, &termio->c_oflag); - termios->c_oflag = (termios->c_oflag & 0xffff0000) | oflag; - err |=__get_user(cflag, &termio->c_cflag); - termios->c_cflag = (termios->c_cflag & 0xffff0000) | cflag; - err |=__get_user(lflag, &termio->c_lflag); - termios->c_lflag = (termios->c_lflag & 0xffff0000) | lflag; - err |=__get_user(termios->c_line, &termio->c_line); - if (err) - return -EFAULT; - - if (__copy_from_user(termios->c_cc, termio->c_cc, NCC)) - return -EFAULT; - - return 0; -} - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) -{ - int err; - - if (!access_ok(termio, sizeof(struct termio))) - return -EFAULT; - - err = __put_user(termios->c_iflag, &termio->c_iflag); - err |= __put_user(termios->c_oflag, &termio->c_oflag); - err |= __put_user(termios->c_cflag, &termio->c_cflag); - err |= __put_user(termios->c_lflag, &termio->c_lflag); - err |= __put_user(termios->c_line, &termio->c_line); - if (err) - return -EFAULT; - - if (__copy_to_user(termio->c_cc, termios->c_cc, NCC)) - return -EFAULT; - - return 0; -} - -static inline int user_termios_to_kernel_termios(struct ktermios __user *k, - struct termios2 *u) -{ - return copy_from_user(k, u, sizeof(struct termios2)) ? -EFAULT : 0; -} - -static inline int kernel_termios_to_user_termios(struct termios2 __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios2)) ? -EFAULT : 0; -} - -static inline int user_termios_to_kernel_termios_1(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)) ? -EFAULT : 0; -} - -static inline int kernel_termios_to_user_termios_1(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)) ? -EFAULT : 0; -} - -#endif /* _ASM_TERMIOS_H */ diff --git a/arch/parisc/include/asm/termios.h b/arch/parisc/include/asm/termios.h deleted file mode 100644 index cded9dc90c1b..000000000000 --- a/arch/parisc/include/asm/termios.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _PARISC_TERMIOS_H -#define _PARISC_TERMIOS_H - -#include - - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ - unsigned short __tmp; \ - get_user(__tmp,&(termio)->x); \ - *(unsigned short *) &(termios)->x = __tmp; \ -} - -#define user_termio_to_kernel_termios(termios, termio) \ -({ \ - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ - copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ -}) - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -#define kernel_termios_to_user_termio(termio, termios) \ -({ \ - put_user((termios)->c_iflag, &(termio)->c_iflag); \ - put_user((termios)->c_oflag, &(termio)->c_oflag); \ - put_user((termios)->c_cflag, &(termio)->c_cflag); \ - put_user((termios)->c_lflag, &(termio)->c_lflag); \ - put_user((termios)->c_line, &(termio)->c_line); \ - copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ -}) - -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) -#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) - -#endif /* _PARISC_TERMIOS_H */ diff --git a/arch/parisc/include/uapi/asm/termios.h b/arch/parisc/include/uapi/asm/termios.h deleted file mode 100644 index aba174f23ef0..000000000000 --- a/arch/parisc/include/uapi/asm/termios.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI_PARISC_TERMIOS_H -#define _UAPI_PARISC_TERMIOS_H - -#include -#include - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - - -#endif /* _UAPI_PARISC_TERMIOS_H */ diff --git a/arch/powerpc/include/asm/termios.h b/arch/powerpc/include/asm/termios.h deleted file mode 100644 index 205de8f8a9d3..000000000000 --- a/arch/powerpc/include/asm/termios.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Liberally adapted from alpha/termios.h. In particular, the c_cc[] - * fields have been reordered so that termio & termios share the - * common subset in the same order (for brain dead programs that don't - * know or care about the differences). - */ -#ifndef _ASM_POWERPC_TERMIOS_H -#define _ASM_POWERPC_TERMIOS_H - -#include - -/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */ -#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025" - -#include - -#endif /* _ASM_POWERPC_TERMIOS_H */ diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h deleted file mode 100644 index 46fa3020b41e..000000000000 --- a/arch/s390/include/asm/termios.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * S390 version - * - * Derived from "include/asm-i386/termios.h" - */ -#ifndef _S390_TERMIOS_H -#define _S390_TERMIOS_H - -#include - - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) - -#include - -#endif /* _S390_TERMIOS_H */ diff --git a/arch/s390/include/uapi/asm/termios.h b/arch/s390/include/uapi/asm/termios.h deleted file mode 100644 index 54223169c806..000000000000 --- a/arch/s390/include/uapi/asm/termios.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * S390 version - * - * Derived from "include/asm-i386/termios.h" - */ - -#ifndef _UAPI_S390_TERMIOS_H -#define _UAPI_S390_TERMIOS_H - -#include -#include - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - - -#endif /* _UAPI_S390_TERMIOS_H */ diff --git a/arch/sparc/include/asm/termios.h b/arch/sparc/include/asm/termios.h deleted file mode 100644 index 4a558efdfa93..000000000000 --- a/arch/sparc/include/asm/termios.h +++ /dev/null @@ -1,147 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _SPARC_TERMIOS_H -#define _SPARC_TERMIOS_H - -#include - - -/* - * c_cc characters in the termio structure. Oh, how I love being - * backwardly compatible. Notice that character 4 and 5 are - * interpreted differently depending on whether ICANON is set in - * c_lflag. If it's set, they are used as _VEOF and _VEOL, otherwise - * as _VMIN and V_TIME. This is for compatibility with OSF/1 (which - * is compatible with sysV)... - */ -#define _VMIN 4 -#define _VTIME 5 - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D eol=\0 eol2=\0 sxtc=\0 - start=^Q stop=^S susp=^Z dsusp=^Y - reprint=^R discard=^U werase=^W lnext=^V - vmin=\1 vtime=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\000\000\000\021\023\032\031\022\025\027\026\001" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -#define user_termio_to_kernel_termios(termios, termio) \ -({ \ - unsigned short tmp; \ - int err; \ - err = get_user(tmp, &(termio)->c_iflag); \ - (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ - err |= get_user(tmp, &(termio)->c_oflag); \ - (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ - err |= get_user(tmp, &(termio)->c_cflag); \ - (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ - err |= get_user(tmp, &(termio)->c_lflag); \ - (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ - err |= copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ - err; \ -}) - -/* - * Translate a "termios" structure into a "termio". Ugh. - * - * Note the "fun" _VMIN overloading. - */ -#define kernel_termios_to_user_termio(termio, termios) \ -({ \ - int err; \ - err = put_user((termios)->c_iflag, &(termio)->c_iflag); \ - err |= put_user((termios)->c_oflag, &(termio)->c_oflag); \ - err |= put_user((termios)->c_cflag, &(termio)->c_cflag); \ - err |= put_user((termios)->c_lflag, &(termio)->c_lflag); \ - err |= put_user((termios)->c_line, &(termio)->c_line); \ - err |= copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ - if (!((termios)->c_lflag & ICANON)) { \ - err |= put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \ - err |= put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \ - } \ - err; \ -}) - -#define user_termios_to_kernel_termios(k, u) \ -({ \ - int err; \ - err = get_user((k)->c_iflag, &(u)->c_iflag); \ - err |= get_user((k)->c_oflag, &(u)->c_oflag); \ - err |= get_user((k)->c_cflag, &(u)->c_cflag); \ - err |= get_user((k)->c_lflag, &(u)->c_lflag); \ - err |= get_user((k)->c_line, &(u)->c_line); \ - err |= copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \ - if ((k)->c_lflag & ICANON) { \ - err |= get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - err |= get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ - } else { \ - err |= get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - err |= get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ - } \ - err |= get_user((k)->c_ispeed, &(u)->c_ispeed); \ - err |= get_user((k)->c_ospeed, &(u)->c_ospeed); \ - err; \ -}) - -#define kernel_termios_to_user_termios(u, k) \ -({ \ - int err; \ - err = put_user((k)->c_iflag, &(u)->c_iflag); \ - err |= put_user((k)->c_oflag, &(u)->c_oflag); \ - err |= put_user((k)->c_cflag, &(u)->c_cflag); \ - err |= put_user((k)->c_lflag, &(u)->c_lflag); \ - err |= put_user((k)->c_line, &(u)->c_line); \ - err |= copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \ - if (!((k)->c_lflag & ICANON)) { \ - err |= put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - err |= put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ - } else { \ - err |= put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - err |= put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ - } \ - err |= put_user((k)->c_ispeed, &(u)->c_ispeed); \ - err |= put_user((k)->c_ospeed, &(u)->c_ospeed); \ - err; \ -}) - -#define user_termios_to_kernel_termios_1(k, u) \ -({ \ - int err; \ - err = get_user((k)->c_iflag, &(u)->c_iflag); \ - err |= get_user((k)->c_oflag, &(u)->c_oflag); \ - err |= get_user((k)->c_cflag, &(u)->c_cflag); \ - err |= get_user((k)->c_lflag, &(u)->c_lflag); \ - err |= get_user((k)->c_line, &(u)->c_line); \ - err |= copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \ - if ((k)->c_lflag & ICANON) { \ - err |= get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - err |= get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ - } else { \ - err |= get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - err |= get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ - } \ - err; \ -}) - -#define kernel_termios_to_user_termios_1(u, k) \ -({ \ - int err; \ - err = put_user((k)->c_iflag, &(u)->c_iflag); \ - err |= put_user((k)->c_oflag, &(u)->c_oflag); \ - err |= put_user((k)->c_cflag, &(u)->c_cflag); \ - err |= put_user((k)->c_lflag, &(u)->c_lflag); \ - err |= put_user((k)->c_line, &(u)->c_line); \ - err |= copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \ - if (!((k)->c_lflag & ICANON)) { \ - err |= put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - err |= put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ - } else { \ - err |= put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - err |= put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ - } \ - err; \ -}) - -#endif /* _SPARC_TERMIOS_H */ diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index d3a0e072ebe8..620c0c5b749b 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -87,12 +87,13 @@ obj-$(CONFIG_SPARC64_SMP) += hvtramp.o obj-y += auxio_$(BITS).o obj-$(CONFIG_SUN_PM) += apc.o pmc.o +obj-y += termios.o + obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += sparc_ksyms.o obj-$(CONFIG_SPARC_LED) += led.o obj-$(CONFIG_KGDB) += kgdb_$(BITS).o - obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o @@ -104,6 +105,7 @@ obj-$(CONFIG_SPARC64_PCI) += pci_psycho.o pci_sabre.o pci_schizo.o obj-$(CONFIG_SPARC64_PCI) += pci_sun4v.o pci_sun4v_asm.o pci_fire.o obj-$(CONFIG_SPARC64_PCI_MSI) += pci_msi.o + obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o obj-$(CONFIG_US3_MC) += chmc.o diff --git a/arch/sparc/kernel/termios.c b/arch/sparc/kernel/termios.c new file mode 100644 index 000000000000..ee64965c27cd --- /dev/null +++ b/arch/sparc/kernel/termios.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +/* + * c_cc characters in the termio structure. Oh, how I love being + * backwardly compatible. Notice that character 4 and 5 are + * interpreted differently depending on whether ICANON is set in + * c_lflag. If it's set, they are used as _VEOF and _VEOL, otherwise + * as _VMIN and V_TIME. This is for compatibility with OSF/1 (which + * is compatible with sysV)... + */ +#define _VMIN 4 +#define _VTIME 5 + +int kernel_termios_to_user_termio(struct termio __user *termio, + struct ktermios *termios) +{ + struct termio v; + memset(&v, 0, sizeof(struct termio)); + v.c_iflag = termios->c_iflag; + v.c_oflag = termios->c_oflag; + v.c_cflag = termios->c_cflag; + v.c_lflag = termios->c_lflag; + v.c_line = termios->c_line; + memcpy(v.c_cc, termios->c_cc, NCC); + if (!(v.c_lflag & ICANON)) { + v.c_cc[_VMIN] = termios->c_cc[VMIN]; + v.c_cc[_VTIME] = termios->c_cc[VTIME]; + } + return copy_to_user(termio, &v, sizeof(struct termio)); +} + +int user_termios_to_kernel_termios(struct ktermios *k, + struct termios2 __user *u) +{ + int err; + err = get_user(k->c_iflag, &u->c_iflag); + err |= get_user(k->c_oflag, &u->c_oflag); + err |= get_user(k->c_cflag, &u->c_cflag); + err |= get_user(k->c_lflag, &u->c_lflag); + err |= get_user(k->c_line, &u->c_line); + err |= copy_from_user(k->c_cc, u->c_cc, NCCS); + if (k->c_lflag & ICANON) { + err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); + err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); + } else { + err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); + err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); + } + err |= get_user(k->c_ispeed, &u->c_ispeed); + err |= get_user(k->c_ospeed, &u->c_ospeed); + return err; +} + +int kernel_termios_to_user_termios(struct termios2 __user *u, + struct ktermios *k) +{ + int err; + err = put_user(k->c_iflag, &u->c_iflag); + err |= put_user(k->c_oflag, &u->c_oflag); + err |= put_user(k->c_cflag, &u->c_cflag); + err |= put_user(k->c_lflag, &u->c_lflag); + err |= put_user(k->c_line, &u->c_line); + err |= copy_to_user(u->c_cc, k->c_cc, NCCS); + if (!(k->c_lflag & ICANON)) { + err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); + err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); + } else { + err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); + err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); + } + err |= put_user(k->c_ispeed, &u->c_ispeed); + err |= put_user(k->c_ospeed, &u->c_ospeed); + return err; +} + +int user_termios_to_kernel_termios_1(struct ktermios *k, + struct termios __user *u) +{ + int err; + err = get_user(k->c_iflag, &u->c_iflag); + err |= get_user(k->c_oflag, &u->c_oflag); + err |= get_user(k->c_cflag, &u->c_cflag); + err |= get_user(k->c_lflag, &u->c_lflag); + err |= get_user(k->c_line, &u->c_line); + err |= copy_from_user(k->c_cc, u->c_cc, NCCS); + if (k->c_lflag & ICANON) { + err |= get_user(k->c_cc[VEOF], &u->c_cc[VEOF]); + err |= get_user(k->c_cc[VEOL], &u->c_cc[VEOL]); + } else { + err |= get_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); + err |= get_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); + } + return err; +} + +int kernel_termios_to_user_termios_1(struct termios __user *u, + struct ktermios *k) +{ + int err; + err = put_user(k->c_iflag, &u->c_iflag); + err |= put_user(k->c_oflag, &u->c_oflag); + err |= put_user(k->c_cflag, &u->c_cflag); + err |= put_user(k->c_lflag, &u->c_lflag); + err |= put_user(k->c_line, &u->c_line); + err |= copy_to_user(u->c_cc, k->c_cc, NCCS); + if (!(k->c_lflag & ICANON)) { + err |= put_user(k->c_cc[VMIN], &u->c_cc[_VMIN]); + err |= put_user(k->c_cc[VTIME], &u->c_cc[_VTIME]); + } else { + err |= put_user(k->c_cc[VEOF], &u->c_cc[VEOF]); + err |= put_user(k->c_cc[VEOL], &u->c_cc[VEOL]); + } + return err; +} diff --git a/drivers/base/base.h b/drivers/base/base.h index b3a43a164dcd..b902d1ecc247 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -154,8 +154,6 @@ extern void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); void device_driver_detach(struct device *dev); -extern char *make_class_name(const char *name, struct kobject *kobj); - extern int devres_release_all(struct device *dev); extern void device_block_probing(void); extern void device_unblock_probing(void); diff --git a/drivers/base/class.c b/drivers/base/class.c index 8feb85e186e3..64f7b9a0970f 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -260,7 +260,7 @@ EXPORT_SYMBOL_GPL(__class_create); */ void class_destroy(struct class *cls) { - if ((cls == NULL) || (IS_ERR(cls))) + if (IS_ERR_OR_NULL(cls)) return; class_unregister(cls); diff --git a/drivers/base/core.c b/drivers/base/core.c index 5fb4bc51dd8b..d02501933467 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2509,7 +2509,7 @@ static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, rc = kobject_synth_uevent(&dev->kobj, buf, count); if (rc) { - dev_err(dev, "uevent: failed to send synthetic uevent\n"); + dev_err(dev, "uevent: failed to send synthetic uevent: %d\n", rc); return rc; } @@ -4170,7 +4170,7 @@ device_create_groups_vargs(struct class *class, struct device *parent, struct device *dev = NULL; int retval = -ENODEV; - if (class == NULL || IS_ERR(class)) + if (IS_ERR_OR_NULL(class)) goto error; dev = kzalloc(sizeof(*dev), GFP_KERNEL); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index ec69b43f926a..3dda62503102 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -836,7 +836,7 @@ static int __init save_async_options(char *buf) if (strlen(buf) >= ASYNC_DRV_NAMES_MAX_LEN) pr_warn("Too long list of driver names for 'driver_async_probe'!\n"); - strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); + strscpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); async_probe_default = parse_option_str(async_probe_drv_names, "*"); return 1; diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index f4d794d6bb85..1c06781f7114 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -25,6 +25,47 @@ struct devcd_entry { struct device devcd_dev; void *data; size_t datalen; + /* + * Here, mutex is required to serialize the calls to del_wk work between + * user/kernel space which happens when devcd is added with device_add() + * and that sends uevent to user space. User space reads the uevents, + * and calls to devcd_data_write() which try to modify the work which is + * not even initialized/queued from devcoredump. + * + * + * + * cpu0(X) cpu1(Y) + * + * dev_coredump() uevent sent to user space + * device_add() ======================> user space process Y reads the + * uevents writes to devcd fd + * which results into writes to + * + * devcd_data_write() + * mod_delayed_work() + * try_to_grab_pending() + * del_timer() + * debug_assert_init() + * INIT_DELAYED_WORK() + * schedule_delayed_work() + * + * + * Also, mutex alone would not be enough to avoid scheduling of + * del_wk work after it get flush from a call to devcd_free() + * mentioned as below. + * + * disabled_store() + * devcd_free() + * mutex_lock() devcd_data_write() + * flush_delayed_work() + * mutex_unlock() + * mutex_lock() + * mod_delayed_work() + * mutex_unlock() + * So, delete_work flag is required. + */ + struct mutex mutex; + bool delete_work; struct module *owner; ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen); @@ -84,7 +125,12 @@ static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct devcd_entry *devcd = dev_to_devcd(dev); - mod_delayed_work(system_wq, &devcd->del_wk, 0); + mutex_lock(&devcd->mutex); + if (!devcd->delete_work) { + devcd->delete_work = true; + mod_delayed_work(system_wq, &devcd->del_wk, 0); + } + mutex_unlock(&devcd->mutex); return count; } @@ -112,7 +158,12 @@ static int devcd_free(struct device *dev, void *data) { struct devcd_entry *devcd = dev_to_devcd(dev); + mutex_lock(&devcd->mutex); + if (!devcd->delete_work) + devcd->delete_work = true; + flush_delayed_work(&devcd->del_wk); + mutex_unlock(&devcd->mutex); return 0; } @@ -122,6 +173,30 @@ static ssize_t disabled_show(struct class *class, struct class_attribute *attr, return sysfs_emit(buf, "%d\n", devcd_disabled); } +/* + * + * disabled_store() worker() + * class_for_each_device(&devcd_class, + * NULL, NULL, devcd_free) + * ... + * ... + * while ((dev = class_dev_iter_next(&iter)) + * devcd_del() + * device_del() + * put_device() <- last reference + * error = fn(dev, data) devcd_dev_release() + * devcd_free(dev, data) kfree(devcd) + * mutex_lock(&devcd->mutex); + * + * + * In the above diagram, It looks like disabled_store() would be racing with parallely + * running devcd_del() and result in memory abort while acquiring devcd->mutex which + * is called after kfree of devcd memory after dropping its last reference with + * put_device(). However, this will not happens as fn(dev, data) runs + * with its own reference to device via klist_node so it is not its last reference. + * so, above situation would not occur. + */ + static ssize_t disabled_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { @@ -278,13 +353,16 @@ void dev_coredumpm(struct device *dev, struct module *owner, devcd->read = read; devcd->free = free; devcd->failing_dev = get_device(dev); + devcd->delete_work = false; + mutex_init(&devcd->mutex); device_initialize(&devcd->devcd_dev); dev_set_name(&devcd->devcd_dev, "devcd%d", atomic_inc_return(&devcd_count)); devcd->devcd_dev.class = &devcd_class; + mutex_lock(&devcd->mutex); if (device_add(&devcd->devcd_dev)) goto put_device; @@ -301,10 +379,11 @@ void dev_coredumpm(struct device *dev, struct module *owner, INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT); - + mutex_unlock(&devcd->mutex); return; put_device: put_device(&devcd->devcd_dev); + mutex_unlock(&devcd->mutex); put_module: module_put(owner); free: diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 864d0b3f566e..4ab2b50ee38f 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -117,7 +117,9 @@ static __always_inline struct devres * alloc_dr(dr_release_t release, if (unlikely(!dr)) return NULL; - memset(dr, 0, offsetof(struct devres, data)); + /* No need to clear memory twice */ + if (!(gfp & __GFP_ZERO)) + memset(dr, 0, offsetof(struct devres, data)); INIT_LIST_HEAD(&dr->node.entry); dr->node.release = release; diff --git a/drivers/base/property.c b/drivers/base/property.c index ed6f449f8e5c..4d6278a84868 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -17,7 +17,7 @@ #include #include -struct fwnode_handle *dev_fwnode(struct device *dev) +struct fwnode_handle *dev_fwnode(const struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? of_fwnode_handle(dev->of_node) : dev->fwnode; @@ -1200,7 +1200,7 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, } EXPORT_SYMBOL(fwnode_graph_parse_endpoint); -const void *device_get_match_data(struct device *dev) +const void *device_get_match_data(const struct device *dev) { return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 4762a03e1ffe..5cffd96ef2d7 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -157,8 +157,6 @@ static struct dentry *nbd_dbg_dir; #define nbd_name(nbd) ((nbd)->disk->disk_name) -#define NBD_MAGIC 0x68797548 - #define NBD_DEF_BLKSIZE_BITS 10 static unsigned int nbds_max = 16; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8fc49b038372..b2735be81ab2 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2274,7 +2274,8 @@ static int mgslpc_ioctl(struct tty_struct *tty, * tty pointer to tty structure * termios pointer to buffer to hold returned old termios */ -static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void mgslpc_set_termios(struct tty_struct *tty, + const struct ktermios *old_termios) { MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index a06d2a7627aa..7524b62a8870 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -180,7 +180,7 @@ config DMA_SUN6I config DW_AXI_DMAC tristate "Synopsys DesignWare AXI DMA support" - depends on OF || COMPILE_TEST + depends on OF depends on HAS_IOMEM select DMA_ENGINE select DMA_VIRTUAL_CHANNELS diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 487a01aa207d..eea8bd33b4b7 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -2367,7 +2367,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, INIT_LIST_HEAD(&dmadev->channels); /* - * Register as many many memcpy as we have physical channels, + * Register as many memcpy as we have physical channels, * we won't always be able to use all but the code will have * to cope with that situation. */ diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index d1f74a3aa999..317ca76ccafd 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -12,8 +12,9 @@ #include #include #include -#include +#include #include +#include #include "dmaengine.h" @@ -95,7 +96,9 @@ struct admac_data { struct dma_device dma; struct device *dev; __iomem void *base; + struct reset_control *rstc; + int irq; int irq_index; int nchannels; struct admac_chan channels[]; @@ -724,18 +727,17 @@ static int admac_probe(struct platform_device *pdev) if (irq < 0) return dev_err_probe(&pdev->dev, irq, "no usable interrupt\n"); - - err = devm_request_irq(&pdev->dev, irq, admac_interrupt, - 0, dev_name(&pdev->dev), ad); - if (err) - return dev_err_probe(&pdev->dev, err, - "unable to register interrupt\n"); + ad->irq = irq; ad->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ad->base)) return dev_err_probe(&pdev->dev, PTR_ERR(ad->base), "unable to obtain MMIO resource\n"); + ad->rstc = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(ad->rstc)) + return PTR_ERR(ad->rstc); + dma = &ad->dma; dma_cap_set(DMA_PRIVATE, dma->cap_mask); @@ -774,17 +776,38 @@ static int admac_probe(struct platform_device *pdev) tasklet_setup(&adchan->tasklet, admac_chan_tasklet); } - err = dma_async_device_register(&ad->dma); + err = reset_control_reset(ad->rstc); if (err) - return dev_err_probe(&pdev->dev, err, "failed to register DMA device\n"); + return dev_err_probe(&pdev->dev, err, + "unable to trigger reset\n"); + + err = request_irq(irq, admac_interrupt, 0, dev_name(&pdev->dev), ad); + if (err) { + dev_err_probe(&pdev->dev, err, + "unable to register interrupt\n"); + goto free_reset; + } + + err = dma_async_device_register(&ad->dma); + if (err) { + dev_err_probe(&pdev->dev, err, "failed to register DMA device\n"); + goto free_irq; + } err = of_dma_controller_register(pdev->dev.of_node, admac_dma_of_xlate, ad); if (err) { dma_async_device_unregister(&ad->dma); - return dev_err_probe(&pdev->dev, err, "failed to register with OF\n"); + dev_err_probe(&pdev->dev, err, "failed to register with OF\n"); + goto free_irq; } return 0; + +free_irq: + free_irq(ad->irq, ad); +free_reset: + reset_control_rearm(ad->rstc); + return err; } static int admac_remove(struct platform_device *pdev) @@ -793,6 +816,8 @@ static int admac_remove(struct platform_device *pdev) of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&ad->dma); + free_irq(ad->irq, ad); + reset_control_rearm(ad->rstc); return 0; } diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b102d8eb5d83..d6c9781cd46a 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1470,10 +1470,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, bool initd; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_COMPLETE) - return ret; - - if (!txstate) + if (ret == DMA_COMPLETE || !txstate) return ret; spin_lock_irqsave(&atchan->lock, flags); diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index 07f756479663..c54b24ff5206 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -682,15 +681,12 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan) if (chan->status != EDMA_ST_IDLE) return -EBUSY; - pm_runtime_get(chan->dw->chip->dev); - return 0; } static void dw_edma_free_chan_resources(struct dma_chan *dchan) { unsigned long timeout = jiffies + msecs_to_jiffies(5000); - struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan); int ret; while (time_before(jiffies, timeout)) { @@ -703,8 +699,6 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan) cpu_relax(); } - - pm_runtime_put(chan->dw->chip->dev); } static int dw_edma_channel_setup(struct dw_edma *dw, bool write, @@ -977,9 +971,6 @@ int dw_edma_probe(struct dw_edma_chip *chip) if (err) goto err_irq_free; - /* Power management */ - pm_runtime_enable(dev); - /* Turn debugfs on */ dw_edma_v0_core_debugfs_on(dw); @@ -1009,9 +1000,6 @@ int dw_edma_remove(struct dw_edma_chip *chip) for (i = (dw->nr_irqs - 1); i >= 0; i--) free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]); - /* Power management */ - pm_runtime_disable(dev); - /* Deregister eDMA device */ dma_async_device_unregister(&dw->wr_edma); list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels, diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index 43817ced3a3e..c1350a36fddd 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright(c) 2019 HiSilicon Limited. */ +/* Copyright(c) 2019-2022 HiSilicon Limited. */ + #include #include #include @@ -9,32 +10,87 @@ #include #include "virt-dma.h" -#define HISI_DMA_SQ_BASE_L 0x0 -#define HISI_DMA_SQ_BASE_H 0x4 -#define HISI_DMA_SQ_DEPTH 0x8 -#define HISI_DMA_SQ_TAIL_PTR 0xc -#define HISI_DMA_CQ_BASE_L 0x10 -#define HISI_DMA_CQ_BASE_H 0x14 -#define HISI_DMA_CQ_DEPTH 0x18 -#define HISI_DMA_CQ_HEAD_PTR 0x1c -#define HISI_DMA_CTRL0 0x20 -#define HISI_DMA_CTRL0_QUEUE_EN_S 0 -#define HISI_DMA_CTRL0_QUEUE_PAUSE_S 4 -#define HISI_DMA_CTRL1 0x24 -#define HISI_DMA_CTRL1_QUEUE_RESET_S 0 -#define HISI_DMA_Q_FSM_STS 0x30 -#define HISI_DMA_FSM_STS_MASK GENMASK(3, 0) -#define HISI_DMA_INT_STS 0x40 -#define HISI_DMA_INT_STS_MASK GENMASK(12, 0) -#define HISI_DMA_INT_MSK 0x44 -#define HISI_DMA_MODE 0x217c -#define HISI_DMA_OFFSET 0x100 +/* HiSilicon DMA register common field define */ +#define HISI_DMA_Q_SQ_BASE_L 0x0 +#define HISI_DMA_Q_SQ_BASE_H 0x4 +#define HISI_DMA_Q_SQ_DEPTH 0x8 +#define HISI_DMA_Q_SQ_TAIL_PTR 0xc +#define HISI_DMA_Q_CQ_BASE_L 0x10 +#define HISI_DMA_Q_CQ_BASE_H 0x14 +#define HISI_DMA_Q_CQ_DEPTH 0x18 +#define HISI_DMA_Q_CQ_HEAD_PTR 0x1c +#define HISI_DMA_Q_CTRL0 0x20 +#define HISI_DMA_Q_CTRL0_QUEUE_EN BIT(0) +#define HISI_DMA_Q_CTRL0_QUEUE_PAUSE BIT(4) +#define HISI_DMA_Q_CTRL1 0x24 +#define HISI_DMA_Q_CTRL1_QUEUE_RESET BIT(0) +#define HISI_DMA_Q_FSM_STS 0x30 +#define HISI_DMA_Q_FSM_STS_MASK GENMASK(3, 0) +#define HISI_DMA_Q_ERR_INT_NUM0 0x84 +#define HISI_DMA_Q_ERR_INT_NUM1 0x88 +#define HISI_DMA_Q_ERR_INT_NUM2 0x8c -#define HISI_DMA_MSI_NUM 32 -#define HISI_DMA_CHAN_NUM 30 -#define HISI_DMA_Q_DEPTH_VAL 1024 +/* HiSilicon IP08 DMA register and field define */ +#define HISI_DMA_HIP08_MODE 0x217C +#define HISI_DMA_HIP08_Q_BASE 0x0 +#define HISI_DMA_HIP08_Q_CTRL0_ERR_ABORT_EN BIT(2) +#define HISI_DMA_HIP08_Q_INT_STS 0x40 +#define HISI_DMA_HIP08_Q_INT_MSK 0x44 +#define HISI_DMA_HIP08_Q_INT_STS_MASK GENMASK(14, 0) +#define HISI_DMA_HIP08_Q_ERR_INT_NUM3 0x90 +#define HISI_DMA_HIP08_Q_ERR_INT_NUM4 0x94 +#define HISI_DMA_HIP08_Q_ERR_INT_NUM5 0x98 +#define HISI_DMA_HIP08_Q_ERR_INT_NUM6 0x48 +#define HISI_DMA_HIP08_Q_CTRL0_SQCQ_DRCT BIT(24) -#define PCI_BAR_2 2 +/* HiSilicon IP09 DMA register and field define */ +#define HISI_DMA_HIP09_DMA_FLR_DISABLE 0xA00 +#define HISI_DMA_HIP09_DMA_FLR_DISABLE_B BIT(0) +#define HISI_DMA_HIP09_Q_BASE 0x2000 +#define HISI_DMA_HIP09_Q_CTRL0_ERR_ABORT_EN GENMASK(31, 28) +#define HISI_DMA_HIP09_Q_CTRL0_SQ_DRCT BIT(26) +#define HISI_DMA_HIP09_Q_CTRL0_CQ_DRCT BIT(27) +#define HISI_DMA_HIP09_Q_CTRL1_VA_ENABLE BIT(2) +#define HISI_DMA_HIP09_Q_INT_STS 0x40 +#define HISI_DMA_HIP09_Q_INT_MSK 0x44 +#define HISI_DMA_HIP09_Q_INT_STS_MASK 0x1 +#define HISI_DMA_HIP09_Q_ERR_INT_STS 0x48 +#define HISI_DMA_HIP09_Q_ERR_INT_MSK 0x4C +#define HISI_DMA_HIP09_Q_ERR_INT_STS_MASK GENMASK(18, 1) +#define HISI_DMA_HIP09_PORT_CFG_REG(port_id) (0x800 + \ + (port_id) * 0x20) +#define HISI_DMA_HIP09_PORT_CFG_LINK_DOWN_MASK_B BIT(16) + +#define HISI_DMA_HIP09_MAX_PORT_NUM 16 + +#define HISI_DMA_HIP08_MSI_NUM 32 +#define HISI_DMA_HIP08_CHAN_NUM 30 +#define HISI_DMA_HIP09_MSI_NUM 4 +#define HISI_DMA_HIP09_CHAN_NUM 4 +#define HISI_DMA_REVISION_HIP08B 0x21 +#define HISI_DMA_REVISION_HIP09A 0x30 + +#define HISI_DMA_Q_OFFSET 0x100 +#define HISI_DMA_Q_DEPTH_VAL 1024 + +#define PCI_BAR_2 2 + +#define HISI_DMA_POLL_Q_STS_DELAY_US 10 +#define HISI_DMA_POLL_Q_STS_TIME_OUT_US 1000 + +#define HISI_DMA_MAX_DIR_NAME_LEN 128 + +/* + * The HIP08B(HiSilicon IP08) and HIP09A(HiSilicon IP09) are DMA iEPs, they + * have the same pci device id but different pci revision. + * Unfortunately, they have different register layouts, so two layout + * enumerations are defined. + */ +enum hisi_dma_reg_layout { + HISI_DMA_REG_LAYOUT_INVALID = 0, + HISI_DMA_REG_LAYOUT_HIP08, + HISI_DMA_REG_LAYOUT_HIP09 +}; enum hisi_dma_mode { EP = 0, @@ -105,9 +161,162 @@ struct hisi_dma_dev { struct dma_device dma_dev; u32 chan_num; u32 chan_depth; + enum hisi_dma_reg_layout reg_layout; + void __iomem *queue_base; /* queue region start of register */ struct hisi_dma_chan chan[]; }; +#ifdef CONFIG_DEBUG_FS + +static const struct debugfs_reg32 hisi_dma_comm_chan_regs[] = { + {"DMA_QUEUE_SQ_DEPTH ", 0x0008ull}, + {"DMA_QUEUE_SQ_TAIL_PTR ", 0x000Cull}, + {"DMA_QUEUE_CQ_DEPTH ", 0x0018ull}, + {"DMA_QUEUE_CQ_HEAD_PTR ", 0x001Cull}, + {"DMA_QUEUE_CTRL0 ", 0x0020ull}, + {"DMA_QUEUE_CTRL1 ", 0x0024ull}, + {"DMA_QUEUE_FSM_STS ", 0x0030ull}, + {"DMA_QUEUE_SQ_STS ", 0x0034ull}, + {"DMA_QUEUE_CQ_TAIL_PTR ", 0x003Cull}, + {"DMA_QUEUE_INT_STS ", 0x0040ull}, + {"DMA_QUEUE_INT_MSK ", 0x0044ull}, + {"DMA_QUEUE_INT_RO ", 0x006Cull}, +}; + +static const struct debugfs_reg32 hisi_dma_hip08_chan_regs[] = { + {"DMA_QUEUE_BYTE_CNT ", 0x0038ull}, + {"DMA_ERR_INT_NUM6 ", 0x0048ull}, + {"DMA_QUEUE_DESP0 ", 0x0050ull}, + {"DMA_QUEUE_DESP1 ", 0x0054ull}, + {"DMA_QUEUE_DESP2 ", 0x0058ull}, + {"DMA_QUEUE_DESP3 ", 0x005Cull}, + {"DMA_QUEUE_DESP4 ", 0x0074ull}, + {"DMA_QUEUE_DESP5 ", 0x0078ull}, + {"DMA_QUEUE_DESP6 ", 0x007Cull}, + {"DMA_QUEUE_DESP7 ", 0x0080ull}, + {"DMA_ERR_INT_NUM0 ", 0x0084ull}, + {"DMA_ERR_INT_NUM1 ", 0x0088ull}, + {"DMA_ERR_INT_NUM2 ", 0x008Cull}, + {"DMA_ERR_INT_NUM3 ", 0x0090ull}, + {"DMA_ERR_INT_NUM4 ", 0x0094ull}, + {"DMA_ERR_INT_NUM5 ", 0x0098ull}, + {"DMA_QUEUE_SQ_STS2 ", 0x00A4ull}, +}; + +static const struct debugfs_reg32 hisi_dma_hip09_chan_regs[] = { + {"DMA_QUEUE_ERR_INT_STS ", 0x0048ull}, + {"DMA_QUEUE_ERR_INT_MSK ", 0x004Cull}, + {"DFX_SQ_READ_ERR_PTR ", 0x0068ull}, + {"DFX_DMA_ERR_INT_NUM0 ", 0x0084ull}, + {"DFX_DMA_ERR_INT_NUM1 ", 0x0088ull}, + {"DFX_DMA_ERR_INT_NUM2 ", 0x008Cull}, + {"DFX_DMA_QUEUE_SQ_STS2 ", 0x00A4ull}, +}; + +static const struct debugfs_reg32 hisi_dma_hip08_comm_regs[] = { + {"DMA_ECC_ERR_ADDR ", 0x2004ull}, + {"DMA_ECC_ECC_CNT ", 0x2014ull}, + {"COMMON_AND_CH_ERR_STS ", 0x2030ull}, + {"LOCAL_CPL_ID_STS_0 ", 0x20E0ull}, + {"LOCAL_CPL_ID_STS_1 ", 0x20E4ull}, + {"LOCAL_CPL_ID_STS_2 ", 0x20E8ull}, + {"LOCAL_CPL_ID_STS_3 ", 0x20ECull}, + {"LOCAL_TLP_NUM ", 0x2158ull}, + {"SQCQ_TLP_NUM ", 0x2164ull}, + {"CPL_NUM ", 0x2168ull}, + {"INF_BACK_PRESS_STS ", 0x2170ull}, + {"DMA_CH_RAS_LEVEL ", 0x2184ull}, + {"DMA_CM_RAS_LEVEL ", 0x2188ull}, + {"DMA_CH_ERR_STS ", 0x2190ull}, + {"DMA_CH_DONE_STS ", 0x2194ull}, + {"DMA_SQ_TAG_STS_0 ", 0x21A0ull}, + {"DMA_SQ_TAG_STS_1 ", 0x21A4ull}, + {"DMA_SQ_TAG_STS_2 ", 0x21A8ull}, + {"DMA_SQ_TAG_STS_3 ", 0x21ACull}, + {"LOCAL_P_ID_STS_0 ", 0x21B0ull}, + {"LOCAL_P_ID_STS_1 ", 0x21B4ull}, + {"LOCAL_P_ID_STS_2 ", 0x21B8ull}, + {"LOCAL_P_ID_STS_3 ", 0x21BCull}, + {"DMA_PREBUFF_INFO_0 ", 0x2200ull}, + {"DMA_CM_TABLE_INFO_0 ", 0x2220ull}, + {"DMA_CM_CE_RO ", 0x2244ull}, + {"DMA_CM_NFE_RO ", 0x2248ull}, + {"DMA_CM_FE_RO ", 0x224Cull}, +}; + +static const struct debugfs_reg32 hisi_dma_hip09_comm_regs[] = { + {"COMMON_AND_CH_ERR_STS ", 0x0030ull}, + {"DMA_PORT_IDLE_STS ", 0x0150ull}, + {"DMA_CH_RAS_LEVEL ", 0x0184ull}, + {"DMA_CM_RAS_LEVEL ", 0x0188ull}, + {"DMA_CM_CE_RO ", 0x0244ull}, + {"DMA_CM_NFE_RO ", 0x0248ull}, + {"DMA_CM_FE_RO ", 0x024Cull}, + {"DFX_INF_BACK_PRESS_STS0 ", 0x1A40ull}, + {"DFX_INF_BACK_PRESS_STS1 ", 0x1A44ull}, + {"DFX_INF_BACK_PRESS_STS2 ", 0x1A48ull}, + {"DFX_DMA_WRR_DISABLE ", 0x1A4Cull}, + {"DFX_PA_REQ_TLP_NUM ", 0x1C00ull}, + {"DFX_PA_BACK_TLP_NUM ", 0x1C04ull}, + {"DFX_PA_RETRY_TLP_NUM ", 0x1C08ull}, + {"DFX_LOCAL_NP_TLP_NUM ", 0x1C0Cull}, + {"DFX_LOCAL_CPL_HEAD_TLP_NUM ", 0x1C10ull}, + {"DFX_LOCAL_CPL_DATA_TLP_NUM ", 0x1C14ull}, + {"DFX_LOCAL_CPL_EXT_DATA_TLP_NUM ", 0x1C18ull}, + {"DFX_LOCAL_P_HEAD_TLP_NUM ", 0x1C1Cull}, + {"DFX_LOCAL_P_ACK_TLP_NUM ", 0x1C20ull}, + {"DFX_BUF_ALOC_PORT_REQ_NUM ", 0x1C24ull}, + {"DFX_BUF_ALOC_PORT_RESULT_NUM ", 0x1C28ull}, + {"DFX_BUF_FAIL_SIZE_NUM ", 0x1C2Cull}, + {"DFX_BUF_ALOC_SIZE_NUM ", 0x1C30ull}, + {"DFX_BUF_NP_RELEASE_SIZE_NUM ", 0x1C34ull}, + {"DFX_BUF_P_RELEASE_SIZE_NUM ", 0x1C38ull}, + {"DFX_BUF_PORT_RELEASE_SIZE_NUM ", 0x1C3Cull}, + {"DFX_DMA_PREBUF_MEM0_ECC_ERR_ADDR ", 0x1CA8ull}, + {"DFX_DMA_PREBUF_MEM0_ECC_CNT ", 0x1CACull}, + {"DFX_DMA_LOC_NP_OSTB_ECC_ERR_ADDR ", 0x1CB0ull}, + {"DFX_DMA_LOC_NP_OSTB_ECC_CNT ", 0x1CB4ull}, + {"DFX_DMA_PREBUF_MEM1_ECC_ERR_ADDR ", 0x1CC0ull}, + {"DFX_DMA_PREBUF_MEM1_ECC_CNT ", 0x1CC4ull}, + {"DMA_CH_DONE_STS ", 0x02E0ull}, + {"DMA_CH_ERR_STS ", 0x0320ull}, +}; +#endif /* CONFIG_DEBUG_FS*/ + +static enum hisi_dma_reg_layout hisi_dma_get_reg_layout(struct pci_dev *pdev) +{ + if (pdev->revision == HISI_DMA_REVISION_HIP08B) + return HISI_DMA_REG_LAYOUT_HIP08; + else if (pdev->revision >= HISI_DMA_REVISION_HIP09A) + return HISI_DMA_REG_LAYOUT_HIP09; + + return HISI_DMA_REG_LAYOUT_INVALID; +} + +static u32 hisi_dma_get_chan_num(struct pci_dev *pdev) +{ + if (pdev->revision == HISI_DMA_REVISION_HIP08B) + return HISI_DMA_HIP08_CHAN_NUM; + + return HISI_DMA_HIP09_CHAN_NUM; +} + +static u32 hisi_dma_get_msi_num(struct pci_dev *pdev) +{ + if (pdev->revision == HISI_DMA_REVISION_HIP08B) + return HISI_DMA_HIP08_MSI_NUM; + + return HISI_DMA_HIP09_MSI_NUM; +} + +static u32 hisi_dma_get_queue_base(struct pci_dev *pdev) +{ + if (pdev->revision == HISI_DMA_REVISION_HIP08B) + return HISI_DMA_HIP08_Q_BASE; + + return HISI_DMA_HIP09_Q_BASE; +} + static inline struct hisi_dma_chan *to_hisi_dma_chan(struct dma_chan *c) { return container_of(c, struct hisi_dma_chan, vc.chan); @@ -121,7 +330,7 @@ static inline struct hisi_dma_desc *to_hisi_dma_desc(struct virt_dma_desc *vd) static inline void hisi_dma_chan_write(void __iomem *base, u32 reg, u32 index, u32 val) { - writel_relaxed(val, base + reg + index * HISI_DMA_OFFSET); + writel_relaxed(val, base + reg + index * HISI_DMA_Q_OFFSET); } static inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val) @@ -129,70 +338,103 @@ static inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val) u32 tmp; tmp = readl_relaxed(addr); - tmp = val ? tmp | BIT(pos) : tmp & ~BIT(pos); + tmp = val ? tmp | pos : tmp & ~pos; writel_relaxed(tmp, addr); } static void hisi_dma_pause_dma(struct hisi_dma_dev *hdma_dev, u32 index, bool pause) { - void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index * - HISI_DMA_OFFSET; + void __iomem *addr; - hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_PAUSE_S, pause); + addr = hdma_dev->queue_base + HISI_DMA_Q_CTRL0 + + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL0_QUEUE_PAUSE, pause); } static void hisi_dma_enable_dma(struct hisi_dma_dev *hdma_dev, u32 index, bool enable) { - void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL0 + index * - HISI_DMA_OFFSET; + void __iomem *addr; - hisi_dma_update_bit(addr, HISI_DMA_CTRL0_QUEUE_EN_S, enable); + addr = hdma_dev->queue_base + HISI_DMA_Q_CTRL0 + + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL0_QUEUE_EN, enable); } static void hisi_dma_mask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) { - hisi_dma_chan_write(hdma_dev->base, HISI_DMA_INT_MSK, qp_index, - HISI_DMA_INT_STS_MASK); + void __iomem *q_base = hdma_dev->queue_base; + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_MSK, + qp_index, HISI_DMA_HIP08_Q_INT_STS_MASK); + else { + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_MSK, + qp_index, HISI_DMA_HIP09_Q_INT_STS_MASK); + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_MSK, + qp_index, + HISI_DMA_HIP09_Q_ERR_INT_STS_MASK); + } } static void hisi_dma_unmask_irq(struct hisi_dma_dev *hdma_dev, u32 qp_index) { - void __iomem *base = hdma_dev->base; + void __iomem *q_base = hdma_dev->queue_base; - hisi_dma_chan_write(base, HISI_DMA_INT_STS, qp_index, - HISI_DMA_INT_STS_MASK); - hisi_dma_chan_write(base, HISI_DMA_INT_MSK, qp_index, 0); + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_STS, + qp_index, HISI_DMA_HIP08_Q_INT_STS_MASK); + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_INT_MSK, + qp_index, 0); + } else { + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_STS, + qp_index, HISI_DMA_HIP09_Q_INT_STS_MASK); + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_STS, + qp_index, + HISI_DMA_HIP09_Q_ERR_INT_STS_MASK); + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_INT_MSK, + qp_index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_HIP09_Q_ERR_INT_MSK, + qp_index, 0); + } } static void hisi_dma_do_reset(struct hisi_dma_dev *hdma_dev, u32 index) { - void __iomem *addr = hdma_dev->base + HISI_DMA_CTRL1 + index * - HISI_DMA_OFFSET; + void __iomem *addr; - hisi_dma_update_bit(addr, HISI_DMA_CTRL1_QUEUE_RESET_S, 1); + addr = hdma_dev->queue_base + + HISI_DMA_Q_CTRL1 + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_Q_CTRL1_QUEUE_RESET, 1); } static void hisi_dma_reset_qp_point(struct hisi_dma_dev *hdma_dev, u32 index) { - hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, index, 0); - hisi_dma_chan_write(hdma_dev->base, HISI_DMA_CQ_HEAD_PTR, index, 0); + void __iomem *q_base = hdma_dev->queue_base; + + hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_TAIL_PTR, index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, index, 0); } -static void hisi_dma_reset_hw_chan(struct hisi_dma_chan *chan) +static void hisi_dma_reset_or_disable_hw_chan(struct hisi_dma_chan *chan, + bool disable) { struct hisi_dma_dev *hdma_dev = chan->hdma_dev; u32 index = chan->qp_num, tmp; + void __iomem *addr; int ret; hisi_dma_pause_dma(hdma_dev, index, true); hisi_dma_enable_dma(hdma_dev, index, false); hisi_dma_mask_irq(hdma_dev, index); - ret = readl_relaxed_poll_timeout(hdma_dev->base + - HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp, - FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) != RUN, 10, 1000); + addr = hdma_dev->queue_base + + HISI_DMA_Q_FSM_STS + index * HISI_DMA_Q_OFFSET; + + ret = readl_relaxed_poll_timeout(addr, tmp, + FIELD_GET(HISI_DMA_Q_FSM_STS_MASK, tmp) != RUN, + HISI_DMA_POLL_Q_STS_DELAY_US, HISI_DMA_POLL_Q_STS_TIME_OUT_US); if (ret) { dev_err(&hdma_dev->pdev->dev, "disable channel timeout!\n"); WARN_ON(1); @@ -201,12 +443,15 @@ static void hisi_dma_reset_hw_chan(struct hisi_dma_chan *chan) hisi_dma_do_reset(hdma_dev, index); hisi_dma_reset_qp_point(hdma_dev, index); hisi_dma_pause_dma(hdma_dev, index, false); - hisi_dma_enable_dma(hdma_dev, index, true); - hisi_dma_unmask_irq(hdma_dev, index); - ret = readl_relaxed_poll_timeout(hdma_dev->base + - HISI_DMA_Q_FSM_STS + index * HISI_DMA_OFFSET, tmp, - FIELD_GET(HISI_DMA_FSM_STS_MASK, tmp) == IDLE, 10, 1000); + if (!disable) { + hisi_dma_enable_dma(hdma_dev, index, true); + hisi_dma_unmask_irq(hdma_dev, index); + } + + ret = readl_relaxed_poll_timeout(addr, tmp, + FIELD_GET(HISI_DMA_Q_FSM_STS_MASK, tmp) == IDLE, + HISI_DMA_POLL_Q_STS_DELAY_US, HISI_DMA_POLL_Q_STS_TIME_OUT_US); if (ret) { dev_err(&hdma_dev->pdev->dev, "reset channel timeout!\n"); WARN_ON(1); @@ -218,7 +463,7 @@ static void hisi_dma_free_chan_resources(struct dma_chan *c) struct hisi_dma_chan *chan = to_hisi_dma_chan(c); struct hisi_dma_dev *hdma_dev = chan->hdma_dev; - hisi_dma_reset_hw_chan(chan); + hisi_dma_reset_or_disable_hw_chan(chan, false); vchan_free_chan_resources(&chan->vc); memset(chan->sq, 0, sizeof(struct hisi_dma_sqe) * hdma_dev->chan_depth); @@ -267,7 +512,6 @@ static void hisi_dma_start_transfer(struct hisi_dma_chan *chan) vd = vchan_next_desc(&chan->vc); if (!vd) { - dev_err(&hdma_dev->pdev->dev, "no issued task!\n"); chan->desc = NULL; return; } @@ -288,8 +532,8 @@ static void hisi_dma_start_transfer(struct hisi_dma_chan *chan) chan->sq_tail = (chan->sq_tail + 1) % hdma_dev->chan_depth; /* update sq_tail to trigger a new task */ - hisi_dma_chan_write(hdma_dev->base, HISI_DMA_SQ_TAIL_PTR, chan->qp_num, - chan->sq_tail); + hisi_dma_chan_write(hdma_dev->queue_base, HISI_DMA_Q_SQ_TAIL_PTR, + chan->qp_num, chan->sq_tail); } static void hisi_dma_issue_pending(struct dma_chan *c) @@ -299,7 +543,7 @@ static void hisi_dma_issue_pending(struct dma_chan *c) spin_lock_irqsave(&chan->vc.lock, flags); - if (vchan_issue_pending(&chan->vc)) + if (vchan_issue_pending(&chan->vc) && !chan->desc) hisi_dma_start_transfer(chan); spin_unlock_irqrestore(&chan->vc.lock, flags); @@ -363,26 +607,86 @@ static int hisi_dma_alloc_qps_mem(struct hisi_dma_dev *hdma_dev) static void hisi_dma_init_hw_qp(struct hisi_dma_dev *hdma_dev, u32 index) { struct hisi_dma_chan *chan = &hdma_dev->chan[index]; + void __iomem *q_base = hdma_dev->queue_base; u32 hw_depth = hdma_dev->chan_depth - 1; - void __iomem *base = hdma_dev->base; + void __iomem *addr; + u32 tmp; /* set sq, cq base */ - hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_L, index, + hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_BASE_L, index, lower_32_bits(chan->sq_dma)); - hisi_dma_chan_write(base, HISI_DMA_SQ_BASE_H, index, + hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_BASE_H, index, upper_32_bits(chan->sq_dma)); - hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_L, index, + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_BASE_L, index, lower_32_bits(chan->cq_dma)); - hisi_dma_chan_write(base, HISI_DMA_CQ_BASE_H, index, + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_BASE_H, index, upper_32_bits(chan->cq_dma)); /* set sq, cq depth */ - hisi_dma_chan_write(base, HISI_DMA_SQ_DEPTH, index, hw_depth); - hisi_dma_chan_write(base, HISI_DMA_CQ_DEPTH, index, hw_depth); + hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_DEPTH, index, hw_depth); + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_DEPTH, index, hw_depth); /* init sq tail and cq head */ - hisi_dma_chan_write(base, HISI_DMA_SQ_TAIL_PTR, index, 0); - hisi_dma_chan_write(base, HISI_DMA_CQ_HEAD_PTR, index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_Q_SQ_TAIL_PTR, index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, index, 0); + + /* init error interrupt stats */ + hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM0, index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM1, index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_Q_ERR_INT_NUM2, index, 0); + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM3, + index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM4, + index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM5, + index, 0); + hisi_dma_chan_write(q_base, HISI_DMA_HIP08_Q_ERR_INT_NUM6, + index, 0); + /* + * init SQ/CQ direction selecting register. + * "0" is to local side and "1" is to remote side. + */ + addr = q_base + HISI_DMA_Q_CTRL0 + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_HIP08_Q_CTRL0_SQCQ_DRCT, 0); + + /* + * 0 - Continue to next descriptor if error occurs. + * 1 - Abort the DMA queue if error occurs. + */ + hisi_dma_update_bit(addr, + HISI_DMA_HIP08_Q_CTRL0_ERR_ABORT_EN, 0); + } else { + addr = q_base + HISI_DMA_Q_CTRL0 + index * HISI_DMA_Q_OFFSET; + + /* + * init SQ/CQ direction selecting register. + * "0" is to local side and "1" is to remote side. + */ + hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL0_SQ_DRCT, 0); + hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL0_CQ_DRCT, 0); + + /* + * 0 - Continue to next descriptor if error occurs. + * 1 - Abort the DMA queue if error occurs. + */ + + tmp = readl_relaxed(addr); + tmp &= ~HISI_DMA_HIP09_Q_CTRL0_ERR_ABORT_EN; + writel_relaxed(tmp, addr); + + /* + * 0 - dma should process FLR whith CPU. + * 1 - dma not process FLR, only cpu process FLR. + */ + addr = q_base + HISI_DMA_HIP09_DMA_FLR_DISABLE + + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_HIP09_DMA_FLR_DISABLE_B, 0); + + addr = q_base + HISI_DMA_Q_CTRL1 + index * HISI_DMA_Q_OFFSET; + hisi_dma_update_bit(addr, HISI_DMA_HIP09_Q_CTRL1_VA_ENABLE, 1); + } } static void hisi_dma_enable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) @@ -394,7 +698,7 @@ static void hisi_dma_enable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) static void hisi_dma_disable_qp(struct hisi_dma_dev *hdma_dev, u32 qp_index) { - hisi_dma_reset_hw_chan(&hdma_dev->chan[qp_index]); + hisi_dma_reset_or_disable_hw_chan(&hdma_dev->chan[qp_index], true); } static void hisi_dma_enable_qps(struct hisi_dma_dev *hdma_dev) @@ -426,24 +730,23 @@ static irqreturn_t hisi_dma_irq(int irq, void *data) struct hisi_dma_dev *hdma_dev = chan->hdma_dev; struct hisi_dma_desc *desc; struct hisi_dma_cqe *cqe; + void __iomem *q_base; spin_lock(&chan->vc.lock); desc = chan->desc; cqe = chan->cq + chan->cq_head; + q_base = hdma_dev->queue_base; if (desc) { + chan->cq_head = (chan->cq_head + 1) % hdma_dev->chan_depth; + hisi_dma_chan_write(q_base, HISI_DMA_Q_CQ_HEAD_PTR, + chan->qp_num, chan->cq_head); if (FIELD_GET(STATUS_MASK, cqe->w0) == STATUS_SUCC) { - chan->cq_head = (chan->cq_head + 1) % - hdma_dev->chan_depth; - hisi_dma_chan_write(hdma_dev->base, - HISI_DMA_CQ_HEAD_PTR, chan->qp_num, - chan->cq_head); vchan_cookie_complete(&desc->vd); + hisi_dma_start_transfer(chan); } else { dev_err(&hdma_dev->pdev->dev, "task error!\n"); } - - chan->desc = NULL; } spin_unlock(&chan->vc.lock); @@ -497,16 +800,169 @@ static void hisi_dma_disable_hw_channels(void *data) static void hisi_dma_set_mode(struct hisi_dma_dev *hdma_dev, enum hisi_dma_mode mode) { - writel_relaxed(mode == RC ? 1 : 0, hdma_dev->base + HISI_DMA_MODE); + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) + writel_relaxed(mode == RC ? 1 : 0, + hdma_dev->base + HISI_DMA_HIP08_MODE); } +static void hisi_dma_init_hw(struct hisi_dma_dev *hdma_dev) +{ + void __iomem *addr; + int i; + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP09) { + for (i = 0; i < HISI_DMA_HIP09_MAX_PORT_NUM; i++) { + addr = hdma_dev->base + HISI_DMA_HIP09_PORT_CFG_REG(i); + hisi_dma_update_bit(addr, + HISI_DMA_HIP09_PORT_CFG_LINK_DOWN_MASK_B, 1); + } + } +} + +static void hisi_dma_init_dma_dev(struct hisi_dma_dev *hdma_dev) +{ + struct dma_device *dma_dev; + + dma_dev = &hdma_dev->dma_dev; + dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); + dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources; + dma_dev->device_prep_dma_memcpy = hisi_dma_prep_dma_memcpy; + dma_dev->device_tx_status = hisi_dma_tx_status; + dma_dev->device_issue_pending = hisi_dma_issue_pending; + dma_dev->device_terminate_all = hisi_dma_terminate_all; + dma_dev->device_synchronize = hisi_dma_synchronize; + dma_dev->directions = BIT(DMA_MEM_TO_MEM); + dma_dev->dev = &hdma_dev->pdev->dev; + INIT_LIST_HEAD(&dma_dev->channels); +} + +/* --- debugfs implementation --- */ +#ifdef CONFIG_DEBUG_FS +#include +static struct debugfs_reg32 *hisi_dma_get_ch_regs(struct hisi_dma_dev *hdma_dev, + u32 *regs_sz) +{ + struct device *dev = &hdma_dev->pdev->dev; + struct debugfs_reg32 *regs; + u32 regs_sz_comm; + + regs_sz_comm = ARRAY_SIZE(hisi_dma_comm_chan_regs); + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) + *regs_sz = regs_sz_comm + ARRAY_SIZE(hisi_dma_hip08_chan_regs); + else + *regs_sz = regs_sz_comm + ARRAY_SIZE(hisi_dma_hip09_chan_regs); + + regs = devm_kcalloc(dev, *regs_sz, sizeof(struct debugfs_reg32), + GFP_KERNEL); + if (!regs) + return NULL; + memcpy(regs, hisi_dma_comm_chan_regs, sizeof(hisi_dma_comm_chan_regs)); + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) + memcpy(regs + regs_sz_comm, hisi_dma_hip08_chan_regs, + sizeof(hisi_dma_hip08_chan_regs)); + else + memcpy(regs + regs_sz_comm, hisi_dma_hip09_chan_regs, + sizeof(hisi_dma_hip09_chan_regs)); + + return regs; +} + +static int hisi_dma_create_chan_dir(struct hisi_dma_dev *hdma_dev) +{ + char dir_name[HISI_DMA_MAX_DIR_NAME_LEN]; + struct debugfs_regset32 *regsets; + struct debugfs_reg32 *regs; + struct dentry *chan_dir; + struct device *dev; + u32 regs_sz; + int ret; + int i; + + dev = &hdma_dev->pdev->dev; + + regsets = devm_kcalloc(dev, hdma_dev->chan_num, + sizeof(*regsets), GFP_KERNEL); + if (!regsets) + return -ENOMEM; + + regs = hisi_dma_get_ch_regs(hdma_dev, ®s_sz); + if (!regs) + return -ENOMEM; + + for (i = 0; i < hdma_dev->chan_num; i++) { + regsets[i].regs = regs; + regsets[i].nregs = regs_sz; + regsets[i].base = hdma_dev->queue_base + i * HISI_DMA_Q_OFFSET; + regsets[i].dev = dev; + + memset(dir_name, 0, HISI_DMA_MAX_DIR_NAME_LEN); + ret = sprintf(dir_name, "channel%d", i); + if (ret < 0) + return ret; + + chan_dir = debugfs_create_dir(dir_name, + hdma_dev->dma_dev.dbg_dev_root); + debugfs_create_regset32("regs", 0444, chan_dir, ®sets[i]); + } + + return 0; +} + +static void hisi_dma_create_debugfs(struct hisi_dma_dev *hdma_dev) +{ + struct debugfs_regset32 *regset; + struct device *dev; + int ret; + + dev = &hdma_dev->pdev->dev; + + if (hdma_dev->dma_dev.dbg_dev_root == NULL) + return; + + regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return; + + if (hdma_dev->reg_layout == HISI_DMA_REG_LAYOUT_HIP08) { + regset->regs = hisi_dma_hip08_comm_regs; + regset->nregs = ARRAY_SIZE(hisi_dma_hip08_comm_regs); + } else { + regset->regs = hisi_dma_hip09_comm_regs; + regset->nregs = ARRAY_SIZE(hisi_dma_hip09_comm_regs); + } + regset->base = hdma_dev->base; + regset->dev = dev; + + debugfs_create_regset32("regs", 0444, + hdma_dev->dma_dev.dbg_dev_root, regset); + + ret = hisi_dma_create_chan_dir(hdma_dev); + if (ret < 0) + dev_info(&hdma_dev->pdev->dev, "fail to create debugfs for channels!\n"); +} +#else +static void hisi_dma_create_debugfs(struct hisi_dma_dev *hdma_dev) { } +#endif /* CONFIG_DEBUG_FS*/ +/* --- debugfs implementation --- */ + static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + enum hisi_dma_reg_layout reg_layout; struct device *dev = &pdev->dev; struct hisi_dma_dev *hdma_dev; struct dma_device *dma_dev; + u32 chan_num; + u32 msi_num; int ret; + reg_layout = hisi_dma_get_reg_layout(pdev); + if (reg_layout == HISI_DMA_REG_LAYOUT_INVALID) { + dev_err(dev, "unsupported device!\n"); + return -EINVAL; + } + ret = pcim_enable_device(pdev); if (ret) { dev_err(dev, "failed to enable device mem!\n"); @@ -523,40 +979,37 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - hdma_dev = devm_kzalloc(dev, struct_size(hdma_dev, chan, HISI_DMA_CHAN_NUM), GFP_KERNEL); + chan_num = hisi_dma_get_chan_num(pdev); + hdma_dev = devm_kzalloc(dev, struct_size(hdma_dev, chan, chan_num), + GFP_KERNEL); if (!hdma_dev) return -EINVAL; hdma_dev->base = pcim_iomap_table(pdev)[PCI_BAR_2]; hdma_dev->pdev = pdev; - hdma_dev->chan_num = HISI_DMA_CHAN_NUM; hdma_dev->chan_depth = HISI_DMA_Q_DEPTH_VAL; + hdma_dev->chan_num = chan_num; + hdma_dev->reg_layout = reg_layout; + hdma_dev->queue_base = hdma_dev->base + hisi_dma_get_queue_base(pdev); pci_set_drvdata(pdev, hdma_dev); pci_set_master(pdev); + msi_num = hisi_dma_get_msi_num(pdev); + /* This will be freed by 'pcim_release()'. See 'pcim_enable_device()' */ - ret = pci_alloc_irq_vectors(pdev, HISI_DMA_MSI_NUM, HISI_DMA_MSI_NUM, - PCI_IRQ_MSI); + ret = pci_alloc_irq_vectors(pdev, msi_num, msi_num, PCI_IRQ_MSI); if (ret < 0) { dev_err(dev, "Failed to allocate MSI vectors!\n"); return ret; } - dma_dev = &hdma_dev->dma_dev; - dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); - dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources; - dma_dev->device_prep_dma_memcpy = hisi_dma_prep_dma_memcpy; - dma_dev->device_tx_status = hisi_dma_tx_status; - dma_dev->device_issue_pending = hisi_dma_issue_pending; - dma_dev->device_terminate_all = hisi_dma_terminate_all; - dma_dev->device_synchronize = hisi_dma_synchronize; - dma_dev->directions = BIT(DMA_MEM_TO_MEM); - dma_dev->dev = dev; - INIT_LIST_HEAD(&dma_dev->channels); + hisi_dma_init_dma_dev(hdma_dev); hisi_dma_set_mode(hdma_dev, RC); + hisi_dma_init_hw(hdma_dev); + ret = hisi_dma_enable_hw_channels(hdma_dev); if (ret < 0) { dev_err(dev, "failed to enable hw channel!\n"); @@ -568,11 +1021,16 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; + dma_dev = &hdma_dev->dma_dev; ret = dmaenginem_async_device_register(dma_dev); - if (ret < 0) + if (ret < 0) { dev_err(dev, "failed to register device!\n"); + return ret; + } - return ret; + hisi_dma_create_debugfs(hdma_dev); + + return 0; } static const struct pci_device_id hisi_dma_pci_tbl[] = { diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index 92caae55aece..af5a2e252c25 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -16,12 +16,20 @@ * port 3, and so on. */ +#include #include +#include #include #include #include +#include +#include #include +#include +#include #include +#include +#include #include "hsu.h" diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 9e5956345748..3bca577b98a1 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h @@ -10,7 +10,11 @@ #ifndef __DMA_HSU_H__ #define __DMA_HSU_H__ -#include +#include +#include +#include +#include + #include #include "../virt-dma.h" @@ -36,11 +40,11 @@ /* Bits in HSU_CH_SR */ #define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) -#define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) +#define HSU_CH_SR_DESCTO_ANY GENMASK(11, 8) #define HSU_CH_SR_CHE BIT(15) #define HSU_CH_SR_DESCE(x) BIT(16 + (x)) -#define HSU_CH_SR_DESCE_ANY (BIT(19) | BIT(18) | BIT(17) | BIT(16)) -#define HSU_CH_SR_CDESC_ANY (BIT(31) | BIT(30)) +#define HSU_CH_SR_DESCE_ANY GENMASK(19, 16) +#define HSU_CH_SR_CDESC_ANY GENMASK(31, 30) /* Bits in HSU_CH_CR */ #define HSU_CH_CR_CHA BIT(0) diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index 6a2df3dd78d0..0fcc0c0c22fc 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -26,29 +27,32 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) { struct hsu_dma_chip *chip = dev; - u32 dmaisr; - u32 status; + unsigned long dmaisr; unsigned short i; + u32 status; int ret = 0; int err; dmaisr = readl(chip->regs + HSU_PCI_DMAISR); - for (i = 0; i < chip->hsu->nr_channels; i++) { - if (dmaisr & 0x1) { - err = hsu_dma_get_status(chip, i, &status); - if (err > 0) - ret |= 1; - else if (err == 0) - ret |= hsu_dma_do_irq(chip, i, status); - } - dmaisr >>= 1; + for_each_set_bit(i, &dmaisr, chip->hsu->nr_channels) { + err = hsu_dma_get_status(chip, i, &status); + if (err > 0) + ret |= 1; + else if (err == 0) + ret |= hsu_dma_do_irq(chip, i, status); } return IRQ_RETVAL(ret); } +static void hsu_pci_dma_remove(void *chip) +{ + hsu_dma_remove(chip); +} + static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct hsu_dma_chip *chip; int ret; @@ -87,9 +91,13 @@ static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - ret = request_irq(chip->irq, hsu_pci_irq, 0, "hsu_dma_pci", chip); + ret = devm_add_action_or_reset(dev, hsu_pci_dma_remove, chip); if (ret) - goto err_register_irq; + return ret; + + ret = devm_request_irq(dev, chip->irq, hsu_pci_irq, 0, "hsu_dma_pci", chip); + if (ret) + return ret; /* * On Intel Tangier B0 and Anniedale the interrupt line, disregarding @@ -105,18 +113,6 @@ static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, chip); return 0; - -err_register_irq: - hsu_dma_remove(chip); - return ret; -} - -static void hsu_pci_remove(struct pci_dev *pdev) -{ - struct hsu_dma_chip *chip = pci_get_drvdata(pdev); - - free_irq(chip->irq, chip); - hsu_dma_remove(chip); } static const struct pci_device_id hsu_pci_id_table[] = { @@ -130,7 +126,6 @@ static struct pci_driver hsu_pci_driver = { .name = "hsu_dma_pci", .id_table = hsu_pci_id_table, .probe = hsu_pci_probe, - .remove = hsu_pci_remove, }; module_pci_driver(hsu_pci_driver); diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5a8cc52c1abf..2c1e6f6daa62 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -196,6 +196,7 @@ int idxd_wq_enable(struct idxd_wq *wq) } wq->state = IDXD_WQ_ENABLED; + set_bit(wq->id, idxd->wq_enable_map); dev_dbg(dev, "WQ %d enabled\n", wq->id); return 0; } @@ -223,6 +224,7 @@ int idxd_wq_disable(struct idxd_wq *wq, bool reset_config) if (reset_config) idxd_wq_disable_cleanup(wq); + clear_bit(wq->id, idxd->wq_enable_map); wq->state = IDXD_WQ_DISABLED; dev_dbg(dev, "WQ %d disabled\n", wq->id); return 0; @@ -258,7 +260,6 @@ void idxd_wq_reset(struct idxd_wq *wq) operand = BIT(wq->id % 16) | ((wq->id / 16) << 16); idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, NULL); idxd_wq_disable_cleanup(wq); - wq->state = IDXD_WQ_DISABLED; } int idxd_wq_map_portal(struct idxd_wq *wq) @@ -378,17 +379,20 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq) struct idxd_device *idxd = wq->idxd; lockdep_assert_held(&wq->wq_lock); + wq->state = IDXD_WQ_DISABLED; memset(wq->wqcfg, 0, idxd->wqcfg_size); wq->type = IDXD_WQT_NONE; wq->threshold = 0; wq->priority = 0; - wq->ats_dis = 0; wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; clear_bit(WQ_FLAG_DEDICATED, &wq->flags); clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); + clear_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); memset(wq->name, 0, WQ_NAME_SIZE); wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER; wq->max_batch_size = WQ_DEFAULT_MAX_BATCH; + if (wq->opcap_bmap) + bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); } static void idxd_wq_device_reset_cleanup(struct idxd_wq *wq) @@ -705,6 +709,8 @@ static void idxd_groups_clear_state(struct idxd_device *idxd) group->tc_a = -1; group->tc_b = -1; } + group->desc_progress_limit = 0; + group->batch_progress_limit = 0; } } @@ -761,10 +767,10 @@ static void idxd_group_config_write(struct idxd_group *group) /* setup GRPFLAGS */ grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id); - iowrite32(group->grpcfg.flags.bits, idxd->reg_base + grpcfg_offset); - dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n", + iowrite64(group->grpcfg.flags.bits, idxd->reg_base + grpcfg_offset); + dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#llx\n", group->id, grpcfg_offset, - ioread32(idxd->reg_base + grpcfg_offset)); + ioread64(idxd->reg_base + grpcfg_offset)); } static int idxd_groups_config_write(struct idxd_device *idxd) @@ -807,7 +813,7 @@ static int idxd_wq_config_write(struct idxd_wq *wq) struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; u32 wq_offset; - int i; + int i, n; if (!wq->group) return 0; @@ -859,12 +865,23 @@ static int idxd_wq_config_write(struct idxd_wq *wq) wq->wqcfg->bof = 1; if (idxd->hw.wq_cap.wq_ats_support) - wq->wqcfg->wq_ats_disable = wq->ats_dis; + wq->wqcfg->wq_ats_disable = test_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); /* bytes 12-15 */ wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes); wq->wqcfg->max_batch_shift = ilog2(wq->max_batch_size); + /* bytes 32-63 */ + if (idxd->hw.wq_cap.op_config && wq->opcap_bmap) { + memset(wq->wqcfg->op_config, 0, IDXD_MAX_OPCAP_BITS / 8); + for_each_set_bit(n, wq->opcap_bmap, IDXD_MAX_OPCAP_BITS) { + int pos = n % BITS_PER_LONG_LONG; + int idx = n / BITS_PER_LONG_LONG; + + wq->wqcfg->op_config[idx] |= BIT(pos); + } + } + dev_dbg(dev, "WQ %d CFGs\n", wq->id); for (i = 0; i < WQCFG_STRIDES(idxd); i++) { wq_offset = WQCFG_OFFSET(idxd, wq->id, i); @@ -914,6 +931,9 @@ static void idxd_group_flags_setup(struct idxd_device *idxd) group->grpcfg.flags.rdbufs_allowed = group->rdbufs_allowed; else group->grpcfg.flags.rdbufs_allowed = idxd->max_rdbufs; + + group->grpcfg.flags.desc_progress_limit = group->desc_progress_limit; + group->grpcfg.flags.batch_progress_limit = group->batch_progress_limit; } } @@ -1096,8 +1116,8 @@ static void idxd_group_load_config(struct idxd_group *group) } grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id); - group->grpcfg.flags.bits = ioread32(idxd->reg_base + grpcfg_offset); - dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n", + group->grpcfg.flags.bits = ioread64(idxd->reg_base + grpcfg_offset); + dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#llx\n", group->id, grpcfg_offset, group->grpcfg.flags.bits); } diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index fed0dfc1eaa8..1196ab342f01 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "registers.h" @@ -95,6 +96,8 @@ struct idxd_group { u8 rdbufs_reserved; int tc_a; int tc_b; + int desc_progress_limit; + int batch_progress_limit; }; struct idxd_pmu { @@ -132,6 +135,7 @@ enum idxd_wq_state { enum idxd_wq_flag { WQ_FLAG_DEDICATED = 0, WQ_FLAG_BLOCK_ON_FAULT, + WQ_FLAG_ATS_DISABLE, }; enum idxd_wq_type { @@ -194,6 +198,8 @@ struct idxd_wq { enum idxd_wq_state state; unsigned long flags; union wqcfg *wqcfg; + unsigned long *opcap_bmap; + struct dsa_hw_desc **hw_descs; int num_descs; union { @@ -208,7 +214,6 @@ struct idxd_wq { char name[WQ_NAME_SIZE + 1]; u64 max_xfer_bytes; u32 max_batch_size; - bool ats_dis; }; struct idxd_engine { @@ -299,6 +304,7 @@ struct idxd_device { int rdbuf_limit; int nr_rdbufs; /* non-reserved read buffers */ unsigned int wqcfg_size; + unsigned long *wq_enable_map; union sw_err_reg sw_err; wait_queue_head_t cmd_waitq; @@ -308,6 +314,8 @@ struct idxd_device { struct work_struct work; struct idxd_pmu *idxd_pmu; + + unsigned long *opcap_bmap; }; /* IDXD software descriptor */ diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index aa3478257ddb..2b18d512cbfc 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -151,6 +151,12 @@ static int idxd_setup_wqs(struct idxd_device *idxd) if (!idxd->wqs) return -ENOMEM; + idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev)); + if (!idxd->wq_enable_map) { + kfree(idxd->wqs); + return -ENOMEM; + } + for (i = 0; i < idxd->max_wqs; i++) { wq = kzalloc_node(sizeof(*wq), GFP_KERNEL, dev_to_node(dev)); if (!wq) { @@ -185,6 +191,16 @@ static int idxd_setup_wqs(struct idxd_device *idxd) rc = -ENOMEM; goto err; } + + if (idxd->hw.wq_cap.op_config) { + wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); + if (!wq->opcap_bmap) { + put_device(conf_dev); + rc = -ENOMEM; + goto err; + } + bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); + } idxd->wqs[i] = wq; } @@ -369,6 +385,19 @@ static void idxd_read_table_offsets(struct idxd_device *idxd) dev_dbg(dev, "IDXD Perfmon Offset: %#x\n", idxd->perfmon_offset); } +static void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count) +{ + int i, j, nr; + + for (i = 0, nr = 0; i < count; i++) { + for (j = 0; j < BITS_PER_LONG_LONG; j++) { + if (val[i] & BIT(j)) + set_bit(nr, bmap); + nr++; + } + } +} + static void idxd_read_caps(struct idxd_device *idxd) { struct device *dev = &idxd->pdev->dev; @@ -427,6 +456,7 @@ static void idxd_read_caps(struct idxd_device *idxd) IDXD_OPCAP_OFFSET + i * sizeof(u64)); dev_dbg(dev, "opcap[%d]: %#llx\n", i, idxd->hw.opcap.bits[i]); } + multi_u64_to_bmap(idxd->opcap_bmap, &idxd->hw.opcap.bits[0], 4); } static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data) @@ -448,6 +478,12 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d if (idxd->id < 0) return NULL; + idxd->opcap_bmap = bitmap_zalloc_node(IDXD_MAX_OPCAP_BITS, GFP_KERNEL, dev_to_node(dev)); + if (!idxd->opcap_bmap) { + ida_free(&idxd_ida, idxd->id); + return NULL; + } + device_initialize(conf_dev); conf_dev->parent = dev; conf_dev->bus = &dsa_bus_type; diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 743ead5ebc57..aa314ebec587 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -17,12 +17,6 @@ enum irq_work_type { IRQ_WORK_PROCESS_FAULT, }; -struct idxd_fault { - struct work_struct work; - u64 addr; - struct idxd_device *idxd; -}; - struct idxd_resubmit { struct work_struct work; struct idxd_desc *desc; @@ -49,11 +43,12 @@ static void idxd_device_reinit(struct work_struct *work) goto out; for (i = 0; i < idxd->max_wqs; i++) { - struct idxd_wq *wq = idxd->wqs[i]; + if (test_bit(i, idxd->wq_enable_map)) { + struct idxd_wq *wq = idxd->wqs[i]; - if (wq->state == IDXD_WQ_ENABLED) { rc = idxd_wq_enable(wq); if (rc < 0) { + clear_bit(i, idxd->wq_enable_map); dev_warn(dev, "Unable to re-enable wq %s\n", dev_name(wq_confdev(wq))); } @@ -324,13 +319,11 @@ halt: idxd->state = IDXD_DEV_HALTED; idxd_wqs_quiesce(idxd); idxd_wqs_unmap_portal(idxd); - spin_lock(&idxd->dev_lock); idxd_device_clear_state(idxd); dev_err(&idxd->pdev->dev, "idxd halted, need %s.\n", gensts.reset_type == IDXD_DEVICE_RESET_FLR ? "FLR" : "system reset"); - spin_unlock(&idxd->dev_lock); return -ENXIO; } } diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index 02449aa9c454..fe3b8d04f9db 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -54,7 +54,8 @@ union wq_cap_reg { u64 priority:1; u64 occupancy:1; u64 occupancy_int:1; - u64 rsvd3:10; + u64 op_config:1; + u64 rsvd3:9; }; u64 bits; } __packed; @@ -67,7 +68,8 @@ union group_cap_reg { u64 total_rdbufs:8; /* formerly total_tokens */ u64 rdbuf_ctrl:1; /* formerly token_en */ u64 rdbuf_limit:1; /* formerly token_limit */ - u64 rsvd:46; + u64 progress_limit:1; /* descriptor and batch descriptor */ + u64 rsvd:45; }; u64 bits; } __packed; @@ -90,6 +92,8 @@ struct opcap { u64 bits[4]; }; +#define IDXD_MAX_OPCAP_BITS 256U + #define IDXD_OPCAP_OFFSET 0x40 #define IDXD_TABLE_OFFSET 0x60 @@ -285,16 +289,20 @@ union msix_perm { union group_flags { struct { - u32 tc_a:3; - u32 tc_b:3; - u32 rsvd:1; - u32 use_rdbuf_limit:1; - u32 rdbufs_reserved:8; - u32 rsvd2:4; - u32 rdbufs_allowed:8; - u32 rsvd3:4; + u64 tc_a:3; + u64 tc_b:3; + u64 rsvd:1; + u64 use_rdbuf_limit:1; + u64 rdbufs_reserved:8; + u64 rsvd2:4; + u64 rdbufs_allowed:8; + u64 rsvd3:4; + u64 desc_progress_limit:2; + u64 rsvd4:2; + u64 batch_progress_limit:2; + u64 rsvd5:26; }; - u32 bits; + u64 bits; } __packed; struct grpcfg { @@ -348,8 +356,11 @@ union wqcfg { /* bytes 28-31 */ u32 rsvd8; + + /* bytes 32-63 */ + u64 op_config[4]; }; - u32 bits[8]; + u32 bits[16]; } __packed; #define WQCFG_PASID_IDX 2 diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 3f262a57441b..bdaccf9e0436 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -443,6 +443,67 @@ static struct device_attribute dev_attr_group_traffic_class_b = __ATTR(traffic_class_b, 0644, group_traffic_class_b_show, group_traffic_class_b_store); +static ssize_t group_desc_progress_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct idxd_group *group = confdev_to_group(dev); + + return sysfs_emit(buf, "%d\n", group->desc_progress_limit); +} + +static ssize_t group_desc_progress_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_group *group = confdev_to_group(dev); + int val, rc; + + rc = kstrtoint(buf, 10, &val); + if (rc < 0) + return -EINVAL; + + if (val & ~GENMASK(1, 0)) + return -EINVAL; + + group->desc_progress_limit = val; + return count; +} + +static struct device_attribute dev_attr_group_desc_progress_limit = + __ATTR(desc_progress_limit, 0644, group_desc_progress_limit_show, + group_desc_progress_limit_store); + +static ssize_t group_batch_progress_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct idxd_group *group = confdev_to_group(dev); + + return sysfs_emit(buf, "%d\n", group->batch_progress_limit); +} + +static ssize_t group_batch_progress_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_group *group = confdev_to_group(dev); + int val, rc; + + rc = kstrtoint(buf, 10, &val); + if (rc < 0) + return -EINVAL; + + if (val & ~GENMASK(1, 0)) + return -EINVAL; + + group->batch_progress_limit = val; + return count; +} + +static struct device_attribute dev_attr_group_batch_progress_limit = + __ATTR(batch_progress_limit, 0644, group_batch_progress_limit_show, + group_batch_progress_limit_store); static struct attribute *idxd_group_attributes[] = { &dev_attr_group_work_queues.attr, &dev_attr_group_engines.attr, @@ -454,11 +515,35 @@ static struct attribute *idxd_group_attributes[] = { &dev_attr_group_read_buffers_reserved.attr, &dev_attr_group_traffic_class_a.attr, &dev_attr_group_traffic_class_b.attr, + &dev_attr_group_desc_progress_limit.attr, + &dev_attr_group_batch_progress_limit.attr, NULL, }; +static bool idxd_group_attr_progress_limit_invisible(struct attribute *attr, + struct idxd_device *idxd) +{ + return (attr == &dev_attr_group_desc_progress_limit.attr || + attr == &dev_attr_group_batch_progress_limit.attr) && + !idxd->hw.group_cap.progress_limit; +} + +static umode_t idxd_group_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct idxd_group *group = confdev_to_group(dev); + struct idxd_device *idxd = group->idxd; + + if (idxd_group_attr_progress_limit_invisible(attr, idxd)) + return 0; + + return attr->mode; +} + static const struct attribute_group idxd_group_attribute_group = { .attrs = idxd_group_attributes, + .is_visible = idxd_group_attr_visible, }; static const struct attribute_group *idxd_group_attribute_groups[] = { @@ -973,7 +1058,7 @@ static ssize_t wq_ats_disable_show(struct device *dev, struct device_attribute * { struct idxd_wq *wq = confdev_to_wq(dev); - return sysfs_emit(buf, "%u\n", wq->ats_dis); + return sysfs_emit(buf, "%u\n", test_bit(WQ_FLAG_ATS_DISABLE, &wq->flags)); } static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute *attr, @@ -994,7 +1079,10 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute if (rc < 0) return rc; - wq->ats_dis = ats_dis; + if (ats_dis) + set_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); + else + clear_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); return count; } @@ -1055,6 +1143,68 @@ static ssize_t wq_enqcmds_retries_store(struct device *dev, struct device_attrib static struct device_attribute dev_attr_wq_enqcmds_retries = __ATTR(enqcmds_retries, 0644, wq_enqcmds_retries_show, wq_enqcmds_retries_store); +static ssize_t wq_op_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct idxd_wq *wq = confdev_to_wq(dev); + + return sysfs_emit(buf, "%*pb\n", IDXD_MAX_OPCAP_BITS, wq->opcap_bmap); +} + +static int idxd_verify_supported_opcap(struct idxd_device *idxd, unsigned long *opmask) +{ + int bit; + + /* + * The OPCAP is defined as 256 bits that represents each operation the device + * supports per bit. Iterate through all the bits and check if the input mask + * is set for bits that are not set in the OPCAP for the device. If no OPCAP + * bit is set and input mask has the bit set, then return error. + */ + for_each_set_bit(bit, opmask, IDXD_MAX_OPCAP_BITS) { + if (!test_bit(bit, idxd->opcap_bmap)) + return -EINVAL; + } + + return 0; +} + +static ssize_t wq_op_config_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_wq *wq = confdev_to_wq(dev); + struct idxd_device *idxd = wq->idxd; + unsigned long *opmask; + int rc; + + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + + opmask = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); + if (!opmask) + return -ENOMEM; + + rc = bitmap_parse(buf, count, opmask, IDXD_MAX_OPCAP_BITS); + if (rc < 0) + goto err; + + rc = idxd_verify_supported_opcap(idxd, opmask); + if (rc < 0) + goto err; + + bitmap_copy(wq->opcap_bmap, opmask, IDXD_MAX_OPCAP_BITS); + + bitmap_free(opmask); + return count; + +err: + bitmap_free(opmask); + return rc; +} + +static struct device_attribute dev_attr_wq_op_config = + __ATTR(op_config, 0644, wq_op_config_show, wq_op_config_store); + static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_clients.attr, &dev_attr_wq_state.attr, @@ -1072,11 +1222,33 @@ static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_ats_disable.attr, &dev_attr_wq_occupancy.attr, &dev_attr_wq_enqcmds_retries.attr, + &dev_attr_wq_op_config.attr, NULL, }; +static bool idxd_wq_attr_op_config_invisible(struct attribute *attr, + struct idxd_device *idxd) +{ + return attr == &dev_attr_wq_op_config.attr && + !idxd->hw.wq_cap.op_config; +} + +static umode_t idxd_wq_attr_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct idxd_wq *wq = confdev_to_wq(dev); + struct idxd_device *idxd = wq->idxd; + + if (idxd_wq_attr_op_config_invisible(attr, idxd)) + return 0; + + return attr->mode; +} + static const struct attribute_group idxd_wq_attribute_group = { .attrs = idxd_wq_attributes, + .is_visible = idxd_wq_attr_visible, }; static const struct attribute_group *idxd_wq_attribute_groups[] = { @@ -1088,6 +1260,7 @@ static void idxd_conf_wq_release(struct device *dev) { struct idxd_wq *wq = confdev_to_wq(dev); + bitmap_free(wq->opcap_bmap); kfree(wq->wqcfg); kfree(wq); } @@ -1177,14 +1350,8 @@ static ssize_t op_cap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct idxd_device *idxd = confdev_to_idxd(dev); - int i, rc = 0; - for (i = 0; i < 4; i++) - rc += sysfs_emit_at(buf, rc, "%#llx ", idxd->hw.opcap.bits[i]); - - rc--; - rc += sysfs_emit_at(buf, rc, "\n"); - return rc; + return sysfs_emit(buf, "%*pb\n", IDXD_MAX_OPCAP_BITS, idxd->opcap_bmap); } static DEVICE_ATTR_RO(op_cap); @@ -1405,9 +1572,11 @@ static void idxd_conf_device_release(struct device *dev) struct idxd_device *idxd = confdev_to_idxd(dev); kfree(idxd->groups); + bitmap_free(idxd->wq_enable_map); kfree(idxd->wqs); kfree(idxd->engines); ida_free(&idxd_ida, idxd->id); + bitmap_free(idxd->opcap_bmap); kfree(idxd); } diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 37ff4ec7db76..e2070df6cad2 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -656,7 +656,7 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete) if (active - i == 0) { dev_dbg(to_dev(ioat_chan), "%s: cancel completion timeout\n", __func__); - mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); + mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); } /* microsecond delay by sysfs variable per pending descriptor */ @@ -682,7 +682,7 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan) if (chanerr & (IOAT_CHANERR_HANDLE_MASK | IOAT_CHANERR_RECOVER_MASK)) { - mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); + mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); ioat_eh(ioat_chan); } } @@ -879,7 +879,7 @@ static void check_active(struct ioatdma_chan *ioat_chan) } if (test_and_clear_bit(IOAT_CHAN_ACTIVE, &ioat_chan->state)) - mod_timer(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); + mod_timer_pending(&ioat_chan->timer, jiffies + IDLE_TIMEOUT); } static void ioat_reboot_chan(struct ioatdma_chan *ioat_chan) diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index 140cfe3782fb..35e06b382603 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -196,10 +196,8 @@ extern const struct sysfs_ops ioat_sysfs_ops; extern struct ioat_sysfs_entry ioat_version_attr; extern struct ioat_sysfs_entry ioat_cap_attr; extern int ioat_pending_level; -extern int ioat_ring_alloc_order; extern struct kobj_type ioat_ktype; extern struct kmem_cache *ioat_cache; -extern int ioat_ring_max_alloc_order; extern struct kmem_cache *ioat_sed_cache; static inline struct ioatdma_chan *to_ioat_chan(struct dma_chan *c) diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 994fc4d2aca4..dc147cc2436e 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -670,7 +670,7 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan, return mxs_chan->status; } -static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma) +static int mxs_dma_init(struct mxs_dma_engine *mxs_dma) { int ret; @@ -741,7 +741,7 @@ static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec, ofdma->of_node); } -static int __init mxs_dma_probe(struct platform_device *pdev) +static int mxs_dma_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; const struct mxs_dma_type *dma_type; @@ -839,10 +839,7 @@ static struct platform_driver mxs_dma_driver = { .name = "mxs-dma", .of_match_table = mxs_dma_dt_ids, }, + .probe = mxs_dma_probe, }; -static int __init mxs_dma_module_init(void) -{ - return platform_driver_probe(&mxs_dma_driver, mxs_dma_probe); -} -subsys_initcall(mxs_dma_module_init); +builtin_platform_driver(mxs_dma_driver); diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 09915a5cba3e..0d9257fbdfb0 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2752,7 +2752,6 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( return NULL; pch->cyclic = true; - desc->txd.flags = flags; return &desc->txd; } @@ -2804,8 +2803,6 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, desc->bytes_requested = len; - desc->txd.flags = flags; - return &desc->txd; } @@ -2889,7 +2886,6 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } /* Return the last desc in the chain */ - desc->txd.flags = flg; return &desc->txd; } diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 8f0c9c4e2efd..3f56514bbef8 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1150,9 +1150,9 @@ static void gpi_ev_tasklet(unsigned long data) { struct gpii *gpii = (struct gpii *)data; - read_lock_bh(&gpii->pm_lock); + read_lock(&gpii->pm_lock); if (!REG_ACCESS_VALID(gpii->pm_state)) { - read_unlock_bh(&gpii->pm_lock); + read_unlock(&gpii->pm_lock); dev_err(gpii->gpi_dev->dev, "not processing any events, pm_state:%s\n", TO_GPI_PM_STR(gpii->pm_state)); return; @@ -1163,7 +1163,7 @@ static void gpi_ev_tasklet(unsigned long data) /* enable IEOB, switching back to interrupts */ gpi_config_interrupts(gpii, MASK_IEOB_SETTINGS, 1); - read_unlock_bh(&gpii->pm_lock); + read_unlock(&gpii->pm_lock); } /* marks all pending events for the channel as stale */ @@ -2288,6 +2288,7 @@ static int gpi_probe(struct platform_device *pdev) static const struct of_device_id gpi_of_match[] = { { .compatible = "qcom,sc7280-gpi-dma", .data = (void *)0x10000 }, { .compatible = "qcom,sdm845-gpi-dma", .data = (void *)0x0 }, + { .compatible = "qcom,sm6350-gpi-dma", .data = (void *)0x10000 }, { .compatible = "qcom,sm8150-gpi-dma", .data = (void *)0x0 }, { .compatible = "qcom,sm8250-gpi-dma", .data = (void *)0x0 }, { .compatible = "qcom,sm8350-gpi-dma", .data = (void *)0x10000 }, diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c index facdacf8aede..d56caf1681ff 100644 --- a/drivers/dma/qcom/qcom_adm.c +++ b/drivers/dma/qcom/qcom_adm.c @@ -379,13 +379,13 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, if (blk_size < 0) { dev_err(adev->dev, "invalid burst value: %d\n", burst); - return ERR_PTR(-EINVAL); + return NULL; } crci = achan->crci & 0xf; if (!crci || achan->crci > 0x1f) { dev_err(adev->dev, "invalid crci value\n"); - return ERR_PTR(-EINVAL); + return NULL; } } @@ -403,8 +403,10 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, } async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); - if (!async_desc) - return ERR_PTR(-ENOMEM); + if (!async_desc) { + dev_err(adev->dev, "not enough memory for async_desc struct\n"); + return NULL; + } async_desc->mux = achan->mux ? ADM_CRCI_CTL_MUX_SEL : 0; async_desc->crci = crci; @@ -414,8 +416,10 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, sizeof(*cple) + 2 * ADM_DESC_ALIGN; async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); - if (!async_desc->cpl) + if (!async_desc->cpl) { + dev_err(adev->dev, "not enough memory for cpl struct\n"); goto free; + } async_desc->adev = adev; @@ -437,8 +441,10 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, async_desc->dma_len, DMA_TO_DEVICE); - if (dma_mapping_error(adev->dev, async_desc->dma_addr)) + if (dma_mapping_error(adev->dev, async_desc->dma_addr)) { + dev_err(adev->dev, "dma mapping error for cpl\n"); goto free; + } cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); @@ -454,7 +460,7 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, free: kfree(async_desc); - return ERR_PTR(-ENOMEM); + return NULL; } /** @@ -494,7 +500,7 @@ static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) spin_lock_irqsave(&achan->vc.lock, flag); memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); - if (cfg->peripheral_size == sizeof(config)) + if (cfg->peripheral_size == sizeof(*config)) achan->crci = config->crci; spin_unlock_irqrestore(&achan->vc.lock, flag); diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index f6ed7e889781..a09eeb545f7d 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -1094,7 +1094,7 @@ static int s3c24xx_dma_init_virtual_channels(struct s3c24xx_dma_engine *s3cdma, INIT_LIST_HEAD(&dmadev->channels); /* - * Register as many many memcpy as we have physical channels, + * Register as many memcpy as we have physical channels, * we won't always be able to use all but the code will have * to cope with that situation. */ diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index 4f8b8498c5c6..6b524eb6bcf3 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -405,10 +405,8 @@ static int sf_pdma_irq_init(struct platform_device *pdev, struct sf_pdma *pdma) chan = &pdma->chans[i]; irq = platform_get_irq(pdev, i * 2); - if (irq < 0) { - dev_err(&pdev->dev, "ch(%d) Can't get done irq.\n", i); + if (irq < 0) return -EINVAL; - } r = devm_request_irq(&pdev->dev, irq, sf_pdma_done_isr, 0, dev_name(&pdev->dev), (void *)chan); @@ -420,10 +418,8 @@ static int sf_pdma_irq_init(struct platform_device *pdev, struct sf_pdma *pdma) chan->txirq = irq; irq = platform_get_irq(pdev, (i * 2) + 1); - if (irq < 0) { - dev_err(&pdev->dev, "ch(%d) Can't get err irq.\n", i); + if (irq < 0) return -EINVAL; - } r = devm_request_irq(&pdev->dev, irq, sf_pdma_err_isr, 0, dev_name(&pdev->dev), (void *)chan); diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 13d12d660cc2..641d689d17ff 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -103,8 +103,8 @@ struct rcar_dmac_desc_page { struct list_head node; union { - struct rcar_dmac_desc descs[0]; - struct rcar_dmac_xfer_chunk chunks[0]; + DECLARE_FLEX_ARRAY(struct rcar_dmac_desc, descs); + DECLARE_FLEX_ARRAY(struct rcar_dmac_xfer_chunk, chunks); }; }; diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index adb25a11c70f..4891a1767e5a 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -9,6 +9,7 @@ * Pierre-Yves Mordret */ +#include #include #include #include @@ -32,8 +33,10 @@ #define STM32_DMA_LISR 0x0000 /* DMA Low Int Status Reg */ #define STM32_DMA_HISR 0x0004 /* DMA High Int Status Reg */ +#define STM32_DMA_ISR(n) (((n) & 4) ? STM32_DMA_HISR : STM32_DMA_LISR) #define STM32_DMA_LIFCR 0x0008 /* DMA Low Int Flag Clear Reg */ #define STM32_DMA_HIFCR 0x000c /* DMA High Int Flag Clear Reg */ +#define STM32_DMA_IFCR(n) (((n) & 4) ? STM32_DMA_HIFCR : STM32_DMA_LIFCR) #define STM32_DMA_TCI BIT(5) /* Transfer Complete Interrupt */ #define STM32_DMA_HTI BIT(4) /* Half Transfer Interrupt */ #define STM32_DMA_TEI BIT(3) /* Transfer Error Interrupt */ @@ -43,23 +46,22 @@ | STM32_DMA_TEI \ | STM32_DMA_DMEI \ | STM32_DMA_FEI) +/* + * If (chan->id % 4) is 2 or 3, left shift the mask by 16 bits; + * if (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. + */ +#define STM32_DMA_FLAGS_SHIFT(n) ({ typeof(n) (_n) = (n); \ + (((_n) & 2) << 3) | (((_n) & 1) * 6); }) /* DMA Stream x Configuration Register */ #define STM32_DMA_SCR(x) (0x0010 + 0x18 * (x)) /* x = 0..7 */ -#define STM32_DMA_SCR_REQ(n) ((n & 0x7) << 25) +#define STM32_DMA_SCR_REQ_MASK GENMASK(27, 25) #define STM32_DMA_SCR_MBURST_MASK GENMASK(24, 23) -#define STM32_DMA_SCR_MBURST(n) ((n & 0x3) << 23) #define STM32_DMA_SCR_PBURST_MASK GENMASK(22, 21) -#define STM32_DMA_SCR_PBURST(n) ((n & 0x3) << 21) #define STM32_DMA_SCR_PL_MASK GENMASK(17, 16) -#define STM32_DMA_SCR_PL(n) ((n & 0x3) << 16) #define STM32_DMA_SCR_MSIZE_MASK GENMASK(14, 13) -#define STM32_DMA_SCR_MSIZE(n) ((n & 0x3) << 13) #define STM32_DMA_SCR_PSIZE_MASK GENMASK(12, 11) -#define STM32_DMA_SCR_PSIZE(n) ((n & 0x3) << 11) -#define STM32_DMA_SCR_PSIZE_GET(n) ((n & STM32_DMA_SCR_PSIZE_MASK) >> 11) #define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6) -#define STM32_DMA_SCR_DIR(n) ((n & 0x3) << 6) #define STM32_DMA_SCR_TRBUFF BIT(20) /* Bufferable transfer for USART/UART */ #define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */ #define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */ @@ -96,7 +98,6 @@ /* DMA stream x FIFO control register */ #define STM32_DMA_SFCR(x) (0x0024 + 0x18 * (x)) #define STM32_DMA_SFCR_FTH_MASK GENMASK(1, 0) -#define STM32_DMA_SFCR_FTH(n) (n & STM32_DMA_SFCR_FTH_MASK) #define STM32_DMA_SFCR_FEIE BIT(7) /* FIFO error interrupt enable */ #define STM32_DMA_SFCR_DMDIS BIT(2) /* Direct mode disable */ #define STM32_DMA_SFCR_MASK (STM32_DMA_SFCR_FEIE \ @@ -137,11 +138,9 @@ /* DMA Features */ #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) -#define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK) #define STM32_DMA_DIRECT_MODE_MASK BIT(2) -#define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) >> 2) #define STM32_DMA_ALT_ACK_MODE_MASK BIT(4) -#define STM32_DMA_ALT_ACK_MODE_GET(n) (((n) & STM32_DMA_ALT_ACK_MODE_MASK) >> 4) +#define STM32_DMA_MDMA_STREAM_ID_MASK GENMASK(19, 16) enum stm32_dma_width { STM32_DMA_BYTE, @@ -195,6 +194,19 @@ struct stm32_dma_desc { struct stm32_dma_sg_req sg_req[]; }; +/** + * struct stm32_dma_mdma_config - STM32 DMA MDMA configuration + * @stream_id: DMA request to trigger STM32 MDMA transfer + * @ifcr: DMA interrupt flag clear register address, + * used by STM32 MDMA to clear DMA Transfer Complete flag + * @tcf: DMA Transfer Complete flag + */ +struct stm32_dma_mdma_config { + u32 stream_id; + u32 ifcr; + u32 tcf; +}; + struct stm32_dma_chan { struct virt_dma_chan vchan; bool config_init; @@ -209,6 +221,8 @@ struct stm32_dma_chan { u32 mem_burst; u32 mem_width; enum dma_status status; + bool trig_mdma; + struct stm32_dma_mdma_config mdma_config; }; struct stm32_dma_device { @@ -388,6 +402,13 @@ static int stm32_dma_slave_config(struct dma_chan *c, memcpy(&chan->dma_sconfig, config, sizeof(*config)); + /* Check if user is requesting DMA to trigger STM32 MDMA */ + if (config->peripheral_size) { + config->peripheral_config = &chan->mdma_config; + config->peripheral_size = sizeof(chan->mdma_config); + chan->trig_mdma = true; + } + chan->config_init = true; return 0; @@ -401,17 +422,10 @@ static u32 stm32_dma_irq_status(struct stm32_dma_chan *chan) /* * Read "flags" from DMA_xISR register corresponding to the selected * DMA channel at the correct bit offset inside that register. - * - * If (ch % 4) is 2 or 3, left shift the mask by 16 bits. - * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. */ - if (chan->id & 4) - dma_isr = stm32_dma_read(dmadev, STM32_DMA_HISR); - else - dma_isr = stm32_dma_read(dmadev, STM32_DMA_LISR); - - flags = dma_isr >> (((chan->id & 2) << 3) | ((chan->id & 1) * 6)); + dma_isr = stm32_dma_read(dmadev, STM32_DMA_ISR(chan->id)); + flags = dma_isr >> STM32_DMA_FLAGS_SHIFT(chan->id); return flags & STM32_DMA_MASKI; } @@ -424,17 +438,11 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) /* * Write "flags" to the DMA_xIFCR register corresponding to the selected * DMA channel at the correct bit offset inside that register. - * - * If (ch % 4) is 2 or 3, left shift the mask by 16 bits. - * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. */ flags &= STM32_DMA_MASKI; - dma_ifcr = flags << (((chan->id & 2) << 3) | ((chan->id & 1) * 6)); + dma_ifcr = flags << STM32_DMA_FLAGS_SHIFT(chan->id); - if (chan->id & 4) - stm32_dma_write(dmadev, STM32_DMA_HIFCR, dma_ifcr); - else - stm32_dma_write(dmadev, STM32_DMA_LIFCR, dma_ifcr); + stm32_dma_write(dmadev, STM32_DMA_IFCR(chan->id), dma_ifcr); } static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) @@ -576,6 +584,10 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) sg_req = &chan->desc->sg_req[chan->next_sg]; reg = &sg_req->chan_reg; + /* When DMA triggers STM32 MDMA, DMA Transfer Complete is managed by STM32 MDMA */ + if (chan->trig_mdma && chan->dma_sconfig.direction != DMA_MEM_TO_DEV) + reg->dma_scr &= ~STM32_DMA_SCR_TCIE; + reg->dma_scr &= ~STM32_DMA_SCR_EN; stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); @@ -725,6 +737,8 @@ static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr) if (chan->desc->cyclic) { vchan_cyclic_callback(&chan->desc->vdesc); + if (chan->trig_mdma) + return; stm32_dma_sg_inc(chan); /* cyclic while CIRC/DBM disable => post resume reconfiguration needed */ if (!(scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM))) @@ -861,7 +875,8 @@ static int stm32_dma_resume(struct dma_chan *c) sg_req = &chan->desc->sg_req[chan->next_sg - 1]; ndtr = sg_req->chan_reg.dma_sndtr; - offset = (ndtr - chan_reg.dma_sndtr) << STM32_DMA_SCR_PSIZE_GET(chan_reg.dma_scr); + offset = (ndtr - chan_reg.dma_sndtr); + offset <<= FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, chan_reg.dma_scr); spar = sg_req->chan_reg.dma_spar; sm0ar = sg_req->chan_reg.dma_sm0ar; sm1ar = sg_req->chan_reg.dma_sm1ar; @@ -973,16 +988,16 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, if (src_burst_size < 0) return src_burst_size; - dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_DEV) | - STM32_DMA_SCR_PSIZE(dst_bus_width) | - STM32_DMA_SCR_MSIZE(src_bus_width) | - STM32_DMA_SCR_PBURST(dst_burst_size) | - STM32_DMA_SCR_MBURST(src_burst_size); + dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_DEV) | + FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, dst_bus_width) | + FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, src_bus_width) | + FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dst_burst_size) | + FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, src_burst_size); /* Set FIFO threshold */ chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) - chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth); + chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth); /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; @@ -1030,16 +1045,16 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, if (dst_burst_size < 0) return dst_burst_size; - dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_DEV_TO_MEM) | - STM32_DMA_SCR_PSIZE(src_bus_width) | - STM32_DMA_SCR_MSIZE(dst_bus_width) | - STM32_DMA_SCR_PBURST(src_burst_size) | - STM32_DMA_SCR_MBURST(dst_burst_size); + dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_DEV_TO_MEM) | + FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, src_bus_width) | + FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, dst_bus_width) | + FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, src_burst_size) | + FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dst_burst_size); /* Set FIFO threshold */ chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) - chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth); + chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth); /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; @@ -1099,6 +1114,10 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; + /* Activate Double Buffer Mode if DMA triggers STM32 MDMA and more than 1 sg */ + if (chan->trig_mdma && sg_len > 1) + chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; + for_each_sg(sgl, sg, sg_len, i) { ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, sg_dma_len(sg), @@ -1120,6 +1139,8 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg); desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg); + if (chan->trig_mdma) + desc->sg_req[i].chan_reg.dma_sm1ar += sg_dma_len(sg); desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; } @@ -1207,8 +1228,11 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; desc->sg_req[i].chan_reg.dma_sm0ar = buf_addr; desc->sg_req[i].chan_reg.dma_sm1ar = buf_addr; + if (chan->trig_mdma) + desc->sg_req[i].chan_reg.dma_sm1ar += period_len; desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; - buf_addr += period_len; + if (!chan->trig_mdma) + buf_addr += period_len; } desc->num_sgs = num_periods; @@ -1247,16 +1271,15 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); desc->sg_req[i].chan_reg.dma_scr = - STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_MEM) | - STM32_DMA_SCR_PBURST(dma_burst) | - STM32_DMA_SCR_MBURST(dma_burst) | + FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_MEM) | + FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dma_burst) | + FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dma_burst) | STM32_DMA_SCR_MINC | STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; desc->sg_req[i].chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK; - desc->sg_req[i].chan_reg.dma_sfcr |= - STM32_DMA_SFCR_FTH(threshold); + desc->sg_req[i].chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, threshold); desc->sg_req[i].chan_reg.dma_spar = src + offset; desc->sg_req[i].chan_reg.dma_sm0ar = dest + offset; desc->sg_req[i].chan_reg.dma_sndtr = xfer_count; @@ -1275,7 +1298,7 @@ static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); - width = STM32_DMA_SCR_PSIZE_GET(dma_scr); + width = FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, dma_scr); ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); return ndtr << width; @@ -1481,16 +1504,17 @@ static void stm32_dma_set_config(struct stm32_dma_chan *chan, stm32_dma_clear_reg(&chan->chan_reg); chan->chan_reg.dma_scr = cfg->stream_config & STM32_DMA_SCR_CFG_MASK; - chan->chan_reg.dma_scr |= STM32_DMA_SCR_REQ(cfg->request_line); + chan->chan_reg.dma_scr |= FIELD_PREP(STM32_DMA_SCR_REQ_MASK, cfg->request_line); /* Enable Interrupts */ chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE; - chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features); - if (STM32_DMA_DIRECT_MODE_GET(cfg->features)) + chan->threshold = FIELD_GET(STM32_DMA_THRESHOLD_FTR_MASK, cfg->features); + if (FIELD_GET(STM32_DMA_DIRECT_MODE_MASK, cfg->features)) chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE; - if (STM32_DMA_ALT_ACK_MODE_GET(cfg->features)) + if (FIELD_GET(STM32_DMA_ALT_ACK_MODE_MASK, cfg->features)) chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF; + chan->mdma_config.stream_id = FIELD_GET(STM32_DMA_MDMA_STREAM_ID_MASK, cfg->features); } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, @@ -1630,6 +1654,12 @@ static int stm32_dma_probe(struct platform_device *pdev) chan->id = i; chan->vchan.desc_free = stm32_dma_desc_free; vchan_init(&chan->vchan, dd); + + chan->mdma_config.ifcr = res->start; + chan->mdma_config.ifcr += STM32_DMA_IFCR(chan->id); + + chan->mdma_config.tcf = STM32_DMA_TCI; + chan->mdma_config.tcf <<= STM32_DMA_FLAGS_SHIFT(chan->id); } ret = dma_async_device_register(dd); diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index eee0c5aa5fb5..ee3cbbf51006 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -39,13 +39,13 @@ struct stm32_dmamux_data { u32 dma_requests; /* Number of DMA requests connected to DMAMUX */ u32 dmamux_requests; /* Number of DMA requests routed toward DMAs */ spinlock_t lock; /* Protects register access */ - unsigned long *dma_inuse; /* Used DMA channel */ + DECLARE_BITMAP(dma_inuse, STM32_DMAMUX_MAX_DMA_REQUESTS); /* Used DMA channel */ u32 ccr[STM32_DMAMUX_MAX_DMA_REQUESTS]; /* Used to backup CCR register * in suspend */ u32 dma_reqs[]; /* Number of DMA Request per DMA masters. * [0] holds number of DMA Masters. - * To be kept at very end end of this structure + * To be kept at very end of this structure */ }; @@ -147,7 +147,7 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, mux->request = dma_spec->args[0]; /* craft DMA spec */ - dma_spec->args[3] = dma_spec->args[2]; + dma_spec->args[3] = dma_spec->args[2] | mux->chan_id << 16; dma_spec->args[2] = dma_spec->args[1]; dma_spec->args[1] = 0; dma_spec->args[0] = mux->chan_id - min; @@ -229,12 +229,6 @@ static int stm32_dmamux_probe(struct platform_device *pdev) stm32_dmamux->dma_requests = dma_req; stm32_dmamux->dma_reqs[0] = count; - stm32_dmamux->dma_inuse = devm_kcalloc(&pdev->dev, - BITS_TO_LONGS(dma_req), - sizeof(unsigned long), - GFP_KERNEL); - if (!stm32_dmamux->dma_inuse) - return -ENOMEM; if (device_property_read_u32(&pdev->dev, "dma-requests", &stm32_dmamux->dmamux_requests)) { diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index b11927ed4367..e28acbcb53f4 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -199,6 +199,7 @@ struct stm32_mdma_chan_config { u32 transfer_config; u32 mask_addr; u32 mask_data; + bool m2m_hw; /* True when MDMA is triggered by STM32 DMA */ }; struct stm32_mdma_hwdesc { @@ -227,6 +228,12 @@ struct stm32_mdma_desc { struct stm32_mdma_desc_node node[]; }; +struct stm32_mdma_dma_config { + u32 request; /* STM32 DMA channel stream id, triggering MDMA */ + u32 cmar; /* STM32 DMA interrupt flag clear register address */ + u32 cmdr; /* STM32 DMA Transfer Complete flag */ +}; + struct stm32_mdma_chan { struct virt_dma_chan vchan; struct dma_pool *desc_pool; @@ -539,13 +546,23 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, dst_addr = chan->dma_config.dst_addr; /* Set device data size */ + if (chan_config->m2m_hw) + dst_addr_width = stm32_mdma_get_max_width(dst_addr, buf_len, + STM32_MDMA_MAX_BUF_LEN); dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width); if (dst_bus_width < 0) return dst_bus_width; ctcr &= ~STM32_MDMA_CTCR_DSIZE_MASK; ctcr |= STM32_MDMA_CTCR_DSIZE(dst_bus_width); + if (chan_config->m2m_hw) { + ctcr &= ~STM32_MDMA_CTCR_DINCOS_MASK; + ctcr |= STM32_MDMA_CTCR_DINCOS(dst_bus_width); + } /* Set device burst value */ + if (chan_config->m2m_hw) + dst_maxburst = STM32_MDMA_MAX_BUF_LEN / dst_addr_width; + dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, dst_maxburst, dst_addr_width); @@ -588,13 +605,24 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, src_addr = chan->dma_config.src_addr; /* Set device data size */ + if (chan_config->m2m_hw) + src_addr_width = stm32_mdma_get_max_width(src_addr, buf_len, + STM32_MDMA_MAX_BUF_LEN); + src_bus_width = stm32_mdma_get_width(chan, src_addr_width); if (src_bus_width < 0) return src_bus_width; ctcr &= ~STM32_MDMA_CTCR_SSIZE_MASK; ctcr |= STM32_MDMA_CTCR_SSIZE(src_bus_width); + if (chan_config->m2m_hw) { + ctcr &= ~STM32_MDMA_CTCR_SINCOS_MASK; + ctcr |= STM32_MDMA_CTCR_SINCOS(src_bus_width); + } /* Set device burst value */ + if (chan_config->m2m_hw) + src_maxburst = STM32_MDMA_MAX_BUF_LEN / src_addr_width; + src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, src_maxburst, src_addr_width); @@ -702,11 +730,15 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; struct scatterlist *sg; dma_addr_t src_addr, dst_addr; - u32 ccr, ctcr, ctbr; + u32 m2m_hw_period, ccr, ctcr, ctbr; int i, ret = 0; + if (chan_config->m2m_hw) + m2m_hw_period = sg_dma_len(sgl); + for_each_sg(sgl, sg, sg_len, i) { if (sg_dma_len(sg) > STM32_MDMA_MAX_BLOCK_LEN) { dev_err(chan2dev(chan), "Invalid block len\n"); @@ -716,6 +748,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, if (direction == DMA_MEM_TO_DEV) { src_addr = sg_dma_address(sg); dst_addr = dma_config->dst_addr; + if (chan_config->m2m_hw && (i & 1)) + dst_addr += m2m_hw_period; ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr, src_addr, sg_dma_len(sg)); @@ -723,6 +757,8 @@ static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, src_addr); } else { src_addr = dma_config->src_addr; + if (chan_config->m2m_hw && (i & 1)) + src_addr += m2m_hw_period; dst_addr = sg_dma_address(sg); ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr, &ctbr, dst_addr, @@ -755,6 +791,7 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, unsigned long flags, void *context) { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; struct stm32_mdma_desc *desc; int i, ret; @@ -777,6 +814,21 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, if (ret < 0) goto xfer_setup_err; + /* + * In case of M2M HW transfer triggered by STM32 DMA, we do not have to clear the + * transfer complete flag by hardware in order to let the CPU rearm the STM32 DMA + * with the next sg element and update some data in dmaengine framework. + */ + if (chan_config->m2m_hw && direction == DMA_MEM_TO_DEV) { + struct stm32_mdma_hwdesc *hwdesc; + + for (i = 0; i < sg_len; i++) { + hwdesc = desc->node[i].hwdesc; + hwdesc->cmar = 0; + hwdesc->cmdr = 0; + } + } + desc->cyclic = false; return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); @@ -798,6 +850,7 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct dma_slave_config *dma_config = &chan->dma_config; + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; struct stm32_mdma_desc *desc; dma_addr_t src_addr, dst_addr; u32 ccr, ctcr, ctbr, count; @@ -858,8 +911,12 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, if (direction == DMA_MEM_TO_DEV) { src_addr = buf_addr + i * period_len; dst_addr = dma_config->dst_addr; + if (chan_config->m2m_hw && (i & 1)) + dst_addr += period_len; } else { src_addr = dma_config->src_addr; + if (chan_config->m2m_hw && (i & 1)) + src_addr += period_len; dst_addr = buf_addr + i * period_len; } @@ -1244,6 +1301,17 @@ static int stm32_mdma_slave_config(struct dma_chan *c, memcpy(&chan->dma_config, config, sizeof(*config)); + /* Check if user is requesting STM32 DMA to trigger MDMA */ + if (config->peripheral_size) { + struct stm32_mdma_dma_config *mdma_config; + + mdma_config = (struct stm32_mdma_dma_config *)chan->dma_config.peripheral_config; + chan->chan_config.request = mdma_config->request; + chan->chan_config.mask_addr = mdma_config->cmar; + chan->chan_config.mask_data = mdma_config->cmdr; + chan->chan_config.m2m_hw = true; + } + return 0; } diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 4cbca80ee16e..fa06d7e6d8e3 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -352,12 +352,6 @@ static inline void edma_modify_array(struct edma_cc *ecc, int offset, int i, edma_modify(ecc, offset + (i << 2), and, or); } -static inline void edma_or_array(struct edma_cc *ecc, int offset, int i, - unsigned or) -{ - edma_or(ecc, offset + (i << 2), or); -} - static inline void edma_or_array2(struct edma_cc *ecc, int offset, int i, int j, unsigned or) { @@ -370,11 +364,6 @@ static inline void edma_write_array2(struct edma_cc *ecc, int offset, int i, edma_write(ecc, offset + ((i * 2 + j) << 2), val); } -static inline unsigned int edma_shadow0_read(struct edma_cc *ecc, int offset) -{ - return edma_read(ecc, EDMA_SHADOW0 + offset); -} - static inline unsigned int edma_shadow0_read_array(struct edma_cc *ecc, int offset, int i) { @@ -393,36 +382,12 @@ static inline void edma_shadow0_write_array(struct edma_cc *ecc, int offset, edma_write(ecc, EDMA_SHADOW0 + offset + (i << 2), val); } -static inline unsigned int edma_param_read(struct edma_cc *ecc, int offset, - int param_no) -{ - return edma_read(ecc, EDMA_PARM + offset + (param_no << 5)); -} - -static inline void edma_param_write(struct edma_cc *ecc, int offset, - int param_no, unsigned val) -{ - edma_write(ecc, EDMA_PARM + offset + (param_no << 5), val); -} - static inline void edma_param_modify(struct edma_cc *ecc, int offset, int param_no, unsigned and, unsigned or) { edma_modify(ecc, EDMA_PARM + offset + (param_no << 5), and, or); } -static inline void edma_param_and(struct edma_cc *ecc, int offset, int param_no, - unsigned and) -{ - edma_and(ecc, EDMA_PARM + offset + (param_no << 5), and); -} - -static inline void edma_param_or(struct edma_cc *ecc, int offset, int param_no, - unsigned or) -{ - edma_or(ecc, EDMA_PARM + offset + (param_no << 5), or); -} - static void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no, int priority) { @@ -743,11 +708,6 @@ static void edma_free_channel(struct edma_chan *echan) edma_setup_interrupt(echan, false); } -static inline struct edma_cc *to_edma_cc(struct dma_device *d) -{ - return container_of(d, struct edma_cc, dma_slave); -} - static inline struct edma_chan *to_edma_chan(struct dma_chan *c) { return container_of(c, struct edma_chan, vchan.chan); diff --git a/drivers/dma/ti/k3-psil-j7200.c b/drivers/dma/ti/k3-psil-j7200.c index 5ea63ea74822..e3feff869991 100644 --- a/drivers/dma/ti/k3-psil-j7200.c +++ b/drivers/dma/ti/k3-psil-j7200.c @@ -143,6 +143,57 @@ static struct psil_ep j7200_src_ep_map[] = { /* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ static struct psil_ep j7200_dst_ep_map[] = { + /* PDMA_MCASP - McASP0-2 */ + PSIL_PDMA_MCASP(0xc400), + PSIL_PDMA_MCASP(0xc401), + PSIL_PDMA_MCASP(0xc402), + /* PDMA_SPI_G0 - SPI0-3 */ + PSIL_PDMA_XY_PKT(0xc600), + PSIL_PDMA_XY_PKT(0xc601), + PSIL_PDMA_XY_PKT(0xc602), + PSIL_PDMA_XY_PKT(0xc603), + PSIL_PDMA_XY_PKT(0xc604), + PSIL_PDMA_XY_PKT(0xc605), + PSIL_PDMA_XY_PKT(0xc606), + PSIL_PDMA_XY_PKT(0xc607), + PSIL_PDMA_XY_PKT(0xc608), + PSIL_PDMA_XY_PKT(0xc609), + PSIL_PDMA_XY_PKT(0xc60a), + PSIL_PDMA_XY_PKT(0xc60b), + PSIL_PDMA_XY_PKT(0xc60c), + PSIL_PDMA_XY_PKT(0xc60d), + PSIL_PDMA_XY_PKT(0xc60e), + PSIL_PDMA_XY_PKT(0xc60f), + /* PDMA_SPI_G1 - SPI4-7 */ + PSIL_PDMA_XY_PKT(0xc610), + PSIL_PDMA_XY_PKT(0xc611), + PSIL_PDMA_XY_PKT(0xc612), + PSIL_PDMA_XY_PKT(0xc613), + PSIL_PDMA_XY_PKT(0xc614), + PSIL_PDMA_XY_PKT(0xc615), + PSIL_PDMA_XY_PKT(0xc616), + PSIL_PDMA_XY_PKT(0xc617), + PSIL_PDMA_XY_PKT(0xc618), + PSIL_PDMA_XY_PKT(0xc619), + PSIL_PDMA_XY_PKT(0xc61a), + PSIL_PDMA_XY_PKT(0xc61b), + PSIL_PDMA_XY_PKT(0xc61c), + PSIL_PDMA_XY_PKT(0xc61d), + PSIL_PDMA_XY_PKT(0xc61e), + PSIL_PDMA_XY_PKT(0xc61f), + /* PDMA_USART_G0 - UART0-1 */ + PSIL_PDMA_XY_PKT(0xc700), + PSIL_PDMA_XY_PKT(0xc701), + /* PDMA_USART_G1 - UART2-3 */ + PSIL_PDMA_XY_PKT(0xc702), + PSIL_PDMA_XY_PKT(0xc703), + /* PDMA_USART_G2 - UART4-9 */ + PSIL_PDMA_XY_PKT(0xc704), + PSIL_PDMA_XY_PKT(0xc705), + PSIL_PDMA_XY_PKT(0xc706), + PSIL_PDMA_XY_PKT(0xc707), + PSIL_PDMA_XY_PKT(0xc708), + PSIL_PDMA_XY_PKT(0xc709), /* CPSW5 */ PSIL_ETHERNET(0xca00), PSIL_ETHERNET(0xca01), @@ -161,6 +212,22 @@ static struct psil_ep j7200_dst_ep_map[] = { PSIL_ETHERNET(0xf005), PSIL_ETHERNET(0xf006), PSIL_ETHERNET(0xf007), + /* MCU_PDMA_MISC_G0 - SPI0 */ + PSIL_PDMA_XY_PKT(0xf100), + PSIL_PDMA_XY_PKT(0xf101), + PSIL_PDMA_XY_PKT(0xf102), + PSIL_PDMA_XY_PKT(0xf103), + /* MCU_PDMA_MISC_G1 - SPI1-2 */ + PSIL_PDMA_XY_PKT(0xf200), + PSIL_PDMA_XY_PKT(0xf201), + PSIL_PDMA_XY_PKT(0xf202), + PSIL_PDMA_XY_PKT(0xf203), + PSIL_PDMA_XY_PKT(0xf204), + PSIL_PDMA_XY_PKT(0xf205), + PSIL_PDMA_XY_PKT(0xf206), + PSIL_PDMA_XY_PKT(0xf207), + /* MCU_PDMA_MISC_G2 - UART0 */ + PSIL_PDMA_XY_PKT(0xf300), /* SA2UL */ PSIL_SA2UL(0xf500, 1), PSIL_SA2UL(0xf501, 1), diff --git a/drivers/dma/ti/k3-psil-j721e.c b/drivers/dma/ti/k3-psil-j721e.c index 34e3fc565a37..e7c83d668bb6 100644 --- a/drivers/dma/ti/k3-psil-j721e.c +++ b/drivers/dma/ti/k3-psil-j721e.c @@ -266,6 +266,69 @@ static struct psil_ep j721e_dst_ep_map[] = { PSIL_ETHERNET(0xc205), PSIL_ETHERNET(0xc206), PSIL_ETHERNET(0xc207), + /* PDMA6 (PSIL_PDMA_MCASP_G0) - McASP0-2 */ + PSIL_PDMA_MCASP(0xc400), + PSIL_PDMA_MCASP(0xc401), + PSIL_PDMA_MCASP(0xc402), + /* PDMA7 (PSIL_PDMA_MCASP_G1) - McASP3-11 */ + PSIL_PDMA_MCASP(0xc500), + PSIL_PDMA_MCASP(0xc501), + PSIL_PDMA_MCASP(0xc502), + PSIL_PDMA_MCASP(0xc503), + PSIL_PDMA_MCASP(0xc504), + PSIL_PDMA_MCASP(0xc505), + PSIL_PDMA_MCASP(0xc506), + PSIL_PDMA_MCASP(0xc507), + PSIL_PDMA_MCASP(0xc508), + /* PDMA8 (PDMA_MISC_G0) - SPI0-1 */ + PSIL_PDMA_XY_PKT(0xc600), + PSIL_PDMA_XY_PKT(0xc601), + PSIL_PDMA_XY_PKT(0xc602), + PSIL_PDMA_XY_PKT(0xc603), + PSIL_PDMA_XY_PKT(0xc604), + PSIL_PDMA_XY_PKT(0xc605), + PSIL_PDMA_XY_PKT(0xc606), + PSIL_PDMA_XY_PKT(0xc607), + /* PDMA9 (PDMA_MISC_G1) - SPI2-3 */ + PSIL_PDMA_XY_PKT(0xc60c), + PSIL_PDMA_XY_PKT(0xc60d), + PSIL_PDMA_XY_PKT(0xc60e), + PSIL_PDMA_XY_PKT(0xc60f), + PSIL_PDMA_XY_PKT(0xc610), + PSIL_PDMA_XY_PKT(0xc611), + PSIL_PDMA_XY_PKT(0xc612), + PSIL_PDMA_XY_PKT(0xc613), + /* PDMA10 (PDMA_MISC_G2) - SPI4-5 */ + PSIL_PDMA_XY_PKT(0xc618), + PSIL_PDMA_XY_PKT(0xc619), + PSIL_PDMA_XY_PKT(0xc61a), + PSIL_PDMA_XY_PKT(0xc61b), + PSIL_PDMA_XY_PKT(0xc61c), + PSIL_PDMA_XY_PKT(0xc61d), + PSIL_PDMA_XY_PKT(0xc61e), + PSIL_PDMA_XY_PKT(0xc61f), + /* PDMA11 (PDMA_MISC_G3) */ + PSIL_PDMA_XY_PKT(0xc624), + PSIL_PDMA_XY_PKT(0xc625), + PSIL_PDMA_XY_PKT(0xc626), + PSIL_PDMA_XY_PKT(0xc627), + PSIL_PDMA_XY_PKT(0xc628), + PSIL_PDMA_XY_PKT(0xc629), + PSIL_PDMA_XY_PKT(0xc630), + PSIL_PDMA_XY_PKT(0xc63a), + /* PDMA13 (PDMA_USART_G0) - UART0-1 */ + PSIL_PDMA_XY_PKT(0xc700), + PSIL_PDMA_XY_PKT(0xc701), + /* PDMA14 (PDMA_USART_G1) - UART2-3 */ + PSIL_PDMA_XY_PKT(0xc702), + PSIL_PDMA_XY_PKT(0xc703), + /* PDMA15 (PDMA_USART_G2) - UART4-9 */ + PSIL_PDMA_XY_PKT(0xc704), + PSIL_PDMA_XY_PKT(0xc705), + PSIL_PDMA_XY_PKT(0xc706), + PSIL_PDMA_XY_PKT(0xc707), + PSIL_PDMA_XY_PKT(0xc708), + PSIL_PDMA_XY_PKT(0xc709), /* CPSW9 */ PSIL_ETHERNET(0xca00), PSIL_ETHERNET(0xca01), @@ -284,6 +347,22 @@ static struct psil_ep j721e_dst_ep_map[] = { PSIL_ETHERNET(0xf005), PSIL_ETHERNET(0xf006), PSIL_ETHERNET(0xf007), + /* MCU_PDMA0 (MCU_PDMA_MISC_G0) - SPI0 */ + PSIL_PDMA_XY_PKT(0xf100), + PSIL_PDMA_XY_PKT(0xf101), + PSIL_PDMA_XY_PKT(0xf102), + PSIL_PDMA_XY_PKT(0xf103), + /* MCU_PDMA1 (MCU_PDMA_MISC_G1) - SPI1-2 */ + PSIL_PDMA_XY_PKT(0xf200), + PSIL_PDMA_XY_PKT(0xf201), + PSIL_PDMA_XY_PKT(0xf202), + PSIL_PDMA_XY_PKT(0xf203), + PSIL_PDMA_XY_PKT(0xf204), + PSIL_PDMA_XY_PKT(0xf205), + PSIL_PDMA_XY_PKT(0xf206), + PSIL_PDMA_XY_PKT(0xf207), + /* MCU_PDMA2 (MCU_PDMA_MISC_G2) - UART0 */ + PSIL_PDMA_XY_PKT(0xf300), /* SA2UL */ PSIL_SA2UL(0xf500, 1), PSIL_SA2UL(0xf501, 1), diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 2f0d2c68c93c..7b5081989b3d 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -263,6 +263,7 @@ struct udma_chan_config { enum udma_tp_level channel_tpl; /* Channel Throughput Level */ u32 tr_trigger_type; + unsigned long tx_flags; /* PKDMA mapped channel */ int mapped_channel_id; @@ -300,8 +301,6 @@ struct udma_chan { struct udma_tx_drain tx_drain; - u32 bcnt; /* number of bytes completed since the start of the channel */ - /* Channel configuration parameters */ struct udma_chan_config config; @@ -757,6 +756,20 @@ static void udma_reset_rings(struct udma_chan *uc) } } +static void udma_decrement_byte_counters(struct udma_chan *uc, u32 val) +{ + if (uc->desc->dir == DMA_DEV_TO_MEM) { + udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); + udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); + udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); + } else { + udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); + udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); + if (!uc->bchan) + udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); + } +} + static void udma_reset_counters(struct udma_chan *uc) { u32 val; @@ -790,8 +803,6 @@ static void udma_reset_counters(struct udma_chan *uc) val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG); udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); } - - uc->bcnt = 0; } static int udma_reset_chan(struct udma_chan *uc, bool hard) @@ -1045,9 +1056,14 @@ static bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d) { u32 peer_bcnt, bcnt; - /* Only TX towards PDMA is affected */ + /* + * Only TX towards PDMA is affected. + * If DMA_PREP_INTERRUPT is not set by consumer then skip the transfer + * completion calculation, consumer must ensure that there is no stale + * data in DMA fabric in this case. + */ if (uc->config.ep_type == PSIL_EP_NATIVE || - uc->config.dir != DMA_MEM_TO_DEV) + uc->config.dir != DMA_MEM_TO_DEV || !(uc->config.tx_flags & DMA_PREP_INTERRUPT)) return true; peer_bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG); @@ -1115,7 +1131,7 @@ static void udma_check_tx_completion(struct work_struct *work) if (uc->desc) { struct udma_desc *d = uc->desc; - uc->bcnt += d->residue; + udma_decrement_byte_counters(uc, d->residue); udma_start(uc); vchan_cookie_complete(&d->vd); break; @@ -1168,7 +1184,7 @@ static irqreturn_t udma_ring_irq_handler(int irq, void *data) vchan_cyclic_callback(&d->vd); } else { if (udma_is_desc_really_done(uc, d)) { - uc->bcnt += d->residue; + udma_decrement_byte_counters(uc, d->residue); udma_start(uc); vchan_cookie_complete(&d->vd); } else { @@ -1204,7 +1220,7 @@ static irqreturn_t udma_udma_irq_handler(int irq, void *data) vchan_cyclic_callback(&d->vd); } else { /* TODO: figure out the real amount of data */ - uc->bcnt += d->residue; + udma_decrement_byte_counters(uc, d->residue); udma_start(uc); vchan_cookie_complete(&d->vd); } @@ -3408,6 +3424,8 @@ udma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!burst) burst = 1; + uc->config.tx_flags = tx_flags; + if (uc->config.pkt_mode) d = udma_prep_slave_sg_pkt(uc, sgl, sglen, dir, tx_flags, context); @@ -3809,7 +3827,6 @@ static enum dma_status udma_tx_status(struct dma_chan *chan, bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); } - bcnt -= uc->bcnt; if (bcnt && !(bcnt % uc->desc->residue)) residue = 0; else diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 3f4ee3954384..21472a5d7636 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -795,6 +795,17 @@ static int zynqmp_dma_device_terminate_all(struct dma_chan *dchan) return 0; } +/** + * zynqmp_dma_synchronize - Synchronizes the termination of a transfers to the current context. + * @dchan: DMA channel pointer + */ +static void zynqmp_dma_synchronize(struct dma_chan *dchan) +{ + struct zynqmp_dma_chan *chan = to_chan(dchan); + + tasklet_kill(&chan->tasklet); +} + /** * zynqmp_dma_prep_memcpy - prepare descriptors for memcpy transaction * @dchan: DMA channel @@ -1057,6 +1068,7 @@ static int zynqmp_dma_probe(struct platform_device *pdev) p = &zdev->common; p->device_prep_dma_memcpy = zynqmp_dma_prep_memcpy; p->device_terminate_all = zynqmp_dma_device_terminate_all; + p->device_synchronize = zynqmp_dma_synchronize; p->device_issue_pending = zynqmp_dma_issue_pending; p->device_alloc_chan_resources = zynqmp_dma_alloc_chan_resources; p->device_free_chan_resources = zynqmp_dma_free_chan_resources; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 198ba846d34b..34f5a092c99e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -51,6 +51,18 @@ config DRM_DEBUG_MM If in doubt, say "N". +config DRM_USE_DYNAMIC_DEBUG + bool "use dynamic debug to implement drm.debug" + default y + depends on DRM + depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE + depends on JUMP_LABEL + help + Use dynamic-debug to avoid drm_debug_enabled() runtime overheads. + Due to callsite counts in DRM drivers (~4k in amdgpu) and 56 + bytes per callsite, the .data costs can be substantial, and + are therefore configurable. + config DRM_KUNIT_TEST tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS depends on DRM && KUNIT diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 25d0ba310509..0b283e46f28b 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,6 +3,8 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. +CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE + drm-y := drm_aperture.o drm_auth.o drm_cache.o \ drm_file.o drm_gem.o drm_ioctl.o \ drm_drv.o \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 16f6a313335e..3c9fecdd6b2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include "amdgpu.h" #include "amdgpu_irq.h" @@ -186,6 +188,18 @@ int amdgpu_vcnfw_log; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), .delayed_reset_work = __DELAYED_WORK_INITIALIZER( diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 9f055d9710ea..16565a0a5da6 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,18 @@ #include "drm_dp_helper_internal.h" +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + struct dp_aux_backlight { struct backlight_device *base; struct drm_dp_aux *aux; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 457448cc60f7..7d86020b5244 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,18 @@ #include "drm_crtc_helper_internal.h" +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + /** * DOC: overview * diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index f783d4963d4b..5b93c11895bb 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -23,14 +23,13 @@ * Rob Clark */ -#define DEBUG /* for pr_debug() */ - #include #include #include #include #include +#include #include #include @@ -40,7 +39,7 @@ * __drm_debug: Enable debug output. * Bitmask of DRM_UT_x. See include/drm/drm_print.h for details. */ -unsigned int __drm_debug; +unsigned long __drm_debug; EXPORT_SYMBOL(__drm_debug); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" @@ -52,7 +51,30 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat "\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" "\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n" "\t\tBit 8 (0x100) will enable DP messages (displayport code)"); -module_param_named(debug, __drm_debug, int, 0600); + +#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) +module_param_named(debug, __drm_debug, ulong, 0600); +#else +/* classnames must match vals of enum drm_debug_category */ +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + +static struct ddebug_class_param drm_debug_bitmap = { + .bits = &__drm_debug, + .flags = "p", + .map = &drm_debug_classes, +}; +module_param_cb(debug, ¶m_ops_dyndbg_classes, &drm_debug_bitmap, 0600); +#endif void __drm_puts_coredump(struct drm_printer *p, const char *str) { @@ -162,7 +184,8 @@ EXPORT_SYMBOL(__drm_printfn_info); void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf) { - pr_debug("%s %pV", p->prefix, vaf); + /* pr_debug callsite decorations are unhelpful here */ + printk(KERN_DEBUG "%s %pV", p->prefix, vaf); } EXPORT_SYMBOL(__drm_printfn_debug); @@ -256,15 +279,16 @@ void drm_dev_printk(const struct device *dev, const char *level, } EXPORT_SYMBOL(drm_dev_printk); -void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, - const char *format, ...) +void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev, + enum drm_debug_category category, const char *format, ...) { struct va_format vaf; va_list args; - if (!drm_debug_enabled(category)) + if (!__drm_debug_enabled(category)) return; + /* we know we are printing for either syslog, tracefs, or both */ va_start(args, format); vaf.fmt = format; vaf.va = &args; @@ -278,14 +302,14 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, va_end(args); } -EXPORT_SYMBOL(drm_dev_dbg); +EXPORT_SYMBOL(__drm_dev_dbg); -void __drm_dbg(enum drm_debug_category category, const char *format, ...) +void ___drm_dbg(struct _ddebug *desc, enum drm_debug_category category, const char *format, ...) { struct va_format vaf; va_list args; - if (!drm_debug_enabled(category)) + if (!__drm_debug_enabled(category)) return; va_start(args, format); @@ -297,7 +321,7 @@ void __drm_dbg(enum drm_debug_category category, const char *format, ...) va_end(args); } -EXPORT_SYMBOL(__drm_dbg); +EXPORT_SYMBOL(___drm_dbg); void __drm_err(const char *format, ...) { diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 6fc475a5db61..d1e4d528cb17 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -29,6 +29,18 @@ #include "i915_params.h" #include "i915_drv.h" +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + #define i915_param_named(name, T, perm, desc) \ module_param_named(name, i915_modparams.name, T, perm); \ MODULE_PARM_DESC(name, desc) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 561309d447e0..fd99ec0f4257 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,18 @@ #include "nouveau_svm.h" #include "nouveau_dmem.h" +DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "DRM_UT_CORE", + "DRM_UT_DRIVER", + "DRM_UT_KMS", + "DRM_UT_PRIME", + "DRM_UT_ATOMIC", + "DRM_UT_VBL", + "DRM_UT_STATE", + "DRM_UT_LEASE", + "DRM_UT_DP", + "DRM_UT_DRMRES"); + MODULE_PARM_DESC(config, "option string to pass to driver core"); static char *nouveau_config; module_param_named(config, nouveau_config, charp, 0400); diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c index 20d2b9ec1227..fc00274070b6 100644 --- a/drivers/ipack/devices/ipoctal.c +++ b/drivers/ipack/devices/ipoctal.c @@ -497,7 +497,7 @@ static unsigned int ipoctal_chars_in_buffer(struct tty_struct *tty) } static void ipoctal_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { unsigned int cflag; unsigned char mr1 = 0; diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index e012b21c4fd7..790787f0eba8 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -425,12 +425,14 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) { - u16 frame_size = le16_to_cpu( - fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); - int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * - frame_size, i, j, ret; + struct usb_host_interface *alt = fc_usb->uintf->cur_altsetting; + u16 frame_size; + int bufsize, i, j, ret; int buffer_offset = 0; + frame_size = usb_endpoint_maxp(&alt->endpoint[0].desc); + bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size; + deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); @@ -501,17 +503,21 @@ urb_error: static int flexcop_usb_init(struct flexcop_usb *fc_usb) { - /* use the alternate setting with the larges buffer */ - int ret = usb_set_interface(fc_usb->udev, 0, 1); + struct usb_host_interface *alt; + int ret; + /* use the alternate setting with the largest buffer */ + ret = usb_set_interface(fc_usb->udev, 0, 1); if (ret) { err("set interface failed."); return ret; } - if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1) + alt = fc_usb->uintf->cur_altsetting; + + if (alt->desc.bNumEndpoints < 1) return -ENODEV; - if (!usb_endpoint_is_isoc_in(&fc_usb->uintf->cur_altsetting->endpoint[0].desc)) + if (!usb_endpoint_is_isoc_in(&alt->endpoint[0].desc)) return -ENODEV; switch (fc_usb->udev->speed) { diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 97f312020516..c95a2229f4fa 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "uvcvideo.h" diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 744051b52e12..215fb483efb0 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -20,6 +20,7 @@ #include #include +#include #include "uvcvideo.h" @@ -34,198 +35,6 @@ static unsigned int uvc_quirks_param = -1; unsigned int uvc_dbg_param; unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; -/* ------------------------------------------------------------------------ - * Video formats - */ - -static struct uvc_format_desc uvc_fmts[] = { - { - .name = "YUV 4:2:2 (YUYV)", - .guid = UVC_GUID_FORMAT_YUY2, - .fcc = V4L2_PIX_FMT_YUYV, - }, - { - .name = "YUV 4:2:2 (YUYV)", - .guid = UVC_GUID_FORMAT_YUY2_ISIGHT, - .fcc = V4L2_PIX_FMT_YUYV, - }, - { - .name = "YUV 4:2:0 (NV12)", - .guid = UVC_GUID_FORMAT_NV12, - .fcc = V4L2_PIX_FMT_NV12, - }, - { - .name = "MJPEG", - .guid = UVC_GUID_FORMAT_MJPEG, - .fcc = V4L2_PIX_FMT_MJPEG, - }, - { - .name = "YVU 4:2:0 (YV12)", - .guid = UVC_GUID_FORMAT_YV12, - .fcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "YUV 4:2:0 (I420)", - .guid = UVC_GUID_FORMAT_I420, - .fcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:0 (M420)", - .guid = UVC_GUID_FORMAT_M420, - .fcc = V4L2_PIX_FMT_M420, - }, - { - .name = "YUV 4:2:2 (UYVY)", - .guid = UVC_GUID_FORMAT_UYVY, - .fcc = V4L2_PIX_FMT_UYVY, - }, - { - .name = "Greyscale 8-bit (Y800)", - .guid = UVC_GUID_FORMAT_Y800, - .fcc = V4L2_PIX_FMT_GREY, - }, - { - .name = "Greyscale 8-bit (Y8 )", - .guid = UVC_GUID_FORMAT_Y8, - .fcc = V4L2_PIX_FMT_GREY, - }, - { - .name = "Greyscale 8-bit (D3DFMT_L8)", - .guid = UVC_GUID_FORMAT_D3DFMT_L8, - .fcc = V4L2_PIX_FMT_GREY, - }, - { - .name = "IR 8-bit (L8_IR)", - .guid = UVC_GUID_FORMAT_KSMEDIA_L8_IR, - .fcc = V4L2_PIX_FMT_GREY, - }, - { - .name = "Greyscale 10-bit (Y10 )", - .guid = UVC_GUID_FORMAT_Y10, - .fcc = V4L2_PIX_FMT_Y10, - }, - { - .name = "Greyscale 12-bit (Y12 )", - .guid = UVC_GUID_FORMAT_Y12, - .fcc = V4L2_PIX_FMT_Y12, - }, - { - .name = "Greyscale 16-bit (Y16 )", - .guid = UVC_GUID_FORMAT_Y16, - .fcc = V4L2_PIX_FMT_Y16, - }, - { - .name = "BGGR Bayer (BY8 )", - .guid = UVC_GUID_FORMAT_BY8, - .fcc = V4L2_PIX_FMT_SBGGR8, - }, - { - .name = "BGGR Bayer (BA81)", - .guid = UVC_GUID_FORMAT_BA81, - .fcc = V4L2_PIX_FMT_SBGGR8, - }, - { - .name = "GBRG Bayer (GBRG)", - .guid = UVC_GUID_FORMAT_GBRG, - .fcc = V4L2_PIX_FMT_SGBRG8, - }, - { - .name = "GRBG Bayer (GRBG)", - .guid = UVC_GUID_FORMAT_GRBG, - .fcc = V4L2_PIX_FMT_SGRBG8, - }, - { - .name = "RGGB Bayer (RGGB)", - .guid = UVC_GUID_FORMAT_RGGB, - .fcc = V4L2_PIX_FMT_SRGGB8, - }, - { - .name = "RGB565", - .guid = UVC_GUID_FORMAT_RGBP, - .fcc = V4L2_PIX_FMT_RGB565, - }, - { - .name = "BGR 8:8:8 (BGR3)", - .guid = UVC_GUID_FORMAT_BGR3, - .fcc = V4L2_PIX_FMT_BGR24, - }, - { - .name = "H.264", - .guid = UVC_GUID_FORMAT_H264, - .fcc = V4L2_PIX_FMT_H264, - }, - { - .name = "H.265", - .guid = UVC_GUID_FORMAT_H265, - .fcc = V4L2_PIX_FMT_HEVC, - }, - { - .name = "Greyscale 8 L/R (Y8I)", - .guid = UVC_GUID_FORMAT_Y8I, - .fcc = V4L2_PIX_FMT_Y8I, - }, - { - .name = "Greyscale 12 L/R (Y12I)", - .guid = UVC_GUID_FORMAT_Y12I, - .fcc = V4L2_PIX_FMT_Y12I, - }, - { - .name = "Depth data 16-bit (Z16)", - .guid = UVC_GUID_FORMAT_Z16, - .fcc = V4L2_PIX_FMT_Z16, - }, - { - .name = "Bayer 10-bit (SRGGB10P)", - .guid = UVC_GUID_FORMAT_RW10, - .fcc = V4L2_PIX_FMT_SRGGB10P, - }, - { - .name = "Bayer 16-bit (SBGGR16)", - .guid = UVC_GUID_FORMAT_BG16, - .fcc = V4L2_PIX_FMT_SBGGR16, - }, - { - .name = "Bayer 16-bit (SGBRG16)", - .guid = UVC_GUID_FORMAT_GB16, - .fcc = V4L2_PIX_FMT_SGBRG16, - }, - { - .name = "Bayer 16-bit (SRGGB16)", - .guid = UVC_GUID_FORMAT_RG16, - .fcc = V4L2_PIX_FMT_SRGGB16, - }, - { - .name = "Bayer 16-bit (SGRBG16)", - .guid = UVC_GUID_FORMAT_GR16, - .fcc = V4L2_PIX_FMT_SGRBG16, - }, - { - .name = "Depth data 16-bit (Z16)", - .guid = UVC_GUID_FORMAT_INVZ, - .fcc = V4L2_PIX_FMT_Z16, - }, - { - .name = "Greyscale 10-bit (Y10 )", - .guid = UVC_GUID_FORMAT_INVI, - .fcc = V4L2_PIX_FMT_Y10, - }, - { - .name = "IR:Depth 26-bit (INZI)", - .guid = UVC_GUID_FORMAT_INZI, - .fcc = V4L2_PIX_FMT_INZI, - }, - { - .name = "4-bit Depth Confidence (Packed)", - .guid = UVC_GUID_FORMAT_CNF4, - .fcc = V4L2_PIX_FMT_CNF4, - }, - { - .name = "HEVC", - .guid = UVC_GUID_FORMAT_HEVC, - .fcc = V4L2_PIX_FMT_HEVC, - }, -}; - /* ------------------------------------------------------------------------ * Utility functions */ @@ -245,19 +54,6 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, return NULL; } -static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) -{ - unsigned int len = ARRAY_SIZE(uvc_fmts); - unsigned int i; - - for (i = 0; i < len; ++i) { - if (memcmp(guid, uvc_fmts[i].guid, 16) == 0) - return &uvc_fmts[i]; - } - - return NULL; -} - static enum v4l2_colorspace uvc_colorspace(const u8 primaries) { static const enum v4l2_colorspace colorprimaries[] = { @@ -329,90 +125,6 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients) return V4L2_YCBCR_ENC_DEFAULT; /* Reserved */ } -/* - * Simplify a fraction using a simple continued fraction decomposition. The - * idea here is to convert fractions such as 333333/10000000 to 1/30 using - * 32 bit arithmetic only. The algorithm is not perfect and relies upon two - * arbitrary parameters to remove non-significative terms from the simple - * continued fraction decomposition. Using 8 and 333 for n_terms and threshold - * respectively seems to give nice results. - */ -void uvc_simplify_fraction(u32 *numerator, u32 *denominator, - unsigned int n_terms, unsigned int threshold) -{ - u32 *an; - u32 x, y, r; - unsigned int i, n; - - an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL); - if (an == NULL) - return; - - /* - * Convert the fraction to a simple continued fraction. See - * https://en.wikipedia.org/wiki/Continued_fraction - * Stop if the current term is bigger than or equal to the given - * threshold. - */ - x = *numerator; - y = *denominator; - - for (n = 0; n < n_terms && y != 0; ++n) { - an[n] = x / y; - if (an[n] >= threshold) { - if (n < 2) - n++; - break; - } - - r = x - an[n] * y; - x = y; - y = r; - } - - /* Expand the simple continued fraction back to an integer fraction. */ - x = 0; - y = 1; - - for (i = n; i > 0; --i) { - r = y; - y = an[i-1] * y + x; - x = r; - } - - *numerator = y; - *denominator = x; - kfree(an); -} - -/* - * Convert a fraction to a frame interval in 100ns multiples. The idea here is - * to compute numerator / denominator * 10000000 using 32 bit fixed point - * arithmetic only. - */ -u32 uvc_fraction_to_interval(u32 numerator, u32 denominator) -{ - u32 multiplier; - - /* Saturate the result if the operation would overflow. */ - if (denominator == 0 || - numerator/denominator >= ((u32)-1)/10000000) - return (u32)-1; - - /* - * Divide both the denominator and the multiplier by two until - * numerator * multiplier doesn't overflow. If anyone knows a better - * algorithm please let me know. - */ - multiplier = 10000000; - while (numerator > ((u32)-1)/multiplier) { - multiplier /= 2; - denominator /= 2; - } - - return denominator ? numerator * multiplier / denominator : 0; -} - /* ------------------------------------------------------------------------ * Terminal and unit management */ diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 4cc3fa6b8c98..f4d4c33b6dfb 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -386,7 +386,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, mutex_unlock(&stream->mutex); denominator = 10000000; - uvc_simplify_fraction(&numerator, &denominator, 8, 333); + v4l2_simplify_fraction(&numerator, &denominator, 8, 333); memset(parm, 0, sizeof(*parm)); parm->type = stream->type; @@ -427,7 +427,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, else timeperframe = parm->parm.output.timeperframe; - interval = uvc_fraction_to_interval(timeperframe.numerator, + interval = v4l2_fraction_to_interval(timeperframe.numerator, timeperframe.denominator); uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n", timeperframe.numerator, timeperframe.denominator, interval); @@ -481,7 +481,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; timeperframe.denominator = 10000000; - uvc_simplify_fraction(&timeperframe.numerator, + v4l2_simplify_fraction(&timeperframe.numerator, &timeperframe.denominator, 8, 333); if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -1275,7 +1275,7 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, fival->discrete.numerator = frame->dwFrameInterval[index]; fival->discrete.denominator = 10000000; - uvc_simplify_fraction(&fival->discrete.numerator, + v4l2_simplify_fraction(&fival->discrete.numerator, &fival->discrete.denominator, 8, 333); } else { fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; @@ -1285,11 +1285,11 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, fival->stepwise.max.denominator = 10000000; fival->stepwise.step.numerator = frame->dwFrameInterval[2]; fival->stepwise.step.denominator = 10000000; - uvc_simplify_fraction(&fival->stepwise.min.numerator, + v4l2_simplify_fraction(&fival->stepwise.min.numerator, &fival->stepwise.min.denominator, 8, 333); - uvc_simplify_fraction(&fival->stepwise.max.numerator, + v4l2_simplify_fraction(&fival->stepwise.max.numerator, &fival->stepwise.max.denominator, 8, 333); - uvc_simplify_fraction(&fival->stepwise.step.numerator, + v4l2_simplify_fraction(&fival->stepwise.step.numerator, &fival->stepwise.step.denominator, 8, 333); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 24c911aeebce..df93db259312 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -41,144 +41,6 @@ #define UVC_EXT_GPIO_UNIT 0x7ffe #define UVC_EXT_GPIO_UNIT_ID 0x100 -/* ------------------------------------------------------------------------ - * GUIDs - */ -#define UVC_GUID_UVC_CAMERA \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} -#define UVC_GUID_UVC_OUTPUT \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} -#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03} -#define UVC_GUID_UVC_PROCESSING \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01} -#define UVC_GUID_UVC_SELECTOR \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02} -#define UVC_GUID_EXT_GPIO_CONTROLLER \ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03} - -#define UVC_GUID_FORMAT_MJPEG \ - { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YUY2 \ - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YUY2_ISIGHT \ - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_NV12 \ - { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_YV12 \ - { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_I420 \ - { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_UYVY \ - { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y800 \ - { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y8 \ - { 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y10 \ - { 'Y', '1', '0', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y12 \ - { 'Y', '1', '2', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y16 \ - { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_BY8 \ - { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_BA81 \ - { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_GBRG \ - { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_GRBG \ - { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_RGGB \ - { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_BG16 \ - { 'B', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_GB16 \ - { 'G', 'B', '1', '6', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_RG16 \ - { 'R', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_GR16 \ - { 'G', 'R', '1', '6', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_RGBP \ - { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_BGR3 \ - { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ - 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} -#define UVC_GUID_FORMAT_M420 \ - { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} - -#define UVC_GUID_FORMAT_H264 \ - { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_H265 \ - { 'H', '2', '6', '5', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y8I \ - { 'Y', '8', 'I', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Y12I \ - { 'Y', '1', '2', 'I', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_Z16 \ - { 'Z', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_RW10 \ - { 'R', 'W', '1', '0', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_INVZ \ - { 'I', 'N', 'V', 'Z', 0x90, 0x2d, 0x58, 0x4a, \ - 0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b} -#define UVC_GUID_FORMAT_INZI \ - { 'I', 'N', 'Z', 'I', 0x66, 0x1a, 0x42, 0xa2, \ - 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a} -#define UVC_GUID_FORMAT_INVI \ - { 'I', 'N', 'V', 'I', 0xdb, 0x57, 0x49, 0x5e, \ - 0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f} -#define UVC_GUID_FORMAT_CNF4 \ - { 'C', ' ', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} - -#define UVC_GUID_FORMAT_D3DFMT_L8 \ - {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \ - {0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} - -#define UVC_GUID_FORMAT_HEVC \ - { 'H', 'E', 'V', 'C', 0x00, 0x00, 0x10, 0x00, \ - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} - - /* ------------------------------------------------------------------------ * Driver specific constants. */ @@ -283,12 +145,6 @@ struct uvc_control { struct uvc_fh *handle; /* File handle that last changed the control. */ }; -struct uvc_format_desc { - char *name; - u8 guid[16]; - u32 fcc; -}; - /* * The term 'entity' refers to both UVC units and UVC terminals. * @@ -911,9 +767,6 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry); /* Utility functions */ -void uvc_simplify_fraction(u32 *numerator, u32 *denominator, - unsigned int n_terms, unsigned int threshold); -u32 uvc_fraction_to_interval(u32 numerator, u32 denominator); struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index e0fbe6ba4b6c..40f56e044640 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -484,3 +484,89 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul, return freq > 0 ? freq : -EINVAL; } EXPORT_SYMBOL_GPL(v4l2_get_link_freq); + +/* + * Simplify a fraction using a simple continued fraction decomposition. The + * idea here is to convert fractions such as 333333/10000000 to 1/30 using + * 32 bit arithmetic only. The algorithm is not perfect and relies upon two + * arbitrary parameters to remove non-significative terms from the simple + * continued fraction decomposition. Using 8 and 333 for n_terms and threshold + * respectively seems to give nice results. + */ +void v4l2_simplify_fraction(u32 *numerator, u32 *denominator, + unsigned int n_terms, unsigned int threshold) +{ + u32 *an; + u32 x, y, r; + unsigned int i, n; + + an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL); + if (an == NULL) + return; + + /* + * Convert the fraction to a simple continued fraction. See + * https://en.wikipedia.org/wiki/Continued_fraction + * Stop if the current term is bigger than or equal to the given + * threshold. + */ + x = *numerator; + y = *denominator; + + for (n = 0; n < n_terms && y != 0; ++n) { + an[n] = x / y; + if (an[n] >= threshold) { + if (n < 2) + n++; + break; + } + + r = x - an[n] * y; + x = y; + y = r; + } + + /* Expand the simple continued fraction back to an integer fraction. */ + x = 0; + y = 1; + + for (i = n; i > 0; --i) { + r = y; + y = an[i-1] * y + x; + x = r; + } + + *numerator = y; + *denominator = x; + kfree(an); +} +EXPORT_SYMBOL_GPL(v4l2_simplify_fraction); + +/* + * Convert a fraction to a frame interval in 100ns multiples. The idea here is + * to compute numerator / denominator * 10000000 using 32 bit fixed point + * arithmetic only. + */ +u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator) +{ + u32 multiplier; + + /* Saturate the result if the operation would overflow. */ + if (denominator == 0 || + numerator/denominator >= ((u32)-1)/10000000) + return (u32)-1; + + /* + * Divide both the denominator and the multiplier by two until + * numerator * multiplier doesn't overflow. If anyone knows a better + * algorithm please let me know. + */ + multiplier = 10000000; + while (numerator > ((u32)-1)/multiplier) { + multiplier /= 2; + denominator /= 2; + } + + return denominator ? numerator * multiplier / denominator : 0; +} +EXPORT_SYMBOL_GPL(v4l2_fraction_to_interval); diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index 414aa82abc39..ae7ef2e038be 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -246,7 +246,7 @@ static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port, static void sdio_uart_change_speed(struct sdio_uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned char cval, fcr = 0; unsigned int baud, quot; @@ -859,7 +859,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } static void sdio_uart_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct sdio_uart_port *port = tty->driver_data; unsigned int cflag = tty->termios.c_cflag; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f8221a7acf62..ce1f6081d582 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1380,7 +1380,8 @@ static void hso_serial_cleanup(struct tty_struct *tty) } /* setup the term */ -static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) +static void hso_serial_set_termios(struct tty_struct *tty, + const struct ktermios *old) { struct hso_serial *serial = tty->driver_data; unsigned long flags; diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index b8c7843730ed..62e9f7d6c9fe 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 300b0f2b5f84..7bd00a11d074 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -91,6 +91,7 @@ source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" source "drivers/phy/socionext/Kconfig" source "drivers/phy/st/Kconfig" +source "drivers/phy/sunplus/Kconfig" source "drivers/phy/tegra/Kconfig" source "drivers/phy/ti/Kconfig" source "drivers/phy/intel/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 01e9efffc726..54f312c10a40 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -31,6 +31,7 @@ obj-y += allwinner/ \ samsung/ \ socionext/ \ st/ \ + sunplus/ \ tegra/ \ ti/ \ xilinx/ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index d5f3b42eb8ce..3a3831f6059a 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -768,7 +768,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (data->cfg->dedicated_clocks) snprintf(name, sizeof(name), "usb%d_phy", i); else - strlcpy(name, "usb_phy", sizeof(name)); + strscpy(name, "usb_phy", sizeof(name)); phy->clk = devm_clk_get(dev, name); if (IS_ERR(phy->clk)) { diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c index 1027ece6ca12..a3e1108b736d 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c @@ -197,7 +197,7 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) struct phy_provider *phy; struct device *dev = &pdev->dev; struct phy_axg_mipi_pcie_analog_priv *priv; - struct device_node *np = dev->of_node; + struct device_node *np = dev->of_node, *parent_np; struct regmap *map; int ret; @@ -206,7 +206,9 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) return -ENOMEM; /* Get the hhi system controller node */ - map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + parent_np = of_get_parent(dev->of_node); + map = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); if (IS_ERR(map)) { dev_err(dev, "failed to get HHI regmap\n"); diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c index 54d65a6f0fcc..d2a1da8d9e58 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c @@ -388,7 +388,6 @@ static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) struct phy_g12a_usb3_pcie_priv *priv; struct phy_provider *phy_provider; void __iomem *base; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -408,43 +407,24 @@ static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) if (IS_ERR(priv->regmap_cr)) return PTR_ERR(priv->regmap_cr); - priv->clk_ref = devm_clk_get(dev, "ref_clk"); + priv->clk_ref = devm_clk_get_enabled(dev, "ref_clk"); if (IS_ERR(priv->clk_ref)) return PTR_ERR(priv->clk_ref); - ret = clk_prepare_enable(priv->clk_ref); - if (ret) - return ret; - priv->reset = devm_reset_control_array_get_exclusive(dev); - if (IS_ERR(priv->reset)) { - ret = PTR_ERR(priv->reset); - goto err_disable_clk_ref; - } + if (IS_ERR(priv->reset)) + return PTR_ERR(priv->reset); priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); - if (IS_ERR(priv->phy)) { - ret = PTR_ERR(priv->phy); - dev_err_probe(dev, ret, "failed to create PHY\n"); - goto err_disable_clk_ref; - } + if (IS_ERR(priv->phy)) + return dev_err_probe(dev, PTR_ERR(priv->phy), "failed to create PHY\n"); phy_set_drvdata(priv->phy, priv); dev_set_drvdata(dev, priv); phy_provider = devm_of_phy_provider_register(dev, phy_g12a_usb3_pcie_xlate); - if (IS_ERR(phy_provider)) { - ret = PTR_ERR(phy_provider); - goto err_disable_clk_ref; - } - - return 0; - -err_disable_clk_ref: - clk_disable_unprepare(priv->clk_ref); - - return ret; + return PTR_ERR_OR_ZERO(phy_provider); } static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index 157683d10367..6010e246d52e 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -413,44 +413,29 @@ static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy) u32 val; cbphy->core_clk = devm_clk_get(dev, NULL); - if (IS_ERR(cbphy->core_clk)) { - ret = PTR_ERR(cbphy->core_clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Get clk failed:%d!\n", ret); - return ret; - } + if (IS_ERR(cbphy->core_clk)) + return dev_err_probe(dev, PTR_ERR(cbphy->core_clk), + "Get clk failed!\n"); cbphy->core_rst = devm_reset_control_get_optional(dev, "core"); - if (IS_ERR(cbphy->core_rst)) { - ret = PTR_ERR(cbphy->core_rst); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Get core reset control err: %d!\n", ret); - return ret; - } + if (IS_ERR(cbphy->core_rst)) + return dev_err_probe(dev, PTR_ERR(cbphy->core_rst), + "Get core reset control err!\n"); cbphy->phy_rst = devm_reset_control_get_optional(dev, "phy"); - if (IS_ERR(cbphy->phy_rst)) { - ret = PTR_ERR(cbphy->phy_rst); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Get PHY reset control err: %d!\n", ret); - return ret; - } + if (IS_ERR(cbphy->phy_rst)) + return dev_err_probe(dev, PTR_ERR(cbphy->phy_rst), + "Get PHY reset control err!\n"); cbphy->iphy[0].app_rst = devm_reset_control_get_optional(dev, "iphy0"); - if (IS_ERR(cbphy->iphy[0].app_rst)) { - ret = PTR_ERR(cbphy->iphy[0].app_rst); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Get phy0 reset control err: %d!\n", ret); - return ret; - } + if (IS_ERR(cbphy->iphy[0].app_rst)) + return dev_err_probe(dev, PTR_ERR(cbphy->iphy[0].app_rst), + "Get phy0 reset control err!\n"); cbphy->iphy[1].app_rst = devm_reset_control_get_optional(dev, "iphy1"); - if (IS_ERR(cbphy->iphy[1].app_rst)) { - ret = PTR_ERR(cbphy->iphy[1].app_rst); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Get phy1 reset control err: %d!\n", ret); - return ret; - } + if (IS_ERR(cbphy->iphy[1].app_rst)) + return dev_err_probe(dev, PTR_ERR(cbphy->iphy[1].app_rst), + "Get phy1 reset control err!\n"); cbphy->app_base = devm_platform_ioremap_resource_byname(pdev, "app"); if (IS_ERR(cbphy->app_base)) diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c index 31266e7ca324..232fd3f1ff1b 100644 --- a/drivers/phy/mediatek/phy-mtk-dp.c +++ b/drivers/phy/mediatek/phy-mtk-dp.c @@ -85,7 +85,7 @@ struct mtk_dp_phy { static int mtk_dp_phy_init(struct phy *phy) { struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); - u32 driving_params[] = { + static const u32 driving_params[] = { DRIVING_PARAM_3_DEFAULT, DRIVING_PARAM_4_DEFAULT, DRIVING_PARAM_5_DEFAULT, diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c index b74c65a1762c..e51b2d13eab4 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt2701.c @@ -5,83 +5,66 @@ */ #include "phy-mtk-hdmi.h" +#include "phy-mtk-io.h" #define HDMI_CON0 0x00 -#define RG_HDMITX_DRV_IBIAS 0 -#define RG_HDMITX_DRV_IBIAS_MASK (0x3f << 0) -#define RG_HDMITX_EN_SER 12 -#define RG_HDMITX_EN_SER_MASK (0x0f << 12) -#define RG_HDMITX_EN_SLDO 16 -#define RG_HDMITX_EN_SLDO_MASK (0x0f << 16) -#define RG_HDMITX_EN_PRED 20 -#define RG_HDMITX_EN_PRED_MASK (0x0f << 20) -#define RG_HDMITX_EN_IMP 24 -#define RG_HDMITX_EN_IMP_MASK (0x0f << 24) -#define RG_HDMITX_EN_DRV 28 -#define RG_HDMITX_EN_DRV_MASK (0x0f << 28) +#define RG_HDMITX_DRV_IBIAS_MASK GENMASK(5, 0) +#define RG_HDMITX_EN_SER_MASK GENMASK(15, 12) +#define RG_HDMITX_EN_SLDO_MASK GENMASK(19, 16) +#define RG_HDMITX_EN_PRED_MASK GENMASK(23, 20) +#define RG_HDMITX_EN_IMP_MASK GENMASK(27, 24) +#define RG_HDMITX_EN_DRV_MASK GENMASK(31, 28) #define HDMI_CON1 0x04 -#define RG_HDMITX_PRED_IBIAS 18 -#define RG_HDMITX_PRED_IBIAS_MASK (0x0f << 18) -#define RG_HDMITX_PRED_IMP (0x01 << 22) -#define RG_HDMITX_DRV_IMP 26 -#define RG_HDMITX_DRV_IMP_MASK (0x3f << 26) +#define RG_HDMITX_PRED_IBIAS_MASK GENMASK(21, 18) +#define RG_HDMITX_PRED_IMP BIT(22) +#define RG_HDMITX_DRV_IMP_MASK GENMASK(31, 26) #define HDMI_CON2 0x08 -#define RG_HDMITX_EN_TX_CKLDO (0x01 << 0) -#define RG_HDMITX_EN_TX_POSDIV (0x01 << 1) -#define RG_HDMITX_TX_POSDIV 3 -#define RG_HDMITX_TX_POSDIV_MASK (0x03 << 3) -#define RG_HDMITX_EN_MBIAS (0x01 << 6) -#define RG_HDMITX_MBIAS_LPF_EN (0x01 << 7) +#define RG_HDMITX_EN_TX_CKLDO BIT(0) +#define RG_HDMITX_EN_TX_POSDIV BIT(1) +#define RG_HDMITX_TX_POSDIV_MASK GENMASK(4, 3) +#define RG_HDMITX_EN_MBIAS BIT(6) +#define RG_HDMITX_MBIAS_LPF_EN BIT(7) #define HDMI_CON4 0x10 -#define RG_HDMITX_RESERVE_MASK (0xffffffff << 0) +#define RG_HDMITX_RESERVE_MASK GENMASK(31, 0) #define HDMI_CON6 0x18 -#define RG_HTPLL_BR 0 -#define RG_HTPLL_BR_MASK (0x03 << 0) -#define RG_HTPLL_BC 2 -#define RG_HTPLL_BC_MASK (0x03 << 2) -#define RG_HTPLL_BP 4 -#define RG_HTPLL_BP_MASK (0x0f << 4) -#define RG_HTPLL_IR 8 -#define RG_HTPLL_IR_MASK (0x0f << 8) -#define RG_HTPLL_IC 12 -#define RG_HTPLL_IC_MASK (0x0f << 12) -#define RG_HTPLL_POSDIV 16 -#define RG_HTPLL_POSDIV_MASK (0x03 << 16) -#define RG_HTPLL_PREDIV 18 -#define RG_HTPLL_PREDIV_MASK (0x03 << 18) -#define RG_HTPLL_FBKSEL 20 -#define RG_HTPLL_FBKSEL_MASK (0x03 << 20) -#define RG_HTPLL_RLH_EN (0x01 << 22) -#define RG_HTPLL_FBKDIV 24 -#define RG_HTPLL_FBKDIV_MASK (0x7f << 24) -#define RG_HTPLL_EN (0x01 << 31) +#define RG_HTPLL_BR_MASK GENMASK(1, 0) +#define RG_HTPLL_BC_MASK GENMASK(3, 2) +#define RG_HTPLL_BP_MASK GENMASK(7, 4) +#define RG_HTPLL_IR_MASK GENMASK(11, 8) +#define RG_HTPLL_IC_MASK GENMASK(15, 12) +#define RG_HTPLL_POSDIV_MASK GENMASK(17, 16) +#define RG_HTPLL_PREDIV_MASK GENMASK(19, 18) +#define RG_HTPLL_FBKSEL_MASK GENMASK(21, 20) +#define RG_HTPLL_RLH_EN BIT(22) +#define RG_HTPLL_FBKDIV_MASK GENMASK(30, 24) +#define RG_HTPLL_EN BIT(31) #define HDMI_CON7 0x1c -#define RG_HTPLL_AUTOK_EN (0x01 << 23) -#define RG_HTPLL_DIVEN 28 -#define RG_HTPLL_DIVEN_MASK (0x07 << 28) +#define RG_HTPLL_AUTOK_EN BIT(23) +#define RG_HTPLL_DIVEN_MASK GENMASK(30, 28) static int mtk_hdmi_pll_prepare(struct clk_hw *hw) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + mtk_phy_set_bits(base + HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_EN_MBIAS); usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_EN); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_DRV_MASK); usleep_range(80, 100); return 0; } @@ -89,20 +72,21 @@ static int mtk_hdmi_pll_prepare(struct clk_hw *hw) static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_EN); usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_EN_MBIAS); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_phy_clear_bits(base + HDMI_CON7, RG_HTPLL_AUTOK_EN); usleep_range(80, 100); } @@ -116,6 +100,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; u32 pos_div; if (rate <= 64000000) @@ -125,37 +110,25 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, else pos_div = 1; - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_PREDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IC), - RG_HTPLL_IC_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_IR), - RG_HTPLL_IR_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON2, (pos_div << RG_HDMITX_TX_POSDIV), - RG_HDMITX_TX_POSDIV_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (1 << RG_HTPLL_FBKSEL), - RG_HTPLL_FBKSEL_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (19 << RG_HTPLL_FBKDIV), - RG_HTPLL_FBKDIV_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON7, (0x2 << RG_HTPLL_DIVEN), - RG_HTPLL_DIVEN_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0xc << RG_HTPLL_BP), - RG_HTPLL_BP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x2 << RG_HTPLL_BC), - RG_HTPLL_BC_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, (0x1 << RG_HTPLL_BR), - RG_HTPLL_BR_MASK); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_PREDIV_MASK); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_EN_TX_POSDIV); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_IC_MASK, 0x1); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_IR_MASK, 0x1); + mtk_phy_update_field(base + HDMI_CON2, RG_HDMITX_TX_POSDIV_MASK, pos_div); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_FBKSEL_MASK, 1); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_FBKDIV_MASK, 19); + mtk_phy_update_field(base + HDMI_CON7, RG_HTPLL_DIVEN_MASK, 0x2); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_BP_MASK, 0xc); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_BC_MASK, 0x2); + mtk_phy_update_field(base + HDMI_CON6, RG_HTPLL_BR_MASK, 0x1); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PRED_IMP); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x3 << RG_HDMITX_PRED_IBIAS), - RG_HDMITX_PRED_IBIAS_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_IMP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, (0x28 << RG_HDMITX_DRV_IMP), - RG_HDMITX_DRV_IMP_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, 0x28, RG_HDMITX_RESERVE_MASK); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, (0xa << RG_HDMITX_DRV_IBIAS), - RG_HDMITX_DRV_IBIAS_MASK); + mtk_phy_clear_bits(base + HDMI_CON1, RG_HDMITX_PRED_IMP); + mtk_phy_update_field(base + HDMI_CON1, RG_HDMITX_PRED_IBIAS_MASK, 0x3); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_IMP_MASK); + mtk_phy_update_field(base + HDMI_CON1, RG_HDMITX_DRV_IMP_MASK, 0x28); + mtk_phy_update_field(base + HDMI_CON4, RG_HDMITX_RESERVE_MASK, 0x28); + mtk_phy_update_field(base + HDMI_CON0, RG_HDMITX_DRV_IBIAS_MASK, 0xa); return 0; } @@ -164,9 +137,10 @@ static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); unsigned long out_rate, val; + u32 tmp; - val = (readl(hdmi_phy->regs + HDMI_CON6) - & RG_HTPLL_PREDIV_MASK) >> RG_HTPLL_PREDIV; + tmp = readl(hdmi_phy->regs + HDMI_CON6); + val = FIELD_GET(RG_HTPLL_PREDIV_MASK, tmp); switch (val) { case 0x00: out_rate = parent_rate; @@ -179,14 +153,14 @@ static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, break; } - val = (readl(hdmi_phy->regs + HDMI_CON6) - & RG_HTPLL_FBKDIV_MASK) >> RG_HTPLL_FBKDIV; + val = FIELD_GET(RG_HTPLL_FBKDIV_MASK, tmp); out_rate *= (val + 1) * 2; - val = (readl(hdmi_phy->regs + HDMI_CON2) - & RG_HDMITX_TX_POSDIV_MASK); - out_rate >>= (val >> RG_HDMITX_TX_POSDIV); - if (readl(hdmi_phy->regs + HDMI_CON2) & RG_HDMITX_EN_TX_POSDIV) + tmp = readl(hdmi_phy->regs + HDMI_CON2); + val = FIELD_GET(RG_HDMITX_TX_POSDIV_MASK, tmp); + out_rate >>= val; + + if (tmp & RG_HDMITX_EN_TX_POSDIV) out_rate /= 5; return out_rate; @@ -202,37 +176,41 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = { static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) { - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); + void __iomem *base = hdmi_phy->regs; + + mtk_phy_set_bits(base + HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_EN_MBIAS); usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_phy_set_bits(base + HDMI_CON6, RG_HTPLL_EN); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); usleep_range(80, 100); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_phy_set_bits(base + HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_EN_DRV_MASK); usleep_range(80, 100); } static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) { - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_DRV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_PRED_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SER_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); + void __iomem *base = hdmi_phy->regs; + + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_DRV_MASK); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_PRED_MASK); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_SER_MASK); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_MBIAS_LPF_EN); usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_EN); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_EN_SLDO_MASK); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_EN_TX_CKLDO); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_EN); usleep_range(80, 100); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON2, RG_HDMITX_EN_MBIAS); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_POSDIV_MASK); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON6, RG_HTPLL_RLH_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON7, RG_HTPLL_AUTOK_EN); + mtk_phy_clear_bits(base + HDMI_CON2, RG_HDMITX_EN_MBIAS); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_POSDIV_MASK); + mtk_phy_clear_bits(base + HDMI_CON6, RG_HTPLL_RLH_EN); + mtk_phy_clear_bits(base + HDMI_CON7, RG_HTPLL_AUTOK_EN); usleep_range(80, 100); } diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c index 6cdfdf5a698a..d04758396046 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8173.c @@ -5,121 +5,99 @@ */ #include "phy-mtk-hdmi.h" +#include "phy-mtk-io.h" #define HDMI_CON0 0x00 #define RG_HDMITX_PLL_EN BIT(31) -#define RG_HDMITX_PLL_FBKDIV (0x7f << 24) -#define PLL_FBKDIV_SHIFT 24 -#define RG_HDMITX_PLL_FBKSEL (0x3 << 22) -#define PLL_FBKSEL_SHIFT 22 -#define RG_HDMITX_PLL_PREDIV (0x3 << 20) -#define PREDIV_SHIFT 20 -#define RG_HDMITX_PLL_POSDIV (0x3 << 18) -#define POSDIV_SHIFT 18 -#define RG_HDMITX_PLL_RST_DLY (0x3 << 16) -#define RG_HDMITX_PLL_IR (0xf << 12) -#define PLL_IR_SHIFT 12 -#define RG_HDMITX_PLL_IC (0xf << 8) -#define PLL_IC_SHIFT 8 -#define RG_HDMITX_PLL_BP (0xf << 4) -#define PLL_BP_SHIFT 4 -#define RG_HDMITX_PLL_BR (0x3 << 2) -#define PLL_BR_SHIFT 2 -#define RG_HDMITX_PLL_BC (0x3 << 0) -#define PLL_BC_SHIFT 0 +#define RG_HDMITX_PLL_FBKDIV GENMASK(30, 24) +#define RG_HDMITX_PLL_FBKSEL GENMASK(23, 22) +#define RG_HDMITX_PLL_PREDIV GENMASK(21, 20) +#define RG_HDMITX_PLL_POSDIV GENMASK(19, 18) +#define RG_HDMITX_PLL_RST_DLY GENMASK(17, 16) +#define RG_HDMITX_PLL_IR GENMASK(15, 12) +#define RG_HDMITX_PLL_IC GENMASK(11, 8) +#define RG_HDMITX_PLL_BP GENMASK(7, 4) +#define RG_HDMITX_PLL_BR GENMASK(3, 2) +#define RG_HDMITX_PLL_BC GENMASK(1, 0) #define HDMI_CON1 0x04 -#define RG_HDMITX_PLL_DIVEN (0x7 << 29) -#define PLL_DIVEN_SHIFT 29 +#define RG_HDMITX_PLL_DIVEN GENMASK(31, 29) #define RG_HDMITX_PLL_AUTOK_EN BIT(28) -#define RG_HDMITX_PLL_AUTOK_KF (0x3 << 26) -#define RG_HDMITX_PLL_AUTOK_KS (0x3 << 24) +#define RG_HDMITX_PLL_AUTOK_KF GENMASK(27, 26) +#define RG_HDMITX_PLL_AUTOK_KS GENMASK(25, 24) #define RG_HDMITX_PLL_AUTOK_LOAD BIT(23) -#define RG_HDMITX_PLL_BAND (0x3f << 16) +#define RG_HDMITX_PLL_BAND GENMASK(21, 16) #define RG_HDMITX_PLL_REF_SEL BIT(15) #define RG_HDMITX_PLL_BIAS_EN BIT(14) #define RG_HDMITX_PLL_BIAS_LPF_EN BIT(13) #define RG_HDMITX_PLL_TXDIV_EN BIT(12) -#define RG_HDMITX_PLL_TXDIV (0x3 << 10) -#define PLL_TXDIV_SHIFT 10 +#define RG_HDMITX_PLL_TXDIV GENMASK(11, 10) #define RG_HDMITX_PLL_LVROD_EN BIT(9) #define RG_HDMITX_PLL_MONVC_EN BIT(8) #define RG_HDMITX_PLL_MONCK_EN BIT(7) #define RG_HDMITX_PLL_MONREF_EN BIT(6) #define RG_HDMITX_PLL_TST_EN BIT(5) #define RG_HDMITX_PLL_TST_CK_EN BIT(4) -#define RG_HDMITX_PLL_TST_SEL (0xf << 0) +#define RG_HDMITX_PLL_TST_SEL GENMASK(3, 0) #define HDMI_CON2 0x08 -#define RGS_HDMITX_PLL_AUTOK_BAND (0x7f << 8) +#define RGS_HDMITX_PLL_AUTOK_BAND GENMASK(14, 8) #define RGS_HDMITX_PLL_AUTOK_FAIL BIT(1) #define RG_HDMITX_EN_TX_CKLDO BIT(0) #define HDMI_CON3 0x0c -#define RG_HDMITX_SER_EN (0xf << 28) -#define RG_HDMITX_PRD_EN (0xf << 24) -#define RG_HDMITX_PRD_IMP_EN (0xf << 20) -#define RG_HDMITX_DRV_EN (0xf << 16) -#define RG_HDMITX_DRV_IMP_EN (0xf << 12) -#define DRV_IMP_EN_SHIFT 12 +#define RG_HDMITX_SER_EN GENMASK(31, 28) +#define RG_HDMITX_PRD_EN GENMASK(27, 24) +#define RG_HDMITX_PRD_IMP_EN GENMASK(23, 20) +#define RG_HDMITX_DRV_EN GENMASK(19, 16) +#define RG_HDMITX_DRV_IMP_EN GENMASK(15, 12) #define RG_HDMITX_MHLCK_FORCE BIT(10) #define RG_HDMITX_MHLCK_PPIX_EN BIT(9) #define RG_HDMITX_MHLCK_EN BIT(8) -#define RG_HDMITX_SER_DIN_SEL (0xf << 4) +#define RG_HDMITX_SER_DIN_SEL GENMASK(7, 4) #define RG_HDMITX_SER_5T1_BIST_EN BIT(3) #define RG_HDMITX_SER_BIST_TOG BIT(2) #define RG_HDMITX_SER_DIN_TOG BIT(1) #define RG_HDMITX_SER_CLKDIG_INV BIT(0) #define HDMI_CON4 0x10 -#define RG_HDMITX_PRD_IBIAS_CLK (0xf << 24) -#define RG_HDMITX_PRD_IBIAS_D2 (0xf << 16) -#define RG_HDMITX_PRD_IBIAS_D1 (0xf << 8) -#define RG_HDMITX_PRD_IBIAS_D0 (0xf << 0) -#define PRD_IBIAS_CLK_SHIFT 24 -#define PRD_IBIAS_D2_SHIFT 16 -#define PRD_IBIAS_D1_SHIFT 8 -#define PRD_IBIAS_D0_SHIFT 0 +#define RG_HDMITX_PRD_IBIAS_CLK GENMASK(27, 24) +#define RG_HDMITX_PRD_IBIAS_D2 GENMASK(19, 16) +#define RG_HDMITX_PRD_IBIAS_D1 GENMASK(11, 8) +#define RG_HDMITX_PRD_IBIAS_D0 GENMASK(3, 0) #define HDMI_CON5 0x14 -#define RG_HDMITX_DRV_IBIAS_CLK (0x3f << 24) -#define RG_HDMITX_DRV_IBIAS_D2 (0x3f << 16) -#define RG_HDMITX_DRV_IBIAS_D1 (0x3f << 8) -#define RG_HDMITX_DRV_IBIAS_D0 (0x3f << 0) -#define DRV_IBIAS_CLK_SHIFT 24 -#define DRV_IBIAS_D2_SHIFT 16 -#define DRV_IBIAS_D1_SHIFT 8 -#define DRV_IBIAS_D0_SHIFT 0 +#define RG_HDMITX_DRV_IBIAS_CLK GENMASK(29, 24) +#define RG_HDMITX_DRV_IBIAS_D2 GENMASK(21, 16) +#define RG_HDMITX_DRV_IBIAS_D1 GENMASK(13, 8) +#define RG_HDMITX_DRV_IBIAS_D0 GENMASK(5, 0) #define HDMI_CON6 0x18 -#define RG_HDMITX_DRV_IMP_CLK (0x3f << 24) -#define RG_HDMITX_DRV_IMP_D2 (0x3f << 16) -#define RG_HDMITX_DRV_IMP_D1 (0x3f << 8) -#define RG_HDMITX_DRV_IMP_D0 (0x3f << 0) -#define DRV_IMP_CLK_SHIFT 24 -#define DRV_IMP_D2_SHIFT 16 -#define DRV_IMP_D1_SHIFT 8 -#define DRV_IMP_D0_SHIFT 0 +#define RG_HDMITX_DRV_IMP_CLK GENMASK(29, 24) +#define RG_HDMITX_DRV_IMP_D2 GENMASK(21, 16) +#define RG_HDMITX_DRV_IMP_D1 GENMASK(13, 8) +#define RG_HDMITX_DRV_IMP_D0 GENMASK(5, 0) #define HDMI_CON7 0x1c -#define RG_HDMITX_MHLCK_DRV_IBIAS (0x1f << 27) -#define RG_HDMITX_SER_DIN (0x3ff << 16) -#define RG_HDMITX_CHLDC_TST (0xf << 12) -#define RG_HDMITX_CHLCK_TST (0xf << 8) -#define RG_HDMITX_RESERVE (0xff << 0) +#define RG_HDMITX_MHLCK_DRV_IBIAS GENMASK(31, 27) +#define RG_HDMITX_SER_DIN GENMASK(25, 16) +#define RG_HDMITX_CHLDC_TST GENMASK(15, 12) +#define RG_HDMITX_CHLCK_TST GENMASK(11, 8) +#define RG_HDMITX_RESERVE GENMASK(7, 0) #define HDMI_CON8 0x20 -#define RGS_HDMITX_2T1_LEV (0xf << 16) -#define RGS_HDMITX_2T1_EDG (0xf << 12) -#define RGS_HDMITX_5T1_LEV (0xf << 8) -#define RGS_HDMITX_5T1_EDG (0xf << 4) +#define RGS_HDMITX_2T1_LEV GENMASK(19, 16) +#define RGS_HDMITX_2T1_EDG GENMASK(15, 12) +#define RGS_HDMITX_5T1_LEV GENMASK(11, 8) +#define RGS_HDMITX_5T1_EDG GENMASK(7, 4) #define RGS_HDMITX_PLUG_TST BIT(0) static int mtk_hdmi_pll_prepare(struct clk_hw *hw) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_MHLCK_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); + mtk_phy_set_bits(base + HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_phy_clear_bits(base + HDMI_CON3, RG_HDMITX_MHLCK_EN); + mtk_phy_set_bits(base + HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); usleep_range(100, 150); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_PLL_EN); usleep_range(100, 150); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); + mtk_phy_set_bits(base + HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); + mtk_phy_set_bits(base + HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); return 0; } @@ -127,15 +105,16 @@ static int mtk_hdmi_pll_prepare(struct clk_hw *hw) static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); + mtk_phy_clear_bits(base + HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN); + mtk_phy_clear_bits(base + HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN); usleep_range(100, 150); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_EN); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_PLL_EN); usleep_range(100, 150); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); + mtk_phy_clear_bits(base + HDMI_CON1, RG_HDMITX_PLL_BIAS_EN); + mtk_phy_clear_bits(base + HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_phy_clear_bits(base + HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN); usleep_range(100, 150); } @@ -157,6 +136,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *base = hdmi_phy->regs; unsigned int pre_div; unsigned int div; unsigned int pre_ibias; @@ -177,65 +157,57 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, div = 1; } - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (pre_div << PREDIV_SHIFT), RG_HDMITX_PLL_PREDIV); - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0x1 << PLL_IC_SHIFT) | (0x1 << PLL_IR_SHIFT), - RG_HDMITX_PLL_IC | RG_HDMITX_PLL_IR); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, - (div << PLL_TXDIV_SHIFT), RG_HDMITX_PLL_TXDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0x1 << PLL_FBKSEL_SHIFT) | (19 << PLL_FBKDIV_SHIFT), - RG_HDMITX_PLL_FBKSEL | RG_HDMITX_PLL_FBKDIV); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON1, - (0x2 << PLL_DIVEN_SHIFT), RG_HDMITX_PLL_DIVEN); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON0, - (0xc << PLL_BP_SHIFT) | (0x2 << PLL_BC_SHIFT) | - (0x1 << PLL_BR_SHIFT), - RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC | - RG_HDMITX_PLL_BR); + mtk_phy_update_field(base + HDMI_CON0, RG_HDMITX_PLL_PREDIV, pre_div); + mtk_phy_set_bits(base + HDMI_CON0, RG_HDMITX_PLL_POSDIV); + mtk_phy_update_bits(base + HDMI_CON0, + RG_HDMITX_PLL_IC | RG_HDMITX_PLL_IR, + FIELD_PREP(RG_HDMITX_PLL_IC, 0x1) | + FIELD_PREP(RG_HDMITX_PLL_IR, 0x1)); + mtk_phy_update_field(base + HDMI_CON1, RG_HDMITX_PLL_TXDIV, div); + mtk_phy_update_bits(base + HDMI_CON0, + RG_HDMITX_PLL_FBKSEL | RG_HDMITX_PLL_FBKDIV, + FIELD_PREP(RG_HDMITX_PLL_FBKSEL, 0x1) | + FIELD_PREP(RG_HDMITX_PLL_FBKDIV, 19)); + mtk_phy_update_field(base + HDMI_CON1, RG_HDMITX_PLL_DIVEN, 0x2); + mtk_phy_update_bits(base + HDMI_CON0, + RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC | + RG_HDMITX_PLL_BR, + FIELD_PREP(RG_HDMITX_PLL_BP, 0xc) | + FIELD_PREP(RG_HDMITX_PLL_BC, 0x2) | + FIELD_PREP(RG_HDMITX_PLL_BR, 0x1)); if (rate < 165000000) { - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_PRD_IMP_EN); + mtk_phy_clear_bits(base + HDMI_CON3, RG_HDMITX_PRD_IMP_EN); pre_ibias = 0x3; imp_en = 0x0; hdmi_ibias = hdmi_phy->ibias; } else { - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_PRD_IMP_EN); + mtk_phy_set_bits(base + HDMI_CON3, RG_HDMITX_PRD_IMP_EN); pre_ibias = 0x6; imp_en = 0xf; hdmi_ibias = hdmi_phy->ibias_up; } - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4, - (pre_ibias << PRD_IBIAS_CLK_SHIFT) | - (pre_ibias << PRD_IBIAS_D2_SHIFT) | - (pre_ibias << PRD_IBIAS_D1_SHIFT) | - (pre_ibias << PRD_IBIAS_D0_SHIFT), - RG_HDMITX_PRD_IBIAS_CLK | - RG_HDMITX_PRD_IBIAS_D2 | - RG_HDMITX_PRD_IBIAS_D1 | - RG_HDMITX_PRD_IBIAS_D0); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3, - (imp_en << DRV_IMP_EN_SHIFT), - RG_HDMITX_DRV_IMP_EN); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6, - (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) | - (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) | - (hdmi_phy->drv_imp_d1 << DRV_IMP_D1_SHIFT) | - (hdmi_phy->drv_imp_d0 << DRV_IMP_D0_SHIFT), - RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 | - RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0); - mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5, - (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D2_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D1_SHIFT) | - (hdmi_ibias << DRV_IBIAS_D0_SHIFT), - RG_HDMITX_DRV_IBIAS_CLK | - RG_HDMITX_DRV_IBIAS_D2 | - RG_HDMITX_DRV_IBIAS_D1 | - RG_HDMITX_DRV_IBIAS_D0); + mtk_phy_update_bits(base + HDMI_CON4, + RG_HDMITX_PRD_IBIAS_CLK | RG_HDMITX_PRD_IBIAS_D2 | + RG_HDMITX_PRD_IBIAS_D1 | RG_HDMITX_PRD_IBIAS_D0, + FIELD_PREP(RG_HDMITX_PRD_IBIAS_CLK, pre_ibias) | + FIELD_PREP(RG_HDMITX_PRD_IBIAS_D2, pre_ibias) | + FIELD_PREP(RG_HDMITX_PRD_IBIAS_D1, pre_ibias) | + FIELD_PREP(RG_HDMITX_PRD_IBIAS_D0, pre_ibias)); + mtk_phy_update_field(base + HDMI_CON3, RG_HDMITX_DRV_IMP_EN, imp_en); + mtk_phy_update_bits(base + HDMI_CON6, + RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 | + RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0, + FIELD_PREP(RG_HDMITX_DRV_IMP_CLK, hdmi_phy->drv_imp_clk) | + FIELD_PREP(RG_HDMITX_DRV_IMP_D2, hdmi_phy->drv_imp_d2) | + FIELD_PREP(RG_HDMITX_DRV_IMP_D1, hdmi_phy->drv_imp_d1) | + FIELD_PREP(RG_HDMITX_DRV_IMP_D0, hdmi_phy->drv_imp_d0)); + mtk_phy_update_bits(base + HDMI_CON5, + RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 | + RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0, + FIELD_PREP(RG_HDMITX_DRV_IBIAS_CLK, hdmi_ibias) | + FIELD_PREP(RG_HDMITX_DRV_IBIAS_D2, hdmi_ibias) | + FIELD_PREP(RG_HDMITX_DRV_IBIAS_D1, hdmi_ibias) | + FIELD_PREP(RG_HDMITX_DRV_IBIAS_D0, hdmi_ibias)); return 0; } @@ -257,17 +229,17 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = { static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) { - mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_SER_EN | RG_HDMITX_PRD_EN | - RG_HDMITX_DRV_EN); + mtk_phy_set_bits(hdmi_phy->regs + HDMI_CON3, + RG_HDMITX_SER_EN | RG_HDMITX_PRD_EN | + RG_HDMITX_DRV_EN); usleep_range(100, 150); } static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) { - mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, - RG_HDMITX_DRV_EN | RG_HDMITX_PRD_EN | - RG_HDMITX_SER_EN); + mtk_phy_clear_bits(hdmi_phy->regs + HDMI_CON3, + RG_HDMITX_DRV_EN | RG_HDMITX_PRD_EN | + RG_HDMITX_SER_EN); } struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c index d4bd419abc3c..b16d437d6721 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi.c @@ -15,39 +15,6 @@ static const struct phy_ops mtk_hdmi_phy_dev_ops = { .owner = THIS_MODULE, }; -void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp &= ~bits; - writel(tmp, reg); -} - -void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp |= bits; - writel(tmp, reg); -} - -void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 val, u32 mask) -{ - void __iomem *reg = hdmi_phy->regs + offset; - u32 tmp; - - tmp = readl(reg); - tmp = (tmp & ~mask) | (val & mask); - writel(tmp, reg); -} - inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) { return container_of(hw, struct mtk_hdmi_phy, pll_hw); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h index dcf9bb13699b..c7fa65cff989 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.h +++ b/drivers/phy/mediatek/phy-mtk-hdmi.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -42,12 +41,6 @@ struct mtk_hdmi_phy { unsigned int ibias_up; }; -void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits); -void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 bits); -void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, - u32 val, u32 mask); struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; diff --git a/drivers/phy/mediatek/phy-mtk-io.h b/drivers/phy/mediatek/phy-mtk-io.h index 500fcdab165d..d20ad5e5be81 100644 --- a/drivers/phy/mediatek/phy-mtk-io.h +++ b/drivers/phy/mediatek/phy-mtk-io.h @@ -8,6 +8,7 @@ #ifndef __PHY_MTK_H__ #define __PHY_MTK_H__ +#include #include static inline void mtk_phy_clear_bits(void __iomem *reg, u32 bits) @@ -35,4 +36,11 @@ static inline void mtk_phy_update_bits(void __iomem *reg, u32 mask, u32 val) writel(tmp, reg); } +/* field @mask shall be constant and continuous */ +#define mtk_phy_update_field(reg, mask, val) \ +({ \ + typeof(mask) mask_ = (mask); \ + mtk_phy_update_bits(reg, mask_, FIELD_PREP(mask_, val)); \ +}) + #endif diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c index 7a847954594f..673cb0f08959 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8173.c @@ -4,14 +4,15 @@ * Author: jitao.shi */ +#include "phy-mtk-io.h" #include "phy-mtk-mipi-dsi.h" #define MIPITX_DSI_CON 0x00 #define RG_DSI_LDOCORE_EN BIT(0) #define RG_DSI_CKG_LDOOUT_EN BIT(1) -#define RG_DSI_BCLK_SEL (3 << 2) -#define RG_DSI_LD_IDX_SEL (7 << 4) -#define RG_DSI_PHYCLK_SEL (2 << 8) +#define RG_DSI_BCLK_SEL GENMASK(3, 2) +#define RG_DSI_LD_IDX_SEL GENMASK(6, 4) +#define RG_DSI_PHYCLK_SEL GENMASK(9, 8) #define RG_DSI_DSICLK_FREQ_SEL BIT(10) #define RG_DSI_LPTX_CLMP_EN BIT(11) @@ -27,41 +28,46 @@ #define RG_DSI_LNTx_LPTX_IMINUS BIT(4) #define RG_DSI_LNTx_LPCD_IPLUS BIT(5) #define RG_DSI_LNTx_LPCD_IMINUS BIT(6) -#define RG_DSI_LNTx_RT_CODE (0xf << 8) +#define RG_DSI_LNTx_RT_CODE GENMASK(11, 8) #define MIPITX_DSI_TOP_CON 0x40 #define RG_DSI_LNT_INTR_EN BIT(0) #define RG_DSI_LNT_HS_BIAS_EN BIT(1) #define RG_DSI_LNT_IMP_CAL_EN BIT(2) #define RG_DSI_LNT_TESTMODE_EN BIT(3) -#define RG_DSI_LNT_IMP_CAL_CODE (0xf << 4) -#define RG_DSI_LNT_AIO_SEL (7 << 8) +#define RG_DSI_LNT_IMP_CAL_CODE GENMASK(7, 4) +#define RG_DSI_LNT_AIO_SEL GENMASK(10, 8) #define RG_DSI_PAD_TIE_LOW_EN BIT(11) #define RG_DSI_DEBUG_INPUT_EN BIT(12) -#define RG_DSI_PRESERVE (7 << 13) +#define RG_DSI_PRESERVE GENMASK(15, 13) #define MIPITX_DSI_BG_CON 0x44 #define RG_DSI_BG_CORE_EN BIT(0) #define RG_DSI_BG_CKEN BIT(1) -#define RG_DSI_BG_DIV (0x3 << 2) +#define RG_DSI_BG_DIV GENMASK(3, 2) #define RG_DSI_BG_FAST_CHARGE BIT(4) -#define RG_DSI_VOUT_MSK (0x3ffff << 5) -#define RG_DSI_V12_SEL (7 << 5) -#define RG_DSI_V10_SEL (7 << 8) -#define RG_DSI_V072_SEL (7 << 11) -#define RG_DSI_V04_SEL (7 << 14) -#define RG_DSI_V032_SEL (7 << 17) -#define RG_DSI_V02_SEL (7 << 20) -#define RG_DSI_BG_R1_TRIM (0xf << 24) -#define RG_DSI_BG_R2_TRIM (0xf << 28) + +#define RG_DSI_V12_SEL GENMASK(7, 5) +#define RG_DSI_V10_SEL GENMASK(10, 8) +#define RG_DSI_V072_SEL GENMASK(13, 11) +#define RG_DSI_V04_SEL GENMASK(16, 14) +#define RG_DSI_V032_SEL GENMASK(19, 17) +#define RG_DSI_V02_SEL GENMASK(22, 20) +#define RG_DSI_VOUT_MSK \ + (RG_DSI_V12_SEL | RG_DSI_V10_SEL | RG_DSI_V072_SEL | \ + RG_DSI_V04_SEL | RG_DSI_V032_SEL | RG_DSI_V02_SEL) +#define RG_DSI_BG_R1_TRIM GENMASK(27, 24) +#define RG_DSI_BG_R2_TRIM GENMASK(31, 28) #define MIPITX_DSI_PLL_CON0 0x50 #define RG_DSI_MPPLL_PLL_EN BIT(0) -#define RG_DSI_MPPLL_DIV_MSK (0x1ff << 1) -#define RG_DSI_MPPLL_PREDIV (3 << 1) -#define RG_DSI_MPPLL_TXDIV0 (3 << 3) -#define RG_DSI_MPPLL_TXDIV1 (3 << 5) -#define RG_DSI_MPPLL_POSDIV (7 << 7) +#define RG_DSI_MPPLL_PREDIV GENMASK(2, 1) +#define RG_DSI_MPPLL_TXDIV0 GENMASK(4, 3) +#define RG_DSI_MPPLL_TXDIV1 GENMASK(6, 5) +#define RG_DSI_MPPLL_POSDIV GENMASK(9, 7) +#define RG_DSI_MPPLL_DIV_MSK \ + (RG_DSI_MPPLL_PREDIV | RG_DSI_MPPLL_TXDIV0 | \ + RG_DSI_MPPLL_TXDIV1 | RG_DSI_MPPLL_POSDIV) #define RG_DSI_MPPLL_MONVC_EN BIT(10) #define RG_DSI_MPPLL_MONREF_EN BIT(11) #define RG_DSI_MPPLL_VOD_EN BIT(12) @@ -70,12 +76,12 @@ #define RG_DSI_MPPLL_SDM_FRA_EN BIT(0) #define RG_DSI_MPPLL_SDM_SSC_PH_INIT BIT(1) #define RG_DSI_MPPLL_SDM_SSC_EN BIT(2) -#define RG_DSI_MPPLL_SDM_SSC_PRD (0xffff << 16) +#define RG_DSI_MPPLL_SDM_SSC_PRD GENMASK(31, 16) #define MIPITX_DSI_PLL_CON2 0x58 #define MIPITX_DSI_PLL_TOP 0x64 -#define RG_DSI_MPPLL_PRESERVE (0xff << 8) +#define RG_DSI_MPPLL_PRESERVE GENMASK(15, 8) #define MIPITX_DSI_PLL_PWR 0x68 #define RG_DSI_MPPLL_SDM_PWR_ON BIT(0) @@ -116,6 +122,7 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) { struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); + void __iomem *base = mipi_tx->regs; u8 txdiv, txdiv0, txdiv1; u64 pcw; @@ -145,34 +152,38 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) return -EINVAL; } - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON, - RG_DSI_VOUT_MSK | - RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN, - (4 << 20) | (4 << 17) | (4 << 14) | - (4 << 11) | (4 << 8) | (4 << 5) | - RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); + mtk_phy_update_bits(base + MIPITX_DSI_BG_CON, + RG_DSI_VOUT_MSK | RG_DSI_BG_CKEN | + RG_DSI_BG_CORE_EN, + FIELD_PREP(RG_DSI_V02_SEL, 4) | + FIELD_PREP(RG_DSI_V032_SEL, 4) | + FIELD_PREP(RG_DSI_V04_SEL, 4) | + FIELD_PREP(RG_DSI_V072_SEL, 4) | + FIELD_PREP(RG_DSI_V10_SEL, 4) | + FIELD_PREP(RG_DSI_V12_SEL, 4) | + RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); usleep_range(30, 100); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON, - RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN, - (8 << 4) | RG_DSI_LNT_HS_BIAS_EN); + mtk_phy_update_bits(base + MIPITX_DSI_TOP_CON, + RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN, + FIELD_PREP(RG_DSI_LNT_IMP_CAL_CODE, 8) | + RG_DSI_LNT_HS_BIAS_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON, - RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); + mtk_phy_set_bits(base + MIPITX_DSI_CON, + RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR, - RG_DSI_MPPLL_SDM_PWR_ON | - RG_DSI_MPPLL_SDM_ISO_EN, - RG_DSI_MPPLL_SDM_PWR_ON); + mtk_phy_update_bits(base + MIPITX_DSI_PLL_PWR, + RG_DSI_MPPLL_SDM_PWR_ON | RG_DSI_MPPLL_SDM_ISO_EN, + RG_DSI_MPPLL_SDM_PWR_ON); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, - RG_DSI_MPPLL_PLL_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0, - RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 | - RG_DSI_MPPLL_PREDIV, - (txdiv0 << 3) | (txdiv1 << 5)); + mtk_phy_update_bits(base + MIPITX_DSI_PLL_CON0, + RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 | + RG_DSI_MPPLL_PREDIV, + FIELD_PREP(RG_DSI_MPPLL_TXDIV0, txdiv0) | + FIELD_PREP(RG_DSI_MPPLL_TXDIV1, txdiv1)); /* * PLL PCW config @@ -182,23 +193,20 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) * Post DIV =4, so need data_Rate*4 * Ref_clk is 26MHz */ - pcw = div_u64(((u64)mipi_tx->data_rate * 2 * txdiv) << 24, - 26000000); - writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2); + pcw = div_u64(((u64)mipi_tx->data_rate * 2 * txdiv) << 24, 26000000); + writel(pcw, base + MIPITX_DSI_PLL_CON2); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1, - RG_DSI_MPPLL_SDM_FRA_EN); + mtk_phy_set_bits(base + MIPITX_DSI_PLL_CON1, RG_DSI_MPPLL_SDM_FRA_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN); + mtk_phy_set_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN); usleep_range(20, 100); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1, - RG_DSI_MPPLL_SDM_SSC_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON1, RG_DSI_MPPLL_SDM_SSC_EN); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP, - RG_DSI_MPPLL_PRESERVE, - mipi_tx->driver_data->mppll_preserve); + mtk_phy_update_field(base + MIPITX_DSI_PLL_TOP, + RG_DSI_MPPLL_PRESERVE, + mipi_tx->driver_data->mppll_preserve); return 0; } @@ -206,31 +214,27 @@ static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw) { struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); + void __iomem *base = mipi_tx->regs; dev_dbg(mipi_tx->dev, "unprepare\n"); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, - RG_DSI_MPPLL_PLL_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_TOP, - RG_DSI_MPPLL_PRESERVE, 0); + mtk_phy_clear_bits(base + MIPITX_DSI_PLL_TOP, RG_DSI_MPPLL_PRESERVE); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR, - RG_DSI_MPPLL_SDM_ISO_EN | - RG_DSI_MPPLL_SDM_PWR_ON, - RG_DSI_MPPLL_SDM_ISO_EN); + mtk_phy_update_bits(base + MIPITX_DSI_PLL_PWR, + RG_DSI_MPPLL_SDM_ISO_EN | RG_DSI_MPPLL_SDM_PWR_ON, + RG_DSI_MPPLL_SDM_ISO_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_TOP_CON, - RG_DSI_LNT_HS_BIAS_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_TOP_CON, RG_DSI_LNT_HS_BIAS_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_CON, - RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_CON, + RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_BG_CON, - RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); + mtk_phy_clear_bits(base + MIPITX_DSI_BG_CON, + RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, - RG_DSI_MPPLL_DIV_MSK); + mtk_phy_clear_bits(base + MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_DIV_MSK); } static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -254,10 +258,10 @@ static void mtk_mipi_tx_power_on_signal(struct phy *phy) for (reg = MIPITX_DSI_CLOCK_LANE; reg <= MIPITX_DSI_DATA_LANE3; reg += 4) - mtk_mipi_tx_set_bits(mipi_tx, reg, RG_DSI_LNTx_LDOOUT_EN); + mtk_phy_set_bits(mipi_tx->regs + reg, RG_DSI_LNTx_LDOOUT_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_TOP_CON, - RG_DSI_PAD_TIE_LOW_EN); + mtk_phy_clear_bits(mipi_tx->regs + MIPITX_DSI_TOP_CON, + RG_DSI_PAD_TIE_LOW_EN); } static void mtk_mipi_tx_power_off_signal(struct phy *phy) @@ -265,23 +269,23 @@ static void mtk_mipi_tx_power_off_signal(struct phy *phy) struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); u32 reg; - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON, - RG_DSI_PAD_TIE_LOW_EN); + mtk_phy_set_bits(mipi_tx->regs + MIPITX_DSI_TOP_CON, + RG_DSI_PAD_TIE_LOW_EN); for (reg = MIPITX_DSI_CLOCK_LANE; reg <= MIPITX_DSI_DATA_LANE3; reg += 4) - mtk_mipi_tx_clear_bits(mipi_tx, reg, RG_DSI_LNTx_LDOOUT_EN); + mtk_phy_clear_bits(mipi_tx->regs + reg, RG_DSI_LNTx_LDOOUT_EN); } const struct mtk_mipitx_data mt2701_mipitx_data = { - .mppll_preserve = (3 << 8), + .mppll_preserve = 3, .mipi_tx_clk_ops = &mtk_mipi_tx_pll_ops, .mipi_tx_enable_signal = mtk_mipi_tx_power_on_signal, .mipi_tx_disable_signal = mtk_mipi_tx_power_off_signal, }; const struct mtk_mipitx_data mt8173_mipitx_data = { - .mppll_preserve = (0 << 8), + .mppll_preserve = 0, .mipi_tx_clk_ops = &mtk_mipi_tx_pll_ops, .mipi_tx_enable_signal = mtk_mipi_tx_power_on_signal, .mipi_tx_disable_signal = mtk_mipi_tx_power_off_signal, diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c index 99108426d57c..f021ec5a70e5 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi-mt8183.c @@ -4,6 +4,7 @@ * Author: jitao.shi */ +#include "phy-mtk-io.h" #include "phy-mtk-mipi-dsi.h" #define MIPITX_LANE_CON 0x000c @@ -18,7 +19,7 @@ #define RG_DSI_PAD_TIEL_SEL BIT(8) #define MIPITX_VOLTAGE_SEL 0x0010 -#define RG_DSI_HSTX_LDO_REF_SEL (0xf << 6) +#define RG_DSI_HSTX_LDO_REF_SEL GENMASK(9, 6) #define MIPITX_PLL_PWR 0x0028 #define MIPITX_PLL_CON0 0x002c @@ -26,7 +27,7 @@ #define MIPITX_PLL_CON2 0x0034 #define MIPITX_PLL_CON3 0x0038 #define MIPITX_PLL_CON4 0x003c -#define RG_DSI_PLL_IBIAS (3 << 10) +#define RG_DSI_PLL_IBIAS GENMASK(11, 10) #define MIPITX_D2P_RTCODE 0x0100 #define MIPITX_D2_SW_CTL_EN 0x0144 @@ -41,11 +42,12 @@ #define AD_DSI_PLL_SDM_ISO_EN BIT(1) #define RG_DSI_PLL_EN BIT(4) -#define RG_DSI_PLL_POSDIV (0x7 << 8) +#define RG_DSI_PLL_POSDIV GENMASK(10, 8) static int mtk_mipi_tx_pll_enable(struct clk_hw *hw) { struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); + void __iomem *base = mipi_tx->regs; unsigned int txdiv, txdiv0; u64 pcw; @@ -70,17 +72,16 @@ static int mtk_mipi_tx_pll_enable(struct clk_hw *hw) return -EINVAL; } - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_PLL_CON4, RG_DSI_PLL_IBIAS); + mtk_phy_clear_bits(base + MIPITX_PLL_CON4, RG_DSI_PLL_IBIAS); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_PLL_CON1, RG_DSI_PLL_EN); + mtk_phy_set_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON); + mtk_phy_clear_bits(base + MIPITX_PLL_CON1, RG_DSI_PLL_EN); udelay(1); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_PLL_PWR, AD_DSI_PLL_SDM_ISO_EN); + mtk_phy_clear_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_ISO_EN); pcw = div_u64(((u64)mipi_tx->data_rate * txdiv) << 24, 26000000); - writel(pcw, mipi_tx->regs + MIPITX_PLL_CON0); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_PLL_CON1, RG_DSI_PLL_POSDIV, - txdiv0 << 8); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_PLL_CON1, RG_DSI_PLL_EN); + writel(pcw, base + MIPITX_PLL_CON0); + mtk_phy_update_field(base + MIPITX_PLL_CON1, RG_DSI_PLL_POSDIV, txdiv0); + mtk_phy_set_bits(base + MIPITX_PLL_CON1, RG_DSI_PLL_EN); return 0; } @@ -88,11 +89,12 @@ static int mtk_mipi_tx_pll_enable(struct clk_hw *hw) static void mtk_mipi_tx_pll_disable(struct clk_hw *hw) { struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); + void __iomem *base = mipi_tx->regs; - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_PLL_CON1, RG_DSI_PLL_EN); + mtk_phy_clear_bits(base + MIPITX_PLL_CON1, RG_DSI_PLL_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_PLL_PWR, AD_DSI_PLL_SDM_ISO_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON); + mtk_phy_set_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_ISO_EN); + mtk_phy_clear_bits(base + MIPITX_PLL_PWR, AD_DSI_PLL_SDM_PWR_ON); } static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -121,7 +123,7 @@ static void mtk_mipi_tx_config_calibration_data(struct mtk_mipi_tx *mipi_tx) mipi_tx->rt_code[i] |= 0x10 << 5; for (j = 0; j < 10; j++) - mtk_mipi_tx_update_bits(mipi_tx, + mtk_phy_update_bits(mipi_tx->regs + MIPITX_D2P_RTCODE * (i + 1) + j * 4, 1, mipi_tx->rt_code[i] >> j & 1); } @@ -130,44 +132,42 @@ static void mtk_mipi_tx_config_calibration_data(struct mtk_mipi_tx *mipi_tx) static void mtk_mipi_tx_power_on_signal(struct phy *phy) { struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); + void __iomem *base = mipi_tx->regs; /* BG_LPF_EN / BG_CORE_EN */ - writel(RG_DSI_PAD_TIEL_SEL | RG_DSI_BG_CORE_EN, - mipi_tx->regs + MIPITX_LANE_CON); + writel(RG_DSI_PAD_TIEL_SEL | RG_DSI_BG_CORE_EN, base + MIPITX_LANE_CON); usleep_range(30, 100); - writel(RG_DSI_BG_CORE_EN | RG_DSI_BG_LPF_EN, - mipi_tx->regs + MIPITX_LANE_CON); + writel(RG_DSI_BG_CORE_EN | RG_DSI_BG_LPF_EN, base + MIPITX_LANE_CON); /* Switch OFF each Lane */ - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_D0_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_D1_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_D2_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_D3_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_CK_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_clear_bits(base + MIPITX_D0_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_clear_bits(base + MIPITX_D1_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_clear_bits(base + MIPITX_D2_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_clear_bits(base + MIPITX_D3_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_clear_bits(base + MIPITX_CK_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_update_bits(mipi_tx, MIPITX_VOLTAGE_SEL, - RG_DSI_HSTX_LDO_REF_SEL, - (mipi_tx->mipitx_drive - 3000) / 200 << 6); + mtk_phy_update_field(base + MIPITX_VOLTAGE_SEL, RG_DSI_HSTX_LDO_REF_SEL, + (mipi_tx->mipitx_drive - 3000) / 200); mtk_mipi_tx_config_calibration_data(mipi_tx); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_CK_CKMODE_EN, DSI_CK_CKMODE_EN); + mtk_phy_set_bits(base + MIPITX_CK_CKMODE_EN, DSI_CK_CKMODE_EN); } static void mtk_mipi_tx_power_off_signal(struct phy *phy) { struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); + void __iomem *base = mipi_tx->regs; /* Switch ON each Lane */ - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_D0_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_D1_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_D2_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_D3_SW_CTL_EN, DSI_SW_CTL_EN); - mtk_mipi_tx_set_bits(mipi_tx, MIPITX_CK_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_set_bits(base + MIPITX_D0_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_set_bits(base + MIPITX_D1_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_set_bits(base + MIPITX_D2_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_set_bits(base + MIPITX_D3_SW_CTL_EN, DSI_SW_CTL_EN); + mtk_phy_set_bits(base + MIPITX_CK_SW_CTL_EN, DSI_SW_CTL_EN); - writel(RG_DSI_PAD_TIEL_SEL | RG_DSI_BG_CORE_EN, - mipi_tx->regs + MIPITX_LANE_CON); - writel(RG_DSI_PAD_TIEL_SEL, mipi_tx->regs + MIPITX_LANE_CON); + writel(RG_DSI_PAD_TIEL_SEL | RG_DSI_BG_CORE_EN, base + MIPITX_LANE_CON); + writel(RG_DSI_PAD_TIEL_SEL, base + MIPITX_LANE_CON); } const struct mtk_mipitx_data mt8183_mipitx_data = { diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 28506932bd91..cf9c386385bb 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -10,30 +10,6 @@ inline struct mtk_mipi_tx *mtk_mipi_tx_from_clk_hw(struct clk_hw *hw) return container_of(hw, struct mtk_mipi_tx, pll_hw); } -void mtk_mipi_tx_clear_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, - u32 bits) -{ - u32 temp = readl(mipi_tx->regs + offset); - - writel(temp & ~bits, mipi_tx->regs + offset); -} - -void mtk_mipi_tx_set_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, - u32 bits) -{ - u32 temp = readl(mipi_tx->regs + offset); - - writel(temp | bits, mipi_tx->regs + offset); -} - -void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, - u32 mask, u32 data) -{ - u32 temp = readl(mipi_tx->regs + offset); - - writel((temp & ~mask) | (data & mask), mipi_tx->regs + offset); -} - int mtk_mipi_tx_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h index c76f07c3fdeb..47b60b1a7226 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -37,10 +36,6 @@ struct mtk_mipi_tx { }; struct mtk_mipi_tx *mtk_mipi_tx_from_clk_hw(struct clk_hw *hw); -void mtk_mipi_tx_clear_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, u32 bits); -void mtk_mipi_tx_set_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, u32 bits); -void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, u32 mask, - u32 data); int mtk_mipi_tx_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); unsigned long mtk_mipi_tx_pll_recalc_rate(struct clk_hw *hw, diff --git a/drivers/phy/mediatek/phy-mtk-pcie.c b/drivers/phy/mediatek/phy-mtk-pcie.c index 7f29d43442bf..25dbd6e35722 100644 --- a/drivers/phy/mediatek/phy-mtk-pcie.c +++ b/drivers/phy/mediatek/phy-mtk-pcie.c @@ -89,14 +89,14 @@ static void mtk_pcie_efuse_set_lane(struct mtk_pcie_phy *pcie_phy, addr = pcie_phy->sif_base + PEXTP_ANA_LN0_TRX_REG + lane * PEXTP_ANA_LANE_OFFSET; - mtk_phy_update_bits(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_PMOS_SEL, - FIELD_PREP(EFUSE_LN_TX_PMOS_SEL, data->tx_pmos)); + mtk_phy_update_field(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_PMOS_SEL, + data->tx_pmos); - mtk_phy_update_bits(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_NMOS_SEL, - FIELD_PREP(EFUSE_LN_TX_NMOS_SEL, data->tx_nmos)); + mtk_phy_update_field(addr + PEXTP_ANA_TX_REG, EFUSE_LN_TX_NMOS_SEL, + data->tx_nmos); - mtk_phy_update_bits(addr + PEXTP_ANA_RX_REG, EFUSE_LN_RX_SEL, - FIELD_PREP(EFUSE_LN_RX_SEL, data->rx_data)); + mtk_phy_update_field(addr + PEXTP_ANA_RX_REG, EFUSE_LN_RX_SEL, + data->rx_data); } /** @@ -116,9 +116,8 @@ static int mtk_pcie_phy_init(struct phy *phy) return 0; /* Set global data */ - mtk_phy_update_bits(pcie_phy->sif_base + PEXTP_ANA_GLB_00_REG, - EFUSE_GLB_INTR_SEL, - FIELD_PREP(EFUSE_GLB_INTR_SEL, pcie_phy->efuse_glb_intr)); + mtk_phy_update_field(pcie_phy->sif_base + PEXTP_ANA_GLB_00_REG, + EFUSE_GLB_INTR_SEL, pcie_phy->efuse_glb_intr); for (i = 0; i < pcie_phy->data->num_lanes; i++) mtk_pcie_efuse_set_lane(pcie_phy, i); diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 8ee7682b8e93..e906a82791bd 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -49,35 +49,28 @@ #define U3P_USBPHYACR0 0x000 #define PA0_RG_U2PLL_FORCE_ON BIT(15) #define PA0_USB20_PLL_PREDIV GENMASK(7, 6) -#define PA0_USB20_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) #define PA0_RG_USB20_INTR_EN BIT(5) #define U3P_USBPHYACR1 0x004 #define PA1_RG_INTR_CAL GENMASK(23, 19) -#define PA1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19) #define PA1_RG_VRT_SEL GENMASK(14, 12) -#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12) #define PA1_RG_TERM_SEL GENMASK(10, 8) -#define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8) #define U3P_USBPHYACR2 0x008 #define PA2_RG_U2PLL_BW GENMASK(21, 19) -#define PA2_RG_U2PLL_BW_VAL(x) ((0x7 & (x)) << 19) #define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18) #define U3P_USBPHYACR5 0x014 #define PA5_RG_U2_HSTX_SRCAL_EN BIT(15) #define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12) -#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) #define PA5_RG_U2_HS_100U_U3_EN BIT(11) #define U3P_USBPHYACR6 0x018 +#define PA6_RG_U2_PRE_EMP GENMASK(31, 30) #define PA6_RG_U2_BC11_SW_EN BIT(23) #define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20) #define PA6_RG_U2_DISCTH GENMASK(7, 4) -#define PA6_RG_U2_DISCTH_VAL(x) ((0xf & (x)) << 4) #define PA6_RG_U2_SQTH GENMASK(3, 0) -#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x)) #define U3P_U2PHYACR4 0x020 #define P2C_RG_USB20_GPIO_CTL BIT(9) @@ -104,11 +97,9 @@ #define P2C_FORCE_SUSPENDM BIT(18) #define P2C_FORCE_TERMSEL BIT(17) #define P2C_RG_DATAIN GENMASK(13, 10) -#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10) #define P2C_RG_DMPULLDOWN BIT(7) #define P2C_RG_DPPULLDOWN BIT(6) #define P2C_RG_XCVRSEL GENMASK(5, 4) -#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4) #define P2C_RG_SUSPENDM BIT(3) #define P2C_RG_TERMSEL BIT(2) #define P2C_DTM0_PART_MASK \ @@ -139,87 +130,65 @@ #define U3P_U3_PHYA_REG0 0x000 #define P3A_RG_IEXT_INTR GENMASK(15, 10) -#define P3A_RG_IEXT_INTR_VAL(x) ((0x3f & (x)) << 10) #define P3A_RG_CLKDRV_OFF GENMASK(3, 2) -#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2) #define U3P_U3_PHYA_REG1 0x004 #define P3A_RG_CLKDRV_AMP GENMASK(31, 29) -#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29) #define U3P_U3_PHYA_REG6 0x018 #define P3A_RG_TX_EIDLE_CM GENMASK(31, 28) -#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28) #define U3P_U3_PHYA_REG9 0x024 #define P3A_RG_RX_DAC_MUX GENMASK(5, 1) -#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1) #define U3P_U3_PHYA_DA_REG0 0x100 #define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16) -#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16) #define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12) -#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12) #define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10) -#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10) #define U3P_U3_PHYA_DA_REG4 0x108 #define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19) #define P3A_RG_PLL_BC_PE2H GENMASK(7, 6) -#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6) #define U3P_U3_PHYA_DA_REG5 0x10c #define P3A_RG_PLL_BR_PE2H GENMASK(29, 28) -#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28) #define P3A_RG_PLL_IC_PE2H GENMASK(15, 12) -#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12) #define U3P_U3_PHYA_DA_REG6 0x110 #define P3A_RG_PLL_IR_PE2H GENMASK(19, 16) -#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16) #define U3P_U3_PHYA_DA_REG7 0x114 #define P3A_RG_PLL_BP_PE2H GENMASK(19, 16) -#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16) #define U3P_U3_PHYA_DA_REG20 0x13c #define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16) -#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16) #define U3P_U3_PHYA_DA_REG25 0x148 #define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0) -#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x)) #define U3P_U3_PHYD_LFPS1 0x00c #define P3D_RG_FWAKE_TH GENMASK(21, 16) -#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16) #define U3P_U3_PHYD_IMPCAL0 0x010 #define P3D_RG_FORCE_TX_IMPEL BIT(31) #define P3D_RG_TX_IMPEL GENMASK(28, 24) -#define P3D_RG_TX_IMPEL_VAL(x) ((0x1f & (x)) << 24) #define U3P_U3_PHYD_IMPCAL1 0x014 #define P3D_RG_FORCE_RX_IMPEL BIT(31) #define P3D_RG_RX_IMPEL GENMASK(28, 24) -#define P3D_RG_RX_IMPEL_VAL(x) ((0x1f & (x)) << 24) #define U3P_U3_PHYD_RSV 0x054 #define P3D_RG_EFUSE_AUTO_LOAD_DIS BIT(12) #define U3P_U3_PHYD_CDR1 0x05c #define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24) -#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24) #define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8) -#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8) #define U3P_U3_PHYD_RXDET1 0x128 #define P3D_RG_RXDET_STB2_SET GENMASK(17, 9) -#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9) #define U3P_U3_PHYD_RXDET2 0x12c #define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0) -#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x)) #define U3P_SPLLC_XTALCTL3 0x018 #define XC3_RG_U3_XTAL_RX_PWD BIT(9) @@ -227,10 +196,8 @@ #define U3P_U2FREQ_FMCR0 0x00 #define P2F_RG_MONCLK_SEL GENMASK(27, 26) -#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26) #define P2F_RG_FREQDET_EN BIT(24) #define P2F_RG_CYCLECNT GENMASK(23, 0) -#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x)) #define U3P_U2FREQ_VALUE 0x0c @@ -247,60 +214,45 @@ #define PHYD_CTRL_SIGNAL_MODE4 0x1c /* CDR Charge Pump P-path current adjustment */ #define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20) -#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20) #define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8) -#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8) #define PHYD_DESIGN_OPTION2 0x24 /* Symbol lock count selection */ #define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4) -#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4) #define PHYD_DESIGN_OPTION9 0x40 /* COMWAK GAP width window */ #define RG_TG_MAX_MSK GENMASK(20, 16) -#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16) /* COMINIT GAP width window */ #define RG_T2_MAX_MSK GENMASK(13, 8) -#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8) /* COMWAK GAP width window */ #define RG_TG_MIN_MSK GENMASK(7, 5) -#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5) /* COMINIT GAP width window */ #define RG_T2_MIN_MSK GENMASK(4, 0) -#define RG_T2_MIN_VAL(x) (0x1f & (x)) #define ANA_RG_CTRL_SIGNAL1 0x4c /* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */ #define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8) -#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8) #define ANA_RG_CTRL_SIGNAL4 0x58 #define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20) -#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20) /* Loop filter R1 resistance adjustment for Gen1 speed */ #define RG_CDR_BR_GEN2_MSK GENMASK(10, 8) -#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8) #define ANA_RG_CTRL_SIGNAL6 0x60 /* I-path capacitance adjustment for Gen1 */ #define RG_CDR_BC_GEN1_MSK GENMASK(28, 24) -#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24) #define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0) -#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x)) #define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c /* RX Gen1 LEQ tuning step */ #define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8) -#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8) #define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8 #define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16) -#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16) #define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) -#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) /* PHY switch between pcie/usb3/sgmii/sata */ #define USB_PHY_SWITCH_CTRL 0x0 @@ -370,6 +322,7 @@ struct mtk_phy_instance { int eye_term; int intr; int discth; + int pre_emphasis; bool bc12_en; }; @@ -411,9 +364,9 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, /* set cycle count as 1024, and select u2 channel */ tmp = readl(fmreg + U3P_U2FREQ_FMCR0); tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL); - tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT); + tmp |= FIELD_PREP(P2F_RG_CYCLECNT, U3P_FM_DET_CYCLE_CNT); if (tphy->pdata->version == MTK_PHY_V1) - tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1); + tmp |= FIELD_PREP(P2F_RG_MONCLK_SEL, instance->index >> 1); writel(tmp, fmreg + U3P_U2FREQ_FMCR0); @@ -446,8 +399,8 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, tphy->src_ref_clk, tphy->src_coef); /* set HS slew rate */ - mtk_phy_update_bits(com + U3P_USBPHYACR5, PA5_RG_U2_HSTX_SRCTRL, - PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val)); + mtk_phy_update_field(com + U3P_USBPHYACR5, PA5_RG_U2_HSTX_SRCTRL, + calibration_val); /* disable USB ring oscillator */ mtk_phy_clear_bits(com + U3P_USBPHYACR5, PA5_RG_U2_HSTX_SRCAL_EN); @@ -457,33 +410,30 @@ static void u3_phy_instance_init(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) { struct u3phy_banks *u3_banks = &instance->u3_banks; + void __iomem *phya = u3_banks->phya; + void __iomem *phyd = u3_banks->phyd; /* gating PCIe Analog XTAL clock */ mtk_phy_set_bits(u3_banks->spllc + U3P_SPLLC_XTALCTL3, XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD); /* gating XSQ */ - mtk_phy_update_bits(u3_banks->phya + U3P_U3_PHYA_DA_REG0, - P3A_RG_XTAL_EXT_EN_U3, P3A_RG_XTAL_EXT_EN_U3_VAL(2)); + mtk_phy_update_field(phya + U3P_U3_PHYA_DA_REG0, P3A_RG_XTAL_EXT_EN_U3, 2); - mtk_phy_update_bits(u3_banks->phya + U3P_U3_PHYA_REG9, - P3A_RG_RX_DAC_MUX, P3A_RG_RX_DAC_MUX_VAL(4)); + mtk_phy_update_field(phya + U3P_U3_PHYA_REG9, P3A_RG_RX_DAC_MUX, 4); - mtk_phy_update_bits(u3_banks->phya + U3P_U3_PHYA_REG6, - P3A_RG_TX_EIDLE_CM, P3A_RG_TX_EIDLE_CM_VAL(0xe)); + mtk_phy_update_field(phya + U3P_U3_PHYA_REG6, P3A_RG_TX_EIDLE_CM, 0xe); mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_CDR1, P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1, - P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3)); + FIELD_PREP(P3D_RG_CDR_BIR_LTD0, 0xc) | + FIELD_PREP(P3D_RG_CDR_BIR_LTD1, 0x3)); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_LFPS1, - P3D_RG_FWAKE_TH, P3D_RG_FWAKE_TH_VAL(0x34)); + mtk_phy_update_field(phyd + U3P_U3_PHYD_LFPS1, P3D_RG_FWAKE_TH, 0x34); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_RXDET1, - P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10)); + mtk_phy_update_field(phyd + U3P_U3_PHYD_RXDET1, P3D_RG_RXDET_STB2_SET, 0x10); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_RXDET2, - P3D_RG_RXDET_STB2_SET_P3, P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); + mtk_phy_update_field(phyd + U3P_U3_PHYD_RXDET2, P3D_RG_RXDET_STB2_SET_P3, 0x10); dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } @@ -497,11 +447,9 @@ static void u2_phy_pll_26m_set(struct mtk_tphy *tphy, if (!tphy->pdata->sw_pll_48m_to_26m) return; - mtk_phy_update_bits(com + U3P_USBPHYACR0, PA0_USB20_PLL_PREDIV, - PA0_USB20_PLL_PREDIV_VAL(0)); + mtk_phy_update_field(com + U3P_USBPHYACR0, PA0_USB20_PLL_PREDIV, 0); - mtk_phy_update_bits(com + U3P_USBPHYACR2, PA2_RG_U2PLL_BW, - PA2_RG_U2PLL_BW_VAL(3)); + mtk_phy_update_field(com + U3P_USBPHYACR2, PA2_RG_U2PLL_BW, 3); writel(P2R_RG_U2PLL_FBDIV_26M, com + U3P_U2PHYA_RESV); @@ -519,8 +467,8 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, /* switch to USB function, and enable usb pll */ mtk_phy_clear_bits(com + U3P_U2PHYDTM0, P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM); - mtk_phy_update_bits(com + U3P_U2PHYDTM0, P2C_RG_XCVRSEL | P2C_RG_DATAIN, - P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0)); + mtk_phy_clear_bits(com + U3P_U2PHYDTM0, + P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK); mtk_phy_clear_bits(com + U3P_U2PHYDTM1, P2C_RG_UART_EN); @@ -529,8 +477,7 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, /* disable switch 100uA current to SSUSB */ mtk_phy_clear_bits(com + U3P_USBPHYACR5, PA5_RG_U2_HS_100U_U3_EN); - if (!index) - mtk_phy_clear_bits(com + U3P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK); + mtk_phy_clear_bits(com + U3P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK); if (tphy->pdata->avoid_rx_sen_degradation) { if (!index) { @@ -548,7 +495,7 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, /* DP/DM BC1.1 path Disable */ mtk_phy_clear_bits(com + U3P_USBPHYACR6, PA6_RG_U2_BC11_SW_EN); - mtk_phy_update_bits(com + U3P_USBPHYACR6, PA6_RG_U2_SQTH, PA6_RG_U2_SQTH_VAL(2)); + mtk_phy_update_field(com + U3P_USBPHYACR6, PA6_RG_U2_SQTH, 2); /* Workaround only for mt8195, HW fix it for others (V3) */ u2_phy_pll_26m_set(tphy, instance); @@ -563,9 +510,6 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy, void __iomem *com = u2_banks->com; u32 index = instance->index; - mtk_phy_clear_bits(com + U3P_U2PHYDTM0, - P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK); - /* OTG Enable */ mtk_phy_set_bits(com + U3P_USBPHYACR6, PA6_RG_U2_OTG_VBUSCMP_EN); @@ -588,8 +532,6 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy, void __iomem *com = u2_banks->com; u32 index = instance->index; - mtk_phy_clear_bits(com + U3P_U2PHYDTM0, P2C_RG_XCVRSEL | P2C_RG_DATAIN); - /* OTG Disable */ mtk_phy_clear_bits(com + U3P_USBPHYACR6, PA6_RG_U2_OTG_VBUSCMP_EN); @@ -656,43 +598,39 @@ static void pcie_phy_instance_init(struct mtk_tphy *tphy, mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG0, P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, - P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2)); + FIELD_PREP(P3A_RG_XTAL_EXT_PE1H, 0x2) | + FIELD_PREP(P3A_RG_XTAL_EXT_PE2H, 0x2)); /* ref clk drive */ - mtk_phy_update_bits(phya + U3P_U3_PHYA_REG1, P3A_RG_CLKDRV_AMP, - P3A_RG_CLKDRV_AMP_VAL(0x4)); + mtk_phy_update_field(phya + U3P_U3_PHYA_REG1, P3A_RG_CLKDRV_AMP, 0x4); - mtk_phy_update_bits(phya + U3P_U3_PHYA_REG0, P3A_RG_CLKDRV_OFF, - P3A_RG_CLKDRV_OFF_VAL(0x1)); + mtk_phy_update_field(phya + U3P_U3_PHYA_REG0, P3A_RG_CLKDRV_OFF, 0x1); /* SSC delta -5000ppm */ - mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG20, P3A_RG_PLL_DELTA1_PE2H, - P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c)); + mtk_phy_update_field(phya + U3P_U3_PHYA_DA_REG20, P3A_RG_PLL_DELTA1_PE2H, 0x3c); - mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG25, P3A_RG_PLL_DELTA_PE2H, - P3A_RG_PLL_DELTA_PE2H_VAL(0x36)); + mtk_phy_update_field(phya + U3P_U3_PHYA_DA_REG25, P3A_RG_PLL_DELTA_PE2H, 0x36); /* change pll BW 0.6M */ mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG5, P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H, - P3A_RG_PLL_BR_PE2H_VAL(0x1) | P3A_RG_PLL_IC_PE2H_VAL(0x1)); + FIELD_PREP(P3A_RG_PLL_BR_PE2H, 0x1) | + FIELD_PREP(P3A_RG_PLL_IC_PE2H, 0x1)); mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG4, P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H, - P3A_RG_PLL_BC_PE2H_VAL(0x3)); + FIELD_PREP(P3A_RG_PLL_BC_PE2H, 0x3)); - mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG6, P3A_RG_PLL_IR_PE2H, - P3A_RG_PLL_IR_PE2H_VAL(0x2)); + mtk_phy_update_field(phya + U3P_U3_PHYA_DA_REG6, P3A_RG_PLL_IR_PE2H, 0x2); - mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG7, P3A_RG_PLL_BP_PE2H, - P3A_RG_PLL_BP_PE2H_VAL(0xa)); + mtk_phy_update_field(phya + U3P_U3_PHYA_DA_REG7, P3A_RG_PLL_BP_PE2H, 0xa); /* Tx Detect Rx Timing: 10us -> 5us */ - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_RXDET1, - P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10)); + mtk_phy_update_field(u3_banks->phyd + U3P_U3_PHYD_RXDET1, + P3D_RG_RXDET_STB2_SET, 0x10); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_RXDET2, - P3D_RG_RXDET_STB2_SET_P3, P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); + mtk_phy_update_field(u3_banks->phyd + U3P_U3_PHYD_RXDET2, + P3D_RG_RXDET_STB2_SET_P3, 0x10); /* wait for PCIe subsys register to active */ usleep_range(2500, 3000); @@ -733,38 +671,38 @@ static void sata_phy_instance_init(struct mtk_tphy *tphy, /* charge current adjustment */ mtk_phy_update_bits(phyd + ANA_RG_CTRL_SIGNAL6, RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK, - RG_CDR_BIRLTR_GEN1_VAL(0x6) | RG_CDR_BC_GEN1_VAL(0x1a)); + FIELD_PREP(RG_CDR_BIRLTR_GEN1_MSK, 0x6) | + FIELD_PREP(RG_CDR_BC_GEN1_MSK, 0x1a)); - mtk_phy_update_bits(phyd + ANA_EQ_EYE_CTRL_SIGNAL4, RG_CDR_BIRLTD0_GEN1_MSK, - RG_CDR_BIRLTD0_GEN1_VAL(0x18)); + mtk_phy_update_field(phyd + ANA_EQ_EYE_CTRL_SIGNAL4, RG_CDR_BIRLTD0_GEN1_MSK, 0x18); - mtk_phy_update_bits(phyd + ANA_EQ_EYE_CTRL_SIGNAL5, RG_CDR_BIRLTD0_GEN3_MSK, - RG_CDR_BIRLTD0_GEN3_VAL(0x06)); + mtk_phy_update_field(phyd + ANA_EQ_EYE_CTRL_SIGNAL5, RG_CDR_BIRLTD0_GEN3_MSK, 0x06); mtk_phy_update_bits(phyd + ANA_RG_CTRL_SIGNAL4, RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK, - RG_CDR_BICLTR_GEN1_VAL(0x0c) | RG_CDR_BR_GEN2_VAL(0x07)); + FIELD_PREP(RG_CDR_BICLTR_GEN1_MSK, 0x0c) | + FIELD_PREP(RG_CDR_BR_GEN2_MSK, 0x07)); mtk_phy_update_bits(phyd + PHYD_CTRL_SIGNAL_MODE4, RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK, - RG_CDR_BICLTD0_GEN1_VAL(0x08) | RG_CDR_BICLTD1_GEN1_VAL(0x02)); + FIELD_PREP(RG_CDR_BICLTD0_GEN1_MSK, 0x08) | + FIELD_PREP(RG_CDR_BICLTD1_GEN1_MSK, 0x02)); - mtk_phy_update_bits(phyd + PHYD_DESIGN_OPTION2, RG_LOCK_CNT_SEL_MSK, - RG_LOCK_CNT_SEL_VAL(0x02)); + mtk_phy_update_field(phyd + PHYD_DESIGN_OPTION2, RG_LOCK_CNT_SEL_MSK, 0x02); mtk_phy_update_bits(phyd + PHYD_DESIGN_OPTION9, RG_T2_MIN_MSK | RG_TG_MIN_MSK, - RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04)); + FIELD_PREP(RG_T2_MIN_MSK, 0x12) | + FIELD_PREP(RG_TG_MIN_MSK, 0x04)); mtk_phy_update_bits(phyd + PHYD_DESIGN_OPTION9, RG_T2_MAX_MSK | RG_TG_MAX_MSK, - RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e)); + FIELD_PREP(RG_T2_MAX_MSK, 0x31) | + FIELD_PREP(RG_TG_MAX_MSK, 0x0e)); - mtk_phy_update_bits(phyd + ANA_RG_CTRL_SIGNAL1, RG_IDRV_0DB_GEN1_MSK, - RG_IDRV_0DB_GEN1_VAL(0x20)); + mtk_phy_update_field(phyd + ANA_RG_CTRL_SIGNAL1, RG_IDRV_0DB_GEN1_MSK, 0x20); - mtk_phy_update_bits(phyd + ANA_EQ_EYE_CTRL_SIGNAL1, RG_EQ_DLEQ_LFI_GEN1_MSK, - RG_EQ_DLEQ_LFI_GEN1_VAL(0x03)); + mtk_phy_update_field(phyd + ANA_EQ_EYE_CTRL_SIGNAL1, RG_EQ_DLEQ_LFI_GEN1_MSK, 0x03); dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } @@ -841,10 +779,13 @@ static void phy_parse_property(struct mtk_tphy *tphy, &instance->intr); device_property_read_u32(dev, "mediatek,discth", &instance->discth); + device_property_read_u32(dev, "mediatek,pre-emphasis", + &instance->pre_emphasis); dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d, intr:%d, disc:%d\n", instance->bc12_en, instance->eye_src, instance->eye_vrt, instance->eye_term, instance->intr, instance->discth); + dev_dbg(dev, "pre-emp:%d\n", instance->pre_emphasis); } static void u2_phy_props_set(struct mtk_tphy *tphy, @@ -857,24 +798,33 @@ static void u2_phy_props_set(struct mtk_tphy *tphy, mtk_phy_set_bits(com + U3P_U2PHYBC12C, P2C_RG_CHGDT_EN); if (tphy->pdata->version < MTK_PHY_V3 && instance->eye_src) - mtk_phy_update_bits(com + U3P_USBPHYACR5, PA5_RG_U2_HSTX_SRCTRL, - PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src)); + mtk_phy_update_field(com + U3P_USBPHYACR5, PA5_RG_U2_HSTX_SRCTRL, + instance->eye_src); if (instance->eye_vrt) - mtk_phy_update_bits(com + U3P_USBPHYACR1, PA1_RG_VRT_SEL, - PA1_RG_VRT_SEL_VAL(instance->eye_vrt)); + mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_VRT_SEL, + instance->eye_vrt); if (instance->eye_term) - mtk_phy_update_bits(com + U3P_USBPHYACR1, PA1_RG_TERM_SEL, - PA1_RG_TERM_SEL_VAL(instance->eye_term)); + mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_TERM_SEL, + instance->eye_term); - if (instance->intr) - mtk_phy_update_bits(com + U3P_USBPHYACR1, PA1_RG_INTR_CAL, - PA1_RG_INTR_CAL_VAL(instance->intr)); + if (instance->intr) { + if (u2_banks->misc) + mtk_phy_set_bits(u2_banks->misc + U3P_MISC_REG1, + MR1_EFUSE_AUTO_LOAD_DIS); + + mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_INTR_CAL, + instance->intr); + } if (instance->discth) - mtk_phy_update_bits(com + U3P_USBPHYACR6, PA6_RG_U2_DISCTH, - PA6_RG_U2_DISCTH_VAL(instance->discth)); + mtk_phy_update_field(com + U3P_USBPHYACR6, PA6_RG_U2_DISCTH, + instance->discth); + + if (instance->pre_emphasis) + mtk_phy_update_field(com + U3P_USBPHYACR6, PA6_RG_U2_PRE_EMP, + instance->pre_emphasis); } /* type switch for usb3/pcie/sgmii/sata */ @@ -906,7 +856,7 @@ static int phy_type_syscon_get(struct mtk_phy_instance *instance, static int phy_type_set(struct mtk_phy_instance *instance) { int type; - u32 mask; + u32 offset; if (!instance->type_sw) return 0; @@ -929,8 +879,9 @@ static int phy_type_set(struct mtk_phy_instance *instance) return 0; } - mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE); - regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type); + offset = instance->type_sw_index * BITS_PER_BYTE; + regmap_update_bits(instance->type_sw, instance->type_sw_reg, + RG_PHY_SW_TYPE << offset, type << offset); return 0; } @@ -1022,23 +973,23 @@ static void phy_efuse_set(struct mtk_phy_instance *instance) case PHY_TYPE_USB2: mtk_phy_set_bits(u2_banks->misc + U3P_MISC_REG1, MR1_EFUSE_AUTO_LOAD_DIS); - mtk_phy_update_bits(u2_banks->com + U3P_USBPHYACR1, PA1_RG_INTR_CAL, - PA1_RG_INTR_CAL_VAL(instance->efuse_intr)); + mtk_phy_update_field(u2_banks->com + U3P_USBPHYACR1, PA1_RG_INTR_CAL, + instance->efuse_intr); break; case PHY_TYPE_USB3: case PHY_TYPE_PCIE: mtk_phy_set_bits(u3_banks->phyd + U3P_U3_PHYD_RSV, P3D_RG_EFUSE_AUTO_LOAD_DIS); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0, P3D_RG_TX_IMPEL, - P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp)); + mtk_phy_update_field(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0, P3D_RG_TX_IMPEL, + instance->efuse_tx_imp); mtk_phy_set_bits(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0, P3D_RG_FORCE_TX_IMPEL); - mtk_phy_update_bits(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1, P3D_RG_RX_IMPEL, - P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp)); + mtk_phy_update_field(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1, P3D_RG_RX_IMPEL, + instance->efuse_rx_imp); mtk_phy_set_bits(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1, P3D_RG_FORCE_RX_IMPEL); - mtk_phy_update_bits(u3_banks->phya + U3P_U3_PHYA_REG0, P3A_RG_IEXT_INTR, - P3A_RG_IEXT_INTR_VAL(instance->efuse_intr)); + mtk_phy_update_field(u3_banks->phya + U3P_U3_PHYA_REG0, P3A_RG_IEXT_INTR, + instance->efuse_intr); break; default: dev_warn(dev, "no sw efuse for type %d\n", instance->type); diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c index a6af06941203..fc19e0fa8ed5 100644 --- a/drivers/phy/mediatek/phy-mtk-ufs.c +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -11,6 +11,8 @@ #include #include +#include "phy-mtk-io.h" + /* mphy register and offsets */ #define MP_GLB_DIG_8C 0x008C #define FRC_PLL_ISO_EN BIT(8) @@ -39,34 +41,6 @@ struct ufs_mtk_phy { struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; }; -static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) -{ - return readl(phy->mmio + reg); -} - -static inline void mphy_writel(struct ufs_mtk_phy *phy, u32 val, u32 reg) -{ - writel(val, phy->mmio + reg); -} - -static void mphy_set_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) -{ - u32 val; - - val = mphy_readl(phy, reg); - val |= bit; - mphy_writel(phy, val, reg); -} - -static void mphy_clr_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) -{ - u32 val; - - val = mphy_readl(phy, reg); - val &= ~bit; - mphy_writel(phy, val, reg); -} - static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) { return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); @@ -84,57 +58,61 @@ static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) { + void __iomem *mmio = phy->mmio; + /* release DA_MP_PLL_PWR_ON */ - mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); - mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, PLL_PWR_ON); + mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); /* release DA_MP_PLL_ISO_EN */ - mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); - mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, PLL_ISO_EN); + mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); /* release DA_MP_CDR_PWR_ON */ - mphy_set_bit(phy, MP_LN_RX_44, CDR_PWR_ON); - mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); + mtk_phy_set_bits(mmio + MP_LN_RX_44, CDR_PWR_ON); + mtk_phy_clear_bits(mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); /* release DA_MP_CDR_ISO_EN */ - mphy_clr_bit(phy, MP_LN_RX_44, CDR_ISO_EN); - mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); + mtk_phy_clear_bits(mmio + MP_LN_RX_44, CDR_ISO_EN); + mtk_phy_clear_bits(mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); /* release DA_MP_RX0_SQ_EN */ - mphy_set_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); - mphy_clr_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + mtk_phy_set_bits(mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); + mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); /* delay 1us to wait DIFZ stable */ udelay(1); /* release DIFZ */ - mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); } static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) { + void __iomem *mmio = phy->mmio; + /* force DIFZ */ - mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + mtk_phy_set_bits(mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); /* force DA_MP_RX0_SQ_EN */ - mphy_set_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); - mphy_clr_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); + mtk_phy_set_bits(mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + mtk_phy_clear_bits(mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); /* force DA_MP_CDR_ISO_EN */ - mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); - mphy_set_bit(phy, MP_LN_RX_44, CDR_ISO_EN); + mtk_phy_set_bits(mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); + mtk_phy_set_bits(mmio + MP_LN_RX_44, CDR_ISO_EN); /* force DA_MP_CDR_PWR_ON */ - mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); - mphy_clr_bit(phy, MP_LN_RX_44, CDR_PWR_ON); + mtk_phy_set_bits(mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); + mtk_phy_clear_bits(mmio + MP_LN_RX_44, CDR_PWR_ON); /* force DA_MP_PLL_ISO_EN */ - mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); - mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); + mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, PLL_ISO_EN); /* force DA_MP_PLL_PWR_ON */ - mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); - mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); + mtk_phy_set_bits(mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + mtk_phy_clear_bits(mmio + MP_GLB_DIG_8C, PLL_PWR_ON); } static int ufs_mtk_phy_power_on(struct phy *generic_phy) diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c index c0cdb78f77fa..b222fbbd71d1 100644 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c @@ -37,7 +37,6 @@ #define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00) #define P2F_RG_FREQDET_EN BIT(24) #define P2F_RG_CYCLECNT GENMASK(23, 0) -#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x)) #define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c) @@ -50,16 +49,12 @@ #define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04) #define P2A1_RG_INTR_CAL GENMASK(23, 19) -#define P2A1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19) #define P2A1_RG_VRT_SEL GENMASK(14, 12) -#define P2A1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12) #define P2A1_RG_TERM_SEL GENMASK(10, 8) -#define P2A1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8) #define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014) #define P2A5_RG_HSTX_SRCAL_EN BIT(15) #define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12) -#define P2A5_RG_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) #define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018) #define P2A6_RG_BC11_SW_EN BIT(23) @@ -74,15 +69,12 @@ #define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00) #define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16) -#define RG_XTP_GLB_BIAS_INTR_CTRL_VAL(x) ((0x3f & (x)) << 16) #define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04) #define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0) -#define RG_XTP_LN0_TX_IMPSEL_VAL(x) (0x1f & (x)) #define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014) #define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0) -#define RG_XTP_LN0_RX_IMPSEL_VAL(x) (0x1f & (x)) #define XSP_REF_CLK 26 /* MHZ */ #define XSP_SLEW_RATE_COEF 17 @@ -134,8 +126,8 @@ static void u2_phy_slew_rate_calibrate(struct mtk_xsphy *xsphy, mtk_phy_set_bits(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); /* set cycle count as 1024 */ - mtk_phy_update_bits(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT, - P2F_RG_CYCLECNT_VAL(XSP_FM_DET_CYCLE_CNT)); + mtk_phy_update_field(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT, + XSP_FM_DET_CYCLE_CNT); /* enable frequency meter */ mtk_phy_set_bits(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); @@ -166,8 +158,7 @@ static void u2_phy_slew_rate_calibrate(struct mtk_xsphy *xsphy, xsphy->src_ref_clk, xsphy->src_coef); /* set HS slew rate */ - mtk_phy_update_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, - P2A5_RG_HSTX_SRCTRL_VAL(calib_val)); + mtk_phy_update_field(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, calib_val); /* disable USB ring oscillator */ mtk_phy_clear_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); @@ -280,20 +271,20 @@ static void u2_phy_props_set(struct mtk_xsphy *xsphy, void __iomem *pbase = inst->port_base; if (inst->efuse_intr) - mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL, - P2A1_RG_INTR_CAL_VAL(inst->efuse_intr)); + mtk_phy_update_field(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL, + inst->efuse_intr); if (inst->eye_src) - mtk_phy_update_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, - P2A5_RG_HSTX_SRCTRL_VAL(inst->eye_src)); + mtk_phy_update_field(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, + inst->eye_src); if (inst->eye_vrt) - mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL, - P2A1_RG_VRT_SEL_VAL(inst->eye_vrt)); + mtk_phy_update_field(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL, + inst->eye_vrt); if (inst->eye_term) - mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL, - P2A1_RG_TERM_SEL_VAL(inst->eye_term)); + mtk_phy_update_field(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL, + inst->eye_term); } static void u3_phy_props_set(struct mtk_xsphy *xsphy, @@ -302,19 +293,16 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy, void __iomem *pbase = inst->port_base; if (inst->efuse_intr) - mtk_phy_update_bits(xsphy->glb_base + SSPXTP_PHYA_GLB_00, - RG_XTP_GLB_BIAS_INTR_CTRL, - RG_XTP_GLB_BIAS_INTR_CTRL_VAL(inst->efuse_intr)); + mtk_phy_update_field(xsphy->glb_base + SSPXTP_PHYA_GLB_00, + RG_XTP_GLB_BIAS_INTR_CTRL, inst->efuse_intr); if (inst->efuse_tx_imp) - mtk_phy_update_bits(pbase + SSPXTP_PHYA_LN_04, - RG_XTP_LN0_TX_IMPSEL, - RG_XTP_LN0_TX_IMPSEL_VAL(inst->efuse_tx_imp)); + mtk_phy_update_field(pbase + SSPXTP_PHYA_LN_04, + RG_XTP_LN0_TX_IMPSEL, inst->efuse_tx_imp); if (inst->efuse_rx_imp) - mtk_phy_update_bits(pbase + SSPXTP_PHYA_LN_14, - RG_XTP_LN0_RX_IMPSEL, - RG_XTP_LN0_RX_IMPSEL_VAL(inst->efuse_rx_imp)); + mtk_phy_update_field(pbase + SSPXTP_PHYA_LN_14, + RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp); } static int mtk_phy_init(struct phy *phy) diff --git a/drivers/phy/microchip/lan966x_serdes.c b/drivers/phy/microchip/lan966x_serdes.c index d1a50fa81130..c1a41b6cd29b 100644 --- a/drivers/phy/microchip/lan966x_serdes.c +++ b/drivers/phy/microchip/lan966x_serdes.c @@ -42,7 +42,10 @@ #define SERDES_MUX_QSGMII(i, p, m, c) \ SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c) #define SERDES_MUX_RGMII(i, p, m, c) \ - SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c) + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_TXID, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_RXID, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_ID, m, c) static void lan_rmw_(u32 val, u32 mask, void __iomem *mem, u32 offset) { @@ -94,21 +97,29 @@ static const struct serdes_mux lan966x_serdes_muxes[] = { HSIO_HW_CFG_SD6G_1_CFG_SET(1)), SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG | - HSIO_HW_CFG_RGMII_ENA, - HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, + HSIO_HW_CFG_RGMII_0_CFG_SET(0) | + HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(2))), SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG | - HSIO_HW_CFG_RGMII_ENA, - HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, + HSIO_HW_CFG_RGMII_1_CFG_SET(0) | + HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(3))), SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG | - HSIO_HW_CFG_RGMII_ENA, + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), + HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(5))), SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG | - HSIO_HW_CFG_RGMII_ENA, + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), + HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(6))), }; struct serdes_ctrl { @@ -382,6 +393,67 @@ static int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode) return lan966x_sd6g40_setup_lane(macro, conf, idx); } +static int lan966x_rgmii_setup(struct serdes_macro *macro, u32 idx, int mode) +{ + bool tx_delay = false; + bool rx_delay = false; + + /* Configure RGMII */ + lan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) | + HSIO_RGMII_CFG_RGMII_TX_RST_SET(0) | + HSIO_RGMII_CFG_TX_CLK_CFG_SET(macro->speed == SPEED_1000 ? 1 : + macro->speed == SPEED_100 ? 2 : + macro->speed == SPEED_10 ? 3 : 0), + HSIO_RGMII_CFG_RGMII_RX_RST | + HSIO_RGMII_CFG_RGMII_TX_RST | + HSIO_RGMII_CFG_TX_CLK_CFG, + macro->ctrl->regs, HSIO_RGMII_CFG(idx)); + + if (mode == PHY_INTERFACE_MODE_RGMII || + mode == PHY_INTERFACE_MODE_RGMII_TXID) + rx_delay = true; + + if (mode == PHY_INTERFACE_MODE_RGMII || + mode == PHY_INTERFACE_MODE_RGMII_RXID) + tx_delay = true; + + /* Setup DLL configuration */ + lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) | + HSIO_DLL_CFG_DLL_ENA_SET(rx_delay), + HSIO_DLL_CFG_DLL_RST | + HSIO_DLL_CFG_DLL_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2)); + + lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(rx_delay), + HSIO_DLL_CFG_DELAY_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2)); + + lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) | + HSIO_DLL_CFG_DLL_ENA_SET(tx_delay), + HSIO_DLL_CFG_DLL_RST | + HSIO_DLL_CFG_DLL_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3)); + + lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(tx_delay), + HSIO_DLL_CFG_DELAY_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3)); + + return 0; +} + +static int serdes_set_speed(struct phy *phy, int speed) +{ + struct serdes_macro *macro = phy_get_drvdata(phy); + + if (!phy_interface_mode_is_rgmii(macro->mode)) + return 0; + + macro->speed = speed; + lan966x_rgmii_setup(macro, macro->idx - (SERDES6G_MAX + 1), macro->mode); + + return 0; +} + static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct serdes_macro *macro = phy_get_drvdata(phy); @@ -427,7 +499,9 @@ static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) macro->mode); if (macro->idx < RGMII_MAX) - return 0; + return lan966x_rgmii_setup(macro, + macro->idx - (SERDES6G_MAX + 1), + macro->mode); return -EOPNOTSUPP; } @@ -437,6 +511,7 @@ static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) static const struct phy_ops serdes_ops = { .set_mode = serdes_set_mode, + .set_speed = serdes_set_speed, .owner = THIS_MODULE, }; diff --git a/drivers/phy/microchip/lan966x_serdes_regs.h b/drivers/phy/microchip/lan966x_serdes_regs.h index ea30f64ffd5c..ac54cd01fea6 100644 --- a/drivers/phy/microchip/lan966x_serdes_regs.h +++ b/drivers/phy/microchip/lan966x_serdes_regs.h @@ -206,4 +206,46 @@ enum lan966x_target { #define HSIO_HW_CFG_QSGMII_ENA_GET(x)\ FIELD_GET(HSIO_HW_CFG_QSGMII_ENA, x) +/* HSIO:HW_CFGSTAT:RGMII_CFG */ +#define HSIO_RGMII_CFG(r) __REG(TARGET_HSIO, 0, 1, 104, 0, 1, 52, 20, r, 2, 4) + +#define HSIO_RGMII_CFG_TX_CLK_CFG GENMASK(4, 2) +#define HSIO_RGMII_CFG_TX_CLK_CFG_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_TX_CLK_CFG, x) +#define HSIO_RGMII_CFG_TX_CLK_CFG_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_TX_CLK_CFG, x) + +#define HSIO_RGMII_CFG_RGMII_TX_RST BIT(1) +#define HSIO_RGMII_CFG_RGMII_TX_RST_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_RGMII_TX_RST, x) +#define HSIO_RGMII_CFG_RGMII_TX_RST_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_RGMII_TX_RST, x) + +#define HSIO_RGMII_CFG_RGMII_RX_RST BIT(0) +#define HSIO_RGMII_CFG_RGMII_RX_RST_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_RGMII_RX_RST, x) +#define HSIO_RGMII_CFG_RGMII_RX_RST_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_RGMII_RX_RST, x) + +/* HSIO:HW_CFGSTAT:DLL_CFG */ +#define HSIO_DLL_CFG(r) __REG(TARGET_HSIO, 0, 1, 104, 0, 1, 52, 36, r, 4, 4) + +#define HSIO_DLL_CFG_DELAY_ENA BIT(2) +#define HSIO_DLL_CFG_DELAY_ENA_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DELAY_ENA, x) +#define HSIO_DLL_CFG_DELAY_ENA_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DELAY_ENA, x) + +#define HSIO_DLL_CFG_DLL_ENA BIT(1) +#define HSIO_DLL_CFG_DLL_ENA_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DLL_ENA, x) +#define HSIO_DLL_CFG_DLL_ENA_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DLL_ENA, x) + +#define HSIO_DLL_CFG_DLL_RST BIT(0) +#define HSIO_DLL_CFG_DLL_RST_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DLL_RST, x) +#define HSIO_DLL_CFG_DLL_RST_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DLL_RST, x) + #endif /* _LAN966X_HSIO_REGS_H_ */ diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 7e3570789845..fc8ca0f3018d 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -70,8 +70,19 @@ #define TXn_TRAN_DRVR_EMP_EN 0x0078 +struct qcom_edp_cfg { + bool is_dp; + + /* DP PHY swing and pre_emphasis tables */ + const u8 (*swing_hbr_rbr)[4][4]; + const u8 (*swing_hbr3_hbr2)[4][4]; + const u8 (*pre_emphasis_hbr_rbr)[4][4]; + const u8 (*pre_emphasis_hbr3_hbr2)[4][4]; +}; + struct qcom_edp { struct device *dev; + const struct qcom_edp_cfg *cfg; struct phy *phy; @@ -89,10 +100,84 @@ struct qcom_edp { struct regulator_bulk_data supplies[2]; }; +static const u8 dp_swing_hbr_rbr[4][4] = { + { 0x08, 0x0f, 0x16, 0x1f }, + { 0x11, 0x1e, 0x1f, 0xff }, + { 0x16, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + +static const u8 dp_pre_emp_hbr_rbr[4][4] = { + { 0x00, 0x0d, 0x14, 0x1a }, + { 0x00, 0x0e, 0x15, 0xff }, + { 0x00, 0x0e, 0xff, 0xff }, + { 0x03, 0xff, 0xff, 0xff } +}; + +static const u8 dp_swing_hbr2_hbr3[4][4] = { + { 0x02, 0x12, 0x16, 0x1a }, + { 0x09, 0x19, 0x1f, 0xff }, + { 0x10, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + +static const u8 dp_pre_emp_hbr2_hbr3[4][4] = { + { 0x00, 0x0c, 0x15, 0x1b }, + { 0x02, 0x0e, 0x16, 0xff }, + { 0x02, 0x11, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff } +}; + +static const struct qcom_edp_cfg dp_phy_cfg = { + .is_dp = true, + .swing_hbr_rbr = &dp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr, + .pre_emphasis_hbr3_hbr2 = &dp_pre_emp_hbr2_hbr3, +}; + +static const u8 edp_swing_hbr_rbr[4][4] = { + { 0x07, 0x0f, 0x16, 0x1f }, + { 0x0d, 0x16, 0x1e, 0xff }, + { 0x11, 0x1b, 0xff, 0xff }, + { 0x16, 0xff, 0xff, 0xff } +}; + +static const u8 edp_pre_emp_hbr_rbr[4][4] = { + { 0x05, 0x12, 0x17, 0x1d }, + { 0x05, 0x11, 0x18, 0xff }, + { 0x06, 0x11, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff } +}; + +static const u8 edp_swing_hbr2_hbr3[4][4] = { + { 0x0b, 0x11, 0x17, 0x1c }, + { 0x10, 0x19, 0x1f, 0xff }, + { 0x19, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + +static const u8 edp_pre_emp_hbr2_hbr3[4][4] = { + { 0x08, 0x11, 0x17, 0x1b }, + { 0x00, 0x0c, 0x13, 0xff }, + { 0x05, 0x10, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff } +}; + +static const struct qcom_edp_cfg edp_phy_cfg = { + .is_dp = false, + .swing_hbr_rbr = &edp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr, + .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3, +}; + static int qcom_edp_phy_init(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); + const struct qcom_edp_cfg *cfg = edp->cfg; int ret; + u8 cfg8; ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), edp->supplies); if (ret) @@ -117,6 +202,13 @@ static int qcom_edp_phy_init(struct phy *phy) DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, edp->edp + DP_PHY_PD_CTL); + if (cfg && cfg->is_dp) + cfg8 = 0xb7; + else + cfg8 = 0x37; + + writel(0xfc, edp->edp + DP_PHY_MODE); + writel(0x00, edp->edp + DP_PHY_AUX_CFG0); writel(0x13, edp->edp + DP_PHY_AUX_CFG1); writel(0x24, edp->edp + DP_PHY_AUX_CFG2); @@ -125,7 +217,7 @@ static int qcom_edp_phy_init(struct phy *phy) writel(0x26, edp->edp + DP_PHY_AUX_CFG5); writel(0x0a, edp->edp + DP_PHY_AUX_CFG6); writel(0x03, edp->edp + DP_PHY_AUX_CFG7); - writel(0x37, edp->edp + DP_PHY_AUX_CFG8); + writel(cfg8, edp->edp + DP_PHY_AUX_CFG8); writel(0x03, edp->edp + DP_PHY_AUX_CFG9); writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | @@ -142,14 +234,60 @@ out_disable_supplies: return ret; } +static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts) +{ + const struct qcom_edp_cfg *cfg = edp->cfg; + unsigned int v_level = 0; + unsigned int p_level = 0; + u8 ldo_config; + u8 swing; + u8 emph; + int i; + + if (!cfg) + return 0; + + for (i = 0; i < dp_opts->lanes; i++) { + v_level = max(v_level, dp_opts->voltage[i]); + p_level = max(p_level, dp_opts->pre[i]); + } + + if (dp_opts->link_rate <= 2700) { + swing = (*cfg->swing_hbr_rbr)[v_level][p_level]; + emph = (*cfg->pre_emphasis_hbr_rbr)[v_level][p_level]; + } else { + swing = (*cfg->swing_hbr3_hbr2)[v_level][p_level]; + emph = (*cfg->pre_emphasis_hbr3_hbr2)[v_level][p_level]; + } + + if (swing == 0xff || emph == 0xff) + return -EINVAL; + + ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; + + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); + writel(swing, edp->tx0 + TXn_TX_DRV_LVL); + writel(emph, edp->tx0 + TXn_TX_EMP_POST1_LVL); + + writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG); + writel(swing, edp->tx1 + TXn_TX_DRV_LVL); + writel(emph, edp->tx1 + TXn_TX_EMP_POST1_LVL); + + return 0; +} + static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opts) { const struct phy_configure_opts_dp *dp_opts = &opts->dp; struct qcom_edp *edp = phy_get_drvdata(phy); + int ret = 0; memcpy(&edp->dp_opts, dp_opts, sizeof(*dp_opts)); - return 0; + if (dp_opts->set_voltages) + ret = qcom_edp_set_voltages(edp, dp_opts); + + return ret; } static int qcom_edp_configure_ssc(const struct qcom_edp *edp) @@ -272,31 +410,30 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp) return 0; } -static int qcom_edp_set_vco_div(const struct qcom_edp *edp) +static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq) { const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; - unsigned long pixel_freq; u32 vco_div; switch (dp_opts->link_rate) { case 1620: vco_div = 0x1; - pixel_freq = 1620000000UL / 2; + *pixel_freq = 1620000000UL / 2; break; case 2700: vco_div = 0x1; - pixel_freq = 2700000000UL / 2; + *pixel_freq = 2700000000UL / 2; break; case 5400: vco_div = 0x2; - pixel_freq = 5400000000UL / 4; + *pixel_freq = 5400000000UL / 4; break; case 8100: vco_div = 0x0; - pixel_freq = 8100000000UL / 6; + *pixel_freq = 8100000000UL / 6; break; default: @@ -306,18 +443,20 @@ static int qcom_edp_set_vco_div(const struct qcom_edp *edp) writel(vco_div, edp->edp + DP_PHY_VCO_DIV); - clk_set_rate(edp->dp_link_hw.clk, dp_opts->link_rate * 100000); - clk_set_rate(edp->dp_pixel_hw.clk, pixel_freq); - return 0; } static int qcom_edp_phy_power_on(struct phy *phy) { const struct qcom_edp *edp = phy_get_drvdata(phy); + const struct qcom_edp_cfg *cfg = edp->cfg; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + unsigned long pixel_freq; + u8 ldo_config; int timeout; int ret; u32 val; + u8 cfg1; writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | @@ -330,8 +469,11 @@ static int qcom_edp_phy_power_on(struct phy *phy) if (timeout) return timeout; - writel(0x01, edp->tx0 + TXn_LDO_CONFIG); - writel(0x01, edp->tx1 + TXn_LDO_CONFIG); + + ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; + + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); + writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG); writel(0x00, edp->tx0 + TXn_LANE_MODE_1); writel(0x00, edp->tx1 + TXn_LANE_MODE_1); @@ -363,7 +505,7 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x01, edp->tx1 + TXn_TRAN_DRVR_EMP_EN); writel(0x04, edp->tx1 + TXn_TX_BAND); - ret = qcom_edp_set_vco_div(edp); + ret = qcom_edp_set_vco_div(edp, &pixel_freq); if (ret) return ret; @@ -398,19 +540,46 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x1f, edp->tx0 + TXn_TX_DRV_LVL); writel(0x1f, edp->tx1 + TXn_TX_DRV_LVL); - writel(0x4, edp->tx0 + TXn_HIGHZ_DRVR_EN); - writel(0x3, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN); - writel(0x4, edp->tx1 + TXn_HIGHZ_DRVR_EN); - writel(0x0, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN); - writel(0x3, edp->edp + DP_PHY_CFG_1); + if (edp->dp_opts.lanes == 1) { + bias0_en = 0x01; + bias1_en = 0x00; + drvr0_en = 0x06; + drvr1_en = 0x07; + cfg1 = 0x1; + } else if (edp->dp_opts.lanes == 2) { + bias0_en = 0x03; + bias1_en = 0x00; + drvr0_en = 0x04; + drvr1_en = 0x07; + cfg1 = 0x3; + } else { + bias0_en = 0x03; + bias1_en = 0x03; + drvr0_en = 0x04; + drvr1_en = 0x04; + cfg1 = 0xf; + } + + writel(drvr0_en, edp->tx0 + TXn_HIGHZ_DRVR_EN); + writel(bias0_en, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN); + writel(drvr1_en, edp->tx1 + TXn_HIGHZ_DRVR_EN); + writel(bias1_en, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN); + writel(cfg1, edp->edp + DP_PHY_CFG_1); writel(0x18, edp->edp + DP_PHY_CFG); usleep_range(100, 1000); writel(0x19, edp->edp + DP_PHY_CFG); - return readl_poll_timeout(edp->edp + DP_PHY_STATUS, - val, val & BIT(1), 500, 10000); + ret = readl_poll_timeout(edp->edp + DP_PHY_STATUS, + val, val & BIT(1), 500, 10000); + if (ret) + return ret; + + clk_set_rate(edp->dp_link_hw.clk, edp->dp_opts.link_rate * 100000); + clk_set_rate(edp->dp_pixel_hw.clk, pixel_freq); + + return 0; } static int qcom_edp_phy_power_off(struct phy *phy) @@ -571,21 +740,24 @@ static int qcom_edp_clks_register(struct qcom_edp *edp, struct device_node *np) { struct clk_hw_onecell_data *data; struct clk_init_data init = { }; + char name[64]; int ret; data = devm_kzalloc(edp->dev, struct_size(data, hws, 2), GFP_KERNEL); if (!data) return -ENOMEM; + snprintf(name, sizeof(name), "%s::link_clk", dev_name(edp->dev)); init.ops = &qcom_edp_dp_link_clk_ops; - init.name = "edp_phy_pll_link_clk"; + init.name = name; edp->dp_link_hw.init = &init; ret = devm_clk_hw_register(edp->dev, &edp->dp_link_hw); if (ret) return ret; + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(edp->dev)); init.ops = &qcom_edp_dp_pixel_clk_ops; - init.name = "edp_phy_pll_vco_div_clk"; + init.name = name; edp->dp_pixel_hw.init = &init; ret = devm_clk_hw_register(edp->dev, &edp->dp_pixel_hw); if (ret) @@ -610,6 +782,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) return -ENOMEM; edp->dev = dev; + edp->cfg = of_device_get_match_data(&pdev->dev); edp->edp = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(edp->edp)) @@ -670,6 +843,8 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) static const struct of_device_id qcom_edp_phy_match_table[] = { { .compatible = "qcom,sc7280-edp-phy" }, { .compatible = "qcom,sc8180x-edp-phy" }, + { .compatible = "qcom,sc8280xp-dp-phy", .data = &dp_phy_cfg }, + { .compatible = "qcom,sc8280xp-edp-phy", .data = &edp_phy_cfg }, { } }; MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 4b1828976104..9807c4d935cd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -28,16 +28,11 @@ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ #define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) /* QPHY_START_CONTROL bits */ #define SERDES_START BIT(0) #define PCS_START BIT(1) -#define PLL_READY_GATE_EN BIT(3) /* QPHY_PCS_STATUS bit */ #define PHYSTATUS BIT(6) -#define PHYSTATUS_4_20 BIT(7) -/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */ -#define PCS_READY BIT(0) /* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ /* DP PHY soft reset */ @@ -71,11 +66,6 @@ #define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MAX 11 -#define MAX_PROP_NAME 32 - -/* Define the assumed distance between lanes for underspecified device trees. */ -#define QMP_PHY_LEGACY_LANE_STRIDE 0x400 - struct qmp_phy_init_tbl { unsigned int offset; unsigned int val; @@ -115,22 +105,14 @@ struct qmp_phy_init_tbl { /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { - /* Common block control registers */ - QPHY_COM_SW_RESET, - QPHY_COM_POWER_DOWN_CONTROL, - QPHY_COM_START_CONTROL, - QPHY_COM_PCS_READY_STATUS, /* PCS registers */ QPHY_SW_RESET, QPHY_START_CTRL, - QPHY_PCS_READY_STATUS, QPHY_PCS_STATUS, QPHY_PCS_AUTONOMOUS_MODE_CTRL, QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, QPHY_PCS_LFPS_RXTERM_IRQ_STATUS, QPHY_PCS_POWER_DOWN_CONTROL, - /* PCS_MISC registers */ - QPHY_PCS_MISC_TYPEC_CTRL, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -606,6 +588,160 @@ static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20), }; +static const struct qmp_phy_init_tbl qmp_v5_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORE_CLK_EN, 0x1f), +}; + +static const struct qmp_phy_init_tbl qmp_v5_5nm_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_LANE_MODE_3, 0x51), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_PRE_STALL_LDO_BOOST_EN, 0x0), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_INTERFACE_SELECT, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_TRAN_DRVR_EMP_EN, 0xf), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_RX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_TX_BAND, 0x01), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb43dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xfd), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0xfd), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MSB_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MSB_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE1, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x13), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x76), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE0, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE1, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAXVAL2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SVS_MODE_CLK_SEL, 0x0a), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb43dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_LANE_MODE_2, 0xc2), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_LANE_MODE_3, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_TX, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_RX, 0x0a), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb43dp_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B0, 0xd2), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B1, 0xd2), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B3, 0x21), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B4, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B5, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B6, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B7, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B0, 0x6b), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B1, 0x63), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B2, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B3, 0x23), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B4, 0x35), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B5, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B6, 0x8e), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_MODE_RATE2_B7, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_IVCM_CAL_CODE_OVERRIDE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_IVCM_CAL_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_SUMMER_CAL_SPD_MODE, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_UCDR_PI_CONTROLS, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_UCDR_SB2_GAIN2_RATE2, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_RX_IVCM_POSTCAL_OFFSET, 0x7c), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_VGA_CAL_CNTRL1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_VGA_CAL_MAN_VAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_DFE_DAC_ENABLE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_DFE_3, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_GM_CAL, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_UCDR_FO_GAIN_RATE2, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_UCDR_SO_GAIN_RATE2, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_5NM_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x3f), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb43dp_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_CONFIG, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG5, 0x10), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), +}; /* list of regulators */ struct qmp_regulator_data { @@ -618,14 +754,69 @@ static struct qmp_regulator_data qmp_phy_vreg_l[] = { { .name = "vdda-pll", .enable_load = 36000 }, }; +static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = { + { 0x00, 0x0c, 0x15, 0x1a }, + { 0x02, 0x0e, 0x16, 0xff }, + { 0x02, 0x11, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v3_voltage_swing_hbr3_hbr2[4][4] = { + { 0x02, 0x12, 0x16, 0x1a }, + { 0x09, 0x19, 0x1f, 0xff }, + { 0x10, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v3_pre_emphasis_hbr_rbr[4][4] = { + { 0x00, 0x0c, 0x14, 0x19 }, + { 0x00, 0x0b, 0x12, 0xff }, + { 0x00, 0x0b, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = { + { 0x08, 0x0f, 0x16, 0x1f }, + { 0x11, 0x1e, 0x1f, 0xff }, + { 0x19, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v5_pre_emphasis_hbr3_hbr2[4][4] = { + { 0x20, 0x2c, 0x35, 0x3b }, + { 0x22, 0x2e, 0x36, 0xff }, + { 0x22, 0x31, 0xff, 0xff }, + { 0x24, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v5_voltage_swing_hbr3_hbr2[4][4] = { + { 0x22, 0x32, 0x36, 0x3a }, + { 0x29, 0x39, 0x3f, 0xff }, + { 0x30, 0x3f, 0xff, 0xff }, + { 0x3f, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v5_pre_emphasis_hbr_rbr[4][4] = { + { 0x20, 0x2d, 0x34, 0x3a }, + { 0x20, 0x2e, 0x35, 0xff }, + { 0x20, 0x2e, 0xff, 0xff }, + { 0x24, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v5_voltage_swing_hbr_rbr[4][4] = { + { 0x28, 0x2f, 0x36, 0x3f }, + { 0x31, 0x3e, 0x3f, 0xff }, + { 0x36, 0x3f, 0xff, 0xff }, + { 0x3f, 0xff, 0xff, 0xff } +}; + struct qmp_phy; /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { /* phy-type - PCIE/UFS/USB */ unsigned int type; - /* number of lanes provided by phy */ - int nlanes; + int lanes; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; @@ -649,6 +840,12 @@ struct qmp_phy_cfg { const struct qmp_phy_init_tbl *serdes_tbl_hbr3; int serdes_tbl_hbr3_num; + /* DP PHY swing and pre_emphasis tables */ + const u8 (*swing_hbr_rbr)[4][4]; + const u8 (*swing_hbr3_hbr2)[4][4]; + const u8 (*pre_emphasis_hbr_rbr)[4][4]; + const u8 (*pre_emphasis_hbr3_hbr2)[4][4]; + /* DP PHY callbacks */ int (*configure_dp_phy)(struct qmp_phy *qphy); void (*configure_dp_tx)(struct qmp_phy *qphy); @@ -679,11 +876,6 @@ struct qmp_phy_cfg { int pwrdn_delay_min; int pwrdn_delay_max; - /* true, if PHY has a separate DP_COM control block */ - bool has_phy_dp_com_ctrl; - /* true, if PHY has secondary tx/rx lanes to be configured */ - bool is_dual_lane_phy; - /* Offset from PCS to PCS_USB region */ unsigned int pcs_usb_offset; @@ -708,9 +900,7 @@ struct qmp_phy_combo_cfg { * @pcs_misc: iomapped memory space for lane's pcs_misc * @pcs_usb: iomapped memory space for lane's pcs_usb * @pipe_clk: pipe clock - * @index: lane index * @qmp: QMP phy to which this lane belongs - * @lane_rst: lane's reset controller * @mode: current PHY mode * @dp_aux_cfg: Display port aux config * @dp_opts: Display port optional config @@ -728,9 +918,7 @@ struct qmp_phy { void __iomem *pcs_misc; void __iomem *pcs_usb; struct clk *pipe_clk; - unsigned int index; struct qcom_qmp *qmp; - struct reset_control *lane_rst; enum phy_mode mode; unsigned int dp_aux_cfg; struct phy_configure_opts_dp dp_opts; @@ -784,6 +972,8 @@ static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy); static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy); static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy); +static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy); + static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -833,7 +1023,7 @@ static const char * const sc7180_usb3phy_reset_l[] = { static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), @@ -858,14 +1048,11 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { .has_pwrdn_delay = true, .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, - - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sc7180_dpphy_cfg = { .type = PHY_TYPE_DP, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v3_dp_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl), @@ -881,6 +1068,11 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = { .serdes_tbl_hbr3 = qmp_v3_dp_serdes_tbl_hbr3, .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr3), + .swing_hbr_rbr = &qmp_dp_v3_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v3_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v3_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2, + .clk_list = qmp_v3_phy_clk_l, .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = sc7180_usb3phy_reset_l, @@ -889,9 +1081,6 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, - .dp_aux_init = qcom_qmp_v3_phy_dp_aux_init, .configure_dp_tx = qcom_qmp_v3_phy_configure_dp_tx, .configure_dp_phy = qcom_qmp_v3_phy_configure_dp_phy, @@ -903,9 +1092,43 @@ static const struct qmp_phy_combo_cfg sc7180_usb3dpphy_cfg = { .dp_cfg = &sc7180_dpphy_cfg, }; +static const struct qmp_phy_cfg sdm845_usb3phy_cfg = { + .type = PHY_TYPE_USB3, + .lanes = 2, + + .serdes_tbl = qmp_v3_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), + .tx_tbl = qmp_v3_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl), + .rx_tbl = qmp_v3_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl), + .pcs_tbl = qmp_v3_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl), + .clk_list = qmp_v3_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, + + .start_ctrl = SERDES_START | PCS_START, + .pwrdn_ctrl = SW_PWRDN, + .phy_status = PHYSTATUS, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, + .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, +}; + +static const struct qmp_phy_combo_cfg sdm845_usb3dpphy_cfg = { + .usb_cfg = &sdm845_usb3phy_cfg, + .dp_cfg = &sc7180_dpphy_cfg, +}; + static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), @@ -934,14 +1157,11 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { .has_pwrdn_delay = true, .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, - - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sc8180x_dpphy_cfg = { .type = PHY_TYPE_DP, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v4_dp_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl), @@ -957,6 +1177,11 @@ static const struct qmp_phy_cfg sc8180x_dpphy_cfg = { .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + .swing_hbr_rbr = &qmp_dp_v3_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v3_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v3_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2, + .clk_list = qmp_v3_phy_clk_l, .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = sc7180_usb3phy_reset_l, @@ -965,9 +1190,6 @@ static const struct qmp_phy_cfg sc8180x_dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = qmp_v3_usb3phy_regs_layout, - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, - .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy, @@ -979,9 +1201,81 @@ static const struct qmp_phy_combo_cfg sc8180x_usb3dpphy_cfg = { .dp_cfg = &sc8180x_dpphy_cfg, }; +static const struct qmp_phy_cfg sc8280xp_usb43dp_usb_cfg = { + .type = PHY_TYPE_USB3, + .lanes = 2, + + .serdes_tbl = sc8280xp_usb43dp_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb43dp_serdes_tbl), + .tx_tbl = sc8280xp_usb43dp_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sc8280xp_usb43dp_tx_tbl), + .rx_tbl = sc8280xp_usb43dp_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sc8280xp_usb43dp_rx_tbl), + .pcs_tbl = sc8280xp_usb43dp_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sc8280xp_usb43dp_pcs_tbl), + .clk_list = qmp_v4_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + .pcs_usb_offset = 0x300, + + .start_ctrl = SERDES_START | PCS_START, + .pwrdn_ctrl = SW_PWRDN, + .phy_status = PHYSTATUS, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, + .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, +}; + +static const struct qmp_phy_cfg sc8280xp_usb43dp_dp_cfg = { + .type = PHY_TYPE_DP, + .lanes = 2, + + .serdes_tbl = qmp_v5_dp_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v5_dp_serdes_tbl), + .tx_tbl = qmp_v5_5nm_dp_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v5_5nm_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v5_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v5_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, + + .clk_list = qmp_v4_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + + .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v5_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate, +}; + +static const struct qmp_phy_combo_cfg sc8280xp_usb43dpphy_combo_cfg = { + .usb_cfg = &sc8280xp_usb43dp_usb_cfg, + .dp_cfg = &sc8280xp_usb43dp_dp_cfg, +}; + static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), @@ -1009,14 +1303,11 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { .has_pwrdn_delay = true, .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, - - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8250_dpphy_cfg = { .type = PHY_TYPE_DP, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v4_dp_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl), @@ -1032,6 +1323,11 @@ static const struct qmp_phy_cfg sm8250_dpphy_cfg = { .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + .swing_hbr_rbr = &qmp_dp_v3_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v3_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v3_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2, + .clk_list = qmp_v4_phy_clk_l, .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, @@ -1040,9 +1336,6 @@ static const struct qmp_phy_cfg sm8250_dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = qmp_v4_usb3phy_regs_layout, - .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, - .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy, @@ -1054,7 +1347,7 @@ static const struct qmp_phy_combo_cfg sm8250_usb3dpphy_cfg = { .dp_cfg = &sm8250_dpphy_cfg, }; -static void qcom_qmp_phy_combo_configure_lane(void __iomem *base, +static void qmp_combo_configure_lane(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num, @@ -1077,15 +1370,15 @@ static void qcom_qmp_phy_combo_configure_lane(void __iomem *base, } } -static void qcom_qmp_phy_combo_configure(void __iomem *base, +static void qmp_combo_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num) { - qcom_qmp_phy_combo_configure_lane(base, regs, tbl, num, 0xff); + qmp_combo_configure_lane(base, regs, tbl, num, 0xff); } -static int qcom_qmp_phy_combo_serdes_init(struct qmp_phy *qphy) +static int qmp_combo_serdes_init(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *serdes = qphy->serdes; @@ -1093,27 +1386,27 @@ static int qcom_qmp_phy_combo_serdes_init(struct qmp_phy *qphy) const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qcom_qmp_phy_combo_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); + qmp_combo_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); if (cfg->type == PHY_TYPE_DP) { switch (dp_opts->link_rate) { case 1620: - qcom_qmp_phy_combo_configure(serdes, cfg->regs, + qmp_combo_configure(serdes, cfg->regs, cfg->serdes_tbl_rbr, cfg->serdes_tbl_rbr_num); break; case 2700: - qcom_qmp_phy_combo_configure(serdes, cfg->regs, + qmp_combo_configure(serdes, cfg->regs, cfg->serdes_tbl_hbr, cfg->serdes_tbl_hbr_num); break; case 5400: - qcom_qmp_phy_combo_configure(serdes, cfg->regs, + qmp_combo_configure(serdes, cfg->regs, cfg->serdes_tbl_hbr2, cfg->serdes_tbl_hbr2_num); break; case 8100: - qcom_qmp_phy_combo_configure(serdes, cfg->regs, + qmp_combo_configure(serdes, cfg->regs, cfg->serdes_tbl_hbr3, cfg->serdes_tbl_hbr3_num); break; @@ -1169,38 +1462,11 @@ static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy) qphy->pcs + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); } -static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = { - { 0x00, 0x0c, 0x15, 0x1a }, - { 0x02, 0x0e, 0x16, 0xff }, - { 0x02, 0x11, 0xff, 0xff }, - { 0x04, 0xff, 0xff, 0xff } -}; - -static const u8 qmp_dp_v3_voltage_swing_hbr3_hbr2[4][4] = { - { 0x02, 0x12, 0x16, 0x1a }, - { 0x09, 0x19, 0x1f, 0xff }, - { 0x10, 0x1f, 0xff, 0xff }, - { 0x1f, 0xff, 0xff, 0xff } -}; - -static const u8 qmp_dp_v3_pre_emphasis_hbr_rbr[4][4] = { - { 0x00, 0x0c, 0x14, 0x19 }, - { 0x00, 0x0b, 0x12, 0xff }, - { 0x00, 0x0b, 0xff, 0xff }, - { 0x04, 0xff, 0xff, 0xff } -}; - -static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = { - { 0x08, 0x0f, 0x16, 0x1f }, - { 0x11, 0x1e, 0x1f, 0xff }, - { 0x19, 0x1f, 0xff, 0xff }, - { 0x1f, 0xff, 0xff, 0xff } -}; - -static int qcom_qmp_phy_combo_configure_dp_swing(struct qmp_phy *qphy, +static int qmp_combo_configure_dp_swing(struct qmp_phy *qphy, unsigned int drv_lvl_reg, unsigned int emp_post_reg) { const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + const struct qmp_phy_cfg *cfg = qphy->cfg; unsigned int v_level = 0, p_level = 0; u8 voltage_swing_cfg, pre_emphasis_cfg; int i; @@ -1211,11 +1477,11 @@ static int qcom_qmp_phy_combo_configure_dp_swing(struct qmp_phy *qphy, } if (dp_opts->link_rate <= 2700) { - voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; - pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; + voltage_swing_cfg = (*cfg->swing_hbr_rbr)[v_level][p_level]; + pre_emphasis_cfg = (*cfg->pre_emphasis_hbr_rbr)[v_level][p_level]; } else { - voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr3_hbr2[v_level][p_level]; - pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr3_hbr2[v_level][p_level]; + voltage_swing_cfg = (*cfg->swing_hbr3_hbr2)[v_level][p_level]; + pre_emphasis_cfg = (*cfg->pre_emphasis_hbr3_hbr2)[v_level][p_level]; } /* TODO: Move check to config check */ @@ -1239,8 +1505,7 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; u32 bias_en, drvr_en; - if (qcom_qmp_phy_combo_configure_dp_swing(qphy, - QSERDES_V3_TX_TX_DRV_LVL, + if (qmp_combo_configure_dp_swing(qphy, QSERDES_V3_TX_TX_DRV_LVL, QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0) return; @@ -1258,7 +1523,7 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); } -static bool qcom_qmp_phy_combo_configure_dp_mode(struct qmp_phy *qphy) +static bool qmp_combo_configure_dp_mode(struct qmp_phy *qphy) { u32 val; bool reverse = false; @@ -1295,7 +1560,7 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) u32 phy_vco_div, status; unsigned long pixel_freq; - qcom_qmp_phy_combo_configure_dp_mode(qphy); + qmp_combo_configure_dp_mode(qphy); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); @@ -1415,23 +1680,20 @@ static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy) writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); - qcom_qmp_phy_combo_configure_dp_swing(qphy, - QSERDES_V4_TX_TX_DRV_LVL, + qmp_combo_configure_dp_swing(qphy, QSERDES_V4_TX_TX_DRV_LVL, QSERDES_V4_TX_TX_EMP_POST1_LVL); } -static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) +static int qcom_qmp_v45_phy_configure_dp_phy(struct qmp_phy *qphy) { const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; u32 phy_vco_div, status; unsigned long pixel_freq; - u32 bias0_en, drvr0_en, bias1_en, drvr1_en; - bool reverse; writel(0x0f, qphy->pcs + QSERDES_V4_DP_PHY_CFG_1); - reverse = qcom_qmp_phy_combo_configure_dp_mode(qphy); + qmp_combo_configure_dp_mode(qphy); writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); @@ -1509,6 +1771,21 @@ static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) 10000)) return -ETIMEDOUT; + return 0; +} + +static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + bool reverse = false; + u32 status; + int ret; + + ret = qcom_qmp_v45_phy_configure_dp_phy(qphy); + if (ret < 0) + return ret; + /* * At least for 7nm DP PHY this has to be done after enabling link * clock. @@ -1559,6 +1836,63 @@ static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) return 0; } +static int qcom_qmp_v5_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + bool reverse = false; + u32 status; + int ret; + + ret = qcom_qmp_v45_phy_configure_dp_phy(qphy); + if (ret < 0) + return ret; + + if (dp_opts->lanes == 1) { + bias0_en = reverse ? 0x3e : 0x1a; + drvr0_en = reverse ? 0x13 : 0x10; + bias1_en = reverse ? 0x15 : 0x3e; + drvr1_en = reverse ? 0x10 : 0x13; + } else if (dp_opts->lanes == 2) { + bias0_en = reverse ? 0x3f : 0x15; + drvr0_en = 0x10; + bias1_en = reverse ? 0x15 : 0x3f; + drvr1_en = 0x10; + } else { + bias0_en = 0x3f; + bias1_en = 0x3f; + drvr0_en = 0x10; + drvr1_en = 0x10; + } + + writel(drvr0_en, qphy->tx + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN); + writel(bias0_en, qphy->tx + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN); + writel(drvr1_en, qphy->tx2 + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN); + writel(bias1_en, qphy->tx2 + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN); + + writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG); + udelay(2000); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + writel(0x0a, qphy->tx + QSERDES_V5_5NM_TX_TX_POL_INV); + writel(0x0a, qphy->tx2 + QSERDES_V5_5NM_TX_TX_POL_INV); + + writel(0x27, qphy->tx + QSERDES_V5_5NM_TX_TX_DRV_LVL); + writel(0x27, qphy->tx2 + QSERDES_V5_5NM_TX_TX_DRV_LVL); + + writel(0x20, qphy->tx + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL); + writel(0x20, qphy->tx2 + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL); + + return 0; +} + /* * We need to calibrate the aux setting here as many times * as the caller tries @@ -1603,7 +1937,7 @@ static int qcom_qmp_dp_phy_calibrate(struct phy *phy) return 0; } -static int qcom_qmp_phy_combo_com_init(struct qmp_phy *qphy) +static int qmp_combo_com_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -1640,28 +1974,25 @@ static int qcom_qmp_phy_combo_com_init(struct qmp_phy *qphy) if (ret) goto err_assert_reset; - if (cfg->has_phy_dp_com_ctrl) { - qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, - SW_PWRDN); - /* override hardware control for reset of qmp phy */ - qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN); - /* Default type-c orientation, i.e CC1 */ - qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02); + /* override hardware control for reset of qmp phy */ + qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); - qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, - USB3_MODE | DP_MODE); + /* Default type-c orientation, i.e CC1 */ + qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02); - /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ - qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE); - qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); - qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); - } + /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ + qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + + qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); + qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); if (cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL]) qphy_setbits(pcs, @@ -1685,7 +2016,7 @@ err_unlock: return ret; } -static int qcom_qmp_phy_combo_com_exit(struct qmp_phy *qphy) +static int qmp_combo_com_exit(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -1709,7 +2040,7 @@ static int qcom_qmp_phy_combo_com_exit(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_combo_init(struct phy *phy) +static int qmp_combo_init(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -1717,7 +2048,7 @@ static int qcom_qmp_phy_combo_init(struct phy *phy) int ret; dev_vdbg(qmp->dev, "Initializing QMP phy\n"); - ret = qcom_qmp_phy_combo_com_init(qphy); + ret = qmp_combo_com_init(qphy); if (ret) return ret; @@ -1727,7 +2058,7 @@ static int qcom_qmp_phy_combo_init(struct phy *phy) return 0; } -static int qcom_qmp_phy_combo_power_on(struct phy *phy) +static int qmp_combo_power_on(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -1739,7 +2070,7 @@ static int qcom_qmp_phy_combo_power_on(struct phy *phy) unsigned int mask, val, ready; int ret; - qcom_qmp_phy_combo_serdes_init(qphy); + qmp_combo_serdes_init(qphy); ret = clk_prepare_enable(qphy->pipe_clk); if (ret) { @@ -1748,33 +2079,29 @@ static int qcom_qmp_phy_combo_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qcom_qmp_phy_combo_configure_lane(tx, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_combo_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1); - /* Configuration for other LANE for USB-DP combo PHY */ - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_combo_configure_lane(qphy->tx2, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_combo_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl, + cfg->tx_tbl_num, 2); } /* Configure special DP tx tunings */ if (cfg->type == PHY_TYPE_DP) cfg->configure_dp_tx(qphy); - qcom_qmp_phy_combo_configure_lane(rx, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_combo_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_combo_configure_lane(qphy->rx2, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_combo_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl, + cfg->rx_tbl_num, 2); } /* Configure link rate, swing, etc. */ - if (cfg->type == PHY_TYPE_DP) { + if (cfg->type == PHY_TYPE_DP) cfg->configure_dp_phy(qphy); - } else { - qcom_qmp_phy_combo_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); - } + else + qmp_combo_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); ret = reset_control_deassert(qmp->ufs_reset); if (ret) @@ -1808,7 +2135,7 @@ err_disable_pipe_clk: return ret; } -static int qcom_qmp_phy_combo_power_off(struct phy *phy) +static int qmp_combo_power_off(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -1838,42 +2165,41 @@ static int qcom_qmp_phy_combo_power_off(struct phy *phy) return 0; } -static int qcom_qmp_phy_combo_exit(struct phy *phy) +static int qmp_combo_exit(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); - qcom_qmp_phy_combo_com_exit(qphy); + qmp_combo_com_exit(qphy); return 0; } -static int qcom_qmp_phy_combo_enable(struct phy *phy) +static int qmp_combo_enable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_combo_init(phy); + ret = qmp_combo_init(phy); if (ret) return ret; - ret = qcom_qmp_phy_combo_power_on(phy); + ret = qmp_combo_power_on(phy); if (ret) - qcom_qmp_phy_combo_exit(phy); + qmp_combo_exit(phy); return ret; } -static int qcom_qmp_phy_combo_disable(struct phy *phy) +static int qmp_combo_disable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_combo_power_off(phy); + ret = qmp_combo_power_off(phy); if (ret) return ret; - return qcom_qmp_phy_combo_exit(phy); + return qmp_combo_exit(phy); } -static int qcom_qmp_phy_combo_set_mode(struct phy *phy, - enum phy_mode mode, int submode) +static int qmp_combo_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_phy *qphy = phy_get_drvdata(phy); @@ -1882,7 +2208,7 @@ static int qcom_qmp_phy_combo_set_mode(struct phy *phy, return 0; } -static void qcom_qmp_phy_combo_enable_autonomous_mode(struct qmp_phy *qphy) +static void qmp_combo_enable_autonomous_mode(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs; @@ -1911,7 +2237,7 @@ static void qcom_qmp_phy_combo_enable_autonomous_mode(struct qmp_phy *qphy) qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN); } -static void qcom_qmp_phy_combo_disable_autonomous_mode(struct qmp_phy *qphy) +static void qmp_combo_disable_autonomous_mode(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs_usb; @@ -1929,7 +2255,7 @@ static void qcom_qmp_phy_combo_disable_autonomous_mode(struct qmp_phy *qphy) qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); } -static int __maybe_unused qcom_qmp_phy_combo_runtime_suspend(struct device *dev) +static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; @@ -1946,7 +2272,7 @@ static int __maybe_unused qcom_qmp_phy_combo_runtime_suspend(struct device *dev) return 0; } - qcom_qmp_phy_combo_enable_autonomous_mode(qphy); + qmp_combo_enable_autonomous_mode(qphy); clk_disable_unprepare(qphy->pipe_clk); clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); @@ -1954,7 +2280,7 @@ static int __maybe_unused qcom_qmp_phy_combo_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused qcom_qmp_phy_combo_runtime_resume(struct device *dev) +static int __maybe_unused qmp_combo_runtime_resume(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; @@ -1983,12 +2309,12 @@ static int __maybe_unused qcom_qmp_phy_combo_runtime_resume(struct device *dev) return ret; } - qcom_qmp_phy_combo_disable_autonomous_mode(qphy); + qmp_combo_disable_autonomous_mode(qphy); return 0; } -static int qcom_qmp_phy_combo_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_combo_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_vregs; @@ -2020,7 +2346,7 @@ static int qcom_qmp_phy_combo_vreg_init(struct device *dev, const struct qmp_phy return 0; } -static int qcom_qmp_phy_combo_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_combo_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int i; @@ -2041,7 +2367,7 @@ static int qcom_qmp_phy_combo_reset_init(struct device *dev, const struct qmp_ph return 0; } -static int qcom_qmp_phy_combo_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_combo_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_clks; @@ -2309,33 +2635,31 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy, return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } -static const struct phy_ops qcom_qmp_phy_combo_usb_ops = { - .init = qcom_qmp_phy_combo_enable, - .exit = qcom_qmp_phy_combo_disable, - .set_mode = qcom_qmp_phy_combo_set_mode, +static const struct phy_ops qmp_combo_usb_ops = { + .init = qmp_combo_enable, + .exit = qmp_combo_disable, + .set_mode = qmp_combo_set_mode, .owner = THIS_MODULE, }; -static const struct phy_ops qcom_qmp_phy_combo_dp_ops = { - .init = qcom_qmp_phy_combo_init, +static const struct phy_ops qmp_combo_dp_ops = { + .init = qmp_combo_init, .configure = qcom_qmp_dp_phy_configure, - .power_on = qcom_qmp_phy_combo_power_on, + .power_on = qmp_combo_power_on, .calibrate = qcom_qmp_dp_phy_calibrate, - .power_off = qcom_qmp_phy_combo_power_off, - .exit = qcom_qmp_phy_combo_exit, - .set_mode = qcom_qmp_phy_combo_set_mode, + .power_off = qmp_combo_power_off, + .exit = qmp_combo_exit, + .set_mode = qmp_combo_set_mode, .owner = THIS_MODULE, }; -static -int qcom_qmp_phy_combo_create(struct device *dev, struct device_node *np, int id, +static int qmp_combo_create(struct device *dev, struct device_node *np, int id, void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct phy *generic_phy; struct qmp_phy *qphy; const struct phy_ops *ops; - char prop_name[MAX_PROP_NAME]; int ret; qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); @@ -2350,49 +2674,39 @@ int qcom_qmp_phy_combo_create(struct device *dev, struct device_node *np, int id * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 * For single lane PHYs: pcs_misc (optional) -> 3. */ - qphy->tx = of_iomap(np, 0); - if (!qphy->tx) - return -ENOMEM; + qphy->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qphy->tx)) + return PTR_ERR(qphy->tx); - qphy->rx = of_iomap(np, 1); - if (!qphy->rx) - return -ENOMEM; + qphy->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qphy->rx)) + return PTR_ERR(qphy->rx); - qphy->pcs = of_iomap(np, 2); - if (!qphy->pcs) - return -ENOMEM; + qphy->pcs = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qphy->pcs)) + return PTR_ERR(qphy->pcs); if (cfg->pcs_usb_offset) qphy->pcs_usb = qphy->pcs + cfg->pcs_usb_offset; - /* - * If this is a dual-lane PHY, then there should be registers for the - * second lane. Some old device trees did not specify this, so fall - * back to old legacy behavior of assuming they can be reached at an - * offset from the first lane. - */ - if (cfg->is_dual_lane_phy) { - qphy->tx2 = of_iomap(np, 3); - qphy->rx2 = of_iomap(np, 4); - if (!qphy->tx2 || !qphy->rx2) { - dev_warn(dev, - "Underspecified device tree, falling back to legacy register regions\n"); + if (cfg->lanes >= 2) { + qphy->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qphy->tx2)) + return PTR_ERR(qphy->tx2); - /* In the old version, pcs_misc is at index 3. */ - qphy->pcs_misc = qphy->tx2; - qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE; - qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE; - - } else { - qphy->pcs_misc = of_iomap(np, 5); - } + qphy->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qphy->rx2)) + return PTR_ERR(qphy->rx2); + qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL); } else { - qphy->pcs_misc = of_iomap(np, 3); + qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL); } - if (!qphy->pcs_misc) + if (IS_ERR(qphy->pcs_misc)) { dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); + qphy->pcs_misc = NULL; + } /* * Get PHY's Pipe clock, if any. USB3 and PCIe are PIPE3 @@ -2401,24 +2715,19 @@ int qcom_qmp_phy_combo_create(struct device *dev, struct device_node *np, int id * Otherwise, we initialize pipe clock to NULL for * all phys that don't need this. */ - snprintf(prop_name, sizeof(prop_name), "pipe%d", id); - qphy->pipe_clk = devm_get_clk_from_child(dev, np, prop_name); + qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL); if (IS_ERR(qphy->pipe_clk)) { - if (cfg->type == PHY_TYPE_USB3) { - ret = PTR_ERR(qphy->pipe_clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, - "failed to get lane%d pipe_clk, %d\n", - id, ret); - return ret; - } + if (cfg->type == PHY_TYPE_USB3) + return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk), + "failed to get lane%d pipe_clk\n", + id); qphy->pipe_clk = NULL; } if (cfg->type == PHY_TYPE_DP) - ops = &qcom_qmp_phy_combo_dp_ops; + ops = &qmp_combo_dp_ops; else - ops = &qcom_qmp_phy_combo_usb_ops; + ops = &qmp_combo_usb_ops; generic_phy = devm_phy_create(dev, np, ops); if (IS_ERR(generic_phy)) { @@ -2428,7 +2737,6 @@ int qcom_qmp_phy_combo_create(struct device *dev, struct device_node *np, int id } qphy->phy = generic_phy; - qphy->index = id; qphy->qmp = qmp; qmp->phys[id] = qphy; phy_set_drvdata(generic_phy, qphy); @@ -2436,11 +2744,15 @@ int qcom_qmp_phy_combo_create(struct device *dev, struct device_node *np, int id return 0; } -static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = { +static const struct of_device_id qmp_combo_of_match_table[] = { { .compatible = "qcom,sc7180-qmp-usb3-dp-phy", .data = &sc7180_usb3dpphy_cfg, }, + { + .compatible = "qcom,sdm845-qmp-usb3-dp-phy", + .data = &sdm845_usb3dpphy_cfg, + }, { .compatible = "qcom,sm8250-qmp-usb3-dp-phy", .data = &sm8250_usb3dpphy_cfg, @@ -2449,16 +2761,20 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = { .compatible = "qcom,sc8180x-qmp-usb3-dp-phy", .data = &sc8180x_usb3dpphy_cfg, }, + { + .compatible = "qcom,sc8280xp-qmp-usb43dp-phy", + .data = &sc8280xp_usb43dpphy_combo_cfg, + }, { } }; -MODULE_DEVICE_TABLE(of, qcom_qmp_combo_phy_of_match_table); +MODULE_DEVICE_TABLE(of, qmp_combo_of_match_table); -static const struct dev_pm_ops qcom_qmp_phy_combo_pm_ops = { - SET_RUNTIME_PM_OPS(qcom_qmp_phy_combo_runtime_suspend, - qcom_qmp_phy_combo_runtime_resume, NULL) +static const struct dev_pm_ops qmp_combo_pm_ops = { + SET_RUNTIME_PM_OPS(qmp_combo_runtime_suspend, + qmp_combo_runtime_resume, NULL) }; -static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) +static int qmp_combo_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; @@ -2494,12 +2810,9 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) if (IS_ERR(serdes)) return PTR_ERR(serdes); - /* per PHY dp_com; if PHY has dp_com control block */ - if (cfg->has_phy_dp_com_ctrl) { - qmp->dp_com = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(qmp->dp_com)) - return PTR_ERR(qmp->dp_com); - } + qmp->dp_com = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(qmp->dp_com)) + return PTR_ERR(qmp->dp_com); /* Only two serdes for combo PHY */ dp_serdes = devm_platform_ioremap_resource(pdev, 2); @@ -2511,21 +2824,18 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) mutex_init(&qmp->phy_mutex); - ret = qcom_qmp_phy_combo_clk_init(dev, cfg); + ret = qmp_combo_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_combo_reset_init(dev, cfg); + ret = qmp_combo_reset_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_combo_vreg_init(dev, cfg); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + ret = qmp_combo_vreg_init(dev, cfg); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ @@ -2537,7 +2847,9 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) return -ENOMEM; pm_runtime_set_active(dev); - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; /* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs. @@ -2551,7 +2863,7 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) serdes = dp_serdes; /* Create per-lane phy */ - ret = qcom_qmp_phy_combo_create(dev, child, id, serdes, cfg); + ret = qmp_combo_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -2569,7 +2881,7 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) serdes = usb_serdes; /* Create per-lane phy */ - ret = qcom_qmp_phy_combo_create(dev, child, id, serdes, cfg); + ret = qmp_combo_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -2592,29 +2904,24 @@ static int qcom_qmp_phy_combo_probe(struct platform_device *pdev) } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (!IS_ERR(phy_provider)) - dev_info(dev, "Registered Qcom-QMP phy\n"); - else - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); err_node_put: - pm_runtime_disable(dev); of_node_put(child); return ret; } -static struct platform_driver qcom_qmp_phy_combo_driver = { - .probe = qcom_qmp_phy_combo_probe, +static struct platform_driver qmp_combo_driver = { + .probe = qmp_combo_probe, .driver = { .name = "qcom-qmp-combo-phy", - .pm = &qcom_qmp_phy_combo_pm_ops, - .of_match_table = qcom_qmp_combo_phy_of_match_table, + .pm = &qmp_combo_pm_ops, + .of_match_table = qmp_combo_of_match_table, }, }; -module_platform_driver(qcom_qmp_phy_combo_driver); +module_platform_driver(qmp_combo_driver); MODULE_AUTHOR("Vivek Gautam "); MODULE_DESCRIPTION("Qualcomm QMP USB+DP combo PHY driver"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index be6a94439b6c..461f0b5d464a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -36,46 +36,13 @@ /* QPHY_PCS_STATUS bit */ #define PHYSTATUS BIT(6) #define PHYSTATUS_4_20 BIT(7) -/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */ +/* QPHY_COM_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) -/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ -/* DP PHY soft reset */ -#define SW_DPPHY_RESET BIT(0) -/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ -#define SW_DPPHY_RESET_MUX BIT(1) -/* USB3 PHY soft reset */ -#define SW_USB3PHY_RESET BIT(2) -/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ -#define SW_USB3PHY_RESET_MUX BIT(3) - -/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ -#define USB3_MODE BIT(0) /* enables USB3 mode */ -#define DP_MODE BIT(1) /* enables DP mode */ - -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */ -#define RCVR_DETECT BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ - #define PHY_INIT_COMPLETE_TIMEOUT 10000 #define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MAX 11 -#define MAX_PROP_NAME 32 - -/* Define the assumed distance between lanes for underspecified device trees. */ -#define QMP_PHY_LEGACY_LANE_STRIDE 0x400 - struct qmp_phy_init_tbl { unsigned int offset; unsigned int val; @@ -123,14 +90,8 @@ enum qphy_reg_layout { /* PCS registers */ QPHY_SW_RESET, QPHY_START_CTRL, - QPHY_PCS_READY_STATUS, QPHY_PCS_STATUS, - QPHY_PCS_AUTONOMOUS_MODE_CTRL, - QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, - QPHY_PCS_LFPS_RXTERM_IRQ_STATUS, QPHY_PCS_POWER_DOWN_CONTROL, - /* PCS_MISC registers */ - QPHY_PCS_MISC_TYPEC_CTRL, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -223,36 +184,20 @@ static const struct qmp_phy_init_tbl msm8996_pcie_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0, 0x0e), }; -struct qmp_phy; - /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - /* phy-type - PCIE/UFS/USB */ - unsigned int type; - /* number of lanes provided by phy */ - int nlanes; + /* number of PHYs provided by this block */ + int num_phys; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; int serdes_tbl_num; - const struct qmp_phy_init_tbl *serdes_tbl_sec; - int serdes_tbl_num_sec; const struct qmp_phy_init_tbl *tx_tbl; int tx_tbl_num; - const struct qmp_phy_init_tbl *tx_tbl_sec; - int tx_tbl_num_sec; const struct qmp_phy_init_tbl *rx_tbl; int rx_tbl_num; - const struct qmp_phy_init_tbl *rx_tbl_sec; - int rx_tbl_num_sec; const struct qmp_phy_init_tbl *pcs_tbl; int pcs_tbl_num; - const struct qmp_phy_init_tbl *pcs_tbl_sec; - int pcs_tbl_num_sec; - const struct qmp_phy_init_tbl *pcs_misc_tbl; - int pcs_misc_tbl_num; - const struct qmp_phy_init_tbl *pcs_misc_tbl_sec; - int pcs_misc_tbl_num_sec; /* clock ids to be requested */ const char * const *clk_list; @@ -289,12 +234,10 @@ struct qmp_phy_cfg { * @tx: iomapped memory space for lane's tx * @rx: iomapped memory space for lane's rx * @pcs: iomapped memory space for lane's pcs - * @pcs_misc: iomapped memory space for lane's pcs_misc * @pipe_clk: pipe clock * @index: lane index * @qmp: QMP phy to which this lane belongs * @lane_rst: lane's reset controller - * @mode: current PHY mode */ struct qmp_phy { struct phy *phy; @@ -303,12 +246,10 @@ struct qmp_phy { void __iomem *tx; void __iomem *rx; void __iomem *pcs; - void __iomem *pcs_misc; struct clk *pipe_clk; unsigned int index; struct qcom_qmp *qmp; struct reset_control *lane_rst; - enum phy_mode mode; }; /** @@ -377,8 +318,7 @@ static const char * const qmp_phy_vreg_l[] = { }; static const struct qmp_phy_cfg msm8996_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 3, + .num_phys = 3, .serdes_tbl = msm8996_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8996_pcie_serdes_tbl), @@ -406,7 +346,7 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; -static void qcom_qmp_phy_pcie_msm8996_configure_lane(void __iomem *base, +static void qmp_pcie_msm8996_configure_lane(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num, @@ -429,15 +369,15 @@ static void qcom_qmp_phy_pcie_msm8996_configure_lane(void __iomem *base, } } -static void qcom_qmp_phy_pcie_msm8996_configure(void __iomem *base, +static void qmp_pcie_msm8996_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num) { - qcom_qmp_phy_pcie_msm8996_configure_lane(base, regs, tbl, num, 0xff); + qmp_pcie_msm8996_configure_lane(base, regs, tbl, num, 0xff); } -static int qcom_qmp_phy_pcie_msm8996_serdes_init(struct qmp_phy *qphy) +static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -448,11 +388,7 @@ static int qcom_qmp_phy_pcie_msm8996_serdes_init(struct qmp_phy *qphy) unsigned int mask, val; int ret; - qcom_qmp_phy_pcie_msm8996_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); - if (cfg->serdes_tbl_sec) - qcom_qmp_phy_pcie_msm8996_configure(serdes, cfg->regs, cfg->serdes_tbl_sec, - cfg->serdes_tbl_num_sec); - + qmp_pcie_msm8996_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET); qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL], @@ -472,7 +408,7 @@ static int qcom_qmp_phy_pcie_msm8996_serdes_init(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_pcie_msm8996_com_init(struct qmp_phy *qphy) +static int qmp_pcie_msm8996_com_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -525,7 +461,7 @@ err_unlock: return ret; } -static int qcom_qmp_phy_pcie_msm8996_com_exit(struct qmp_phy *qphy) +static int qmp_pcie_msm8996_com_exit(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -555,21 +491,21 @@ static int qcom_qmp_phy_pcie_msm8996_com_exit(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_pcie_msm8996_init(struct phy *phy) +static int qmp_pcie_msm8996_init(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; int ret; dev_vdbg(qmp->dev, "Initializing QMP phy\n"); - ret = qcom_qmp_phy_pcie_msm8996_com_init(qphy); + ret = qmp_pcie_msm8996_com_init(qphy); if (ret) return ret; return 0; } -static int qcom_qmp_phy_pcie_msm8996_power_on(struct phy *phy) +static int qmp_pcie_msm8996_power_on(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -577,12 +513,11 @@ static int qcom_qmp_phy_pcie_msm8996_power_on(struct phy *phy) void __iomem *tx = qphy->tx; void __iomem *rx = qphy->rx; void __iomem *pcs = qphy->pcs; - void __iomem *pcs_misc = qphy->pcs_misc; void __iomem *status; unsigned int mask, val, ready; int ret; - qcom_qmp_phy_pcie_msm8996_serdes_init(qphy); + qmp_pcie_msm8996_serdes_init(qphy); ret = reset_control_deassert(qphy->lane_rst); if (ret) { @@ -598,28 +533,13 @@ static int qcom_qmp_phy_pcie_msm8996_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qcom_qmp_phy_pcie_msm8996_configure_lane(tx, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 1); - if (cfg->tx_tbl_sec) - qcom_qmp_phy_pcie_msm8996_configure_lane(tx, cfg->regs, cfg->tx_tbl_sec, - cfg->tx_tbl_num_sec, 1); + qmp_pcie_msm8996_configure_lane(tx, cfg->regs, cfg->tx_tbl, + cfg->tx_tbl_num, 1); - qcom_qmp_phy_pcie_msm8996_configure_lane(rx, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->rx_tbl_sec) - qcom_qmp_phy_pcie_msm8996_configure_lane(rx, cfg->regs, - cfg->rx_tbl_sec, cfg->rx_tbl_num_sec, 1); + qmp_pcie_msm8996_configure_lane(rx, cfg->regs, cfg->rx_tbl, + cfg->rx_tbl_num, 1); - qcom_qmp_phy_pcie_msm8996_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); - if (cfg->pcs_tbl_sec) - qcom_qmp_phy_pcie_msm8996_configure(pcs, cfg->regs, cfg->pcs_tbl_sec, - cfg->pcs_tbl_num_sec); - - qcom_qmp_phy_pcie_msm8996_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, - cfg->pcs_misc_tbl_num); - if (cfg->pcs_misc_tbl_sec) - qcom_qmp_phy_pcie_msm8996_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl_sec, - cfg->pcs_misc_tbl_num_sec); + qmp_pcie_msm8996_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); /* * Pull out PHY from POWER DOWN state. @@ -657,7 +577,7 @@ err_reset_lane: return ret; } -static int qcom_qmp_phy_pcie_msm8996_power_off(struct phy *phy) +static int qmp_pcie_msm8996_power_off(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -682,53 +602,43 @@ static int qcom_qmp_phy_pcie_msm8996_power_off(struct phy *phy) return 0; } -static int qcom_qmp_phy_pcie_msm8996_exit(struct phy *phy) +static int qmp_pcie_msm8996_exit(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); reset_control_assert(qphy->lane_rst); - qcom_qmp_phy_pcie_msm8996_com_exit(qphy); + qmp_pcie_msm8996_com_exit(qphy); return 0; } -static int qcom_qmp_phy_pcie_msm8996_enable(struct phy *phy) +static int qmp_pcie_msm8996_enable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_pcie_msm8996_init(phy); + ret = qmp_pcie_msm8996_init(phy); if (ret) return ret; - ret = qcom_qmp_phy_pcie_msm8996_power_on(phy); + ret = qmp_pcie_msm8996_power_on(phy); if (ret) - qcom_qmp_phy_pcie_msm8996_exit(phy); + qmp_pcie_msm8996_exit(phy); return ret; } -static int qcom_qmp_phy_pcie_msm8996_disable(struct phy *phy) +static int qmp_pcie_msm8996_disable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_pcie_msm8996_power_off(phy); + ret = qmp_pcie_msm8996_power_off(phy); if (ret) return ret; - return qcom_qmp_phy_pcie_msm8996_exit(phy); + return qmp_pcie_msm8996_exit(phy); } -static int qcom_qmp_phy_pcie_msm8996_set_mode(struct phy *phy, - enum phy_mode mode, int submode) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - - qphy->mode = mode; - - return 0; -} - -static int qcom_qmp_phy_pcie_msm8996_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_msm8996_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_vregs; @@ -744,7 +654,7 @@ static int qcom_qmp_phy_pcie_msm8996_vreg_init(struct device *dev, const struct return devm_regulator_bulk_get(dev, num, qmp->vregs); } -static int qcom_qmp_phy_pcie_msm8996_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_msm8996_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int i; @@ -765,7 +675,7 @@ static int qcom_qmp_phy_pcie_msm8996_reset_init(struct device *dev, const struct return 0; } -static int qcom_qmp_phy_pcie_msm8996_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_msm8996_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_clks; @@ -841,10 +751,9 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } -static const struct phy_ops qcom_qmp_phy_pcie_msm8996_ops = { - .power_on = qcom_qmp_phy_pcie_msm8996_enable, - .power_off = qcom_qmp_phy_pcie_msm8996_disable, - .set_mode = qcom_qmp_phy_pcie_msm8996_set_mode, +static const struct phy_ops qmp_pcie_msm8996_ops = { + .power_on = qmp_pcie_msm8996_enable, + .power_off = qmp_pcie_msm8996_disable, .owner = THIS_MODULE, }; @@ -853,14 +762,12 @@ static void qcom_qmp_reset_control_put(void *data) reset_control_put(data); } -static -int qcom_qmp_phy_pcie_msm8996_create(struct device *dev, struct device_node *np, int id, +static int qmp_pcie_msm8996_create(struct device *dev, struct device_node *np, int id, void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct phy *generic_phy; struct qmp_phy *qphy; - char prop_name[MAX_PROP_NAME]; int ret; qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); @@ -872,36 +779,26 @@ int qcom_qmp_phy_pcie_msm8996_create(struct device *dev, struct device_node *np, /* * Get memory resources for each phy lane: * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. - * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 - * For single lane PHYs: pcs_misc (optional) -> 3. */ - qphy->tx = of_iomap(np, 0); - if (!qphy->tx) - return -ENOMEM; + qphy->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qphy->tx)) + return PTR_ERR(qphy->tx); - qphy->rx = of_iomap(np, 1); - if (!qphy->rx) - return -ENOMEM; + qphy->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qphy->rx)) + return PTR_ERR(qphy->rx); - qphy->pcs = of_iomap(np, 2); - if (!qphy->pcs) - return -ENOMEM; + qphy->pcs = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qphy->pcs)) + return PTR_ERR(qphy->pcs); - qphy->pcs_misc = of_iomap(np, 3); - - if (!qphy->pcs_misc) - dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); - - snprintf(prop_name, sizeof(prop_name), "pipe%d", id); - qphy->pipe_clk = devm_get_clk_from_child(dev, np, prop_name); + qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL); if (IS_ERR(qphy->pipe_clk)) { return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk), "failed to get lane%d pipe clock\n", id); } - /* Get lane reset, if any */ - snprintf(prop_name, sizeof(prop_name), "lane%d", id); - qphy->lane_rst = of_reset_control_get_exclusive(np, prop_name); + qphy->lane_rst = of_reset_control_get_exclusive_by_index(np, 0); if (IS_ERR(qphy->lane_rst)) { dev_err(dev, "failed to get lane%d reset\n", id); return PTR_ERR(qphy->lane_rst); @@ -911,7 +808,7 @@ int qcom_qmp_phy_pcie_msm8996_create(struct device *dev, struct device_node *np, if (ret) return ret; - generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_pcie_msm8996_ops); + generic_phy = devm_phy_create(dev, np, &qmp_pcie_msm8996_ops); if (IS_ERR(generic_phy)) { ret = PTR_ERR(generic_phy); dev_err(dev, "failed to create qphy %d\n", ret); @@ -927,16 +824,16 @@ int qcom_qmp_phy_pcie_msm8996_create(struct device *dev, struct device_node *np, return 0; } -static const struct of_device_id qcom_qmp_phy_pcie_msm8996_of_match_table[] = { +static const struct of_device_id qmp_pcie_msm8996_of_match_table[] = { { .compatible = "qcom,msm8996-qmp-pcie-phy", .data = &msm8996_pciephy_cfg, }, { }, }; -MODULE_DEVICE_TABLE(of, qcom_qmp_phy_pcie_msm8996_of_match_table); +MODULE_DEVICE_TABLE(of, qmp_pcie_msm8996_of_match_table); -static int qcom_qmp_phy_pcie_msm8996_probe(struct platform_device *pdev) +static int qmp_pcie_msm8996_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; @@ -964,25 +861,22 @@ static int qcom_qmp_phy_pcie_msm8996_probe(struct platform_device *pdev) if (IS_ERR(serdes)) return PTR_ERR(serdes); - expected_phys = cfg->nlanes; + expected_phys = cfg->num_phys; mutex_init(&qmp->phy_mutex); - ret = qcom_qmp_phy_pcie_msm8996_clk_init(dev, cfg); + ret = qmp_pcie_msm8996_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_pcie_msm8996_reset_init(dev, cfg); + ret = qmp_pcie_msm8996_reset_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_pcie_msm8996_vreg_init(dev, cfg); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + ret = qmp_pcie_msm8996_vreg_init(dev, cfg); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ @@ -993,18 +887,10 @@ static int qcom_qmp_phy_pcie_msm8996_probe(struct platform_device *pdev) if (!qmp->phys) return -ENOMEM; - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - /* - * Prevent runtime pm from being ON by default. Users can enable - * it using power/control in sysfs. - */ - pm_runtime_forbid(dev); - id = 0; for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ - ret = qcom_qmp_phy_pcie_msm8996_create(dev, child, id, serdes, cfg); + ret = qmp_pcie_msm8996_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -1026,28 +912,23 @@ static int qcom_qmp_phy_pcie_msm8996_probe(struct platform_device *pdev) } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (!IS_ERR(phy_provider)) - dev_info(dev, "Registered Qcom-QMP phy\n"); - else - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); err_node_put: - pm_runtime_disable(dev); of_node_put(child); return ret; } -static struct platform_driver qcom_qmp_phy_pcie_msm8996_driver = { - .probe = qcom_qmp_phy_pcie_msm8996_probe, +static struct platform_driver qmp_pcie_msm8996_driver = { + .probe = qmp_pcie_msm8996_probe, .driver = { .name = "qcom-qmp-msm8996-pcie-phy", - .of_match_table = qcom_qmp_phy_pcie_msm8996_of_match_table, + .of_match_table = qmp_pcie_msm8996_of_match_table, }, }; -module_platform_driver(qcom_qmp_phy_pcie_msm8996_driver); +module_platform_driver(qmp_pcie_msm8996_driver); MODULE_AUTHOR("Vivek Gautam "); MODULE_DESCRIPTION("Qualcomm QMP MSM8996 PCIe PHY driver"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 2d65e1f56bfc..5be5348fbb26 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -32,49 +32,11 @@ /* QPHY_START_CONTROL bits */ #define SERDES_START BIT(0) #define PCS_START BIT(1) -#define PLL_READY_GATE_EN BIT(3) /* QPHY_PCS_STATUS bit */ #define PHYSTATUS BIT(6) #define PHYSTATUS_4_20 BIT(7) -/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */ -#define PCS_READY BIT(0) - -/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ -/* DP PHY soft reset */ -#define SW_DPPHY_RESET BIT(0) -/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ -#define SW_DPPHY_RESET_MUX BIT(1) -/* USB3 PHY soft reset */ -#define SW_USB3PHY_RESET BIT(2) -/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ -#define SW_USB3PHY_RESET_MUX BIT(3) - -/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ -#define USB3_MODE BIT(0) /* enables USB3 mode */ -#define DP_MODE BIT(1) /* enables DP mode */ - -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */ -#define RCVR_DETECT BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ #define PHY_INIT_COMPLETE_TIMEOUT 10000 -#define POWER_DOWN_DELAY_US_MIN 10 -#define POWER_DOWN_DELAY_US_MAX 11 - -#define MAX_PROP_NAME 32 - -/* Define the assumed distance between lanes for underspecified device trees. */ -#define QMP_PHY_LEGACY_LANE_STRIDE 0x400 struct qmp_phy_init_tbl { unsigned int offset; @@ -123,14 +85,8 @@ enum qphy_reg_layout { /* PCS registers */ QPHY_SW_RESET, QPHY_START_CTRL, - QPHY_PCS_READY_STATUS, QPHY_PCS_STATUS, - QPHY_PCS_AUTONOMOUS_MODE_CTRL, - QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, - QPHY_PCS_LFPS_RXTERM_IRQ_STATUS, QPHY_PCS_POWER_DOWN_CONTROL, - /* PCS_MISC registers */ - QPHY_PCS_MISC_TYPEC_CTRL, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -1344,14 +1300,9 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e), }; -struct qmp_phy; - /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - /* phy-type - PCIE/UFS/USB */ - unsigned int type; - /* number of lanes provided by phy */ - int nlanes; + int lanes; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; @@ -1390,7 +1341,6 @@ struct qmp_phy_cfg { unsigned int start_ctrl; unsigned int pwrdn_ctrl; - unsigned int mask_com_pcs_ready; /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */ unsigned int phy_status; @@ -1400,9 +1350,6 @@ struct qmp_phy_cfg { int pwrdn_delay_min; int pwrdn_delay_max; - /* true, if PHY has secondary tx/rx lanes to be configured */ - bool is_dual_lane_phy; - /* QMP PHY pipe clock interface rate */ unsigned long pipe_clock_rate; }; @@ -1420,9 +1367,7 @@ struct qmp_phy_cfg { * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs) * @pcs_misc: iomapped memory space for lane's pcs_misc * @pipe_clk: pipe clock - * @index: lane index * @qmp: QMP phy to which this lane belongs - * @mode: current PHY mode */ struct qmp_phy { struct phy *phy; @@ -1435,9 +1380,7 @@ struct qmp_phy { void __iomem *rx2; void __iomem *pcs_misc; struct clk *pipe_clk; - unsigned int index; struct qcom_qmp *qmp; - enum phy_mode mode; }; /** @@ -1514,8 +1457,7 @@ static const char * const sdm845_pciephy_reset_l[] = { }; static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = ipq8074_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(ipq8074_pcie_serdes_tbl), @@ -1543,8 +1485,7 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { }; static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = ipq8074_pcie_gen3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(ipq8074_pcie_gen3_serdes_tbl), @@ -1573,8 +1514,7 @@ static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = { }; static const struct qmp_phy_cfg ipq6018_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = ipq6018_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(ipq6018_pcie_serdes_tbl), @@ -1603,8 +1543,7 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = { }; static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sdm845_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl), @@ -1634,8 +1573,7 @@ static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = { }; static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sdm845_qhp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl), @@ -1663,8 +1601,7 @@ static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = { }; static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8250_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl), @@ -1702,8 +1639,7 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = { }; static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sm8250_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl), @@ -1735,15 +1671,13 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS, - .is_dual_lane_phy = true, .has_pwrdn_delay = true, .pwrdn_delay_min = 995, /* us */ .pwrdn_delay_max = 1005, /* us */ }; static const struct qmp_phy_cfg msm8998_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = msm8998_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8998_pcie_serdes_tbl), @@ -1767,8 +1701,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = { }; static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sc8180x_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_serdes_tbl), @@ -1797,8 +1730,7 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { }; static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sdx55_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_serdes_tbl), @@ -1822,15 +1754,13 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS_4_20, - .is_dual_lane_phy = true, .has_pwrdn_delay = true, .pwrdn_delay_min = 995, /* us */ .pwrdn_delay_max = 1005, /* us */ }; static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8450_qmp_gen3x1_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_serdes_tbl), @@ -1860,8 +1790,7 @@ static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = { }; static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = { - .type = PHY_TYPE_PCIE, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sm8450_qmp_gen4x2_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8450_qmp_gen4x2_pcie_serdes_tbl), @@ -1885,13 +1814,12 @@ static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, - .is_dual_lane_phy = true, .has_pwrdn_delay = true, .pwrdn_delay_min = 995, /* us */ .pwrdn_delay_max = 1005, /* us */ }; -static void qcom_qmp_phy_pcie_configure_lane(void __iomem *base, +static void qmp_pcie_configure_lane(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num, @@ -1914,31 +1842,30 @@ static void qcom_qmp_phy_pcie_configure_lane(void __iomem *base, } } -static void qcom_qmp_phy_pcie_configure(void __iomem *base, - const unsigned int *regs, - const struct qmp_phy_init_tbl tbl[], - int num) +static void qmp_pcie_configure(void __iomem *base, + const unsigned int *regs, + const struct qmp_phy_init_tbl tbl[], + int num) { - qcom_qmp_phy_pcie_configure_lane(base, regs, tbl, num, 0xff); + qmp_pcie_configure_lane(base, regs, tbl, num, 0xff); } -static int qcom_qmp_phy_pcie_serdes_init(struct qmp_phy *qphy) +static int qmp_pcie_serdes_init(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *serdes = qphy->serdes; const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qcom_qmp_phy_pcie_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); - if (cfg->serdes_tbl_sec) - qcom_qmp_phy_pcie_configure(serdes, cfg->regs, cfg->serdes_tbl_sec, - cfg->serdes_tbl_num_sec); + qmp_pcie_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); + qmp_pcie_configure(serdes, cfg->regs, cfg->serdes_tbl_sec, cfg->serdes_tbl_num_sec); return 0; } -static int qcom_qmp_phy_pcie_com_init(struct qmp_phy *qphy) +static int qmp_pcie_init(struct phy *phy) { + struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs = qphy->pcs; @@ -1985,8 +1912,9 @@ err_disable_regulators: return ret; } -static int qcom_qmp_phy_pcie_com_exit(struct qmp_phy *qphy) +static int qmp_pcie_exit(struct phy *phy) { + struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -1999,21 +1927,7 @@ static int qcom_qmp_phy_pcie_com_exit(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_pcie_init(struct phy *phy) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - struct qcom_qmp *qmp = qphy->qmp; - int ret; - dev_vdbg(qmp->dev, "Initializing QMP phy\n"); - - ret = qcom_qmp_phy_pcie_com_init(qphy); - if (ret) - return ret; - - return 0; -} - -static int qcom_qmp_phy_pcie_power_on(struct phy *phy) +static int qmp_pcie_power_on(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -2026,7 +1940,7 @@ static int qcom_qmp_phy_pcie_power_on(struct phy *phy) unsigned int mask, val, ready; int ret; - qcom_qmp_phy_pcie_serdes_init(qphy); + qmp_pcie_serdes_init(qphy); ret = clk_prepare_enable(qphy->pipe_clk); if (ret) { @@ -2035,47 +1949,31 @@ static int qcom_qmp_phy_pcie_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qcom_qmp_phy_pcie_configure_lane(tx, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 1); - if (cfg->tx_tbl_sec) - qcom_qmp_phy_pcie_configure_lane(tx, cfg->regs, cfg->tx_tbl_sec, - cfg->tx_tbl_num_sec, 1); + qmp_pcie_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_pcie_configure_lane(tx, cfg->regs, cfg->tx_tbl_sec, cfg->tx_tbl_num_sec, 1); - /* Configuration for other LANE for USB-DP combo PHY */ - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_pcie_configure_lane(qphy->tx2, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 2); - if (cfg->tx_tbl_sec) - qcom_qmp_phy_pcie_configure_lane(qphy->tx2, cfg->regs, - cfg->tx_tbl_sec, - cfg->tx_tbl_num_sec, 2); + if (cfg->lanes >= 2) { + qmp_pcie_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl, + cfg->tx_tbl_num, 2); + qmp_pcie_configure_lane(qphy->tx2, cfg->regs, cfg->tx_tbl_sec, + cfg->tx_tbl_num_sec, 2); } - qcom_qmp_phy_pcie_configure_lane(rx, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->rx_tbl_sec) - qcom_qmp_phy_pcie_configure_lane(rx, cfg->regs, - cfg->rx_tbl_sec, cfg->rx_tbl_num_sec, 1); + qmp_pcie_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_pcie_configure_lane(rx, cfg->regs, cfg->rx_tbl_sec, cfg->rx_tbl_num_sec, 1); - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_pcie_configure_lane(qphy->rx2, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 2); - if (cfg->rx_tbl_sec) - qcom_qmp_phy_pcie_configure_lane(qphy->rx2, cfg->regs, - cfg->rx_tbl_sec, - cfg->rx_tbl_num_sec, 2); + if (cfg->lanes >= 2) { + qmp_pcie_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl, + cfg->rx_tbl_num, 2); + qmp_pcie_configure_lane(qphy->rx2, cfg->regs, cfg->rx_tbl_sec, + cfg->rx_tbl_num_sec, 2); } - qcom_qmp_phy_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); - if (cfg->pcs_tbl_sec) - qcom_qmp_phy_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl_sec, - cfg->pcs_tbl_num_sec); + qmp_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_pcie_configure(pcs, cfg->regs, cfg->pcs_tbl_sec, cfg->pcs_tbl_num_sec); - qcom_qmp_phy_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, - cfg->pcs_misc_tbl_num); - if (cfg->pcs_misc_tbl_sec) - qcom_qmp_phy_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl_sec, - cfg->pcs_misc_tbl_num_sec); + qmp_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, cfg->pcs_misc_tbl_num); + qmp_pcie_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl_sec, cfg->pcs_misc_tbl_num_sec); /* * Pull out PHY from POWER DOWN state. @@ -2111,7 +2009,7 @@ err_disable_pipe_clk: return ret; } -static int qcom_qmp_phy_pcie_power_off(struct phy *phy) +static int qmp_pcie_power_off(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -2136,51 +2034,33 @@ static int qcom_qmp_phy_pcie_power_off(struct phy *phy) return 0; } -static int qcom_qmp_phy_pcie_exit(struct phy *phy) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - - qcom_qmp_phy_pcie_com_exit(qphy); - - return 0; -} - -static int qcom_qmp_phy_pcie_enable(struct phy *phy) +static int qmp_pcie_enable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_pcie_init(phy); + ret = qmp_pcie_init(phy); if (ret) return ret; - ret = qcom_qmp_phy_pcie_power_on(phy); + ret = qmp_pcie_power_on(phy); if (ret) - qcom_qmp_phy_pcie_exit(phy); + qmp_pcie_exit(phy); return ret; } -static int qcom_qmp_phy_pcie_disable(struct phy *phy) +static int qmp_pcie_disable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_pcie_power_off(phy); + ret = qmp_pcie_power_off(phy); if (ret) return ret; - return qcom_qmp_phy_pcie_exit(phy); + + return qmp_pcie_exit(phy); } -static int qcom_qmp_phy_pcie_set_mode(struct phy *phy, - enum phy_mode mode, int submode) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - - qphy->mode = mode; - - return 0; -} - -static int qcom_qmp_phy_pcie_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_vregs; @@ -2196,7 +2076,7 @@ static int qcom_qmp_phy_pcie_vreg_init(struct device *dev, const struct qmp_phy_ return devm_regulator_bulk_get(dev, num, qmp->vregs); } -static int qcom_qmp_phy_pcie_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int i; @@ -2217,7 +2097,7 @@ static int qcom_qmp_phy_pcie_reset_init(struct device *dev, const struct qmp_phy return 0; } -static int qcom_qmp_phy_pcie_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_pcie_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_clks; @@ -2300,21 +2180,18 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } -static const struct phy_ops qcom_qmp_phy_pcie_ops = { - .power_on = qcom_qmp_phy_pcie_enable, - .power_off = qcom_qmp_phy_pcie_disable, - .set_mode = qcom_qmp_phy_pcie_set_mode, +static const struct phy_ops qmp_pcie_ops = { + .power_on = qmp_pcie_enable, + .power_off = qmp_pcie_disable, .owner = THIS_MODULE, }; -static -int qcom_qmp_phy_pcie_create(struct device *dev, struct device_node *np, int id, +static int qmp_pcie_create(struct device *dev, struct device_node *np, int id, void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct phy *generic_phy; struct qmp_phy *qphy; - char prop_name[MAX_PROP_NAME]; int ret; qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); @@ -2329,59 +2206,51 @@ int qcom_qmp_phy_pcie_create(struct device *dev, struct device_node *np, int id, * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 * For single lane PHYs: pcs_misc (optional) -> 3. */ - qphy->tx = of_iomap(np, 0); - if (!qphy->tx) - return -ENOMEM; + qphy->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qphy->tx)) + return PTR_ERR(qphy->tx); - qphy->rx = of_iomap(np, 1); - if (!qphy->rx) - return -ENOMEM; + if (of_device_is_compatible(dev->of_node, "qcom,sdm845-qhp-pcie-phy")) + qphy->rx = qphy->tx; + else + qphy->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qphy->rx)) + return PTR_ERR(qphy->rx); - qphy->pcs = of_iomap(np, 2); - if (!qphy->pcs) - return -ENOMEM; + qphy->pcs = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qphy->pcs)) + return PTR_ERR(qphy->pcs); - /* - * If this is a dual-lane PHY, then there should be registers for the - * second lane. Some old device trees did not specify this, so fall - * back to old legacy behavior of assuming they can be reached at an - * offset from the first lane. - */ - if (cfg->is_dual_lane_phy) { - qphy->tx2 = of_iomap(np, 3); - qphy->rx2 = of_iomap(np, 4); - if (!qphy->tx2 || !qphy->rx2) { - dev_warn(dev, - "Underspecified device tree, falling back to legacy register regions\n"); + if (cfg->lanes >= 2) { + qphy->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qphy->tx2)) + return PTR_ERR(qphy->tx2); - /* In the old version, pcs_misc is at index 3. */ - qphy->pcs_misc = qphy->tx2; - qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE; - qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE; - - } else { - qphy->pcs_misc = of_iomap(np, 5); - } + qphy->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qphy->rx2)) + return PTR_ERR(qphy->rx2); + qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL); } else { - qphy->pcs_misc = of_iomap(np, 3); + qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL); } - if (!qphy->pcs_misc && + if (IS_ERR(qphy->pcs_misc) && of_device_is_compatible(dev->of_node, "qcom,ipq6018-qmp-pcie-phy")) qphy->pcs_misc = qphy->pcs + 0x400; - if (!qphy->pcs_misc) - dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); + if (IS_ERR(qphy->pcs_misc)) { + if (cfg->pcs_misc_tbl || cfg->pcs_misc_tbl_sec) + return PTR_ERR(qphy->pcs_misc); + } - snprintf(prop_name, sizeof(prop_name), "pipe%d", id); - qphy->pipe_clk = devm_get_clk_from_child(dev, np, prop_name); + qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL); if (IS_ERR(qphy->pipe_clk)) { return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk), "failed to get lane%d pipe clock\n", id); } - generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_pcie_ops); + generic_phy = devm_phy_create(dev, np, &qmp_pcie_ops); if (IS_ERR(generic_phy)) { ret = PTR_ERR(generic_phy); dev_err(dev, "failed to create qphy %d\n", ret); @@ -2389,7 +2258,6 @@ int qcom_qmp_phy_pcie_create(struct device *dev, struct device_node *np, int id, } qphy->phy = generic_phy; - qphy->index = id; qphy->qmp = qmp; qmp->phys[id] = qphy; phy_set_drvdata(generic_phy, qphy); @@ -2397,7 +2265,7 @@ int qcom_qmp_phy_pcie_create(struct device *dev, struct device_node *np, int id, return 0; } -static const struct of_device_id qcom_qmp_phy_pcie_of_match_table[] = { +static const struct of_device_id qmp_pcie_of_match_table[] = { { .compatible = "qcom,msm8998-qmp-pcie-phy", .data = &msm8998_pciephy_cfg, @@ -2440,9 +2308,9 @@ static const struct of_device_id qcom_qmp_phy_pcie_of_match_table[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, qcom_qmp_phy_pcie_of_match_table); +MODULE_DEVICE_TABLE(of, qmp_pcie_of_match_table); -static int qcom_qmp_phy_pcie_probe(struct platform_device *pdev) +static int qmp_pcie_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; @@ -2470,21 +2338,18 @@ static int qcom_qmp_phy_pcie_probe(struct platform_device *pdev) if (IS_ERR(serdes)) return PTR_ERR(serdes); - ret = qcom_qmp_phy_pcie_clk_init(dev, cfg); + ret = qmp_pcie_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_pcie_reset_init(dev, cfg); + ret = qmp_pcie_reset_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_pcie_vreg_init(dev, cfg); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + ret = qmp_pcie_vreg_init(dev, cfg); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ @@ -2495,18 +2360,10 @@ static int qcom_qmp_phy_pcie_probe(struct platform_device *pdev) if (!qmp->phys) return -ENOMEM; - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - /* - * Prevent runtime pm from being ON by default. Users can enable - * it using power/control in sysfs. - */ - pm_runtime_forbid(dev); - id = 0; for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ - ret = qcom_qmp_phy_pcie_create(dev, child, id, serdes, cfg); + ret = qmp_pcie_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -2528,28 +2385,23 @@ static int qcom_qmp_phy_pcie_probe(struct platform_device *pdev) } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (!IS_ERR(phy_provider)) - dev_info(dev, "Registered Qcom-QMP phy\n"); - else - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); err_node_put: - pm_runtime_disable(dev); of_node_put(child); return ret; } -static struct platform_driver qcom_qmp_phy_pcie_driver = { - .probe = qcom_qmp_phy_pcie_probe, +static struct platform_driver qmp_pcie_driver = { + .probe = qmp_pcie_probe, .driver = { .name = "qcom-qmp-pcie-phy", - .of_match_table = qcom_qmp_phy_pcie_of_match_table, + .of_match_table = qmp_pcie_of_match_table, }, }; -module_platform_driver(qcom_qmp_phy_pcie_driver); +module_platform_driver(qmp_pcie_driver); MODULE_AUTHOR("Vivek Gautam "); MODULE_DESCRIPTION("Qualcomm QMP PCIe PHY driver"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h index 61a44519f969..04f260711ea1 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h @@ -7,11 +7,24 @@ #define QCOM_PHY_QMP_PCS_V5_H_ /* Only for QMP V5 PHY - USB/PCIe PCS registers */ +#define QPHY_V5_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V5_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V5_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V5_PCS_LOCK_DETECT_CONFIG6 0x0d8 #define QPHY_V5_PCS_REFGEN_REQ_CONFIG1 0x0dc #define QPHY_V5_PCS_G3S2_PRE_GAIN 0x170 #define QPHY_V5_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 #define QPHY_V5_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V5_PCS_CDR_RESET_TIME 0x1b0 +#define QPHY_V5_PCS_RX_CONFIG 0x1b0 +#define QPHY_V5_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V5_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V5_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V5_PCS_EQ_CONFIG1 0x1dc #define QPHY_V5_PCS_EQ_CONFIG2 0x1e0 #define QPHY_V5_PCS_EQ_CONFIG3 0x1e4 +#define QPHY_V5_PCS_EQ_CONFIG5 0x1ec #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h new file mode 100644 index 000000000000..a1c088bd5158 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h @@ -0,0 +1,333 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V5_5NM_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V5_5NM_H_ + +/* Only for QMP V5 5NM PHY - TX registers */ +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_TX 0x30 +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_RX 0x34 +#define QSERDES_V5_5NM_TX_LANE_MODE_1 0x78 +#define QSERDES_V5_5NM_TX_LANE_MODE_2 0x7c +#define QSERDES_V5_5NM_TX_LANE_MODE_3 0x80 +#define QSERDES_V5_5NM_TX_BIST_MODE_LANENO 0x00 +#define QSERDES_V5_5NM_TX_BIST_INVERT 0x04 +#define QSERDES_V5_5NM_TX_CLKBUF_ENABLE 0x08 +#define QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL 0x0c +#define QSERDES_V5_5NM_TX_TX_IDLE_LVL_LARGE_AMP 0x10 +#define QSERDES_V5_5NM_TX_TX_DRV_LVL 0x14 +#define QSERDES_V5_5NM_TX_TX_DRV_LVL_OFFSET 0x18 +#define QSERDES_V5_5NM_TX_RESET_TSYNC_EN 0x1c +#define QSERDES_V5_5NM_TX_PRE_STALL_LDO_BOOST_EN 0x20 +#define QSERDES_V5_5NM_TX_LPB_EN 0x24 +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_TX 0x28 +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_RX 0x2c +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_TX 0x30 +#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_RX 0x34 +#define QSERDES_V5_5NM_TX_PERL_LENGTH1 0x38 +#define QSERDES_V5_5NM_TX_PERL_LENGTH2 0x3c +#define QSERDES_V5_5NM_TX_SERDES_BYP_EN_OUT 0x40 +#define QSERDES_V5_5NM_TX_DEBUG_BUS_SEL 0x44 +#define QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN 0x48 +#define QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN 0x4c +#define QSERDES_V5_5NM_TX_TX_POL_INV 0x50 +#define QSERDES_V5_5NM_TX_PARRATE_REC_DETECT_IDLE_EN 0x54 +#define QSERDES_V5_5NM_TX_BIST_PATTERN1 0x58 +#define QSERDES_V5_5NM_TX_BIST_PATTERN2 0x5c +#define QSERDES_V5_5NM_TX_BIST_PATTERN3 0x60 +#define QSERDES_V5_5NM_TX_BIST_PATTERN4 0x64 +#define QSERDES_V5_5NM_TX_BIST_PATTERN5 0x68 +#define QSERDES_V5_5NM_TX_BIST_PATTERN6 0x6c +#define QSERDES_V5_5NM_TX_BIST_PATTERN7 0x70 +#define QSERDES_V5_5NM_TX_BIST_PATTERN8 0x74 +#define QSERDES_V5_5NM_TX_LANE_MODE_1 0x78 +#define QSERDES_V5_5NM_TX_LANE_MODE_2 0x7c +#define QSERDES_V5_5NM_TX_LANE_MODE_3 0x80 +#define QSERDES_V5_5NM_TX_ATB_SEL1 0x84 +#define QSERDES_V5_5NM_TX_ATB_SEL2 0x88 +#define QSERDES_V5_5NM_TX_RCV_DETECT_LVL 0x8c +#define QSERDES_V5_5NM_TX_RCV_DETECT_LVL_2 0x90 +#define QSERDES_V5_5NM_TX_PRBS_SEED1 0x94 +#define QSERDES_V5_5NM_TX_PRBS_SEED2 0x98 +#define QSERDES_V5_5NM_TX_PRBS_SEED3 0x9c +#define QSERDES_V5_5NM_TX_PRBS_SEED4 0xa0 +#define QSERDES_V5_5NM_TX_RESET_GEN 0xa4 +#define QSERDES_V5_5NM_TX_RESET_GEN_MUXES 0xa8 +#define QSERDES_V5_5NM_TX_TRAN_DRVR_EMP_EN 0xac +#define QSERDES_V5_5NM_TX_VMODE_CTRL1 0xb0 +#define QSERDES_V5_5NM_TX_ALOG_OBSV_BUS_CTRL_1 0xb4 +#define QSERDES_V5_5NM_TX_BIST_STATUS 0xb8 +#define QSERDES_V5_5NM_TX_BIST_ERROR_COUNT1 0xbc +#define QSERDES_V5_5NM_TX_BIST_ERROR_COUNT2 0xc0 +#define QSERDES_V5_5NM_TX_ALOG_OBSV_BUS_STATUS_1 0xc4 +#define QSERDES_V5_5NM_TX_LANE_DIG_CONFIG 0xc8 +#define QSERDES_V5_5NM_TX_PI_QEC_CTRL 0xcc +#define QSERDES_V5_5NM_TX_PRE_EMPH 0xd0 +#define QSERDES_V5_5NM_TX_SW_RESET 0xd4 +#define QSERDES_V5_5NM_TX_TX_BAND 0xd8 +#define QSERDES_V5_5NM_TX_SLEW_CNTL0 0xdc +#define QSERDES_V5_5NM_TX_SLEW_CNTL1 0xe0 +#define QSERDES_V5_5NM_TX_INTERFACE_SELECT 0xe4 +#define QSERDES_V5_5NM_TX_DIG_BKUP_CTRL 0xe8 +#define QSERDES_V5_5NM_TX_DEBUG_BUS0 0xec +#define QSERDES_V5_5NM_TX_DEBUG_BUS1 0xf0 +#define QSERDES_V5_5NM_TX_DEBUG_BUS2 0xf4 +#define QSERDES_V5_5NM_TX_DEBUG_BUS3 0xf8 +#define QSERDES_V5_5NM_TX_TX_BKUP_RO_BUS 0xfc + +/* Only for QMP V5 5NM PHY - RX registers */ +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_FO_GAIN_RATE0 0x000 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_FO_GAIN_RATE1 0x004 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x008 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_FO_GAIN_RATE3 0x00c +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_SO_GAIN_RATE0 0x010 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_SO_GAIN_RATE1 0x014 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_SO_GAIN_RATE2 0x018 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_SO_GAIN_RATE3 0x01c +#define QSERDES_V5_5NM_RX_UCDR_SO_SATURATION 0x020 +#define QSERDES_V5_5NM_RX_UCDR_FO_TO_SO_DELAY 0x024 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_LOW_RATE0 0x028 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE0 0x02c +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_LOW_RATE1 0x030 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE1 0x034 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_LOW_RATE2 0x038 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE2 0x03c +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_LOW_RATE3 0x040 +#define QSERDES_V5_5NM_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE3 0x044 +#define QSERDES_V5_5NM_RX_UCDR_PI_CTRL1 0x048 +#define QSERDES_V5_5NM_RX_UCDR_PI_CTRL2 0x04c +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH1_RATE0 0x050 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH1_RATE1 0x054 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH1_RATE2 0x058 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH1_RATE3 0x05c +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH2_RATE0 0x060 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH2_RATE1 0x064 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH2_RATE2 0x068 +#define QSERDES_V5_5NM_RX_UCDR_SB2_THRESH2_RATE3 0x06c +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN1_RATE0 0x070 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN1_RATE1 0x074 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN1_RATE2 0x078 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN1_RATE3 0x07c +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN2_RATE0 0x080 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN2_RATE1 0x084 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN2_RATE2 0x088 +#define QSERDES_V5_5NM_RX_UCDR_SB2_GAIN2_RATE3 0x08c +#define QSERDES_V5_5NM_RX_RXCLK_DIV2_CTRL 0x090 +#define QSERDES_V5_5NM_RX_RX_BAND 0x094 +#define QSERDES_V5_5NM_RX_RX_TERM_BW 0x098 +#define QSERDES_V5_5NM_RX_UCDR_FO_GAIN_RATE0 0x09c +#define QSERDES_V5_5NM_RX_UCDR_FO_GAIN_RATE1 0x0a0 +#define QSERDES_V5_5NM_RX_UCDR_FO_GAIN_RATE2 0x0a4 +#define QSERDES_V5_5NM_RX_UCDR_FO_GAIN_RATE3 0x0a8 +#define QSERDES_V5_5NM_RX_UCDR_SO_GAIN_RATE0 0x0ac +#define QSERDES_V5_5NM_RX_UCDR_SO_GAIN_RATE1 0x0b0 +#define QSERDES_V5_5NM_RX_UCDR_SO_GAIN_RATE2 0x0b4 +#define QSERDES_V5_5NM_RX_UCDR_SO_GAIN_RATE3 0x0b8 +#define QSERDES_V5_5NM_RX_UCDR_PI_CONTROLS 0x0bc +#define QSERDES_V5_5NM_RX_UCDR_PD_DATA_FILTER_ENABLES 0x0c0 +#define QSERDES_V5_5NM_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE0 0x0c4 +#define QSERDES_V5_5NM_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE1 0x0c8 +#define QSERDES_V5_5NM_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE2 0x0cc +#define QSERDES_V5_5NM_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3 0x0d0 +#define QSERDES_V5_5NM_RX_AUX_CONTROL 0x0d4 +#define QSERDES_V5_5NM_RX_AUXDATA_TB 0x0d8 +#define QSERDES_V5_5NM_RX_RCLK_AUXDATA_SEL 0x0dc +#define QSERDES_V5_5NM_RX_EOM_CTRL 0x0e0 +#define QSERDES_V5_5NM_RX_AC_JTAG_ENABLE 0x0e4 +#define QSERDES_V5_5NM_RX_AC_JTAG_INITP 0x0e8 +#define QSERDES_V5_5NM_RX_AC_JTAG_INITN 0x0ec +#define QSERDES_V5_5NM_RX_AC_JTAG_LVL 0x0f0 +#define QSERDES_V5_5NM_RX_AC_JTAG_MODE 0x0f4 +#define QSERDES_V5_5NM_RX_AC_JTAG_RESET 0x0f8 +#define QSERDES_V5_5NM_RX_RX_RCVR_IQ_EN 0x0fc +#define QSERDES_V5_5NM_RX_RX_Q_EN_RATES 0x100 +#define QSERDES_V5_5NM_RX_RX_IDAC_I0_DC_OFFSETS 0x104 +#define QSERDES_V5_5NM_RX_RX_IDAC_I0BAR_DC_OFFSETS 0x108 +#define QSERDES_V5_5NM_RX_RX_IDAC_I1_DC_OFFSETS 0x10c +#define QSERDES_V5_5NM_RX_RX_IDAC_I1BAR_DC_OFFSETS 0x110 +#define QSERDES_V5_5NM_RX_RX_IDAC_Q_DC_OFFSETS 0x114 +#define QSERDES_V5_5NM_RX_RX_IDAC_QBAR_DC_OFFSETS 0x118 +#define QSERDES_V5_5NM_RX_RX_IDAC_A_DC_OFFSETS 0x11c +#define QSERDES_V5_5NM_RX_RX_IDAC_ABAR_DC_OFFSETS 0x120 +#define QSERDES_V5_5NM_RX_RX_IDAC_EN 0x124 +#define QSERDES_V5_5NM_RX_RX_IDAC_ENABLES 0x128 +#define QSERDES_V5_5NM_RX_RX_IDAC_SIGN 0x12c +#define QSERDES_V5_5NM_RX_RX_IVCM_CAL_CODE_OVERRIDE 0x130 +#define QSERDES_V5_5NM_RX_RX_IVCM_CAL_CTRL1 0x134 +#define QSERDES_V5_5NM_RX_RX_IVCM_CAL_CTRL2 0x138 +#define QSERDES_V5_5NM_RX_RX_IVCM_POSTCAL_OFFSET 0x13c +#define QSERDES_V5_5NM_RX_RX_SUMMER_CAL_SPD_MODE 0x140 +#define QSERDES_V5_5NM_RX_RX_HIGHZ_PARRATE 0x144 +#define QSERDES_V5_5NM_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x148 +#define QSERDES_V5_5NM_RX_DFE_1 0x14c +#define QSERDES_V5_5NM_RX_DFE_2 0x150 +#define QSERDES_V5_5NM_RX_DFE_3 0x154 +#define QSERDES_V5_5NM_RX_DFE_4 0x158 +#define QSERDES_V5_5NM_RX_DFE_TAP3_CTRL 0x15c +#define QSERDES_V5_5NM_RX_DFE_TAP3_MANVAL_KTAP 0x160 +#define QSERDES_V5_5NM_RX_DFE_TAP4_CTRL 0x164 +#define QSERDES_V5_5NM_RX_DFE_TAP4_MANVAL_KTAP 0x168 +#define QSERDES_V5_5NM_RX_DFE_TAP5_CTRL 0x16c +#define QSERDES_V5_5NM_RX_DFE_TAP5_MANVAL_KTAP 0x170 +#define QSERDES_V5_5NM_RX_TX_ADPT_CTRL 0x174 +#define QSERDES_V5_5NM_RX_DFE_DAC_ENABLE1 0x178 +#define QSERDES_V5_5NM_RX_DFE_DAC_ENABLE2 0x17c +#define QSERDES_V5_5NM_RX_TX_ADAPT_PRE_THRESH1 0x180 +#define QSERDES_V5_5NM_RX_TX_ADAPT_PRE_THRESH2 0x184 +#define QSERDES_V5_5NM_RX_TX_ADAPT_POST_THRESH1 0x188 +#define QSERDES_V5_5NM_RX_TX_ADAPT_POST_THRESH2 0x18c +#define QSERDES_V5_5NM_RX_TX_ADAPT_MAIN_THRESH1 0x190 +#define QSERDES_V5_5NM_RX_TX_ADAPT_MAIN_THRESH2 0x194 +#define QSERDES_V5_5NM_RX_VGA_CAL_CNTRL1 0x198 +#define QSERDES_V5_5NM_RX_VGA_CAL_CNTRL2 0x19c +#define QSERDES_V5_5NM_RX_VGA_CAL_MAN_VAL 0x1a0 +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_CNTRL1 0x1a4 +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_CNTRL2 0x1a8 +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_MAN_VAL_RATE0 0x1ac +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_MAN_VAL_RATE1 0x1b0 +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_MAN_VAL_RATE2 0x1b4 +#define QSERDES_V5_5NM_RX_VTHRESH_CAL_MAN_VAL_RATE3 0x1b8 +#define QSERDES_V5_5NM_RX_GM_CAL 0x1bc +#define QSERDES_V5_5NM_RX_RX_VGA_GAIN2_BLK1 0x1c0 +#define QSERDES_V5_5NM_RX_RX_VGA_GAIN2_BLK2 0x1c4 +#define QSERDES_V5_5NM_RX_RX_EQU_ADAPTOR_CNTRL2 0x1c8 +#define QSERDES_V5_5NM_RX_RX_EQU_ADAPTOR_CNTRL3 0x1cc +#define QSERDES_V5_5NM_RX_RX_EQU_ADAPTOR_CNTRL4 0x1d0 +#define QSERDES_V5_5NM_RX_RX_IDAC_TSETTLE_LOW 0x1d4 +#define QSERDES_V5_5NM_RX_RX_EQ_OFFSET_LSB 0x1d8 +#define QSERDES_V5_5NM_RX_RX_EQ_OFFSET_MSB 0x1dc +#define QSERDES_V5_5NM_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1e0 +#define QSERDES_V5_5NM_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x1e4 +#define QSERDES_V5_5NM_RX_SIGDET_ENABLES 0x1e8 +#define QSERDES_V5_5NM_RX_SIGDET_CNTRL 0x1ec +#define QSERDES_V5_5NM_RX_SIGDET_LVL 0x1f0 +#define QSERDES_V5_5NM_RX_SIGDET_DEGLITCH_CNTRL 0x1f4 +#define QSERDES_V5_5NM_RX_CDR_FREEZE_UP_DN 0x1f8 +#define QSERDES_V5_5NM_RX_CDR_RESET_OVERRIDE 0x1fc +#define QSERDES_V5_5NM_RX_RX_INTERFACE_MODE 0x200 +#define QSERDES_V5_5NM_RX_JITTER_GEN_MODE 0x204 +#define QSERDES_V5_5NM_RX_SJ_AMP1 0x208 +#define QSERDES_V5_5NM_RX_SJ_AMP2 0x20c +#define QSERDES_V5_5NM_RX_SJ_PER1 0x210 +#define QSERDES_V5_5NM_RX_SJ_PER2 0x214 +#define QSERDES_V5_5NM_RX_PPM_OFFSET1 0x218 +#define QSERDES_V5_5NM_RX_PPM_OFFSET2 0x21c +#define QSERDES_V5_5NM_RX_SIGN_PPM_PERIOD1 0x220 +#define QSERDES_V5_5NM_RX_SIGN_PPM_PERIOD2 0x224 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B0 0x228 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B1 0x22c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B2 0x230 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B3 0x234 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B4 0x238 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B5 0x23c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B6 0x240 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE_0_1_B7 0x244 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B0 0x248 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B1 0x24c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B2 0x250 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B3 0x254 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B4 0x258 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B5 0x25c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B6 0x260 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE2_B7 0x264 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B0 0x268 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B1 0x26c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B2 0x270 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B3 0x274 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B4 0x278 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B5 0x27c +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B6 0x280 +#define QSERDES_V5_5NM_RX_RX_MODE_RATE3_B7 0x284 +#define QSERDES_V5_5NM_RX_PHPRE_CTRL 0x288 +#define QSERDES_V5_5NM_RX_PHPRE_INITVAL 0x28c +#define QSERDES_V5_5NM_RX_DFE_EN_TIMER 0x290 +#define QSERDES_V5_5NM_RX_DFE_CTLE_POST_CAL_OFFSET 0x294 +#define QSERDES_V5_5NM_RX_DCC_CTRL1 0x298 +#define QSERDES_V5_5NM_RX_DCC_CTRL2 0x29c +#define QSERDES_V5_5NM_RX_DCC_OFFSET 0x2a0 +#define QSERDES_V5_5NM_RX_DCC_CMUX_POSTCAL_OFFSET 0x2a4 +#define QSERDES_V5_5NM_RX_DCC_CMUX_CAL_CTRL1 0x2a8 +#define QSERDES_V5_5NM_RX_DCC_CMUX_CAL_CTRL2 0x2ac +#define QSERDES_V5_5NM_RX_ALOG_OBSV_BUS_CTRL_1 0x2b0 +#define QSERDES_V5_5NM_RX_RX_MARG_CTRL1 0x2b4 +#define QSERDES_V5_5NM_RX_RX_MARG_CTRL2 0x2b8 +#define QSERDES_V5_5NM_RX_RX_MARG_CTRL3 0x2bc +#define QSERDES_V5_5NM_RX_RX_MARG_CTRL_4 0x2c0 +#define QSERDES_V5_5NM_RX_RX_MARG_CFG_RATE_0_1 0x2c4 +#define QSERDES_V5_5NM_RX_RX_MARG_CFG_RATE_2_3 0x2c8 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_CTRL1 0x2cc +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_CTRL2 0x2d0 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH1_RATE210 0x2d4 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH1_RATE3 0x2d8 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH2_RATE210 0x2dc +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH2_RATE3 0x2e0 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH3_RATE210 0x2e4 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH3_RATE3 0x2e8 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH4_RATE210 0x2ec +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH4_RATE3 0x2f0 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH5_RATE210 0x2f4 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH5_RATE3 0x2f8 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH6_RATE210 0x2fc +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH6_RATE3 0x300 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH7_RATE210 0x304 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_THRESH7_RATE3 0x308 +#define QSERDES_V5_5NM_RX_Q_PI_INTRINSIC_BIAS_RATE10 0x30c +#define QSERDES_V5_5NM_RX_Q_PI_INTRINSIC_BIAS_RATE32 0x310 +#define QSERDES_V5_5NM_RX_RX_MARG_VERTICAL_CTRL 0x314 +#define QSERDES_V5_5NM_RX_RX_MARG_VERTICAL_CODE 0x318 +#define QSERDES_V5_5NM_RX_RES_CODE_THRESH_HIGH_AND_BYP 0x31c +#define QSERDES_V5_5NM_RX_RES_CODE_THRESH_LOW 0x320 +#define QSERDES_V5_5NM_RX_RX_BKUP_CTRL1 0x324 +#define QSERDES_V5_5NM_RX_RX_BKUP_CTRL2 0x328 +#define QSERDES_V5_5NM_RX_RX_BKUP_CTRL3 0x32c +#define QSERDES_V5_5NM_RX_PI_CTRL1 0x330 +#define QSERDES_V5_5NM_RX_PI_CTRL2 0x334 +#define QSERDES_V5_5NM_RX_PI_QUAD 0x338 +#define QSERDES_V5_5NM_RX_QPI_CTRL1 0x33c +#define QSERDES_V5_5NM_RX_QPI_CTRL2 0x340 +#define QSERDES_V5_5NM_RX_QPI_QUAD 0x344 +#define QSERDES_V5_5NM_RX_IDATA1 0x348 +#define QSERDES_V5_5NM_RX_IDATA2 0x34c +#define QSERDES_V5_5NM_RX_IDATA3 0x350 +#define QSERDES_V5_5NM_RX_AC_JTAG_OUTP 0x354 +#define QSERDES_V5_5NM_RX_AC_JTAG_OUTN 0x358 +#define QSERDES_V5_5NM_RX_RX_SIGDET 0x35c +#define QSERDES_V5_5NM_RX_ALOG_OBSV_BUS_STATUS_1 0x360 +#define QSERDES_V5_5NM_RX_READ_EQCODE 0x364 +#define QSERDES_V5_5NM_RX_READ_OFFSETCODE 0x368 +#define QSERDES_V5_5NM_RX_IA_ERROR_COUNTER_LOW 0x36c +#define QSERDES_V5_5NM_RX_IA_ERROR_COUNTER_HIGH 0x370 +#define QSERDES_V5_5NM_RX_VGA_READ_CODE 0x374 +#define QSERDES_V5_5NM_RX_VTHRESH_READ_CODE 0x378 +#define QSERDES_V5_5NM_RX_DFE_TAP1_READ_CODE 0x37c +#define QSERDES_V5_5NM_RX_DFE_TAP2_READ_CODE 0x380 +#define QSERDES_V5_5NM_RX_DFE_TAP3_READ_CODE 0x384 +#define QSERDES_V5_5NM_RX_DFE_TAP4_READ_CODE 0x388 +#define QSERDES_V5_5NM_RX_DFE_TAP5_READ_CODE 0x38c +#define QSERDES_V5_5NM_RX_IDAC_STATUS_I0 0x390 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_I0BAR 0x394 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_I1 0x398 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_I1BAR 0x39c +#define QSERDES_V5_5NM_RX_IDAC_STATUS_Q 0x3a0 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_QBAR 0x3a4 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_A 0x3a8 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_ABAR 0x3ac +#define QSERDES_V5_5NM_RX_IDAC_STATUS_SM_ON 0x3b0 +#define QSERDES_V5_5NM_RX_IDAC_STATUS_SIGNERROR 0x3b4 +#define QSERDES_V5_5NM_RX_IVCM_CAL_STATUS 0x3b8 +#define QSERDES_V5_5NM_RX_IVCM_CAL_DEBUG_STATUS 0x3bc +#define QSERDES_V5_5NM_RX_DCC_CAL_STATUS 0x3c0 +#define QSERDES_V5_5NM_RX_DCC_READ_CODE_STATUS 0x3c4 +#define QSERDES_V5_5NM_RX_RX_MARG_DEBUG1_STATUS 0x3c8 +#define QSERDES_V5_5NM_RX_RX_MARG_DEBUG2_STATUS 0x3cc +#define QSERDES_V5_5NM_RX_RX_MARG_READ_CODE_STATUS 0x3d0 +#define QSERDES_V5_5NM_RX_EOM_ERR_CNT_LSB_STATUS 0x3d4 +#define QSERDES_V5_5NM_RX_EOM_ERR_CNT_MSB_STATUS 0x3d8 +#define QSERDES_V5_5NM_RX_RX_MARG_COARSE_TUNE_STATUS 0x3dc +#define QSERDES_V5_5NM_RX_RX_BKUP_READ_BUS1_STATUS 0x3e0 +#define QSERDES_V5_5NM_RX_RX_BKUP_READ_BUS2_STATUS 0x3e4 +#define QSERDES_V5_5NM_RX_RX_BKUP_READ_BUS3_STATUS 0x3e8 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index c8583f5a54bd..c08d34ad1313 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -28,53 +28,15 @@ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ #define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) /* QPHY_START_CONTROL bits */ #define SERDES_START BIT(0) #define PCS_START BIT(1) -#define PLL_READY_GATE_EN BIT(3) /* QPHY_PCS_STATUS bit */ #define PHYSTATUS BIT(6) -#define PHYSTATUS_4_20 BIT(7) -/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */ +/* QPHY_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) -/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ -/* DP PHY soft reset */ -#define SW_DPPHY_RESET BIT(0) -/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ -#define SW_DPPHY_RESET_MUX BIT(1) -/* USB3 PHY soft reset */ -#define SW_USB3PHY_RESET BIT(2) -/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ -#define SW_USB3PHY_RESET_MUX BIT(3) - -/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ -#define USB3_MODE BIT(0) /* enables USB3 mode */ -#define DP_MODE BIT(1) /* enables DP mode */ - -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */ -#define RCVR_DETECT BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ - #define PHY_INIT_COMPLETE_TIMEOUT 10000 -#define POWER_DOWN_DELAY_US_MIN 10 -#define POWER_DOWN_DELAY_US_MAX 11 - -#define MAX_PROP_NAME 32 - -/* Define the assumed distance between lanes for underspecified device trees. */ -#define QMP_PHY_LEGACY_LANE_STRIDE 0x400 struct qmp_phy_init_tbl { unsigned int offset; @@ -115,22 +77,11 @@ struct qmp_phy_init_tbl { /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { - /* Common block control registers */ - QPHY_COM_SW_RESET, - QPHY_COM_POWER_DOWN_CONTROL, - QPHY_COM_START_CONTROL, - QPHY_COM_PCS_READY_STATUS, /* PCS registers */ QPHY_SW_RESET, QPHY_START_CTRL, QPHY_PCS_READY_STATUS, - QPHY_PCS_STATUS, - QPHY_PCS_AUTONOMOUS_MODE_CTRL, - QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, - QPHY_PCS_LFPS_RXTERM_IRQ_STATUS, QPHY_PCS_POWER_DOWN_CONTROL, - /* PCS_MISC registers */ - QPHY_PCS_MISC_TYPEC_CTRL, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -580,14 +531,9 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1, 0x02), }; -struct qmp_phy; - /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - /* phy-type - PCIE/UFS/USB */ - unsigned int type; - /* number of lanes provided by phy */ - int nlanes; + int lanes; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; @@ -614,9 +560,6 @@ struct qmp_phy_cfg { /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */ unsigned int phy_status; - /* true, if PHY has secondary tx/rx lanes to be configured */ - bool is_dual_lane_phy; - /* true, if PCS block has no separate SW_RESET register */ bool no_pcs_sw_reset; }; @@ -633,9 +576,7 @@ struct qmp_phy_cfg { * @tx2: iomapped memory space for second lane's tx (in dual lane PHYs) * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs) * @pcs_misc: iomapped memory space for lane's pcs_misc - * @index: lane index * @qmp: QMP phy to which this lane belongs - * @mode: current PHY mode */ struct qmp_phy { struct phy *phy; @@ -647,9 +588,7 @@ struct qmp_phy { void __iomem *tx2; void __iomem *rx2; void __iomem *pcs_misc; - unsigned int index; struct qcom_qmp *qmp; - enum phy_mode mode; }; /** @@ -719,8 +658,7 @@ static const char * const qmp_phy_vreg_l[] = { }; static const struct qmp_phy_cfg msm8996_ufs_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 1, + .lanes = 1, .serdes_tbl = msm8996_ufs_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8996_ufs_serdes_tbl), @@ -745,8 +683,7 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = { }; static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sdm845_ufsphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl), @@ -766,13 +703,11 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - .is_dual_lane_phy = true, .no_pcs_sw_reset = true, }; static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm6115_ufsphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm6115_ufsphy_serdes_tbl), @@ -795,8 +730,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { }; static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sm8150_ufsphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_ufsphy_serdes_tbl), @@ -815,13 +749,10 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .start_ctrl = SERDES_START, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sm8350_ufsphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl), @@ -840,13 +771,10 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .start_ctrl = SERDES_START, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { - .type = PHY_TYPE_UFS, - .nlanes = 2, + .lanes = 2, .serdes_tbl = sm8350_ufsphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl), @@ -865,11 +793,9 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .start_ctrl = SERDES_START, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - - .is_dual_lane_phy = true, }; -static void qcom_qmp_phy_ufs_configure_lane(void __iomem *base, +static void qmp_ufs_configure_lane(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num, @@ -892,27 +818,27 @@ static void qcom_qmp_phy_ufs_configure_lane(void __iomem *base, } } -static void qcom_qmp_phy_ufs_configure(void __iomem *base, +static void qmp_ufs_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num) { - qcom_qmp_phy_ufs_configure_lane(base, regs, tbl, num, 0xff); + qmp_ufs_configure_lane(base, regs, tbl, num, 0xff); } -static int qcom_qmp_phy_ufs_serdes_init(struct qmp_phy *qphy) +static int qmp_ufs_serdes_init(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *serdes = qphy->serdes; const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qcom_qmp_phy_ufs_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); + qmp_ufs_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); return 0; } -static int qcom_qmp_phy_ufs_com_init(struct qmp_phy *qphy) +static int qmp_ufs_com_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -946,7 +872,7 @@ err_disable_regulators: return ret; } -static int qcom_qmp_phy_ufs_com_exit(struct qmp_phy *qphy) +static int qmp_ufs_com_exit(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -960,7 +886,7 @@ static int qcom_qmp_phy_ufs_com_exit(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_ufs_init(struct phy *phy) +static int qmp_ufs_init(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -995,14 +921,14 @@ static int qcom_qmp_phy_ufs_init(struct phy *phy) return ret; } - ret = qcom_qmp_phy_ufs_com_init(qphy); + ret = qmp_ufs_com_init(qphy); if (ret) return ret; return 0; } -static int qcom_qmp_phy_ufs_power_on(struct phy *phy) +static int qmp_ufs_power_on(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -1014,27 +940,24 @@ static int qcom_qmp_phy_ufs_power_on(struct phy *phy) unsigned int mask, val, ready; int ret; - qcom_qmp_phy_ufs_serdes_init(qphy); + qmp_ufs_serdes_init(qphy); /* Tx, Rx, and PCS configurations */ - qcom_qmp_phy_ufs_configure_lane(tx, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_ufs_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1); - /* Configuration for other LANE for USB-DP combo PHY */ - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_ufs_configure_lane(qphy->tx2, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_ufs_configure_lane(qphy->tx2, cfg->regs, + cfg->tx_tbl, cfg->tx_tbl_num, 2); } - qcom_qmp_phy_ufs_configure_lane(rx, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_ufs_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_ufs_configure_lane(qphy->rx2, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_ufs_configure_lane(qphy->rx2, cfg->regs, + cfg->rx_tbl, cfg->rx_tbl_num, 2); } - qcom_qmp_phy_ufs_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_ufs_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); ret = reset_control_deassert(qmp->ufs_reset); if (ret) @@ -1060,7 +983,7 @@ static int qcom_qmp_phy_ufs_power_on(struct phy *phy) return 0; } -static int qcom_qmp_phy_ufs_power_off(struct phy *phy) +static int qmp_ufs_power_off(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -1084,51 +1007,41 @@ static int qcom_qmp_phy_ufs_power_off(struct phy *phy) return 0; } -static int qcom_qmp_phy_ufs_exit(struct phy *phy) +static int qmp_ufs_exit(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); - qcom_qmp_phy_ufs_com_exit(qphy); + qmp_ufs_com_exit(qphy); return 0; } -static int qcom_qmp_phy_ufs_enable(struct phy *phy) +static int qmp_ufs_enable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_ufs_init(phy); + ret = qmp_ufs_init(phy); if (ret) return ret; - ret = qcom_qmp_phy_ufs_power_on(phy); + ret = qmp_ufs_power_on(phy); if (ret) - qcom_qmp_phy_ufs_exit(phy); + qmp_ufs_exit(phy); return ret; } -static int qcom_qmp_phy_ufs_disable(struct phy *phy) +static int qmp_ufs_disable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_ufs_power_off(phy); + ret = qmp_ufs_power_off(phy); if (ret) return ret; - return qcom_qmp_phy_ufs_exit(phy); + return qmp_ufs_exit(phy); } -static int qcom_qmp_phy_ufs_set_mode(struct phy *phy, - enum phy_mode mode, int submode) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - - qphy->mode = mode; - - return 0; -} - -static int qcom_qmp_phy_ufs_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_ufs_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_vregs; @@ -1144,7 +1057,7 @@ static int qcom_qmp_phy_ufs_vreg_init(struct device *dev, const struct qmp_phy_c return devm_regulator_bulk_get(dev, num, qmp->vregs); } -static int qcom_qmp_phy_ufs_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_ufs_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_clks; @@ -1161,14 +1074,12 @@ static int qcom_qmp_phy_ufs_clk_init(struct device *dev, const struct qmp_phy_cf } static const struct phy_ops qcom_qmp_ufs_ops = { - .power_on = qcom_qmp_phy_ufs_enable, - .power_off = qcom_qmp_phy_ufs_disable, - .set_mode = qcom_qmp_phy_ufs_set_mode, + .power_on = qmp_ufs_enable, + .power_off = qmp_ufs_disable, .owner = THIS_MODULE, }; -static -int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id, +static int qmp_ufs_create(struct device *dev, struct device_node *np, int id, void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); @@ -1188,45 +1099,33 @@ int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id, * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 * For single lane PHYs: pcs_misc (optional) -> 3. */ - qphy->tx = of_iomap(np, 0); - if (!qphy->tx) - return -ENOMEM; + qphy->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qphy->tx)) + return PTR_ERR(qphy->tx); - qphy->rx = of_iomap(np, 1); - if (!qphy->rx) - return -ENOMEM; + qphy->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qphy->rx)) + return PTR_ERR(qphy->rx); - qphy->pcs = of_iomap(np, 2); - if (!qphy->pcs) - return -ENOMEM; + qphy->pcs = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qphy->pcs)) + return PTR_ERR(qphy->pcs); - /* - * If this is a dual-lane PHY, then there should be registers for the - * second lane. Some old device trees did not specify this, so fall - * back to old legacy behavior of assuming they can be reached at an - * offset from the first lane. - */ - if (cfg->is_dual_lane_phy) { - qphy->tx2 = of_iomap(np, 3); - qphy->rx2 = of_iomap(np, 4); - if (!qphy->tx2 || !qphy->rx2) { - dev_warn(dev, - "Underspecified device tree, falling back to legacy register regions\n"); + if (cfg->lanes >= 2) { + qphy->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qphy->tx2)) + return PTR_ERR(qphy->tx2); - /* In the old version, pcs_misc is at index 3. */ - qphy->pcs_misc = qphy->tx2; - qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE; - qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE; - - } else { - qphy->pcs_misc = of_iomap(np, 5); - } + qphy->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qphy->rx2)) + return PTR_ERR(qphy->rx2); + qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL); } else { - qphy->pcs_misc = of_iomap(np, 3); + qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL); } - if (!qphy->pcs_misc) + if (IS_ERR(qphy->pcs_misc)) dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); generic_phy = devm_phy_create(dev, np, &qcom_qmp_ufs_ops); @@ -1237,7 +1136,6 @@ int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id, } qphy->phy = generic_phy; - qphy->index = id; qphy->qmp = qmp; qmp->phys[id] = qphy; phy_set_drvdata(generic_phy, qphy); @@ -1245,7 +1143,7 @@ int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id, return 0; } -static const struct of_device_id qcom_qmp_phy_ufs_of_match_table[] = { +static const struct of_device_id qmp_ufs_of_match_table[] = { { .compatible = "qcom,msm8996-qmp-ufs-phy", .data = &msm8996_ufs_cfg, @@ -1282,9 +1180,9 @@ static const struct of_device_id qcom_qmp_phy_ufs_of_match_table[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, qcom_qmp_phy_ufs_of_match_table); +MODULE_DEVICE_TABLE(of, qmp_ufs_of_match_table); -static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev) +static int qmp_ufs_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; @@ -1312,17 +1210,14 @@ static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev) if (IS_ERR(serdes)) return PTR_ERR(serdes); - ret = qcom_qmp_phy_ufs_clk_init(dev, cfg); + ret = qmp_ufs_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_ufs_vreg_init(dev, cfg); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + ret = qmp_ufs_vreg_init(dev, cfg); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ @@ -1333,18 +1228,10 @@ static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev) if (!qmp->phys) return -ENOMEM; - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - /* - * Prevent runtime pm from being ON by default. Users can enable - * it using power/control in sysfs. - */ - pm_runtime_forbid(dev); - id = 0; for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ - ret = qcom_qmp_phy_ufs_create(dev, child, id, serdes, cfg); + ret = qmp_ufs_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -1355,28 +1242,23 @@ static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev) } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (!IS_ERR(phy_provider)) - dev_info(dev, "Registered Qcom-QMP phy\n"); - else - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); err_node_put: - pm_runtime_disable(dev); of_node_put(child); return ret; } -static struct platform_driver qcom_qmp_phy_ufs_driver = { - .probe = qcom_qmp_phy_ufs_probe, +static struct platform_driver qmp_ufs_driver = { + .probe = qmp_ufs_probe, .driver = { .name = "qcom-qmp-ufs-phy", - .of_match_table = qcom_qmp_phy_ufs_of_match_table, + .of_match_table = qmp_ufs_of_match_table, }, }; -module_platform_driver(qcom_qmp_phy_ufs_driver); +module_platform_driver(qmp_ufs_driver); MODULE_AUTHOR("Vivek Gautam "); MODULE_DESCRIPTION("Qualcomm QMP UFS PHY driver"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index 1d270356a97f..b84c0d4b5754 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -28,16 +28,11 @@ #define SW_RESET BIT(0) /* QPHY_POWER_DOWN_CONTROL */ #define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) /* QPHY_START_CONTROL bits */ #define SERDES_START BIT(0) #define PCS_START BIT(1) -#define PLL_READY_GATE_EN BIT(3) /* QPHY_PCS_STATUS bit */ #define PHYSTATUS BIT(6) -#define PHYSTATUS_4_20 BIT(7) -/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */ -#define PCS_READY BIT(0) /* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ /* DP PHY soft reset */ @@ -71,11 +66,6 @@ #define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MAX 11 -#define MAX_PROP_NAME 32 - -/* Define the assumed distance between lanes for underspecified device trees. */ -#define QMP_PHY_LEGACY_LANE_STRIDE 0x400 - struct qmp_phy_init_tbl { unsigned int offset; unsigned int val; @@ -115,15 +105,9 @@ struct qmp_phy_init_tbl { /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { - /* Common block control registers */ - QPHY_COM_SW_RESET, - QPHY_COM_POWER_DOWN_CONTROL, - QPHY_COM_START_CONTROL, - QPHY_COM_PCS_READY_STATUS, /* PCS registers */ QPHY_SW_RESET, QPHY_START_CTRL, - QPHY_PCS_READY_STATUS, QPHY_PCS_STATUS, QPHY_PCS_AUTONOMOUS_MODE_CTRL, QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, @@ -1338,14 +1322,114 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), }; -struct qmp_phy; +static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE2_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE1_MODE1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_ENABLES, 0x00), +}; + +static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG5, 0x10), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x21), +}; /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - /* phy-type - PCIE/UFS/USB */ - unsigned int type; - /* number of lanes provided by phy */ - int nlanes; + int lanes; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_init_tbl *serdes_tbl; @@ -1385,8 +1469,6 @@ struct qmp_phy_cfg { /* true, if PHY has a separate DP_COM control block */ bool has_phy_dp_com_ctrl; - /* true, if PHY has secondary tx/rx lanes to be configured */ - bool is_dual_lane_phy; /* Offset from PCS to PCS_USB region */ unsigned int pcs_usb_offset; @@ -1406,7 +1488,6 @@ struct qmp_phy_cfg { * @pcs_misc: iomapped memory space for lane's pcs_misc * @pcs_usb: iomapped memory space for lane's pcs_usb * @pipe_clk: pipe clock - * @index: lane index * @qmp: QMP phy to which this lane belongs * @mode: current PHY mode */ @@ -1422,7 +1503,6 @@ struct qmp_phy { void __iomem *pcs_misc; void __iomem *pcs_usb; struct clk *pipe_clk; - unsigned int index; struct qcom_qmp *qmp; enum phy_mode mode; }; @@ -1520,8 +1600,7 @@ static const char * const qmp_phy_vreg_l[] = { }; static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = ipq8074_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(ipq8074_usb3_serdes_tbl), @@ -1545,8 +1624,7 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { }; static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = msm8996_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8996_usb3_serdes_tbl), @@ -1570,8 +1648,7 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { }; static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), @@ -1598,12 +1675,10 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), @@ -1630,12 +1705,38 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, +}; + +static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { + .lanes = 1, + + .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl), + .tx_tbl = sc8280xp_usb3_uniphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_tx_tbl), + .rx_tbl = sc8280xp_usb3_uniphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_rx_tbl), + .pcs_tbl = sc8280xp_usb3_uniphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_pcs_tbl), + .clk_list = qmp_v4_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + + .start_ctrl = SERDES_START | PCS_START, + .pwrdn_ctrl = SW_PWRDN, + .phy_status = PHYSTATUS, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, + .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = qmp_v3_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_serdes_tbl), @@ -1663,8 +1764,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = msm8998_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), @@ -1685,13 +1785,10 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .start_ctrl = SERDES_START | PCS_START, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), @@ -1722,12 +1819,10 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), @@ -1758,8 +1853,7 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), @@ -1789,12 +1883,10 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), @@ -1825,8 +1917,7 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), @@ -1857,8 +1948,7 @@ static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), @@ -1889,8 +1979,7 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8350_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), @@ -1920,12 +2009,10 @@ static const struct qmp_phy_cfg sm8350_usb3phy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, .has_phy_dp_com_ctrl = true, - .is_dual_lane_phy = true, }; static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 1, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), @@ -1956,8 +2043,7 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { - .type = PHY_TYPE_USB3, - .nlanes = 1, + .lanes = 2, .serdes_tbl = qcm2290_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), @@ -1978,11 +2064,9 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { .start_ctrl = SERDES_START | PCS_START, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS, - - .is_dual_lane_phy = true, }; -static void qcom_qmp_phy_usb_configure_lane(void __iomem *base, +static void qmp_usb_configure_lane(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num, @@ -2005,28 +2089,29 @@ static void qcom_qmp_phy_usb_configure_lane(void __iomem *base, } } -static void qcom_qmp_phy_usb_configure(void __iomem *base, +static void qmp_usb_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], int num) { - qcom_qmp_phy_usb_configure_lane(base, regs, tbl, num, 0xff); + qmp_usb_configure_lane(base, regs, tbl, num, 0xff); } -static int qcom_qmp_phy_usb_serdes_init(struct qmp_phy *qphy) +static int qmp_usb_serdes_init(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *serdes = qphy->serdes; const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qcom_qmp_phy_usb_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); + qmp_usb_configure(serdes, cfg->regs, serdes_tbl, serdes_tbl_num); return 0; } -static int qcom_qmp_phy_usb_com_init(struct qmp_phy *qphy) +static int qmp_usb_init(struct phy *phy) { + struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs = qphy->pcs; @@ -2097,8 +2182,9 @@ err_disable_regulators: return ret; } -static int qcom_qmp_phy_usb_com_exit(struct qmp_phy *qphy) +static int qmp_usb_exit(struct phy *phy) { + struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -2111,21 +2197,7 @@ static int qcom_qmp_phy_usb_com_exit(struct qmp_phy *qphy) return 0; } -static int qcom_qmp_phy_usb_init(struct phy *phy) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - struct qcom_qmp *qmp = qphy->qmp; - int ret; - dev_vdbg(qmp->dev, "Initializing QMP phy\n"); - - ret = qcom_qmp_phy_usb_com_init(qphy); - if (ret) - return ret; - - return 0; -} - -static int qcom_qmp_phy_usb_power_on(struct phy *phy) +static int qmp_usb_power_on(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; @@ -2137,7 +2209,7 @@ static int qcom_qmp_phy_usb_power_on(struct phy *phy) unsigned int mask, val, ready; int ret; - qcom_qmp_phy_usb_serdes_init(qphy); + qmp_usb_serdes_init(qphy); ret = clk_prepare_enable(qphy->pipe_clk); if (ret) { @@ -2146,25 +2218,22 @@ static int qcom_qmp_phy_usb_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qcom_qmp_phy_usb_configure_lane(tx, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_usb_configure_lane(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num, 1); - /* Configuration for other LANE for USB-DP combo PHY */ - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_usb_configure_lane(qphy->tx2, cfg->regs, - cfg->tx_tbl, cfg->tx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_usb_configure_lane(qphy->tx2, cfg->regs, + cfg->tx_tbl, cfg->tx_tbl_num, 2); } - qcom_qmp_phy_usb_configure_lane(rx, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_usb_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->is_dual_lane_phy) { - qcom_qmp_phy_usb_configure_lane(qphy->rx2, cfg->regs, - cfg->rx_tbl, cfg->rx_tbl_num, 2); + if (cfg->lanes >= 2) { + qmp_usb_configure_lane(qphy->rx2, cfg->regs, + cfg->rx_tbl, cfg->rx_tbl_num, 2); } /* Configure link rate, swing, etc. */ - qcom_qmp_phy_usb_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_usb_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); @@ -2194,7 +2263,7 @@ err_disable_pipe_clk: return ret; } -static int qcom_qmp_phy_usb_power_off(struct phy *phy) +static int qmp_usb_power_off(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qphy->cfg; @@ -2219,42 +2288,32 @@ static int qcom_qmp_phy_usb_power_off(struct phy *phy) return 0; } -static int qcom_qmp_phy_usb_exit(struct phy *phy) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - - qcom_qmp_phy_usb_com_exit(qphy); - - return 0; -} - -static int qcom_qmp_phy_usb_enable(struct phy *phy) +static int qmp_usb_enable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_usb_init(phy); + ret = qmp_usb_init(phy); if (ret) return ret; - ret = qcom_qmp_phy_usb_power_on(phy); + ret = qmp_usb_power_on(phy); if (ret) - qcom_qmp_phy_usb_exit(phy); + qmp_usb_exit(phy); return ret; } -static int qcom_qmp_phy_usb_disable(struct phy *phy) +static int qmp_usb_disable(struct phy *phy) { int ret; - ret = qcom_qmp_phy_usb_power_off(phy); + ret = qmp_usb_power_off(phy); if (ret) return ret; - return qcom_qmp_phy_usb_exit(phy); + return qmp_usb_exit(phy); } -static int qcom_qmp_phy_usb_set_mode(struct phy *phy, - enum phy_mode mode, int submode) +static int qmp_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_phy *qphy = phy_get_drvdata(phy); @@ -2263,7 +2322,7 @@ static int qcom_qmp_phy_usb_set_mode(struct phy *phy, return 0; } -static void qcom_qmp_phy_usb_enable_autonomous_mode(struct qmp_phy *qphy) +static void qmp_usb_enable_autonomous_mode(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs; @@ -2292,7 +2351,7 @@ static void qcom_qmp_phy_usb_enable_autonomous_mode(struct qmp_phy *qphy) qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN); } -static void qcom_qmp_phy_usb_disable_autonomous_mode(struct qmp_phy *qphy) +static void qmp_usb_disable_autonomous_mode(struct qmp_phy *qphy) { const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs_usb = qphy->pcs_usb ?: qphy->pcs; @@ -2310,7 +2369,7 @@ static void qcom_qmp_phy_usb_disable_autonomous_mode(struct qmp_phy *qphy) qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); } -static int __maybe_unused qcom_qmp_phy_usb_runtime_suspend(struct device *dev) +static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; @@ -2318,16 +2377,12 @@ static int __maybe_unused qcom_qmp_phy_usb_runtime_suspend(struct device *dev) dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qphy->mode); - /* Supported only for USB3 PHY and luckily USB3 is the first phy */ - if (cfg->type != PHY_TYPE_USB3) - return 0; - if (!qphy->phy->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; } - qcom_qmp_phy_usb_enable_autonomous_mode(qphy); + qmp_usb_enable_autonomous_mode(qphy); clk_disable_unprepare(qphy->pipe_clk); clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); @@ -2335,7 +2390,7 @@ static int __maybe_unused qcom_qmp_phy_usb_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused qcom_qmp_phy_usb_runtime_resume(struct device *dev) +static int __maybe_unused qmp_usb_runtime_resume(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; @@ -2344,10 +2399,6 @@ static int __maybe_unused qcom_qmp_phy_usb_runtime_resume(struct device *dev) dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qphy->mode); - /* Supported only for USB3 PHY and luckily USB3 is the first phy */ - if (cfg->type != PHY_TYPE_USB3) - return 0; - if (!qphy->phy->init_count) { dev_vdbg(dev, "PHY not initialized, bailing out\n"); return 0; @@ -2364,12 +2415,12 @@ static int __maybe_unused qcom_qmp_phy_usb_runtime_resume(struct device *dev) return ret; } - qcom_qmp_phy_usb_disable_autonomous_mode(qphy); + qmp_usb_disable_autonomous_mode(qphy); return 0; } -static int qcom_qmp_phy_usb_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_usb_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_vregs; @@ -2385,7 +2436,7 @@ static int qcom_qmp_phy_usb_vreg_init(struct device *dev, const struct qmp_phy_c return devm_regulator_bulk_get(dev, num, qmp->vregs); } -static int qcom_qmp_phy_usb_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_usb_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int i; @@ -2406,7 +2457,7 @@ static int qcom_qmp_phy_usb_reset_init(struct device *dev, const struct qmp_phy_ return 0; } -static int qcom_qmp_phy_usb_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) +static int qmp_usb_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int num = cfg->num_clks; @@ -2482,23 +2533,47 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } -static const struct phy_ops qcom_qmp_phy_usb_ops = { - .init = qcom_qmp_phy_usb_enable, - .exit = qcom_qmp_phy_usb_disable, - .set_mode = qcom_qmp_phy_usb_set_mode, +static const struct phy_ops qmp_usb_ops = { + .init = qmp_usb_enable, + .exit = qmp_usb_disable, + .set_mode = qmp_usb_set_mode, .owner = THIS_MODULE, }; +static void __iomem *qmp_usb_iomap(struct device *dev, struct device_node *np, + int index, bool exclusive) +{ + struct resource res; + + if (!exclusive) { + if (of_address_to_resource(np, index, &res)) + return IOMEM_ERR_PTR(-EINVAL); + + return devm_ioremap(dev, res.start, resource_size(&res)); + } + + return devm_of_iomap(dev, np, index, NULL); +} + static -int qcom_qmp_phy_usb_create(struct device *dev, struct device_node *np, int id, +int qmp_usb_create(struct device *dev, struct device_node *np, int id, void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct phy *generic_phy; struct qmp_phy *qphy; - char prop_name[MAX_PROP_NAME]; + bool exclusive = true; int ret; + /* + * FIXME: These bindings should be fixed to not rely on overlapping + * mappings for PCS. + */ + if (of_device_is_compatible(dev->of_node, "qcom,sdx65-qmp-usb3-uni-phy")) + exclusive = false; + if (of_device_is_compatible(dev->of_node, "qcom,sm8350-qmp-usb3-uni-phy")) + exclusive = false; + qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); if (!qphy) return -ENOMEM; @@ -2511,58 +2586,47 @@ int qcom_qmp_phy_usb_create(struct device *dev, struct device_node *np, int id, * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 * For single lane PHYs: pcs_misc (optional) -> 3. */ - qphy->tx = of_iomap(np, 0); - if (!qphy->tx) - return -ENOMEM; + qphy->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qphy->tx)) + return PTR_ERR(qphy->tx); - qphy->rx = of_iomap(np, 1); - if (!qphy->rx) - return -ENOMEM; + qphy->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qphy->rx)) + return PTR_ERR(qphy->rx); - qphy->pcs = of_iomap(np, 2); - if (!qphy->pcs) - return -ENOMEM; + qphy->pcs = qmp_usb_iomap(dev, np, 2, exclusive); + if (IS_ERR(qphy->pcs)) + return PTR_ERR(qphy->pcs); if (cfg->pcs_usb_offset) qphy->pcs_usb = qphy->pcs + cfg->pcs_usb_offset; - /* - * If this is a dual-lane PHY, then there should be registers for the - * second lane. Some old device trees did not specify this, so fall - * back to old legacy behavior of assuming they can be reached at an - * offset from the first lane. - */ - if (cfg->is_dual_lane_phy) { - qphy->tx2 = of_iomap(np, 3); - qphy->rx2 = of_iomap(np, 4); - if (!qphy->tx2 || !qphy->rx2) { - dev_warn(dev, - "Underspecified device tree, falling back to legacy register regions\n"); + if (cfg->lanes >= 2) { + qphy->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qphy->tx2)) + return PTR_ERR(qphy->tx2); - /* In the old version, pcs_misc is at index 3. */ - qphy->pcs_misc = qphy->tx2; - qphy->tx2 = qphy->tx + QMP_PHY_LEGACY_LANE_STRIDE; - qphy->rx2 = qphy->rx + QMP_PHY_LEGACY_LANE_STRIDE; - - } else { - qphy->pcs_misc = of_iomap(np, 5); - } + qphy->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qphy->rx2)) + return PTR_ERR(qphy->rx2); + qphy->pcs_misc = devm_of_iomap(dev, np, 5, NULL); } else { - qphy->pcs_misc = of_iomap(np, 3); + qphy->pcs_misc = devm_of_iomap(dev, np, 3, NULL); } - if (!qphy->pcs_misc) + if (IS_ERR(qphy->pcs_misc)) { dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); + qphy->pcs_misc = NULL; + } - snprintf(prop_name, sizeof(prop_name), "pipe%d", id); - qphy->pipe_clk = devm_get_clk_from_child(dev, np, prop_name); + qphy->pipe_clk = devm_get_clk_from_child(dev, np, NULL); if (IS_ERR(qphy->pipe_clk)) { return dev_err_probe(dev, PTR_ERR(qphy->pipe_clk), "failed to get lane%d pipe clock\n", id); } - generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_usb_ops); + generic_phy = devm_phy_create(dev, np, &qmp_usb_ops); if (IS_ERR(generic_phy)) { ret = PTR_ERR(generic_phy); dev_err(dev, "failed to create qphy %d\n", ret); @@ -2570,7 +2634,6 @@ int qcom_qmp_phy_usb_create(struct device *dev, struct device_node *np, int id, } qphy->phy = generic_phy; - qphy->index = id; qphy->qmp = qmp; qmp->phys[id] = qphy; phy_set_drvdata(generic_phy, qphy); @@ -2578,7 +2641,7 @@ int qcom_qmp_phy_usb_create(struct device *dev, struct device_node *np, int id, return 0; } -static const struct of_device_id qcom_qmp_phy_usb_of_match_table[] = { +static const struct of_device_id qmp_usb_of_match_table[] = { { .compatible = "qcom,ipq8074-qmp-usb3-phy", .data = &ipq8074_usb3phy_cfg, @@ -2594,6 +2657,9 @@ static const struct of_device_id qcom_qmp_phy_usb_of_match_table[] = { }, { .compatible = "qcom,sc8180x-qmp-usb3-phy", .data = &sm8150_usb3phy_cfg, + }, { + .compatible = "qcom,sc8280xp-qmp-usb3-uni-phy", + .data = &sc8280xp_usb3_uniphy_cfg, }, { .compatible = "qcom,sdm845-qmp-usb3-phy", .data = &qmp_v3_usb3phy_cfg, @@ -2636,14 +2702,14 @@ static const struct of_device_id qcom_qmp_phy_usb_of_match_table[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, qcom_qmp_phy_usb_of_match_table); +MODULE_DEVICE_TABLE(of, qmp_usb_of_match_table); -static const struct dev_pm_ops qcom_qmp_phy_usb_pm_ops = { - SET_RUNTIME_PM_OPS(qcom_qmp_phy_usb_runtime_suspend, - qcom_qmp_phy_usb_runtime_resume, NULL) +static const struct dev_pm_ops qmp_usb_pm_ops = { + SET_RUNTIME_PM_OPS(qmp_usb_runtime_suspend, + qmp_usb_runtime_resume, NULL) }; -static int qcom_qmp_phy_usb_probe(struct platform_device *pdev) +static int qmp_usb_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; @@ -2678,21 +2744,18 @@ static int qcom_qmp_phy_usb_probe(struct platform_device *pdev) return PTR_ERR(qmp->dp_com); } - ret = qcom_qmp_phy_usb_clk_init(dev, cfg); + ret = qmp_usb_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_usb_reset_init(dev, cfg); + ret = qmp_usb_reset_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_usb_vreg_init(dev, cfg); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + ret = qmp_usb_vreg_init(dev, cfg); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ @@ -2704,7 +2767,9 @@ static int qcom_qmp_phy_usb_probe(struct platform_device *pdev) return -ENOMEM; pm_runtime_set_active(dev); - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; /* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs. @@ -2714,7 +2779,7 @@ static int qcom_qmp_phy_usb_probe(struct platform_device *pdev) id = 0; for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ - ret = qcom_qmp_phy_usb_create(dev, child, id, serdes, cfg); + ret = qmp_usb_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -2736,29 +2801,24 @@ static int qcom_qmp_phy_usb_probe(struct platform_device *pdev) } phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (!IS_ERR(phy_provider)) - dev_info(dev, "Registered Qcom-QMP phy\n"); - else - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); err_node_put: - pm_runtime_disable(dev); of_node_put(child); return ret; } -static struct platform_driver qcom_qmp_phy_usb_driver = { - .probe = qcom_qmp_phy_usb_probe, +static struct platform_driver qmp_usb_driver = { + .probe = qmp_usb_probe, .driver = { .name = "qcom-qmp-usb-phy", - .pm = &qcom_qmp_phy_usb_pm_ops, - .of_match_table = qcom_qmp_phy_usb_of_match_table, + .pm = &qmp_usb_pm_ops, + .of_match_table = qmp_usb_of_match_table, }, }; -module_platform_driver(qcom_qmp_phy_usb_driver); +module_platform_driver(qmp_usb_driver); MODULE_AUTHOR("Vivek Gautam "); MODULE_DESCRIPTION("Qualcomm QMP USB PHY driver"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index b139c8af5e8b..26274e3c0cf9 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -19,6 +19,7 @@ #include "phy-qcom-qmp-qserdes-com-v5.h" #include "phy-qcom-qmp-qserdes-txrx-v5.h" #include "phy-qcom-qmp-qserdes-txrx-v5_20.h" +#include "phy-qcom-qmp-qserdes-txrx-v5_5nm.h" #include "phy-qcom-qmp-qserdes-pll.h" diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index 7529a7e6e5df..2ef638b32e8f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -973,20 +973,14 @@ static int qusb2_phy_probe(struct platform_device *pdev) return PTR_ERR(qphy->base); qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb"); - if (IS_ERR(qphy->cfg_ahb_clk)) { - ret = PTR_ERR(qphy->cfg_ahb_clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get cfg ahb clk, %d\n", ret); - return ret; - } + if (IS_ERR(qphy->cfg_ahb_clk)) + return dev_err_probe(dev, PTR_ERR(qphy->cfg_ahb_clk), + "failed to get cfg ahb clk\n"); qphy->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(qphy->ref_clk)) { - ret = PTR_ERR(qphy->ref_clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get ref clk, %d\n", ret); - return ret; - } + if (IS_ERR(qphy->ref_clk)) + return dev_err_probe(dev, PTR_ERR(qphy->ref_clk), + "failed to get ref clk\n"); qphy->iface_clk = devm_clk_get_optional(dev, "iface"); if (IS_ERR(qphy->iface_clk)) @@ -1003,12 +997,9 @@ static int qusb2_phy_probe(struct platform_device *pdev) qphy->vregs[i].supply = qusb2_phy_vreg_names[i]; ret = devm_regulator_bulk_get(dev, num, qphy->vregs); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); /* Get the specific init parameters of QMP phy */ qphy->cfg = of_device_get_match_data(dev); diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c index 5d203784f75d..a59063596214 100644 --- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c @@ -52,6 +52,12 @@ #define USB2_SUSPEND_N BIT(2) #define USB2_SUSPEND_N_SEL BIT(3) +#define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0 (0x6c) +#define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1 (0x70) +#define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2 (0x74) +#define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3 (0x78) +#define PARAM_OVRD_MASK 0xFF + #define USB2_PHY_USB_PHY_CFG0 (0x94) #define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0) #define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1) @@ -60,12 +66,47 @@ #define REFCLK_SEL_MASK GENMASK(1, 0) #define REFCLK_SEL_DEFAULT (0x2 << 0) +#define HS_DISCONNECT_MASK GENMASK(2, 0) +#define SQUELCH_DETECTOR_MASK GENMASK(7, 5) + +#define HS_AMPLITUDE_MASK GENMASK(3, 0) +#define PREEMPHASIS_DURATION_MASK BIT(5) +#define PREEMPHASIS_AMPLITUDE_MASK GENMASK(7, 6) + +#define HS_RISE_FALL_MASK GENMASK(1, 0) +#define HS_CROSSOVER_VOLTAGE_MASK GENMASK(3, 2) +#define HS_OUTPUT_IMPEDANCE_MASK GENMASK(5, 4) + +#define LS_FS_OUTPUT_IMPEDANCE_MASK GENMASK(3, 0) + static const char * const qcom_snps_hsphy_vreg_names[] = { "vdda-pll", "vdda33", "vdda18", }; #define SNPS_HS_NUM_VREGS ARRAY_SIZE(qcom_snps_hsphy_vreg_names) +struct override_param { + s32 value; + u8 reg_val; +}; + +struct override_param_map { + const char *prop_name; + const struct override_param *param_table; + u8 table_size; + u8 reg_offset; + u8 param_mask; +}; + +struct phy_override_seq { + bool need_update; + u8 offset; + u8 value; + u8 mask; +}; + +#define NUM_HSPHY_TUNING_PARAMS (9) + /** * struct qcom_snps_hsphy - snps hs phy attributes * @@ -91,6 +132,7 @@ struct qcom_snps_hsphy { bool phy_initialized; enum phy_mode mode; + struct phy_override_seq update_seq_cfg[NUM_HSPHY_TUNING_PARAMS]; }; static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, @@ -173,10 +215,158 @@ static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode, return 0; } +static const struct override_param hs_disconnect_sc7280[] = { + { -272, 0 }, + { 0, 1 }, + { 317, 2 }, + { 630, 3 }, + { 973, 4 }, + { 1332, 5 }, + { 1743, 6 }, + { 2156, 7 }, +}; + +static const struct override_param squelch_det_threshold_sc7280[] = { + { -2090, 7 }, + { -1560, 6 }, + { -1030, 5 }, + { -530, 4 }, + { 0, 3 }, + { 530, 2 }, + { 1060, 1 }, + { 1590, 0 }, +}; + +static const struct override_param hs_amplitude_sc7280[] = { + { -660, 0 }, + { -440, 1 }, + { -220, 2 }, + { 0, 3 }, + { 230, 4 }, + { 440, 5 }, + { 650, 6 }, + { 890, 7 }, + { 1110, 8 }, + { 1330, 9 }, + { 1560, 10 }, + { 1780, 11 }, + { 2000, 12 }, + { 2220, 13 }, + { 2430, 14 }, + { 2670, 15 }, +}; + +static const struct override_param preemphasis_duration_sc7280[] = { + { 10000, 1 }, + { 20000, 0 }, +}; + +static const struct override_param preemphasis_amplitude_sc7280[] = { + { 10000, 1 }, + { 20000, 2 }, + { 30000, 3 }, + { 40000, 0 }, +}; + +static const struct override_param hs_rise_fall_time_sc7280[] = { + { -4100, 3 }, + { 0, 2 }, + { 2810, 1 }, + { 5430, 0 }, +}; + +static const struct override_param hs_crossover_voltage_sc7280[] = { + { -31000, 1 }, + { 0, 3 }, + { 28000, 2 }, +}; + +static const struct override_param hs_output_impedance_sc7280[] = { + { -2300000, 3 }, + { 0, 2 }, + { 2600000, 1 }, + { 6100000, 0 }, +}; + +static const struct override_param ls_fs_output_impedance_sc7280[] = { + { -1053, 15 }, + { -557, 7 }, + { 0, 3 }, + { 612, 1 }, + { 1310, 0 }, +}; + +static const struct override_param_map sc7280_snps_7nm_phy[] = { + { + "qcom,hs-disconnect-bp", + hs_disconnect_sc7280, + ARRAY_SIZE(hs_disconnect_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0, + HS_DISCONNECT_MASK + }, + { + "qcom,squelch-detector-bp", + squelch_det_threshold_sc7280, + ARRAY_SIZE(squelch_det_threshold_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0, + SQUELCH_DETECTOR_MASK + }, + { + "qcom,hs-amplitude-bp", + hs_amplitude_sc7280, + ARRAY_SIZE(hs_amplitude_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, + HS_AMPLITUDE_MASK + }, + { + "qcom,pre-emphasis-duration-bp", + preemphasis_duration_sc7280, + ARRAY_SIZE(preemphasis_duration_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, + PREEMPHASIS_DURATION_MASK, + }, + { + "qcom,pre-emphasis-amplitude-bp", + preemphasis_amplitude_sc7280, + ARRAY_SIZE(preemphasis_amplitude_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1, + PREEMPHASIS_AMPLITUDE_MASK, + }, + { + "qcom,hs-rise-fall-time-bp", + hs_rise_fall_time_sc7280, + ARRAY_SIZE(hs_rise_fall_time_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, + HS_RISE_FALL_MASK + }, + { + "qcom,hs-crossover-voltage-microvolt", + hs_crossover_voltage_sc7280, + ARRAY_SIZE(hs_crossover_voltage_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, + HS_CROSSOVER_VOLTAGE_MASK + }, + { + "qcom,hs-output-impedance-micro-ohms", + hs_output_impedance_sc7280, + ARRAY_SIZE(hs_output_impedance_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2, + HS_OUTPUT_IMPEDANCE_MASK, + }, + { + "qcom,ls-fs-output-impedance-bp", + ls_fs_output_impedance_sc7280, + ARRAY_SIZE(ls_fs_output_impedance_sc7280), + USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3, + LS_FS_OUTPUT_IMPEDANCE_MASK, + }, + {}, +}; + static int qcom_snps_hsphy_init(struct phy *phy) { struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); - int ret; + int ret, i; dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__); @@ -223,6 +413,14 @@ static int qcom_snps_hsphy_init(struct phy *phy) qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1, VBUSVLDEXT0, VBUSVLDEXT0); + for (i = 0; i < ARRAY_SIZE(hsphy->update_seq_cfg); i++) { + if (hsphy->update_seq_cfg[i].need_update) + qcom_snps_hsphy_write_mask(hsphy->base, + hsphy->update_seq_cfg[i].offset, + hsphy->update_seq_cfg[i].mask, + hsphy->update_seq_cfg[i].value); + } + qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2, VREGBYPASS, VREGBYPASS); @@ -280,7 +478,10 @@ static const struct phy_ops qcom_snps_hsphy_gen_ops = { static const struct of_device_id qcom_snps_hsphy_of_match_table[] = { { .compatible = "qcom,sm8150-usb-hs-phy", }, { .compatible = "qcom,usb-snps-hs-5nm-phy", }, - { .compatible = "qcom,usb-snps-hs-7nm-phy", }, + { + .compatible = "qcom,usb-snps-hs-7nm-phy", + .data = &sc7280_snps_7nm_phy, + }, { .compatible = "qcom,usb-snps-femto-v2-phy", }, { } }; @@ -291,6 +492,55 @@ static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = { qcom_snps_hsphy_runtime_resume, NULL) }; +static void qcom_snps_hsphy_override_param_update_val( + const struct override_param_map map, + s32 dt_val, struct phy_override_seq *seq_entry) +{ + int i; + + /* + * Param table for each param is in increasing order + * of dt values. We need to iterate over the list to + * select the entry that matches the dt value and pick + * up the corresponding register value. + */ + for (i = 0; i < map.table_size - 1; i++) { + if (map.param_table[i].value == dt_val) + break; + } + + seq_entry->need_update = true; + seq_entry->offset = map.reg_offset; + seq_entry->mask = map.param_mask; + seq_entry->value = map.param_table[i].reg_val << __ffs(map.param_mask); +} + +static void qcom_snps_hsphy_read_override_param_seq(struct device *dev) +{ + struct device_node *node = dev->of_node; + s32 val; + int ret, i; + struct qcom_snps_hsphy *hsphy; + const struct override_param_map *cfg = of_device_get_match_data(dev); + + if (!cfg) + return; + + hsphy = dev_get_drvdata(dev); + + for (i = 0; cfg[i].prop_name != NULL; i++) { + ret = of_property_read_s32(node, cfg[i].prop_name, &val); + if (ret) + continue; + + qcom_snps_hsphy_override_param_update_val(cfg[i], val, + &hsphy->update_seq_cfg[i]); + dev_dbg(&hsphy->phy->dev, "Read param: %s dt_val: %d reg_val: 0x%x\n", + cfg[i].prop_name, val, hsphy->update_seq_cfg[i].value); + + } +} + static int qcom_snps_hsphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -309,12 +559,9 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) return PTR_ERR(hsphy->base); hsphy->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(hsphy->ref_clk)) { - ret = PTR_ERR(hsphy->ref_clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get ref clk, %d\n", ret); - return ret; - } + if (IS_ERR(hsphy->ref_clk)) + return dev_err_probe(dev, PTR_ERR(hsphy->ref_clk), + "failed to get ref clk\n"); hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(hsphy->phy_reset)) { @@ -327,12 +574,9 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i]; ret = devm_regulator_bulk_get(dev, num, hsphy->vregs); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get regulator supplies: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -352,6 +596,7 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) dev_set_drvdata(dev, hsphy); phy_set_drvdata(generic_phy, hsphy); + qcom_snps_hsphy_read_override_param_seq(dev); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (!IS_ERR(phy_provider)) diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c index 716a77748ed8..20f6dd37c7c1 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hsic.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c @@ -54,8 +54,10 @@ static int qcom_usb_hsic_phy_power_on(struct phy *phy) /* Configure pins for HSIC functionality */ pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT); - if (IS_ERR(pins_default)) - return PTR_ERR(pins_default); + if (IS_ERR(pins_default)) { + ret = PTR_ERR(pins_default); + goto err_ulpi; + } ret = pinctrl_select_state(uphy->pctl, pins_default); if (ret) diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 9022e395c056..94360fc96a6f 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -83,6 +83,15 @@ config PHY_ROCKCHIP_PCIE help Enable this to support the Rockchip PCIe PHY. +config PHY_ROCKCHIP_SNPS_PCIE3 + tristate "Rockchip Snps PCIe3 PHY Driver" + depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST + depends on HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the Rockchip snps PCIe3 PHY. + config PHY_ROCKCHIP_TYPEC tristate "Rockchip TYPEC PHY Driver" depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index a5041efb5b8f..7eab129230d1 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o +obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index ca13a604ab4f..75f948bdea6a 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -27,6 +27,9 @@ #define RK3368_GRF_SOC_CON6_OFFSET 0x0418 +#define RK3568_GRF_VI_CON0 0x0340 +#define RK3568_GRF_VI_CON1 0x0344 + /* PHY */ #define CSIDPHY_CTRL_LANE_ENABLE 0x00 #define CSIDPHY_CTRL_LANE_ENABLE_CK BIT(6) @@ -58,9 +61,11 @@ #define RK1808_CSIDPHY_CLK_WR_THS_SETTLE 0x160 #define RK3326_CSIDPHY_CLK_WR_THS_SETTLE 0x100 #define RK3368_CSIDPHY_CLK_WR_THS_SETTLE 0x100 +#define RK3568_CSIDPHY_CLK_WR_THS_SETTLE 0x160 /* Calibration reception enable */ #define RK1808_CSIDPHY_CLK_CALIB_EN 0x168 +#define RK3568_CSIDPHY_CLK_CALIB_EN 0x168 /* * The higher 16-bit of this register is used for write protection @@ -103,6 +108,12 @@ static const struct dphy_reg rk3368_grf_dphy_regs[] = { [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8), }; +static const struct dphy_reg rk3568_grf_dphy_regs[] = { + [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3568_GRF_VI_CON0, 4, 0), + [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3568_GRF_VI_CON0, 4, 4), + [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3568_GRF_VI_CON0, 1, 8), +}; + struct hsfreq_range { u32 range_h; u8 cfg_bit; @@ -352,6 +363,15 @@ static const struct dphy_drv_data rk3368_mipidphy_drv_data = { .grf_regs = rk3368_grf_dphy_regs, }; +static const struct dphy_drv_data rk3568_mipidphy_drv_data = { + .pwrctl_offset = -1, + .ths_settle_offset = RK3568_CSIDPHY_CLK_WR_THS_SETTLE, + .calib_offset = RK3568_CSIDPHY_CLK_CALIB_EN, + .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges, + .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges), + .grf_regs = rk3568_grf_dphy_regs, +}; + static const struct of_device_id rockchip_inno_csidphy_match_id[] = { { .compatible = "rockchip,px30-csi-dphy", @@ -369,6 +389,10 @@ static const struct of_device_id rockchip_inno_csidphy_match_id[] = { .compatible = "rockchip,rk3368-csi-dphy", .data = &rk3368_mipidphy_drv_data, }, + { + .compatible = "rockchip,rk3568-csi-dphy", + .data = &rk3568_mipidphy_drv_data, + }, {} }; MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c index 630e01b5c19b..2c5847faff63 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -84,9 +84,25 @@ #define DATA_LANE_0_SKEW_PHASE_MASK GENMASK(2, 0) #define DATA_LANE_0_SKEW_PHASE(x) UPDATE(x, 2, 0) /* Analog Register Part: reg08 */ +#define PLL_POST_DIV_ENABLE_MASK BIT(5) +#define PLL_POST_DIV_ENABLE BIT(5) #define SAMPLE_CLOCK_DIRECTION_MASK BIT(4) #define SAMPLE_CLOCK_DIRECTION_REVERSE BIT(4) #define SAMPLE_CLOCK_DIRECTION_FORWARD 0 +#define LOWFRE_EN_MASK BIT(5) +#define PLL_OUTPUT_FREQUENCY_DIV_BY_1 0 +#define PLL_OUTPUT_FREQUENCY_DIV_BY_2 1 +/* Analog Register Part: reg0b */ +#define CLOCK_LANE_VOD_RANGE_SET_MASK GENMASK(3, 0) +#define CLOCK_LANE_VOD_RANGE_SET(x) UPDATE(x, 3, 0) +#define VOD_MIN_RANGE 0x1 +#define VOD_MID_RANGE 0x3 +#define VOD_BIG_RANGE 0x7 +#define VOD_MAX_RANGE 0xf +/* Analog Register Part: reg1E */ +#define PLL_MODE_SEL_MASK GENMASK(6, 5) +#define PLL_MODE_SEL_LVDS_MODE 0 +#define PLL_MODE_SEL_MIPI_MODE BIT(5) /* Digital Register Part: reg00 */ #define REG_DIG_RSTN_MASK BIT(0) #define REG_DIG_RSTN_NORMAL BIT(0) @@ -102,20 +118,22 @@ #define T_LPX_CNT_MASK GENMASK(5, 0) #define T_LPX_CNT(x) UPDATE(x, 5, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg06 */ +#define T_HS_ZERO_CNT_HI_MASK BIT(7) +#define T_HS_ZERO_CNT_HI(x) UPDATE(x, 7, 7) #define T_HS_PREPARE_CNT_MASK GENMASK(6, 0) #define T_HS_PREPARE_CNT(x) UPDATE(x, 6, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg07 */ -#define T_HS_ZERO_CNT_MASK GENMASK(5, 0) -#define T_HS_ZERO_CNT(x) UPDATE(x, 5, 0) +#define T_HS_ZERO_CNT_LO_MASK GENMASK(5, 0) +#define T_HS_ZERO_CNT_LO(x) UPDATE(x, 5, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg08 */ #define T_HS_TRAIL_CNT_MASK GENMASK(6, 0) #define T_HS_TRAIL_CNT(x) UPDATE(x, 6, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg09 */ -#define T_HS_EXIT_CNT_MASK GENMASK(4, 0) -#define T_HS_EXIT_CNT(x) UPDATE(x, 4, 0) +#define T_HS_EXIT_CNT_LO_MASK GENMASK(4, 0) +#define T_HS_EXIT_CNT_LO(x) UPDATE(x, 4, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0a */ -#define T_CLK_POST_CNT_MASK GENMASK(3, 0) -#define T_CLK_POST_CNT(x) UPDATE(x, 3, 0) +#define T_CLK_POST_CNT_LO_MASK GENMASK(3, 0) +#define T_CLK_POST_CNT_LO(x) UPDATE(x, 3, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0c */ #define LPDT_TX_PPI_SYNC_MASK BIT(2) #define LPDT_TX_PPI_SYNC_ENABLE BIT(2) @@ -129,9 +147,13 @@ #define T_CLK_PRE_CNT_MASK GENMASK(3, 0) #define T_CLK_PRE_CNT(x) UPDATE(x, 3, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg10 */ +#define T_CLK_POST_CNT_HI_MASK GENMASK(7, 6) +#define T_CLK_POST_CNT_HI(x) UPDATE(x, 7, 6) #define T_TA_GO_CNT_MASK GENMASK(5, 0) #define T_TA_GO_CNT(x) UPDATE(x, 5, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg11 */ +#define T_HS_EXIT_CNT_HI_MASK BIT(6) +#define T_HS_EXIT_CNT_HI(x) UPDATE(x, 6, 6) #define T_TA_SURE_CNT_MASK GENMASK(5, 0) #define T_TA_SURE_CNT(x) UPDATE(x, 5, 0) /* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg12 */ @@ -169,11 +191,23 @@ #define DSI_PHY_STATUS 0xb0 #define PHY_LOCK BIT(0) +enum phy_max_rate { + MAX_1GHZ, + MAX_2_5GHZ, +}; + +struct inno_video_phy_plat_data { + const struct inno_mipi_dphy_timing *inno_mipi_dphy_timing_table; + const unsigned int num_timings; + enum phy_max_rate max_rate; +}; + struct inno_dsidphy { struct device *dev; struct clk *ref_clk; struct clk *pclk_phy; struct clk *pclk_host; + const struct inno_video_phy_plat_data *pdata; void __iomem *phy_base; void __iomem *host_base; struct reset_control *rst; @@ -200,6 +234,53 @@ enum { REGISTER_PART_LVDS, }; +struct inno_mipi_dphy_timing { + unsigned long rate; + u8 lpx; + u8 hs_prepare; + u8 clk_lane_hs_zero; + u8 data_lane_hs_zero; + u8 hs_trail; +}; + +static const +struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_1ghz[] = { + { 110000000, 0x0, 0x20, 0x16, 0x02, 0x22}, + { 150000000, 0x0, 0x06, 0x16, 0x03, 0x45}, + { 200000000, 0x0, 0x18, 0x17, 0x04, 0x0b}, + { 250000000, 0x0, 0x05, 0x17, 0x05, 0x16}, + { 300000000, 0x0, 0x51, 0x18, 0x06, 0x2c}, + { 400000000, 0x0, 0x64, 0x19, 0x07, 0x33}, + { 500000000, 0x0, 0x20, 0x1b, 0x07, 0x4e}, + { 600000000, 0x0, 0x6a, 0x1d, 0x08, 0x3a}, + { 700000000, 0x0, 0x3e, 0x1e, 0x08, 0x6a}, + { 800000000, 0x0, 0x21, 0x1f, 0x09, 0x29}, + {1000000000, 0x0, 0x09, 0x20, 0x09, 0x27}, +}; + +static const +struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_2_5ghz[] = { + { 110000000, 0x02, 0x7f, 0x16, 0x02, 0x02}, + { 150000000, 0x02, 0x7f, 0x16, 0x03, 0x02}, + { 200000000, 0x02, 0x7f, 0x17, 0x04, 0x02}, + { 250000000, 0x02, 0x7f, 0x17, 0x05, 0x04}, + { 300000000, 0x02, 0x7f, 0x18, 0x06, 0x04}, + { 400000000, 0x03, 0x7e, 0x19, 0x07, 0x04}, + { 500000000, 0x03, 0x7c, 0x1b, 0x07, 0x08}, + { 600000000, 0x03, 0x70, 0x1d, 0x08, 0x10}, + { 700000000, 0x05, 0x40, 0x1e, 0x08, 0x30}, + { 800000000, 0x05, 0x02, 0x1f, 0x09, 0x30}, + {1000000000, 0x05, 0x08, 0x20, 0x09, 0x30}, + {1200000000, 0x06, 0x03, 0x32, 0x14, 0x0f}, + {1400000000, 0x09, 0x03, 0x32, 0x14, 0x0f}, + {1600000000, 0x0d, 0x42, 0x36, 0x0e, 0x0f}, + {1800000000, 0x0e, 0x47, 0x7a, 0x0e, 0x0f}, + {2000000000, 0x11, 0x64, 0x7a, 0x0e, 0x0b}, + {2200000000, 0x13, 0x64, 0x7e, 0x15, 0x0b}, + {2400000000, 0x13, 0x33, 0x7f, 0x15, 0x6a}, + {2500000000, 0x15, 0x54, 0x7f, 0x15, 0x6a}, +}; + static inline struct inno_dsidphy *hw_to_inno(struct clk_hw *hw) { return container_of(hw, struct inno_dsidphy, pll.hw); @@ -290,31 +371,15 @@ static unsigned long inno_dsidphy_pll_calc_rate(struct inno_dsidphy *inno, static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) { struct phy_configure_opts_mipi_dphy *cfg = &inno->dphy_cfg; - const struct { - unsigned long rate; - u8 hs_prepare; - u8 clk_lane_hs_zero; - u8 data_lane_hs_zero; - u8 hs_trail; - } timings[] = { - { 110000000, 0x20, 0x16, 0x02, 0x22}, - { 150000000, 0x06, 0x16, 0x03, 0x45}, - { 200000000, 0x18, 0x17, 0x04, 0x0b}, - { 250000000, 0x05, 0x17, 0x05, 0x16}, - { 300000000, 0x51, 0x18, 0x06, 0x2c}, - { 400000000, 0x64, 0x19, 0x07, 0x33}, - { 500000000, 0x20, 0x1b, 0x07, 0x4e}, - { 600000000, 0x6a, 0x1d, 0x08, 0x3a}, - { 700000000, 0x3e, 0x1e, 0x08, 0x6a}, - { 800000000, 0x21, 0x1f, 0x09, 0x29}, - {1000000000, 0x09, 0x20, 0x09, 0x27}, - }; + const struct inno_mipi_dphy_timing *timings; u32 t_txbyteclkhs, t_txclkesc; u32 txbyteclkhs, txclkesc, esc_clk_div; u32 hs_exit, clk_post, clk_pre, wakeup, lpx, ta_go, ta_sure, ta_wait; u32 hs_prepare, hs_trail, hs_zero, clk_lane_hs_zero, data_lane_hs_zero; unsigned int i; + timings = inno->pdata->inno_mipi_dphy_timing_table; + inno_dsidphy_pll_calc_rate(inno, cfg->hs_clk_rate); /* Select MIPI mode */ @@ -327,6 +392,13 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) REG_FBDIV_HI_MASK, REG_FBDIV_HI(inno->pll.fbdiv)); phy_update_bits(inno, REGISTER_PART_ANALOG, 0x04, REG_FBDIV_LO_MASK, REG_FBDIV_LO(inno->pll.fbdiv)); + if (inno->pdata->max_rate == MAX_2_5GHZ) { + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x08, + PLL_POST_DIV_ENABLE_MASK, PLL_POST_DIV_ENABLE); + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x0b, + CLOCK_LANE_VOD_RANGE_SET_MASK, + CLOCK_LANE_VOD_RANGE_SET(VOD_MAX_RANGE)); + } /* Enable PLL and LDO */ phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, REG_LDOPD_MASK | REG_PLLPD_MASK, @@ -367,14 +439,6 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) */ clk_pre = DIV_ROUND_UP(cfg->clk_pre, BITS_PER_BYTE); - /* - * The value of counter for HS Tlpx Time - * Tlpx = Tpin_txbyteclkhs * (2 + value) - */ - lpx = DIV_ROUND_UP(cfg->lpx, t_txbyteclkhs); - if (lpx >= 2) - lpx -= 2; - /* * The value of counter for HS Tta-go * Tta-go for turnaround @@ -394,13 +458,24 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) */ ta_wait = DIV_ROUND_UP(cfg->ta_get, t_txclkesc); - for (i = 0; i < ARRAY_SIZE(timings); i++) + for (i = 0; i < inno->pdata->num_timings; i++) if (inno->pll.rate <= timings[i].rate) break; - if (i == ARRAY_SIZE(timings)) + if (i == inno->pdata->num_timings) --i; + /* + * The value of counter for HS Tlpx Time + * Tlpx = Tpin_txbyteclkhs * (2 + value) + */ + if (inno->pdata->max_rate == MAX_1GHZ) { + lpx = DIV_ROUND_UP(cfg->lpx, t_txbyteclkhs); + if (lpx >= 2) + lpx -= 2; + } else + lpx = timings[i].lpx; + hs_prepare = timings[i].hs_prepare; hs_trail = timings[i].hs_trail; clk_lane_hs_zero = timings[i].clk_lane_hs_zero; @@ -417,14 +492,23 @@ static void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) T_LPX_CNT(lpx)); phy_update_bits(inno, i, 0x06, T_HS_PREPARE_CNT_MASK, T_HS_PREPARE_CNT(hs_prepare)); - phy_update_bits(inno, i, 0x07, T_HS_ZERO_CNT_MASK, - T_HS_ZERO_CNT(hs_zero)); + if (inno->pdata->max_rate == MAX_2_5GHZ) + phy_update_bits(inno, i, 0x06, T_HS_ZERO_CNT_HI_MASK, + T_HS_ZERO_CNT_HI(hs_zero >> 6)); + phy_update_bits(inno, i, 0x07, T_HS_ZERO_CNT_LO_MASK, + T_HS_ZERO_CNT_LO(hs_zero)); phy_update_bits(inno, i, 0x08, T_HS_TRAIL_CNT_MASK, T_HS_TRAIL_CNT(hs_trail)); - phy_update_bits(inno, i, 0x09, T_HS_EXIT_CNT_MASK, - T_HS_EXIT_CNT(hs_exit)); - phy_update_bits(inno, i, 0x0a, T_CLK_POST_CNT_MASK, - T_CLK_POST_CNT(clk_post)); + if (inno->pdata->max_rate == MAX_2_5GHZ) + phy_update_bits(inno, i, 0x11, T_HS_EXIT_CNT_HI_MASK, + T_HS_EXIT_CNT_HI(hs_exit >> 5)); + phy_update_bits(inno, i, 0x09, T_HS_EXIT_CNT_LO_MASK, + T_HS_EXIT_CNT_LO(hs_exit)); + if (inno->pdata->max_rate == MAX_2_5GHZ) + phy_update_bits(inno, i, 0x10, T_CLK_POST_CNT_HI_MASK, + T_CLK_POST_CNT_HI(clk_post >> 4)); + phy_update_bits(inno, i, 0x0a, T_CLK_POST_CNT_LO_MASK, + T_CLK_POST_CNT_LO(clk_post)); phy_update_bits(inno, i, 0x0e, T_CLK_PRE_CNT_MASK, T_CLK_PRE_CNT(clk_pre)); phy_update_bits(inno, i, 0x0c, T_WAKEUP_CNT_HI_MASK, @@ -452,8 +536,9 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno) /* Sample clock reverse direction */ phy_update_bits(inno, REGISTER_PART_ANALOG, 0x08, - SAMPLE_CLOCK_DIRECTION_MASK, - SAMPLE_CLOCK_DIRECTION_REVERSE); + SAMPLE_CLOCK_DIRECTION_MASK | LOWFRE_EN_MASK, + SAMPLE_CLOCK_DIRECTION_REVERSE | + PLL_OUTPUT_FREQUENCY_DIV_BY_1); /* Select LVDS mode */ phy_update_bits(inno, REGISTER_PART_LVDS, 0x03, @@ -473,6 +558,10 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno) msleep(20); + /* Select PLL mode */ + phy_update_bits(inno, REGISTER_PART_ANALOG, 0x1e, + PLL_MODE_SEL_MASK, PLL_MODE_SEL_LVDS_MODE); + /* Reset LVDS digital logic */ phy_update_bits(inno, REGISTER_PART_LVDS, 0x00, LVDS_DIGITAL_INTERNAL_RESET_MASK, @@ -592,6 +681,18 @@ static const struct phy_ops inno_dsidphy_ops = { .owner = THIS_MODULE, }; +static const struct inno_video_phy_plat_data max_1ghz_video_phy_plat_data = { + .inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_1ghz, + .num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_1ghz), + .max_rate = MAX_1GHZ, +}; + +static const struct inno_video_phy_plat_data max_2_5ghz_video_phy_plat_data = { + .inno_mipi_dphy_timing_table = inno_mipi_dphy_timing_table_max_2_5ghz, + .num_timings = ARRAY_SIZE(inno_mipi_dphy_timing_table_max_2_5ghz), + .max_rate = MAX_2_5GHZ, +}; + static int inno_dsidphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -605,6 +706,7 @@ static int inno_dsidphy_probe(struct platform_device *pdev) return -ENOMEM; inno->dev = dev; + inno->pdata = of_device_get_match_data(inno->dev); platform_set_drvdata(pdev, inno); inno->phy_base = devm_platform_ioremap_resource(pdev, 0); @@ -663,9 +765,19 @@ static int inno_dsidphy_remove(struct platform_device *pdev) } static const struct of_device_id inno_dsidphy_of_match[] = { - { .compatible = "rockchip,px30-dsi-dphy", }, - { .compatible = "rockchip,rk3128-dsi-dphy", }, - { .compatible = "rockchip,rk3368-dsi-dphy", }, + { + .compatible = "rockchip,px30-dsi-dphy", + .data = &max_1ghz_video_phy_plat_data, + }, { + .compatible = "rockchip,rk3128-dsi-dphy", + .data = &max_1ghz_video_phy_plat_data, + }, { + .compatible = "rockchip,rk3368-dsi-dphy", + .data = &max_1ghz_video_phy_plat_data, + }, { + .compatible = "rockchip,rk3568-dsi-dphy", + .data = &max_2_5ghz_video_phy_plat_data, + }, {} }; MODULE_DEVICE_TABLE(of, inno_dsidphy_of_match); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 0b1e9337ee8e..e6ededc51523 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1124,7 +1124,7 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, struct rockchip_usb2phy_port *rport, struct device_node *child_np) { - int ret; + int ret, id; rport->port_id = USB2PHY_PORT_OTG; rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG]; @@ -1162,13 +1162,15 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, ret = devm_extcon_register_notifier(rphy->dev, rphy->edev, EXTCON_USB_HOST, &rport->event_nb); - if (ret) + if (ret) { dev_err(rphy->dev, "register USB HOST notifier failed\n"); + goto out; + } if (!of_property_read_bool(rphy->dev->of_node, "extcon")) { /* do initial sync of usb state */ - ret = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); - extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !ret); + id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); + extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id); } } diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c new file mode 100644 index 000000000000..1d355b32ba55 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip PCIE3.0 phy driver + * + * Copyright (C) 2022 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register for RK3568 */ +#define GRF_PCIE30PHY_CON1 0x4 +#define GRF_PCIE30PHY_CON6 0x18 +#define GRF_PCIE30PHY_CON9 0x24 +#define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31)) +#define GRF_PCIE30PHY_STATUS0 0x80 +#define GRF_PCIE30PHY_WR_EN (0xf << 16) +#define SRAM_INIT_DONE(reg) (reg & BIT(14)) + +#define RK3568_BIFURCATION_LANE_0_1 BIT(0) + +/* Register for RK3588 */ +#define PHP_GRF_PCIESEL_CON 0x100 +#define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 +#define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 +#define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 +#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) + +#define RK3588_BIFURCATION_LANE_0_1 BIT(0) +#define RK3588_BIFURCATION_LANE_2_3 BIT(1) +#define RK3588_LANE_AGGREGATION BIT(2) + +struct rockchip_p3phy_ops; + +struct rockchip_p3phy_priv { + const struct rockchip_p3phy_ops *ops; + void __iomem *mmio; + /* mode: RC, EP */ + int mode; + /* pcie30_phymode: Aggregation, Bifurcation */ + int pcie30_phymode; + struct regmap *phy_grf; + struct regmap *pipe_grf; + struct reset_control *p30phy; + struct phy *phy; + struct clk_bulk_data *clks; + int num_clks; + int num_lanes; + u32 lanes[4]; +}; + +struct rockchip_p3phy_ops { + int (*phy_init)(struct rockchip_p3phy_priv *priv); +}; + +static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); + + /* Actually We don't care EP/RC mode, but just record it */ + switch (submode) { + case PHY_MODE_PCIE_RC: + priv->mode = PHY_MODE_PCIE_RC; + break; + case PHY_MODE_PCIE_EP: + priv->mode = PHY_MODE_PCIE_EP; + break; + default: + dev_err(&phy->dev, "%s, invalid mode\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int rockchip_p3phy_rk3568_init(struct rockchip_p3phy_priv *priv) +{ + struct phy *phy = priv->phy; + bool bifurcation = false; + int ret; + u32 reg; + + /* Deassert PCIe PMA output clamp mode */ + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); + + for (int i = 0; i < priv->num_lanes; i++) { + dev_info(&phy->dev, "lane number %d, val %d\n", i, priv->lanes[i]); + if (priv->lanes[i] > 1) + bifurcation = true; + } + + /* Set bifurcation if needed, and it doesn't care RC/EP */ + if (bifurcation) { + dev_info(&phy->dev, "bifurcation enabled\n"); + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, + GRF_PCIE30PHY_WR_EN | RK3568_BIFURCATION_LANE_0_1); + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1, + GRF_PCIE30PHY_DA_OCM); + } else { + dev_dbg(&phy->dev, "bifurcation disabled\n"); + regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6, + GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1); + } + + reset_control_deassert(priv->p30phy); + + ret = regmap_read_poll_timeout(priv->phy_grf, + GRF_PCIE30PHY_STATUS0, + reg, SRAM_INIT_DONE(reg), + 0, 500); + if (ret) + dev_err(&priv->phy->dev, "%s: lock failed 0x%x, check input refclk and power supply\n", + __func__, reg); + return ret; +} + +static const struct rockchip_p3phy_ops rk3568_ops = { + .phy_init = rockchip_p3phy_rk3568_init, +}; + +static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) +{ + u32 reg = 0; + u8 mode = 0; + int ret; + + /* Deassert PCIe PMA output clamp mode */ + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); + + /* Set bifurcation if needed */ + for (int i = 0; i < priv->num_lanes; i++) { + if (!priv->lanes[i]) + mode |= (BIT(i) << 3); + + if (priv->lanes[i] > 1) + mode |= (BIT(i) >> 1); + } + + if (!mode) + reg = RK3588_LANE_AGGREGATION; + else { + if (mode & (BIT(0) | BIT(1))) + reg |= RK3588_BIFURCATION_LANE_0_1; + + if (mode & (BIT(2) | BIT(3))) + reg |= RK3588_BIFURCATION_LANE_2_3; + } + + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, (0x7<<16) | reg); + + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ + if (!IS_ERR(priv->pipe_grf)) { + reg = (mode & (BIT(6) | BIT(7))) >> 6; + if (reg) + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << 16) | reg); + } + + reset_control_deassert(priv->p30phy); + + ret = regmap_read_poll_timeout(priv->phy_grf, + RK3588_PCIE3PHY_GRF_PHY0_STATUS1, + reg, RK3588_SRAM_INIT_DONE(reg), + 0, 500); + ret |= regmap_read_poll_timeout(priv->phy_grf, + RK3588_PCIE3PHY_GRF_PHY1_STATUS1, + reg, RK3588_SRAM_INIT_DONE(reg), + 0, 500); + if (ret) + dev_err(&priv->phy->dev, "lock failed 0x%x, check input refclk and power supply\n", + reg); + return ret; +} + +static const struct rockchip_p3phy_ops rk3588_ops = { + .phy_init = rockchip_p3phy_rk3588_init, +}; + +static int rochchip_p3phy_init(struct phy *phy) +{ + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) { + dev_err(&priv->phy->dev, "failed to enable PCIe bulk clks %d\n", ret); + return ret; + } + + reset_control_assert(priv->p30phy); + udelay(1); + + if (priv->ops->phy_init) { + ret = priv->ops->phy_init(priv); + if (ret) + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + } + + return ret; +} + +static int rochchip_p3phy_exit(struct phy *phy) +{ + struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + reset_control_assert(priv->p30phy); + return 0; +} + +static const struct phy_ops rochchip_p3phy_ops = { + .init = rochchip_p3phy_init, + .exit = rochchip_p3phy_exit, + .set_mode = rockchip_p3phy_set_mode, + .owner = THIS_MODULE, +}; + +static int rockchip_p3phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct rockchip_p3phy_priv *priv; + struct device_node *np = dev->of_node; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(priv->mmio)) { + ret = PTR_ERR(priv->mmio); + return ret; + } + + priv->ops = of_device_get_match_data(&pdev->dev); + if (!priv->ops) { + dev_err(dev, "no of match data provided\n"); + return -EINVAL; + } + + priv->phy_grf = syscon_regmap_lookup_by_phandle(np, "rockchip,phy-grf"); + if (IS_ERR(priv->phy_grf)) { + dev_err(dev, "failed to find rockchip,phy_grf regmap\n"); + return PTR_ERR(priv->phy_grf); + } + + if (of_device_is_compatible(np, "rockchip,rk3588-pcie3-phy")) { + priv->pipe_grf = + syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,pipe-grf"); + if (IS_ERR(priv->pipe_grf)) + dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); + } else { + priv->pipe_grf = NULL; + } + + priv->num_lanes = of_property_read_variable_u32_array(dev->of_node, "data-lanes", + priv->lanes, 2, + ARRAY_SIZE(priv->lanes)); + + /* if no data-lanes assume aggregation */ + if (priv->num_lanes == -EINVAL) { + dev_dbg(dev, "no data-lanes property found\n"); + priv->num_lanes = 1; + priv->lanes[0] = 1; + } else if (priv->num_lanes < 0) { + dev_err(dev, "failed to read data-lanes property %d\n", priv->num_lanes); + return priv->num_lanes; + } + + priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); + if (IS_ERR(priv->phy)) { + dev_err(dev, "failed to create combphy\n"); + return PTR_ERR(priv->phy); + } + + priv->p30phy = devm_reset_control_get_optional_exclusive(dev, "phy"); + if (IS_ERR(priv->p30phy)) { + return dev_err_probe(dev, PTR_ERR(priv->p30phy), + "failed to get phy reset control\n"); + } + if (!priv->p30phy) + dev_info(dev, "no phy reset control specified\n"); + + priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); + if (priv->num_clks < 1) + return -ENODEV; + + dev_set_drvdata(dev, priv); + phy_set_drvdata(priv->phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id rockchip_p3phy_of_match[] = { + { .compatible = "rockchip,rk3568-pcie3-phy", .data = &rk3568_ops }, + { .compatible = "rockchip,rk3588-pcie3-phy", .data = &rk3588_ops }, + { }, +}; +MODULE_DEVICE_TABLE(of, rockchip_p3phy_of_match); + +static struct platform_driver rockchip_p3phy_driver = { + .probe = rockchip_p3phy_probe, + .driver = { + .name = "rockchip-snps-pcie3-phy", + .of_match_table = rockchip_p3phy_of_match, + }, +}; +module_platform_driver(rockchip_p3phy_driver); +MODULE_DESCRIPTION("Rockchip Synopsys PCIe 3.0 PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/sunplus/Kconfig b/drivers/phy/sunplus/Kconfig new file mode 100644 index 000000000000..3bd3cfb53a63 --- /dev/null +++ b/drivers/phy/sunplus/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PHY_SUNPLUS_USB + tristate "Sunplus SP7021 USB 2.0 PHY driver" + depends on OF && (SOC_SP7021 || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support the USB 2.0 PHY on Sunplus SP7021 + SoC. The USB 2.0 PHY controller supports battery charger + and synchronous signals, various power down modes including + operating, partial and suspend modes, and high-speed, + full-speed and low-speed data transfer. diff --git a/drivers/phy/sunplus/Makefile b/drivers/phy/sunplus/Makefile new file mode 100644 index 000000000000..71754d5cb545 --- /dev/null +++ b/drivers/phy/sunplus/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_SUNPLUS_USB) += phy-sunplus-usb2.o diff --git a/drivers/phy/sunplus/phy-sunplus-usb2.c b/drivers/phy/sunplus/phy-sunplus-usb2.c new file mode 100644 index 000000000000..b932087c55b2 --- /dev/null +++ b/drivers/phy/sunplus/phy-sunplus-usb2.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Sunplus SP7021 USB 2.0 phy driver + * + * Copyright (C) 2022 Sunplus Technology Inc., All rights reserved. + * + * Note 1 : non-posted write command for the registers accesses of + * Sunplus SP7021. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HIGH_MASK_BITS GENMASK(31, 16) +#define LOW_MASK_BITS GENMASK(15, 0) +#define OTP_DISC_LEVEL_DEFAULT 0xd + +/* GROUP UPHY */ +#define CONFIG1 0x4 +#define J_HS_TX_PWRSAV BIT(5) +#define CONFIG3 0xc +#define J_FORCE_DISC_ON BIT(5) +#define J_DEBUG_CTRL_ADDR_MACRO BIT(0) +#define CONFIG7 0x1c +#define J_DISC 0X1f +#define CONFIG9 0x24 +#define J_ECO_PATH BIT(6) +#define CONFIG16 0x40 +#define J_TBCWAIT_MASK GENMASK(6, 5) +#define J_TBCWAIT_1P1_MS FIELD_PREP(J_TBCWAIT_MASK, 0) +#define J_TVDM_SRC_DIS_MASK GENMASK(4, 3) +#define J_TVDM_SRC_DIS_8P2_MS FIELD_PREP(J_TVDM_SRC_DIS_MASK, 3) +#define J_TVDM_SRC_EN_MASK GENMASK(2, 1) +#define J_TVDM_SRC_EN_1P6_MS FIELD_PREP(J_TVDM_SRC_EN_MASK, 0) +#define J_BC_EN BIT(0) +#define CONFIG17 0x44 +#define IBG_TRIM0_MASK GENMASK(7, 5) +#define IBG_TRIM0_SSLVHT FIELD_PREP(IBG_TRIM0_MASK, 4) +#define J_VDATREE_TRIM_MASK GENMASK(4, 1) +#define J_VDATREE_TRIM_DEFAULT FIELD_PREP(J_VDATREE_TRIM_MASK, 9) +#define CONFIG23 0x5c +#define PROB_MASK GENMASK(5, 3) +#define PROB FIELD_PREP(PROB_MASK, 7) + +/* GROUP MOON4 */ +#define UPHY_CONTROL0 0x0 +#define UPHY_CONTROL1 0x4 +#define UPHY_CONTROL2 0x8 +#define MO1_UPHY_RX_CLK_SEL BIT(6) +#define MASK_MO1_UPHY_RX_CLK_SEL BIT(6 + 16) +#define UPHY_CONTROL3 0xc +#define MO1_UPHY_PLL_POWER_OFF_SEL BIT(7) +#define MASK_MO1_UPHY_PLL_POWER_OFF_SEL BIT(7 + 16) +#define MO1_UPHY_PLL_POWER_OFF BIT(3) +#define MASK_UPHY_PLL_POWER_OFF BIT(3 + 16) + +struct sp_usbphy { + struct device *dev; + struct resource *phy_res_mem; + struct resource *moon4_res_mem; + struct reset_control *rstc; + struct clk *phy_clk; + void __iomem *phy_regs; + void __iomem *moon4_regs; + u32 disc_vol_addr_off; +}; + +static int update_disc_vol(struct sp_usbphy *usbphy) +{ + struct nvmem_cell *cell; + char *disc_name = "disc_vol"; + ssize_t otp_l = 0; + char *otp_v; + u32 val, set; + + cell = nvmem_cell_get(usbphy->dev, disc_name); + if (IS_ERR_OR_NULL(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } + + otp_v = nvmem_cell_read(cell, &otp_l); + nvmem_cell_put(cell); + + if (!IS_ERR(otp_v)) { + set = *(otp_v + 1); + set = (set << (sizeof(char) * 8)) | *otp_v; + set = (set >> usbphy->disc_vol_addr_off) & J_DISC; + } + + if (IS_ERR(otp_v) || set == 0) + set = OTP_DISC_LEVEL_DEFAULT; + + val = readl(usbphy->phy_regs + CONFIG7); + val = (val & ~J_DISC) | set; + writel(val, usbphy->phy_regs + CONFIG7); + + return 0; +} + +static int sp_uphy_init(struct phy *phy) +{ + struct sp_usbphy *usbphy = phy_get_drvdata(phy); + u32 val; + int ret; + + ret = clk_prepare_enable(usbphy->phy_clk); + if (ret) + goto err_clk; + + ret = reset_control_deassert(usbphy->rstc); + if (ret) + goto err_reset; + + /* Default value modification */ + writel(HIGH_MASK_BITS | 0x4002, usbphy->moon4_regs + UPHY_CONTROL0); + writel(HIGH_MASK_BITS | 0x8747, usbphy->moon4_regs + UPHY_CONTROL1); + + /* disconnect voltage */ + ret = update_disc_vol(usbphy); + if (ret < 0) + return ret; + + /* board uphy 0 internal register modification for tid certification */ + val = readl(usbphy->phy_regs + CONFIG9); + val &= ~(J_ECO_PATH); + writel(val, usbphy->phy_regs + CONFIG9); + + val = readl(usbphy->phy_regs + CONFIG1); + val &= ~(J_HS_TX_PWRSAV); + writel(val, usbphy->phy_regs + CONFIG1); + + val = readl(usbphy->phy_regs + CONFIG23); + val = (val & ~PROB) | PROB; + writel(val, usbphy->phy_regs + CONFIG23); + + /* port 0 uphy clk fix */ + writel(MASK_MO1_UPHY_RX_CLK_SEL | MO1_UPHY_RX_CLK_SEL, + usbphy->moon4_regs + UPHY_CONTROL2); + + /* battery charger */ + writel(J_TBCWAIT_1P1_MS | J_TVDM_SRC_DIS_8P2_MS | J_TVDM_SRC_EN_1P6_MS | J_BC_EN, + usbphy->phy_regs + CONFIG16); + writel(IBG_TRIM0_SSLVHT | J_VDATREE_TRIM_DEFAULT, usbphy->phy_regs + CONFIG17); + + /* chirp mode */ + writel(J_FORCE_DISC_ON | J_DEBUG_CTRL_ADDR_MACRO, usbphy->phy_regs + CONFIG3); + + return 0; + +err_reset: + reset_control_assert(usbphy->rstc); +err_clk: + clk_disable_unprepare(usbphy->phy_clk); + + return ret; +} + +static int sp_uphy_power_on(struct phy *phy) +{ + struct sp_usbphy *usbphy = phy_get_drvdata(phy); + u32 pll_pwr_on, pll_pwr_off; + + /* PLL power off/on twice */ + pll_pwr_off = (readl(usbphy->moon4_regs + UPHY_CONTROL3) & ~LOW_MASK_BITS) + | MO1_UPHY_PLL_POWER_OFF_SEL | MO1_UPHY_PLL_POWER_OFF; + pll_pwr_on = (readl(usbphy->moon4_regs + UPHY_CONTROL3) & ~LOW_MASK_BITS) + | MO1_UPHY_PLL_POWER_OFF_SEL; + + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | pll_pwr_off, + usbphy->moon4_regs + UPHY_CONTROL3); + mdelay(1); + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | pll_pwr_on, + usbphy->moon4_regs + UPHY_CONTROL3); + mdelay(1); + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | pll_pwr_off, + usbphy->moon4_regs + UPHY_CONTROL3); + mdelay(1); + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | pll_pwr_on, + usbphy->moon4_regs + UPHY_CONTROL3); + mdelay(1); + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | 0x0, + usbphy->moon4_regs + UPHY_CONTROL3); + + return 0; +} + +static int sp_uphy_power_off(struct phy *phy) +{ + struct sp_usbphy *usbphy = phy_get_drvdata(phy); + u32 pll_pwr_off; + + pll_pwr_off = (readl(usbphy->moon4_regs + UPHY_CONTROL3) & ~LOW_MASK_BITS) + | MO1_UPHY_PLL_POWER_OFF_SEL | MO1_UPHY_PLL_POWER_OFF; + + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | pll_pwr_off, + usbphy->moon4_regs + UPHY_CONTROL3); + mdelay(1); + writel(MASK_MO1_UPHY_PLL_POWER_OFF_SEL | MASK_UPHY_PLL_POWER_OFF | 0x0, + usbphy->moon4_regs + UPHY_CONTROL3); + + return 0; +} + +static int sp_uphy_exit(struct phy *phy) +{ + struct sp_usbphy *usbphy = phy_get_drvdata(phy); + + reset_control_assert(usbphy->rstc); + clk_disable_unprepare(usbphy->phy_clk); + + return 0; +} + +static const struct phy_ops sp_uphy_ops = { + .init = sp_uphy_init, + .power_on = sp_uphy_power_on, + .power_off = sp_uphy_power_off, + .exit = sp_uphy_exit, +}; + +static const struct of_device_id sp_uphy_dt_ids[] = { + {.compatible = "sunplus,sp7021-usb2-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, sp_uphy_dt_ids); + +static int sp_usb_phy_probe(struct platform_device *pdev) +{ + struct sp_usbphy *usbphy; + struct phy_provider *phy_provider; + struct phy *phy; + int ret; + + usbphy = devm_kzalloc(&pdev->dev, sizeof(*usbphy), GFP_KERNEL); + if (!usbphy) + return -ENOMEM; + + usbphy->dev = &pdev->dev; + + usbphy->phy_res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + usbphy->phy_regs = devm_ioremap_resource(&pdev->dev, usbphy->phy_res_mem); + if (IS_ERR(usbphy->phy_regs)) + return PTR_ERR(usbphy->phy_regs); + + usbphy->moon4_res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon4"); + usbphy->moon4_regs = devm_ioremap(&pdev->dev, usbphy->moon4_res_mem->start, + resource_size(usbphy->moon4_res_mem)); + if (IS_ERR(usbphy->moon4_regs)) + return PTR_ERR(usbphy->moon4_regs); + + usbphy->phy_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(usbphy->phy_clk)) + return PTR_ERR(usbphy->phy_clk); + + usbphy->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(usbphy->rstc)) + return PTR_ERR(usbphy->rstc); + + of_property_read_u32(pdev->dev.of_node, "sunplus,disc-vol-addr-off", + &usbphy->disc_vol_addr_off); + + phy = devm_phy_create(&pdev->dev, NULL, &sp_uphy_ops); + if (IS_ERR(phy)) { + ret = -PTR_ERR(phy); + return ret; + } + + phy_set_drvdata(phy, usbphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver sunplus_usb_phy_driver = { + .probe = sp_usb_phy_probe, + .driver = { + .name = "sunplus-usb2-phy", + .of_match_table = sp_uphy_dt_ids, + }, +}; +module_platform_driver(sunplus_usb_phy_driver); + +MODULE_AUTHOR("Vincent Shih "); +MODULE_DESCRIPTION("Sunplus USB 2.0 phy driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c index ae3915ed9fef..0996ede63387 100644 --- a/drivers/phy/tegra/xusb-tegra186.c +++ b/drivers/phy/tegra/xusb-tegra186.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. */ #include @@ -638,7 +638,7 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) mutex_unlock(&padctl->lock); } -static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy) +static void tegra186_utmi_pad_power_on(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; @@ -656,6 +656,8 @@ static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy) return; } + dev_dbg(dev, "power on UTMI pad %u\n", index); + tegra186_utmi_bias_pad_power_on(padctl); udelay(2); @@ -669,7 +671,7 @@ static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy) padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); } -static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy) +static void tegra186_utmi_pad_power_down(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_padctl *padctl = lane->pad->padctl; @@ -679,6 +681,8 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy) if (!phy) return; + dev_dbg(padctl->dev, "power down UTMI pad %u\n", index); + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); value |= USB2_OTG_PD; padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); @@ -849,15 +853,14 @@ static int tegra186_utmi_phy_power_on(struct phy *phy) value |= RPD_CTRL(priv->calib.rpd_ctrl); padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); - /* TODO: pad power saving */ - tegra_phy_xusb_utmi_pad_power_on(phy); + tegra186_utmi_pad_power_on(phy); + return 0; } static int tegra186_utmi_phy_power_off(struct phy *phy) { - /* TODO: pad power saving */ - tegra_phy_xusb_utmi_pad_power_down(phy); + tegra186_utmi_pad_power_down(phy); return 0; } @@ -1381,12 +1384,9 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) return -ENOMEM; err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to read calibration fuse: %d\n", - err); - return err; - } + if (err) + return dev_err_probe(dev, err, + "failed to read calibration fuse\n"); dev_dbg(dev, "FUSE_USB_CALIB_0 %#x\n", value); @@ -1486,6 +1486,8 @@ static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = { .suspend_noirq = tegra186_xusb_padctl_suspend_noirq, .resume_noirq = tegra186_xusb_padctl_resume_noirq, .vbus_override = tegra186_xusb_padctl_vbus_override, + .utmi_pad_power_on = tegra186_utmi_pad_power_on, + .utmi_pad_power_down = tegra186_utmi_pad_power_down, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index aa5237eacd29..95091876c422 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. */ #include @@ -656,6 +656,7 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port) struct usb_role_switch_desc role_sx_desc = { .fwnode = dev_fwnode(&port->dev), .set = tegra_xusb_role_sw_set, + .allow_userspace_control = true, }; int err = 0; @@ -1270,7 +1271,7 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) padctl->soc->ops->remove(padctl); - return err; + return 0; } static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev) @@ -1458,6 +1459,26 @@ int tegra_phy_xusb_utmi_port_reset(struct phy *phy) } EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset); +void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy) +{ + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; + + if (padctl->soc->ops->utmi_pad_power_on) + padctl->soc->ops->utmi_pad_power_on(phy); +} +EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_on); + +void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy) +{ + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; + + if (padctl->soc->ops->utmi_pad_power_down) + padctl->soc->ops->utmi_pad_power_down(phy); +} +EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_pad_power_down); + int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl, unsigned int port) { diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h index 034f7a2c28d6..8cfbbdbd6e0c 100644 --- a/drivers/phy/tegra/xusb.h +++ b/drivers/phy/tegra/xusb.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2015, Google Inc. */ @@ -412,6 +412,8 @@ struct tegra_xusb_padctl_ops { unsigned int index, bool enable); int (*vbus_override)(struct tegra_xusb_padctl *padctl, bool set); int (*utmi_port_reset)(struct phy *phy); + void (*utmi_pad_power_on)(struct phy *phy); + void (*utmi_pad_power_down)(struct phy *phy); }; struct tegra_xusb_padctl_soc { diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index d0ab69750c6b..0bcfd6d96b4d 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -22,6 +22,12 @@ #define AM33XX_GMII_SEL_MODE_RMII 1 #define AM33XX_GMII_SEL_MODE_RGMII 2 +/* J72xx SoC specific definitions for the CONTROL port */ +#define J72XX_GMII_SEL_MODE_QSGMII 4 +#define J72XX_GMII_SEL_MODE_QSGMII_SUB 6 + +#define PHY_GMII_PORT(n) BIT((n) - 1) + enum { PHY_GMII_SEL_PORT_MODE = 0, PHY_GMII_SEL_RGMII_ID_MODE, @@ -43,6 +49,7 @@ struct phy_gmii_sel_soc_data { u32 features; const struct reg_field (*regfields)[PHY_GMII_SEL_LAST]; bool use_of_data; + u64 extra_modes; }; struct phy_gmii_sel_priv { @@ -53,6 +60,7 @@ struct phy_gmii_sel_priv { struct phy_gmii_sel_phy_priv *if_phys; u32 num_ports; u32 reg_offset; + u32 qsgmii_main_ports; }; static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) @@ -88,10 +96,17 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII; break; + case PHY_INTERFACE_MODE_QSGMII: + if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_QSGMII))) + goto unsupported; + if (if_phy->priv->qsgmii_main_ports & BIT(if_phy->id - 1)) + gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII; + else + gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB; + break; + default: - dev_warn(dev, "port%u: unsupported mode: \"%s\"\n", - if_phy->id, phy_modes(submode)); - return -EINVAL; + goto unsupported; } if_phy->phy_if_mode = submode; @@ -123,6 +138,11 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) } return 0; + +unsupported: + dev_warn(dev, "port%u: unsupported mode: \"%s\"\n", + if_phy->id, phy_modes(submode)); + return -EINVAL; } static const @@ -188,6 +208,13 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = { .regfields = phy_gmii_sel_fields_am654, }; +static const +struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { + .use_of_data = true, + .regfields = phy_gmii_sel_fields_am654, + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII), +}; + static const struct of_device_id phy_gmii_sel_id_table[] = { { .compatible = "ti,am3352-phy-gmii-sel", @@ -209,6 +236,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = { .compatible = "ti,am654-phy-gmii-sel", .data = &phy_gmii_sel_soc_am654, }, + { + .compatible = "ti,j7200-cpsw5g-phy-gmii-sel", + .data = &phy_gmii_sel_cpsw5g_soc_j7200, + }, {} }; MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table); @@ -350,6 +381,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; const struct of_device_id *of_id; struct phy_gmii_sel_priv *priv; + u32 main_ports = 1; int ret; of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node); @@ -363,6 +395,15 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->soc_data = of_id->data; priv->num_ports = priv->soc_data->num_ports; + of_property_read_u32(node, "ti,qsgmii-main-ports", &main_ports); + /* + * Ensure that main_ports is within bounds. If the property + * ti,qsgmii-main-ports is not mentioned, or the value mentioned + * is out of bounds, default to 1. + */ + if (main_ports < 1 || main_ports > 4) + main_ports = 1; + priv->qsgmii_main_ports = PHY_GMII_PORT(main_ports); priv->regmap = syscon_node_to_regmap(node->parent); if (IS_ERR(priv->regmap)) { diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 70bac931f99a..41725c6bcdf6 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,15 @@ #include #include +#define REF_CLK_19_2MHZ 19200000 +#define REF_CLK_25MHZ 25000000 +#define REF_CLK_100MHZ 100000000 +#define REF_CLK_156_25MHZ 156250000 + +/* SCM offsets */ +#define SERDES_SUP_CTRL 0x4400 + +/* SERDES offsets */ #define WIZ_SERDES_CTRL 0x404 #define WIZ_SERDES_TOP_CTRL 0x408 #define WIZ_SERDES_RST 0x40c @@ -85,6 +95,18 @@ static const struct reg_field pma_cmn_refclk_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27); static const struct reg_field pma_cmn_refclk1_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25); + +static const struct reg_field sup_pll0_refclk_mux_sel = + REG_FIELD(SERDES_SUP_CTRL, 0, 1); +static const struct reg_field sup_pll1_refclk_mux_sel = + REG_FIELD(SERDES_SUP_CTRL, 2, 3); +static const struct reg_field sup_pma_cmn_refclk1_int_mode = + REG_FIELD(SERDES_SUP_CTRL, 4, 5); +static const struct reg_field sup_refclk_dig_sel_10g = + REG_FIELD(SERDES_SUP_CTRL, 6, 7); +static const struct reg_field sup_legacy_clk_override = + REG_FIELD(SERDES_SUP_CTRL, 8, 8); + static const char * const output_clk_names[] = { [TI_WIZ_PLL0_REFCLK] = "pll0-refclk", [TI_WIZ_PLL1_REFCLK] = "pll1-refclk", @@ -129,6 +151,26 @@ static const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(3), 22, 23), }; +static const struct reg_field p0_mac_src_sel[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANECTL(0), 20, 21), + REG_FIELD(WIZ_LANECTL(1), 20, 21), + REG_FIELD(WIZ_LANECTL(2), 20, 21), + REG_FIELD(WIZ_LANECTL(3), 20, 21), +}; + +static const struct reg_field p0_rxfclk_sel[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANECTL(0), 6, 7), + REG_FIELD(WIZ_LANECTL(1), 6, 7), + REG_FIELD(WIZ_LANECTL(2), 6, 7), + REG_FIELD(WIZ_LANECTL(3), 6, 7), +}; + +static const struct reg_field p0_refclk_sel[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANECTL(0), 18, 19), + REG_FIELD(WIZ_LANECTL(1), 18, 19), + REG_FIELD(WIZ_LANECTL(2), 18, 19), + REG_FIELD(WIZ_LANECTL(3), 18, 19), +}; static const struct reg_field p_mac_div_sel0[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANEDIV(0), 16, 22), REG_FIELD(WIZ_LANEDIV(1), 16, 22), @@ -228,6 +270,27 @@ static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = { }, }; +static const struct wiz_clk_mux_sel clk_mux_sel_10g_2_refclk[] = { + { + .num_parents = 3, + .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, + .table = { 2, 3, 0 }, + .node_name = "pll0-refclk", + }, + { + .num_parents = 3, + .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, + .table = { 2, 3, 0 }, + .node_name = "pll1-refclk", + }, + { + .num_parents = 3, + .parents = { WIZ_CORE_REFCLK, WIZ_CORE_REFCLK1, WIZ_EXT_REFCLK }, + .table = { 2, 3, 0 }, + .node_name = "refclk-dig", + }, +}; + static const struct clk_div_table clk_div_table[] = { { .val = 0, .div = 1, }, { .val = 1, .div = 2, }, @@ -249,14 +312,18 @@ static const struct wiz_clk_div_sel clk_div_sel[] = { enum wiz_type { J721E_WIZ_16G, - J721E_WIZ_10G, + J721E_WIZ_10G, /* Also for J7200 SR1.0 */ AM64_WIZ_10G, + J7200_WIZ_10G, /* J7200 SR2.0 */ }; struct wiz_data { enum wiz_type type; + const struct reg_field *pll0_refclk_mux_sel; + const struct reg_field *pll1_refclk_mux_sel; const struct reg_field *refclk_dig_sel; const struct reg_field *pma_cmn_refclk1_dig_div; + const struct reg_field *pma_cmn_refclk1_int_mode; const struct wiz_clk_mux_sel *clk_mux_sel; unsigned int clk_div_sel_num; }; @@ -266,6 +333,7 @@ struct wiz_data { struct wiz { struct regmap *regmap; + struct regmap *scm_regmap; enum wiz_type type; const struct wiz_clk_mux_sel *clk_mux_sel; const struct wiz_clk_div_sel *clk_div_sel; @@ -280,13 +348,18 @@ struct wiz { struct regmap_field *p_mac_div_sel0[WIZ_MAX_LANES]; struct regmap_field *p_mac_div_sel1[WIZ_MAX_LANES]; struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES]; + struct regmap_field *p0_mac_src_sel[WIZ_MAX_LANES]; + struct regmap_field *p0_rxfclk_sel[WIZ_MAX_LANES]; + struct regmap_field *p0_refclk_sel[WIZ_MAX_LANES]; struct regmap_field *pma_cmn_refclk_int_mode; + struct regmap_field *pma_cmn_refclk1_int_mode; struct regmap_field *pma_cmn_refclk_mode; struct regmap_field *pma_cmn_refclk_dig_div; struct regmap_field *pma_cmn_refclk1_dig_div; struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS]; struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G]; struct regmap_field *typec_ln10_swap; + struct regmap_field *sup_legacy_clk_override; struct device *dev; u32 num_lanes; @@ -325,7 +398,9 @@ static int wiz_p_mac_div_sel(struct wiz *wiz) int i; for (i = 0; i < num_lanes; i++) { - if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) { + if (wiz->lane_phy_type[i] == PHY_TYPE_SGMII || + wiz->lane_phy_type[i] == PHY_TYPE_QSGMII || + wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { ret = regmap_field_write(wiz->p_mac_div_sel0[i], 1); if (ret) return ret; @@ -354,6 +429,13 @@ static int wiz_mode_select(struct wiz *wiz) else continue; + if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { + ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3); + ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3); + ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3); + mode = LANE_MODE_GEN1; + } + ret = regmap_field_write(wiz->p_standard_mode[i], mode); if (ret) return ret; @@ -416,6 +498,7 @@ static int wiz_init(struct wiz *wiz) static int wiz_regfield_init(struct wiz *wiz) { struct regmap *regmap = wiz->regmap; + struct regmap *scm_regmap = wiz->regmap; /* updated later to scm_regmap if applicable */ int num_lanes = wiz->num_lanes; struct device *dev = wiz->dev; const struct wiz_data *data = wiz->data; @@ -465,27 +548,46 @@ static int wiz_regfield_init(struct wiz *wiz) } } + if (wiz->scm_regmap) { + scm_regmap = wiz->scm_regmap; + wiz->sup_legacy_clk_override = + devm_regmap_field_alloc(dev, scm_regmap, sup_legacy_clk_override); + if (IS_ERR(wiz->sup_legacy_clk_override)) { + dev_err(dev, "SUP_LEGACY_CLK_OVERRIDE reg field init failed\n"); + return PTR_ERR(wiz->sup_legacy_clk_override); + } + } + wiz->mux_sel_field[PLL0_REFCLK] = - devm_regmap_field_alloc(dev, regmap, pll0_refclk_mux_sel); + devm_regmap_field_alloc(dev, scm_regmap, *data->pll0_refclk_mux_sel); if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) { dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n"); return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]); } wiz->mux_sel_field[PLL1_REFCLK] = - devm_regmap_field_alloc(dev, regmap, pll1_refclk_mux_sel); + devm_regmap_field_alloc(dev, scm_regmap, *data->pll1_refclk_mux_sel); if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) { dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n"); return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]); } - wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, + wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, scm_regmap, *data->refclk_dig_sel); if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) { dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n"); return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]); } + if (data->pma_cmn_refclk1_int_mode) { + wiz->pma_cmn_refclk1_int_mode = + devm_regmap_field_alloc(dev, scm_regmap, *data->pma_cmn_refclk1_int_mode); + if (IS_ERR(wiz->pma_cmn_refclk1_int_mode)) { + dev_err(dev, "PMA_CMN_REFCLK1_INT_MODE reg field init failed\n"); + return PTR_ERR(wiz->pma_cmn_refclk1_int_mode); + } + } + for (i = 0; i < num_lanes; i++) { wiz->p_enable[i] = devm_regmap_field_alloc(dev, regmap, p_enable[i]); @@ -523,6 +625,24 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->p0_fullrt_div[i]); } + wiz->p0_mac_src_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_mac_src_sel[i]); + if (IS_ERR(wiz->p0_mac_src_sel[i])) { + dev_err(dev, "P%d_MAC_SRC_SEL reg field init failed\n", i); + return PTR_ERR(wiz->p0_mac_src_sel[i]); + } + + wiz->p0_rxfclk_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_rxfclk_sel[i]); + if (IS_ERR(wiz->p0_rxfclk_sel[i])) { + dev_err(dev, "P%d_RXFCLK_SEL reg field init failed\n", i); + return PTR_ERR(wiz->p0_rxfclk_sel[i]); + } + + wiz->p0_refclk_sel[i] = devm_regmap_field_alloc(dev, regmap, p0_refclk_sel[i]); + if (IS_ERR(wiz->p0_refclk_sel[i])) { + dev_err(dev, "P%d_REFCLK_SEL reg field init failed\n", i); + return PTR_ERR(wiz->p0_refclk_sel[i]); + } + wiz->p_mac_div_sel0[i] = devm_regmap_field_alloc(dev, regmap, p_mac_div_sel0[i]); if (IS_ERR(wiz->p_mac_div_sel0[i])) { @@ -597,6 +717,8 @@ static int wiz_phy_en_refclk_register(struct wiz *wiz) struct device *dev = wiz->dev; struct clk_init_data *init; struct clk *clk; + char *clk_name; + unsigned int sz; wiz_phy_en_refclk = devm_kzalloc(dev, sizeof(*wiz_phy_en_refclk), GFP_KERNEL); if (!wiz_phy_en_refclk) @@ -606,12 +728,23 @@ static int wiz_phy_en_refclk_register(struct wiz *wiz) init->ops = &wiz_phy_en_refclk_ops; init->flags = 0; - init->name = output_clk_names[TI_WIZ_PHY_EN_REFCLK]; + + sz = strlen(dev_name(dev)) + strlen(output_clk_names[TI_WIZ_PHY_EN_REFCLK]) + 2; + + clk_name = kzalloc(sz, GFP_KERNEL); + if (!clk_name) + return -ENOMEM; + + snprintf(clk_name, sz, "%s_%s", dev_name(dev), output_clk_names[TI_WIZ_PHY_EN_REFCLK]); + init->name = clk_name; wiz_phy_en_refclk->phy_en_refclk = wiz->phy_en_refclk; wiz_phy_en_refclk->hw.init = init; clk = devm_clk_register(dev, &wiz_phy_en_refclk->hw); + + kfree(clk_name); + if (IS_ERR(clk)) return PTR_ERR(clk); @@ -856,9 +989,13 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) struct device_node *clk_node; int i; - if (wiz->type == AM64_WIZ_10G) { + switch (wiz->type) { + case AM64_WIZ_10G: + case J7200_WIZ_10G: of_clk_del_provider(dev->of_node); return; + default: + break; } for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { @@ -885,9 +1022,6 @@ static int wiz_clock_register(struct wiz *wiz) int ret; int i; - if (wiz->type != AM64_WIZ_10G) - return 0; - clk_index = TI_WIZ_PLL0_REFCLK; for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) { ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index); @@ -937,6 +1071,41 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) else regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3); + switch (wiz->type) { + case AM64_WIZ_10G: + case J7200_WIZ_10G: + switch (rate) { + case REF_CLK_100MHZ: + regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0x2); + break; + case REF_CLK_156_25MHZ: + regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0x3); + break; + default: + regmap_field_write(wiz->div_sel_field[CMN_REFCLK_DIG_DIV], 0); + break; + } + break; + default: + break; + } + + if (wiz->data->pma_cmn_refclk1_int_mode) { + clk = devm_clk_get(dev, "core_ref1_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "core_ref1_clk clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + wiz->input_clks[WIZ_CORE_REFCLK1] = clk; + + rate = clk_get_rate(clk); + if (rate >= 100000000) + regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1); + else + regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3); + } + clk = devm_clk_get(dev, "ext_ref_clk"); if (IS_ERR(clk)) { dev_err(dev, "ext_ref_clk clock not found\n"); @@ -951,11 +1120,15 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) else regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); - if (wiz->type == AM64_WIZ_10G) { + switch (wiz->type) { + case AM64_WIZ_10G: + case J7200_WIZ_10G: ret = wiz_clock_register(wiz); if (ret) dev_err(dev, "Failed to register wiz clocks\n"); return ret; + default: + break; } for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { @@ -1025,12 +1198,19 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev, static int wiz_phy_fullrt_div(struct wiz *wiz, int lane) { - if (wiz->type != AM64_WIZ_10G) + switch (wiz->type) { + case AM64_WIZ_10G: + if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); + break; + case J721E_WIZ_10G: + case J7200_WIZ_10G: + if (wiz->lane_phy_type[lane] == PHY_TYPE_SGMII) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x2); + break; + default: return 0; - - if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) - return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); - + } return 0; } @@ -1083,6 +1263,8 @@ static const struct regmap_config wiz_regmap_config = { static struct wiz_data j721e_16g_data = { .type = J721E_WIZ_16G, + .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, .refclk_dig_sel = &refclk_dig_sel_16g, .pma_cmn_refclk1_dig_div = &pma_cmn_refclk1_dig_div, .clk_mux_sel = clk_mux_sel_16g, @@ -1091,6 +1273,8 @@ static struct wiz_data j721e_16g_data = { static struct wiz_data j721e_10g_data = { .type = J721E_WIZ_10G, + .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, .refclk_dig_sel = &refclk_dig_sel_10g, .clk_mux_sel = clk_mux_sel_10g, .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, @@ -1098,11 +1282,23 @@ static struct wiz_data j721e_10g_data = { static struct wiz_data am64_10g_data = { .type = AM64_WIZ_10G, + .pll0_refclk_mux_sel = &pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &pll1_refclk_mux_sel, .refclk_dig_sel = &refclk_dig_sel_10g, .clk_mux_sel = clk_mux_sel_10g, .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, }; +static struct wiz_data j7200_pg2_10g_data = { + .type = J7200_WIZ_10G, + .pll0_refclk_mux_sel = &sup_pll0_refclk_mux_sel, + .pll1_refclk_mux_sel = &sup_pll1_refclk_mux_sel, + .refclk_dig_sel = &sup_refclk_dig_sel_10g, + .pma_cmn_refclk1_int_mode = &sup_pma_cmn_refclk1_int_mode, + .clk_mux_sel = clk_mux_sel_10g_2_refclk, + .clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G, +}; + static const struct of_device_id wiz_id_table[] = { { .compatible = "ti,j721e-wiz-16g", .data = &j721e_16g_data, @@ -1113,6 +1309,9 @@ static const struct of_device_id wiz_id_table[] = { { .compatible = "ti,am64-wiz-10g", .data = &am64_10g_data, }, + { + .compatible = "ti,j7200-wiz-10g", .data = &j7200_pg2_10g_data, + }, {} }; MODULE_DEVICE_TABLE(of, wiz_id_table); @@ -1210,6 +1409,17 @@ static int wiz_probe(struct platform_device *pdev) goto err_addr_to_resource; } + wiz->scm_regmap = syscon_regmap_lookup_by_phandle(node, "ti,scm"); + if (IS_ERR(wiz->scm_regmap)) { + if (wiz->type == J7200_WIZ_10G) { + dev_err(dev, "Couldn't get ti,scm regmap\n"); + ret = -ENODEV; + goto err_addr_to_resource; + } + + wiz->scm_regmap = NULL; + } + ret = of_property_read_u32(node, "num-lanes", &num_lanes); if (ret) { dev_err(dev, "Failed to read num-lanes property\n"); @@ -1254,7 +1464,7 @@ static int wiz_probe(struct platform_device *pdev) ret = wiz_get_lane_phy_types(dev, wiz); if (ret) - return ret; + goto err_addr_to_resource; wiz->dev = dev; wiz->regmap = regmap; @@ -1271,6 +1481,10 @@ static int wiz_probe(struct platform_device *pdev) goto err_addr_to_resource; } + /* Enable supplemental Control override if available */ + if (wiz->scm_regmap) + regmap_field_write(wiz->sup_legacy_clk_override, 1); + phy_reset_dev = &wiz->wiz_phy_reset_dev; phy_reset_dev->dev = dev; phy_reset_dev->ops = &wiz_phy_reset_ops, diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 5c83f71c1d0e..26e3995ac062 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1760,7 +1760,7 @@ tty3270_flush_chars(struct tty_struct *tty) * Check for visible/invisible input switches */ static void -tty3270_set_termios(struct tty_struct *tty, struct ktermios *old) +tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old) { struct tty3270 *tp; int new; diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index d95b07896a3e..76515c33e639 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -11,11 +11,12 @@ #include "bus.h" #include "sysfs_local.h" -static DEFINE_IDA(sdw_ida); +static DEFINE_IDA(sdw_bus_ida); +static DEFINE_IDA(sdw_peripheral_ida); static int sdw_get_id(struct sdw_bus *bus) { - int rc = ida_alloc(&sdw_ida, GFP_KERNEL); + int rc = ida_alloc(&sdw_bus_ida, GFP_KERNEL); if (rc < 0) return rc; @@ -75,7 +76,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, /* * Initialize multi_link flag - * TODO: populate this flag by reading property from FW node */ bus->multi_link = false; if (bus->ops->read_prop) { @@ -157,9 +157,11 @@ static int sdw_delete_slave(struct device *dev, void *data) mutex_lock(&bus->bus_lock); - if (slave->dev_num) /* clear dev_num if assigned */ + if (slave->dev_num) { /* clear dev_num if assigned */ clear_bit(slave->dev_num, bus->assigned); - + if (bus->dev_num_ida_min) + ida_free(&sdw_peripheral_ida, slave->dev_num); + } list_del_init(&slave->node); mutex_unlock(&bus->bus_lock); @@ -179,7 +181,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus) sdw_master_device_del(bus); sdw_bus_debugfs_exit(bus); - ida_free(&sdw_ida, bus->id); + ida_free(&sdw_bus_ida, bus->id); } EXPORT_SYMBOL(sdw_bus_master_delete); @@ -671,10 +673,18 @@ static int sdw_get_device_num(struct sdw_slave *slave) { int bit; - bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); - if (bit == SDW_MAX_DEVICES) { - bit = -ENODEV; - goto err; + if (slave->bus->dev_num_ida_min) { + bit = ida_alloc_range(&sdw_peripheral_ida, + slave->bus->dev_num_ida_min, SDW_MAX_DEVICES, + GFP_KERNEL); + if (bit < 0) + goto err; + } else { + bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); + if (bit == SDW_MAX_DEVICES) { + bit = -ENODEV; + goto err; + } } /* @@ -751,7 +761,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, } EXPORT_SYMBOL(sdw_extract_slave_id); -static int sdw_program_device_num(struct sdw_bus *bus) +static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed) { u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0}; struct sdw_slave *slave, *_s; @@ -761,6 +771,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) int count = 0, ret; u64 addr; + *programmed = false; + /* No Slave, so use raw xfer api */ ret = sdw_fill_msg(&msg, NULL, SDW_SCP_DEVID_0, SDW_NUM_DEV_ID_REGISTERS, 0, SDW_MSG_FLAG_READ, buf); @@ -795,6 +807,16 @@ static int sdw_program_device_num(struct sdw_bus *bus) if (sdw_compare_devid(slave, id) == 0) { found = true; + /* + * To prevent skipping state-machine stages don't + * program a device until we've seen it UNATTACH. + * Must return here because no other device on #0 + * can be detected until this one has been + * assigned a device ID. + */ + if (slave->status != SDW_SLAVE_UNATTACHED) + return 0; + /* * Assign a new dev_num to this Slave and * not mark it present. It will be marked @@ -809,6 +831,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) return ret; } + *programmed = true; + break; } } @@ -848,13 +872,13 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, mutex_lock(&bus->bus_lock); dev_vdbg(bus->dev, - "%s: changing status slave %d status %d new status %d\n", - __func__, slave->dev_num, slave->status, status); + "changing status slave %d status %d new status %d\n", + slave->dev_num, slave->status, status); if (status == SDW_SLAVE_UNATTACHED) { dev_dbg(&slave->dev, - "%s: initializing enumeration and init completion for Slave %d\n", - __func__, slave->dev_num); + "initializing enumeration and init completion for Slave %d\n", + slave->dev_num); init_completion(&slave->enumeration_complete); init_completion(&slave->initialization_complete); @@ -862,8 +886,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, } else if ((status == SDW_SLAVE_ATTACHED) && (slave->status == SDW_SLAVE_UNATTACHED)) { dev_dbg(&slave->dev, - "%s: signaling enumeration completion for Slave %d\n", - __func__, slave->dev_num); + "signaling enumeration completion for Slave %d\n", + slave->dev_num); complete(&slave->enumeration_complete); } @@ -1630,7 +1654,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) port = buf2[0] & SDW_SCP_INTSTAT2_PORT4_10; for_each_set_bit(bit, &port, 8) { /* scp2 ports start from 4 */ - port_num = bit + 3; + port_num = bit + 4; sdw_handle_port_interrupt(slave, port_num, &port_status[port_num]); @@ -1642,7 +1666,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) port = buf2[1] & SDW_SCP_INTSTAT3_PORT11_14; for_each_set_bit(bit, &port, 8) { /* scp3 ports start from 11 */ - port_num = bit + 10; + port_num = bit + 11; sdw_handle_port_interrupt(slave, port_num, &port_status[port_num]); @@ -1768,7 +1792,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, { enum sdw_slave_status prev_status; struct sdw_slave *slave; - bool attached_initializing; + bool attached_initializing, id_programmed; int i, ret = 0; /* first check if any Slaves fell off the bus */ @@ -1789,19 +1813,33 @@ int sdw_handle_slave_status(struct sdw_bus *bus, dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", i, slave->status); sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ + ret = sdw_update_slave_status(slave, status[i]); + if (ret < 0) + dev_warn(&slave->dev, "Update Slave status failed:%d\n", ret); } } if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); - ret = sdw_program_device_num(bus); - if (ret < 0) - dev_err(bus->dev, "Slave attach failed: %d\n", ret); + /* - * programming a device number will have side effects, - * so we deal with other devices at a later time + * Programming a device number will have side effects, + * so we deal with other devices at a later time. + * This relies on those devices reporting ATTACHED, which will + * trigger another call to this function. This will only + * happen if at least one device ID was programmed. + * Error returns from sdw_program_device_num() are currently + * ignored because there's no useful recovery that can be done. + * Returning the error here could result in the current status + * of other devices not being handled, because if no device IDs + * were programmed there's nothing to guarantee a status change + * to trigger another call to this function. */ - return ret; + sdw_program_device_num(bus, &id_programmed); + if (id_programmed) + return 0; } /* Continue to check other slave statuses */ @@ -1870,8 +1908,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, "Update Slave status failed:%d\n", ret); if (attached_initializing) { dev_dbg(&slave->dev, - "%s: signaling initialization completion for Slave %d\n", - __func__, slave->dev_num); + "signaling initialization completion for Slave %d\n", + slave->dev_num); complete(&slave->initialization_complete); diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 615b0b63a3e1..93929f19d083 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -544,9 +544,12 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns, return SDW_CMD_IGNORED; } - /* fill response */ - for (i = 0; i < count; i++) - msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA, cdns->response_buf[i]); + if (msg->flags == SDW_MSG_FLAG_READ) { + /* fill response */ + for (i = 0; i < count; i++) + msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA, + cdns->response_buf[i]); + } return SDW_CMD_OK; } @@ -566,7 +569,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, } base = CDNS_MCP_CMD_BASE; - addr = msg->addr; + addr = msg->addr + offset; for (i = 0; i < count; i++) { data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num); @@ -705,18 +708,15 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) { ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN, CDNS_MCP_CMD_LEN, false); - if (ret < 0) - goto exit; + if (ret != SDW_CMD_OK) + return ret; } if (!(msg->len % CDNS_MCP_CMD_LEN)) - goto exit; + return SDW_CMD_OK; - ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN, - msg->len % CDNS_MCP_CMD_LEN, false); - -exit: - return ret; + return _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN, + msg->len % CDNS_MCP_CMD_LEN, false); } EXPORT_SYMBOL(cdns_xfer_msg); @@ -790,6 +790,7 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; bool is_slave = false; u32 mask; + u32 val; int i, set_status; memset(status, 0, sizeof(status)); @@ -797,41 +798,38 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, for (i = 0; i <= SDW_MAX_DEVICES; i++) { mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) & CDNS_MCP_SLAVE_STATUS_BITS; - if (!mask) - continue; - is_slave = true; set_status = 0; - if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) { - status[i] = SDW_SLAVE_RESERVED; - set_status++; + if (mask) { + is_slave = true; + + if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) { + status[i] = SDW_SLAVE_RESERVED; + set_status++; + } + + if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) { + status[i] = SDW_SLAVE_ATTACHED; + set_status++; + } + + if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) { + status[i] = SDW_SLAVE_ALERT; + set_status++; + } + + if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) { + status[i] = SDW_SLAVE_UNATTACHED; + set_status++; + } } - if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) { - status[i] = SDW_SLAVE_ATTACHED; - set_status++; - } - - if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) { - status[i] = SDW_SLAVE_ALERT; - set_status++; - } - - if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) { - status[i] = SDW_SLAVE_UNATTACHED; - set_status++; - } - - /* first check if Slave reported multiple status */ - if (set_status > 1) { - u32 val; - - dev_warn_ratelimited(cdns->dev, - "Slave %d reported multiple Status: %d\n", - i, mask); - - /* check latest status extracted from PING commands */ + /* + * check that there was a single reported Slave status and when + * there is not use the latest status extracted from PING commands + */ + if (set_status != 1) { val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); val >>= (i * 2); @@ -850,11 +848,6 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, status[i] = SDW_SLAVE_RESERVED; break; } - - dev_warn_ratelimited(cdns->dev, - "Slave %d status updated to %d\n", - i, status[i]); - } } @@ -969,9 +962,22 @@ static void cdns_update_slave_status_work(struct work_struct *work) u32 device0_status; int retry_count = 0; + /* + * Clear main interrupt first so we don't lose any assertions + * that happen during this function. + */ + cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK); + slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0); slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1); + /* + * Clear the bits before handling so we don't lose any + * bits that re-assert. + */ + cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0); + cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1); + /* combine the two status */ slave_intstat = ((u64)slave1 << 32) | slave0; @@ -979,8 +985,6 @@ static void cdns_update_slave_status_work(struct work_struct *work) update_status: cdns_update_slave_status(cdns, slave_intstat); - cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0); - cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1); /* * When there is more than one peripheral per link, it's @@ -997,6 +1001,11 @@ update_status: * attention with PING commands. There is no need to check for * ALERTS since they are not allowed until a non-zero * device_number is assigned. + * + * Do not clear the INTSTAT0/1. While looping to enumerate devices on + * #0 there could be status changes on other devices - these must + * be kept in the INTSTAT so they can be handled when all #0 devices + * have been handled. */ device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); @@ -1016,8 +1025,7 @@ update_status: } } - /* clear and unmask Slave interrupt now */ - cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK); + /* unmask Slave interrupt now */ cdns_updatel(cdns, CDNS_MCP_INTMASK, CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK); diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 747983743a14..f81cdd83ec26 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -55,7 +55,26 @@ static const struct adr_remap dell_sku_0A3E[] = { {} }; +/* + * The HP Omen 16-k0005TX does not expose the correct version of RT711 on link0 + * and does not expose a RT1316 on link3 + */ +static const struct adr_remap hp_omen_16[] = { + /* rt711-sdca on link0 */ + { + 0x000020025d071100ull, + 0x000030025d071101ull + }, + /* rt1316-sdca on link3 */ + { + 0x000120025d071100ull, + 0x000330025d131601ull + }, + {} +}; + static const struct dmi_system_id adr_remap_quirk_table[] = { + /* TGL devices */ { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), @@ -78,6 +97,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { }, .driver_data = (void *)dell_sku_0A3E, }, + /* ADL devices */ + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"), + }, + .driver_data = (void *)hp_omen_16, + }, {} }; diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index a5965e8827b9..244209358784 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -22,6 +22,9 @@ #include "bus.h" #include "intel.h" +/* IDA min selected to avoid conflicts with HDaudio/iDISP SDI values */ +#define INTEL_DEV_NUM_IDA_MIN 4 + #define INTEL_MASTER_SUSPEND_DELAY_MS 3000 #define INTEL_MASTER_RESET_ITERATIONS 10 @@ -135,7 +138,7 @@ static int intel_reg_show(struct seq_file *s_file, void *data) if (!buf) return -ENOMEM; - links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0); + links = intel_readl(s, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_LCOUNT_MASK; ret = scnprintf(buf, RD_BUF, "Register Value\n"); ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n"); @@ -167,9 +170,8 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSYCHC(i, j)); } - ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n"); + ret += scnprintf(buf + ret, RD_BUF - ret, "\n IOCTL, CTMCTL\n"); - ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i)); ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i)); ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i)); } @@ -258,86 +260,6 @@ static void intel_debugfs_exit(struct sdw_intel *sdw) {} /* * shim ops */ - -static int intel_link_power_up(struct sdw_intel *sdw) -{ - unsigned int link_id = sdw->instance; - void __iomem *shim = sdw->link_res->shim; - u32 *shim_mask = sdw->link_res->shim_mask; - struct sdw_bus *bus = &sdw->cdns.bus; - struct sdw_master_prop *prop = &bus->prop; - u32 spa_mask, cpa_mask; - u32 link_control; - int ret = 0; - u32 syncprd; - u32 sync_reg; - - mutex_lock(sdw->link_res->shim_lock); - - /* - * The hardware relies on an internal counter, typically 4kHz, - * to generate the SoundWire SSP - which defines a 'safe' - * synchronization point between commands and audio transport - * and allows for multi link synchronization. The SYNCPRD value - * is only dependent on the oscillator clock provided to - * the IP, so adjust based on _DSD properties reported in DSDT - * tables. The values reported are based on either 24MHz - * (CNL/CML) or 38.4 MHz (ICL/TGL+). - */ - if (prop->mclk_freq % 6000000) - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; - else - syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; - - if (!*shim_mask) { - dev_dbg(sdw->cdns.dev, "%s: powering up all links\n", __func__); - - /* we first need to program the SyncPRD/CPU registers */ - dev_dbg(sdw->cdns.dev, - "%s: first link up, programming SYNCPRD\n", __func__); - - /* set SyncPRD period */ - sync_reg = intel_readl(shim, SDW_SHIM_SYNC); - u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD); - - /* Set SyncCPU bit */ - sync_reg |= SDW_SHIM_SYNC_SYNCCPU; - intel_writel(shim, SDW_SHIM_SYNC, sync_reg); - - /* Link power up sequence */ - link_control = intel_readl(shim, SDW_SHIM_LCTL); - - /* only power-up enabled links */ - spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask); - cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask); - - link_control |= spa_mask; - - ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); - if (ret < 0) { - dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret); - goto out; - } - - /* SyncCPU will change once link is active */ - ret = intel_wait_bit(shim, SDW_SHIM_SYNC, - SDW_SHIM_SYNC_SYNCCPU, 0); - if (ret < 0) { - dev_err(sdw->cdns.dev, - "Failed to set SHIM_SYNC: %d\n", ret); - goto out; - } - } - - *shim_mask |= BIT(link_id); - - sdw->cdns.link_up = true; -out: - mutex_unlock(sdw->link_res->shim_lock); - - return ret; -} - /* this needs to be called with shim_lock */ static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw) { @@ -389,15 +311,13 @@ static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw) /* at this point Integration Glue has full control of the I/Os */ } -static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) +/* this needs to be called with shim_lock */ +static void intel_shim_init(struct sdw_intel *sdw) { void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; - int ret = 0; u16 ioctl = 0, act = 0; - mutex_lock(sdw->link_res->shim_lock); - /* Initialize Shim */ ioctl |= SDW_SHIM_IOCTL_BKE; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); @@ -422,10 +342,17 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) act |= SDW_SHIM_CTMCTL_DODS; intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); usleep_range(10, 15); +} - mutex_unlock(sdw->link_res->shim_lock); +static int intel_shim_check_wake(struct sdw_intel *sdw) +{ + void __iomem *shim; + u16 wake_sts; - return ret; + shim = sdw->link_res->shim; + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + + return wake_sts & BIT(sdw->instance); } static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) @@ -454,6 +381,88 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) mutex_unlock(sdw->link_res->shim_lock); } +static int intel_link_power_up(struct sdw_intel *sdw) +{ + unsigned int link_id = sdw->instance; + void __iomem *shim = sdw->link_res->shim; + u32 *shim_mask = sdw->link_res->shim_mask; + struct sdw_bus *bus = &sdw->cdns.bus; + struct sdw_master_prop *prop = &bus->prop; + u32 spa_mask, cpa_mask; + u32 link_control; + int ret = 0; + u32 syncprd; + u32 sync_reg; + + mutex_lock(sdw->link_res->shim_lock); + + /* + * The hardware relies on an internal counter, typically 4kHz, + * to generate the SoundWire SSP - which defines a 'safe' + * synchronization point between commands and audio transport + * and allows for multi link synchronization. The SYNCPRD value + * is only dependent on the oscillator clock provided to + * the IP, so adjust based on _DSD properties reported in DSDT + * tables. The values reported are based on either 24MHz + * (CNL/CML) or 38.4 MHz (ICL/TGL+). + */ + if (prop->mclk_freq % 6000000) + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; + else + syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; + + if (!*shim_mask) { + dev_dbg(sdw->cdns.dev, "powering up all links\n"); + + /* we first need to program the SyncPRD/CPU registers */ + dev_dbg(sdw->cdns.dev, + "first link up, programming SYNCPRD\n"); + + /* set SyncPRD period */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD); + + /* Set SyncCPU bit */ + sync_reg |= SDW_SHIM_SYNC_SYNCCPU; + intel_writel(shim, SDW_SHIM_SYNC, sync_reg); + + /* Link power up sequence */ + link_control = intel_readl(shim, SDW_SHIM_LCTL); + + /* only power-up enabled links */ + spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask); + cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask); + + link_control |= spa_mask; + + ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + if (ret < 0) { + dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret); + goto out; + } + + /* SyncCPU will change once link is active */ + ret = intel_wait_bit(shim, SDW_SHIM_SYNC, + SDW_SHIM_SYNC_SYNCCPU, 0); + if (ret < 0) { + dev_err(sdw->cdns.dev, + "Failed to set SHIM_SYNC: %d\n", ret); + goto out; + } + } + + *shim_mask |= BIT(link_id); + + sdw->cdns.link_up = true; + + intel_shim_init(sdw); + +out: + mutex_unlock(sdw->link_res->shim_lock); + + return ret; +} + static int intel_link_power_down(struct sdw_intel *sdw) { u32 link_control, spa_mask, cpa_mask; @@ -476,7 +485,7 @@ static int intel_link_power_down(struct sdw_intel *sdw) if (!*shim_mask) { - dev_dbg(sdw->cdns.dev, "%s: powering down all links\n", __func__); + dev_dbg(sdw->cdns.dev, "powering down all links\n"); /* Link power down sequence */ link_control = intel_readl(shim, SDW_SHIM_LCTL); @@ -1169,11 +1178,20 @@ static int intel_create_dai(struct sdw_cdns *cdns, static int intel_register_dai(struct sdw_intel *sdw) { + struct sdw_cdns_stream_config config; struct sdw_cdns *cdns = &sdw->cdns; struct sdw_cdns_streams *stream; struct snd_soc_dai_driver *dais; int num_dai, ret, off = 0; + /* Read the PDI config and initialize cadence PDI */ + intel_pdi_init(sdw, &config); + ret = sdw_cdns_pdi_init(cdns, config); + if (ret) + return ret; + + intel_pdi_ch_update(sdw); + /* DAIs are created based on total number of PDIs supported */ num_dai = cdns->pcm.num_pdi; @@ -1201,8 +1219,208 @@ static int intel_register_dai(struct sdw_intel *sdw) if (ret) return ret; - return snd_soc_register_component(cdns->dev, &dai_component, - dais, num_dai); + return devm_snd_soc_register_component(cdns->dev, &dai_component, + dais, num_dai); +} + +static int intel_start_bus(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + int ret; + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); + return ret; + } + + /* + * follow recommended programming flows to avoid timeouts when + * gsync is enabled + */ + if (bus->multi_link) + intel_shim_sync_arm(sdw); + + ret = sdw_cdns_init(cdns); + if (ret < 0) { + dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret); + goto err_interrupt; + } + + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); + goto err_interrupt; + } + + if (bus->multi_link) { + ret = intel_shim_sync_go(sdw); + if (ret < 0) { + dev_err(dev, "%s: sync go failed: %d\n", __func__, ret); + goto err_interrupt; + } + } + sdw_cdns_check_self_clearing_bits(cdns, __func__, + true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; + +err_interrupt: + sdw_cdns_enable_interrupt(cdns, false); + return ret; +} + +static int intel_start_bus_after_reset(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + bool clock_stop0; + int status; + int ret; + + /* + * An exception condition occurs for the CLK_STOP_BUS_RESET + * case if one or more masters remain active. In this condition, + * all the masters are powered on for they are in the same power + * domain. Master can preserve its context for clock stop0, so + * there is no need to clear slave status and reset bus. + */ + clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); + + if (!clock_stop0) { + + /* + * make sure all Slaves are tagged as UNATTACHED and + * provide reason for reinitialization + */ + + status = SDW_UNATTACH_REQUEST_MASTER_RESET; + sdw_clear_slave_status(bus, status); + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + /* + * follow recommended programming flows to avoid + * timeouts when gsync is enabled + */ + if (bus->multi_link) + intel_shim_sync_arm(sdw); + + /* + * Re-initialize the IP since it was powered-off + */ + sdw_cdns_init(&sdw->cdns); + + } else { + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + } + + ret = sdw_cdns_clock_restart(cdns, !clock_stop0); + if (ret < 0) { + dev_err(dev, "unable to restart clock during resume\n"); + goto err_interrupt; + } + + if (!clock_stop0) { + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "unable to exit bus reset sequence during resume\n"); + goto err_interrupt; + } + + if (bus->multi_link) { + ret = intel_shim_sync_go(sdw); + if (ret < 0) { + dev_err(sdw->cdns.dev, "sync go failed during resume\n"); + goto err_interrupt; + } + } + } + sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; + +err_interrupt: + sdw_cdns_enable_interrupt(cdns, false); + return ret; +} + +static void intel_check_clock_stop(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + bool clock_stop0; + + clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); + if (!clock_stop0) + dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__); +} + +static int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + int ret; + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); + return ret; + } + + ret = sdw_cdns_clock_restart(cdns, false); + if (ret < 0) { + dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret); + sdw_cdns_enable_interrupt(cdns, false); + return ret; + } + + sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks", + true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; +} + +static int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + bool wake_enable = false; + int ret; + + if (clock_stop) { + ret = sdw_cdns_clock_stop(cdns, true); + if (ret < 0) + dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret); + else + wake_enable = true; + } + + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret); + return ret; + } + + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret); + return ret; + } + + intel_shim_wake(sdw, wake_enable); + + return 0; } static int sdw_master_read_intel_prop(struct sdw_bus *bus) @@ -1254,7 +1472,7 @@ static int intel_prop_read(struct sdw_bus *bus) } static struct sdw_master_ops sdw_intel_ops = { - .read_prop = sdw_master_read_prop, + .read_prop = intel_prop_read, .override_adr = sdw_dmi_override_adr, .xfer_msg = cdns_xfer_msg, .xfer_msg_defer = cdns_xfer_msg_defer, @@ -1265,20 +1483,6 @@ static struct sdw_master_ops sdw_intel_ops = { .read_ping_status = cdns_read_ping_status, }; -static int intel_init(struct sdw_intel *sdw) -{ - bool clock_stop; - - /* Initialize shim and controller */ - intel_link_power_up(sdw); - - clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns); - - intel_shim_init(sdw, clock_stop); - - return 0; -} - /* * probe and init (aux_dev_id argument is required by function prototype but not used) */ @@ -1308,11 +1512,11 @@ static int intel_link_probe(struct auxiliary_device *auxdev, cdns->msg_count = 0; bus->link_id = auxdev->id; + bus->dev_num_ida_min = INTEL_DEV_NUM_IDA_MIN; sdw_cdns_probe(cdns); - /* Set property read ops */ - sdw_intel_ops.read_prop = intel_prop_read; + /* Set ops */ bus->ops = &sdw_intel_ops; /* set driver data, accessed by snd_soc_dai_get_drvdata() */ @@ -1345,7 +1549,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev, int intel_link_startup(struct auxiliary_device *auxdev) { - struct sdw_cdns_stream_config config; struct device *dev = &auxdev->dev; struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev); struct sdw_intel *sdw = cdns_to_intel(cdns); @@ -1366,7 +1569,6 @@ int intel_link_startup(struct auxiliary_device *auxdev) multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK); if (!multi_link) { dev_dbg(dev, "Multi-link is disabled\n"); - bus->multi_link = false; } else { /* * hardware-based synchronization is required regardless @@ -1374,68 +1576,31 @@ int intel_link_startup(struct auxiliary_device *auxdev) * synchronization is gated by gsync when the multi-master * mode is set. */ - bus->multi_link = true; bus->hw_sync_min_links = 1; } + bus->multi_link = multi_link; /* Initialize shim, controller */ - ret = intel_init(sdw); + ret = intel_link_power_up(sdw); if (ret) goto err_init; - /* Read the PDI config and initialize cadence PDI */ - intel_pdi_init(sdw, &config); - ret = sdw_cdns_pdi_init(cdns, config); - if (ret) - goto err_init; - - intel_pdi_ch_update(sdw); - - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts\n"); - goto err_init; - } - - /* - * follow recommended programming flows to avoid timeouts when - * gsync is enabled - */ - if (multi_link) - intel_shim_sync_arm(sdw); - - ret = sdw_cdns_init(cdns); - if (ret < 0) { - dev_err(dev, "unable to initialize Cadence IP\n"); - goto err_interrupt; - } - - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence\n"); - goto err_interrupt; - } - - if (multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(dev, "sync go failed: %d\n", ret); - goto err_interrupt; - } - } - sdw_cdns_check_self_clearing_bits(cdns, __func__, - true, INTEL_MASTER_RESET_ITERATIONS); - /* Register DAIs */ ret = intel_register_dai(sdw); if (ret) { dev_err(dev, "DAI registration failed: %d\n", ret); - snd_soc_unregister_component(dev); - goto err_interrupt; + goto err_power_up; } intel_debugfs_init(sdw); + /* start bus */ + ret = intel_start_bus(sdw); + if (ret) { + dev_err(dev, "bus start failed: %d\n", ret); + goto err_power_up; + } + /* Enable runtime PM */ if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) { pm_runtime_set_autosuspend_delay(dev, @@ -1480,15 +1645,14 @@ int intel_link_startup(struct auxiliary_device *auxdev) sdw->startup_done = true; return 0; -err_interrupt: - sdw_cdns_enable_interrupt(cdns, false); +err_power_up: + intel_link_power_down(sdw); err_init: return ret; } static void intel_link_remove(struct auxiliary_device *auxdev) { - struct device *dev = &auxdev->dev; struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev); struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_bus *bus = &cdns->bus; @@ -1501,7 +1665,6 @@ static void intel_link_remove(struct auxiliary_device *auxdev) if (!bus->prop.hw_disabled) { intel_debugfs_exit(sdw); sdw_cdns_enable_interrupt(cdns, false); - snd_soc_unregister_component(dev); } sdw_bus_master_delete(bus); } @@ -1511,8 +1674,6 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) struct device *dev = &auxdev->dev; struct sdw_intel *sdw; struct sdw_bus *bus; - void __iomem *shim; - u16 wake_sts; sdw = auxiliary_get_drvdata(auxdev); bus = &sdw->cdns.bus; @@ -1523,10 +1684,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) return 0; } - shim = sdw->link_res->shim; - wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); - - if (!(wake_sts & BIT(sdw->instance))) + if (!intel_shim_check_wake(sdw)) return 0; /* disable WAKEEN interrupt ASAP to prevent interrupt flood */ @@ -1554,11 +1712,11 @@ static int intel_resume_child_device(struct device *dev, void *data) struct sdw_slave *slave = dev_to_sdw_dev(dev); if (!slave->probed) { - dev_dbg(dev, "%s: skipping device, no probed driver\n", __func__); + dev_dbg(dev, "skipping device, no probed driver\n"); return 0; } if (!slave->dev_num_sticky) { - dev_dbg(dev, "%s: skipping device, never detected on bus\n", __func__); + dev_dbg(dev, "skipping device, never detected on bus\n"); return 0; } @@ -1644,7 +1802,7 @@ static int __maybe_unused intel_suspend(struct device *dev) } if (pm_runtime_suspended(dev)) { - dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__); + dev_dbg(dev, "pm_runtime status: suspended\n"); clock_stop_quirks = sdw->link_res->clock_stop_quirks; @@ -1665,20 +1823,12 @@ static int __maybe_unused intel_suspend(struct device *dev) return 0; } - ret = sdw_cdns_enable_interrupt(cdns, false); + ret = intel_stop_bus(sdw, false); if (ret < 0) { - dev_err(dev, "cannot disable interrupts on suspend\n"); + dev_err(dev, "%s: cannot stop bus: %d\n", __func__, ret); return ret; } - ret = intel_link_power_down(sdw); - if (ret) { - dev_err(dev, "Link power down failed: %d\n", ret); - return ret; - } - - intel_shim_wake(sdw, false); - return 0; } @@ -1699,44 +1849,19 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) clock_stop_quirks = sdw->link_res->clock_stop_quirks; if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { - - ret = sdw_cdns_enable_interrupt(cdns, false); + ret = intel_stop_bus(sdw, false); if (ret < 0) { - dev_err(dev, "cannot disable interrupts on suspend\n"); + dev_err(dev, "%s: cannot stop bus during teardown: %d\n", + __func__, ret); return ret; } - - ret = intel_link_power_down(sdw); - if (ret) { - dev_err(dev, "Link power down failed: %d\n", ret); - return ret; - } - - intel_shim_wake(sdw, false); - - } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET || - !clock_stop_quirks) { - bool wake_enable = true; - - ret = sdw_cdns_clock_stop(cdns, true); + } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET || !clock_stop_quirks) { + ret = intel_stop_bus(sdw, true); if (ret < 0) { - dev_err(dev, "cannot enable clock stop on suspend\n"); - wake_enable = false; - } - - ret = sdw_cdns_enable_interrupt(cdns, false); - if (ret < 0) { - dev_err(dev, "cannot disable interrupts on suspend\n"); + dev_err(dev, "%s: cannot stop bus during clock_stop: %d\n", + __func__, ret); return ret; } - - ret = intel_link_power_down(sdw); - if (ret) { - dev_err(dev, "Link power down failed: %d\n", ret); - return ret; - } - - intel_shim_wake(sdw, wake_enable); } else { dev_err(dev, "%s clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); @@ -1752,7 +1877,6 @@ static int __maybe_unused intel_resume(struct device *dev) struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_bus *bus = &cdns->bus; int link_flags; - bool multi_link; int ret; if (bus->prop.hw_disabled || !sdw->startup_done) { @@ -1762,10 +1886,9 @@ static int __maybe_unused intel_resume(struct device *dev) } link_flags = md_flags >> (bus->link_id * 8); - multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK); if (pm_runtime_suspended(dev)) { - dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__); + dev_dbg(dev, "pm_runtime status was suspended, forcing active\n"); /* follow required sequence from runtime_pm.rst */ pm_runtime_disable(dev); @@ -1779,7 +1902,7 @@ static int __maybe_unused intel_resume(struct device *dev) pm_runtime_idle(dev); } - ret = intel_init(sdw); + ret = intel_link_power_up(sdw); if (ret) { dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; @@ -1791,41 +1914,13 @@ static int __maybe_unused intel_resume(struct device *dev) */ sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); - ret = sdw_cdns_enable_interrupt(cdns, true); + ret = intel_start_bus(sdw); if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); + dev_err(dev, "cannot start bus during resume\n"); + intel_link_power_down(sdw); return ret; } - /* - * follow recommended programming flows to avoid timeouts when - * gsync is enabled - */ - if (multi_link) - intel_shim_sync_arm(sdw); - - ret = sdw_cdns_init(&sdw->cdns); - if (ret < 0) { - dev_err(dev, "unable to initialize Cadence IP during resume\n"); - return ret; - } - - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); - return ret; - } - - if (multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(dev, "sync go failed during resume\n"); - return ret; - } - } - sdw_cdns_check_self_clearing_bits(cdns, __func__, - true, INTEL_MASTER_RESET_ITERATIONS); - /* * after system resume, the pm_runtime suspend() may kick in * during the enumeration, before any children device force the @@ -1838,7 +1933,7 @@ static int __maybe_unused intel_resume(struct device *dev) */ pm_runtime_mark_last_busy(dev); - return ret; + return 0; } static int __maybe_unused intel_resume_runtime(struct device *dev) @@ -1847,10 +1942,6 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_bus *bus = &cdns->bus; u32 clock_stop_quirks; - bool clock_stop0; - int link_flags; - bool multi_link; - int status; int ret; if (bus->prop.hw_disabled || !sdw->startup_done) { @@ -1862,15 +1953,12 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) /* unconditionally disable WAKEEN interrupt */ intel_shim_wake(sdw, false); - link_flags = md_flags >> (bus->link_id * 8); - multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK); - clock_stop_quirks = sdw->link_res->clock_stop_quirks; if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { - ret = intel_init(sdw); + ret = intel_link_power_up(sdw); if (ret) { - dev_err(dev, "%s failed: %d\n", __func__, ret); + dev_err(dev, "%s: power_up failed after teardown: %d\n", __func__, ret); return ret; } @@ -1880,145 +1968,45 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) */ sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); - ret = sdw_cdns_enable_interrupt(cdns, true); + ret = intel_start_bus(sdw); if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); + dev_err(dev, "%s: cannot start bus after teardown: %d\n", __func__, ret); + intel_link_power_down(sdw); return ret; } - /* - * follow recommended programming flows to avoid - * timeouts when gsync is enabled - */ - if (multi_link) - intel_shim_sync_arm(sdw); - - ret = sdw_cdns_init(&sdw->cdns); - if (ret < 0) { - dev_err(dev, "unable to initialize Cadence IP during resume\n"); - return ret; - } - - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); - return ret; - } - - if (multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(dev, "sync go failed during resume\n"); - return ret; - } - } - sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime TEARDOWN", - true, INTEL_MASTER_RESET_ITERATIONS); } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { - ret = intel_init(sdw); + ret = intel_link_power_up(sdw); if (ret) { - dev_err(dev, "%s failed: %d\n", __func__, ret); + dev_err(dev, "%s: power_up failed after bus reset: %d\n", __func__, ret); return ret; } - /* - * An exception condition occurs for the CLK_STOP_BUS_RESET - * case if one or more masters remain active. In this condition, - * all the masters are powered on for they are in the same power - * domain. Master can preserve its context for clock stop0, so - * there is no need to clear slave status and reset bus. - */ - clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); - - if (!clock_stop0) { - - /* - * make sure all Slaves are tagged as UNATTACHED and - * provide reason for reinitialization - */ - - status = SDW_UNATTACH_REQUEST_MASTER_RESET; - sdw_clear_slave_status(bus, status); - - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); - return ret; - } - - /* - * follow recommended programming flows to avoid - * timeouts when gsync is enabled - */ - if (multi_link) - intel_shim_sync_arm(sdw); - - /* - * Re-initialize the IP since it was powered-off - */ - sdw_cdns_init(&sdw->cdns); - - } else { - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); - return ret; - } - } - - ret = sdw_cdns_clock_restart(cdns, !clock_stop0); + ret = intel_start_bus_after_reset(sdw); if (ret < 0) { - dev_err(dev, "unable to restart clock during resume\n"); + dev_err(dev, "%s: cannot start bus after reset: %d\n", __func__, ret); + intel_link_power_down(sdw); return ret; } - - if (!clock_stop0) { - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); - return ret; - } - - if (multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(sdw->cdns.dev, "sync go failed during resume\n"); - return ret; - } - } - } - sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime BUS_RESET", - true, INTEL_MASTER_RESET_ITERATIONS); - } else if (!clock_stop_quirks) { - clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); - if (!clock_stop0) - dev_err(dev, "%s invalid configuration, clock was not stopped", __func__); + intel_check_clock_stop(sdw); - ret = intel_init(sdw); + ret = intel_link_power_up(sdw); if (ret) { - dev_err(dev, "%s failed: %d\n", __func__, ret); + dev_err(dev, "%s: power_up failed: %d\n", __func__, ret); return ret; } - ret = sdw_cdns_enable_interrupt(cdns, true); + ret = intel_start_bus_after_clock_stop(sdw); if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); + dev_err(dev, "%s: cannot start bus after clock stop: %d\n", __func__, ret); + intel_link_power_down(sdw); return ret; } - - ret = sdw_cdns_clock_restart(cdns, false); - if (ret < 0) { - dev_err(dev, "unable to resume master during resume\n"); - return ret; - } - - sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks", - true, INTEL_MASTER_RESET_ITERATIONS); } else { - dev_err(dev, "%s clock_stop_quirks %x unsupported\n", + dev_err(dev, "%s: clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); ret = -EINVAL; } diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 824f4f32d4dc..d091513919df 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -306,7 +306,7 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) /* Check SNDWLCAP.LCOUNT */ caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP); - caps &= GENMASK(2, 0); + caps &= SDW_SHIM_LCAP_LCOUNT_MASK; /* Check HW supported vs property value */ if (caps < ctx->count) { diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 3a992a6478c3..b33d5db494a5 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -420,7 +420,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); - for (dev_num = 0; dev_num <= SDW_MAX_DEVICES; dev_num++) { + for (dev_num = 1; dev_num <= SDW_MAX_DEVICES; dev_num++) { status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { @@ -440,7 +440,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); ctrl->slave_status = val; - for (i = 0; i <= SDW_MAX_DEVICES; i++) { + for (i = 1; i <= SDW_MAX_DEVICES; i++) { u32 s; s = (val >> (i * 2)); @@ -573,11 +573,10 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) break; case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED: case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: - dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n", - __func__); + dev_dbg_ratelimited(swrm->dev, "SWR new slave attached\n"); swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status); if (swrm->slave_status == slave_status) { - dev_err(swrm->dev, "Slave status not changed %x\n", + dev_dbg(swrm->dev, "Slave status not changed %x\n", slave_status); } else { qcom_swrm_get_device_status(swrm); diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index e8fa7f53cd5e..81b06d88ed0d 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -1267,7 +1267,8 @@ static int fwtty_ioctl(struct tty_struct *tty, unsigned int cmd, return err; } -static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old) +static void fwtty_set_termios(struct tty_struct *tty, + const struct ktermios *old) { struct fwtty_port *port = tty->driver_data; unsigned int baud; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index dc4ed0ff1ae2..90ff07f2cbf7 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -480,7 +480,7 @@ static int gb_tty_break_ctl(struct tty_struct *tty, int state) } static void gb_tty_set_termios(struct tty_struct *tty, - struct ktermios *termios_old) + const struct ktermios *termios_old) { struct gb_uart_set_line_coding_request newline; struct gb_tty *gb_tty = tty->driver_data; diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig index f12d0a3ee3e2..448fd2ec8f6e 100644 --- a/drivers/thunderbolt/Kconfig +++ b/drivers/thunderbolt/Kconfig @@ -27,6 +27,16 @@ config USB4_DEBUGFS_WRITE Only enable this if you know what you are doing! Never enable this for production systems or distro kernels. +config USB4_DEBUGFS_MARGINING + bool "Expose receiver lane margining operations under USB4 ports (DANGEROUS)" + depends on DEBUG_FS + depends on USB4_DEBUGFS_WRITE + help + Enables hardware and software based receiver lane margining support + under each USB4 port. Used for electrical quality and robustness + validation during manufacturing. Should not be enabled by distro + kernels. + config USB4_KUNIT_TEST bool "KUnit tests" if !KUNIT_ALL_TESTS depends on USB4 && KUNIT=y diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index c850b0ac098c..834bcad42e9f 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -12,6 +12,7 @@ #include #include "tb.h" +#include "sb_regs.h" #define PORT_CAP_PCIE_LEN 1 #define PORT_CAP_POWER_LEN 2 @@ -187,6 +188,828 @@ static ssize_t switch_regs_write(struct file *file, const char __user *user_buf, #define DEBUGFS_MODE 0400 #endif +#if IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING) +/** + * struct tb_margining - Lane margining support + * @caps: Port lane margining capabilities + * @results: Last lane margining results + * @lanes: %0, %1 or %7 (all) + * @min_ber_level: Minimum supported BER level contour value + * @max_ber_level: Maximum supported BER level contour value + * @ber_level: Current BER level contour value + * @voltage_steps: Number of mandatory voltage steps + * @max_voltage_offset: Maximum mandatory voltage offset (in mV) + * @time_steps: Number of time margin steps + * @max_time_offset: Maximum time margin offset (in mUI) + * @software: %true if software margining is used instead of hardware + * @time: %true if time margining is used instead of voltage + * @right_high: %false if left/low margin test is performed, %true if + * right/high + */ +struct tb_margining { + u32 caps[2]; + u32 results[2]; + unsigned int lanes; + unsigned int min_ber_level; + unsigned int max_ber_level; + unsigned int ber_level; + unsigned int voltage_steps; + unsigned int max_voltage_offset; + unsigned int time_steps; + unsigned int max_time_offset; + bool software; + bool time; + bool right_high; +}; + +static bool supports_software(const struct usb4_port *usb4) +{ + return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW; +} + +static bool supports_hardware(const struct usb4_port *usb4) +{ + return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW; +} + +static bool both_lanes(const struct usb4_port *usb4) +{ + return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES; +} + +static unsigned int independent_voltage_margins(const struct usb4_port *usb4) +{ + return (usb4->margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK) >> + USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT; +} + +static bool supports_time(const struct usb4_port *usb4) +{ + return usb4->margining->caps[0] & USB4_MARGIN_CAP_0_TIME; +} + +/* Only applicable if supports_time() returns true */ +static unsigned int independent_time_margins(const struct usb4_port *usb4) +{ + return (usb4->margining->caps[1] & USB4_MARGIN_CAP_1_TIME_INDP_MASK) >> + USB4_MARGIN_CAP_1_TIME_INDP_SHIFT; +} + +static ssize_t +margining_ber_level_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + unsigned int val; + int ret = 0; + char *buf; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + if (usb4->margining->software) { + ret = -EINVAL; + goto out_unlock; + } + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto out_unlock; + } + + buf[count - 1] = '\0'; + + ret = kstrtouint(buf, 10, &val); + if (ret) + goto out_free; + + if (val < usb4->margining->min_ber_level || + val > usb4->margining->max_ber_level) { + ret = -EINVAL; + goto out_free; + } + + usb4->margining->ber_level = val; + +out_free: + free_page((unsigned long)buf); +out_unlock: + mutex_unlock(&tb->lock); + + return ret < 0 ? ret : count; +} + +static void ber_level_show(struct seq_file *s, unsigned int val) +{ + if (val % 2) + seq_printf(s, "3 * 1e%d (%u)\n", -12 + (val + 1) / 2, val); + else + seq_printf(s, "1e%d (%u)\n", -12 + val / 2, val); +} + +static int margining_ber_level_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + + if (usb4->margining->software) + return -EINVAL; + ber_level_show(s, usb4->margining->ber_level); + return 0; +} +DEBUGFS_ATTR_RW(margining_ber_level); + +static int margining_caps_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + u32 cap0, cap1; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + /* Dump the raw caps first */ + cap0 = usb4->margining->caps[0]; + seq_printf(s, "0x%08x\n", cap0); + cap1 = usb4->margining->caps[1]; + seq_printf(s, "0x%08x\n", cap1); + + seq_printf(s, "# software margining: %s\n", + supports_software(usb4) ? "yes" : "no"); + if (supports_hardware(usb4)) { + seq_puts(s, "# hardware margining: yes\n"); + seq_puts(s, "# minimum BER level contour: "); + ber_level_show(s, usb4->margining->min_ber_level); + seq_puts(s, "# maximum BER level contour: "); + ber_level_show(s, usb4->margining->max_ber_level); + } else { + seq_puts(s, "# hardware margining: no\n"); + } + + seq_printf(s, "# both lanes simultaneously: %s\n", + both_lanes(usb4) ? "yes" : "no"); + seq_printf(s, "# voltage margin steps: %u\n", + usb4->margining->voltage_steps); + seq_printf(s, "# maximum voltage offset: %u mV\n", + usb4->margining->max_voltage_offset); + + switch (independent_voltage_margins(usb4)) { + case USB4_MARGIN_CAP_0_VOLTAGE_MIN: + seq_puts(s, "# returns minimum between high and low voltage margins\n"); + break; + case USB4_MARGIN_CAP_0_VOLTAGE_HL: + seq_puts(s, "# returns high or low voltage margin\n"); + break; + case USB4_MARGIN_CAP_0_VOLTAGE_BOTH: + seq_puts(s, "# returns both high and low margins\n"); + break; + } + + if (supports_time(usb4)) { + seq_puts(s, "# time margining: yes\n"); + seq_printf(s, "# time margining is destructive: %s\n", + cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no"); + + switch (independent_time_margins(usb4)) { + case USB4_MARGIN_CAP_1_TIME_MIN: + seq_puts(s, "# returns minimum between left and right time margins\n"); + break; + case USB4_MARGIN_CAP_1_TIME_LR: + seq_puts(s, "# returns left or right margin\n"); + break; + case USB4_MARGIN_CAP_1_TIME_BOTH: + seq_puts(s, "# returns both left and right margins\n"); + break; + } + + seq_printf(s, "# time margin steps: %u\n", + usb4->margining->time_steps); + seq_printf(s, "# maximum time offset: %u mUI\n", + usb4->margining->max_time_offset); + } else { + seq_puts(s, "# time margining: no\n"); + } + + mutex_unlock(&tb->lock); + return 0; +} +DEBUGFS_ATTR_RO(margining_caps); + +static ssize_t +margining_lanes_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + if (mutex_lock_interruptible(&tb->lock)) { + ret = -ERESTARTSYS; + goto out_free; + } + + if (!strcmp(buf, "0")) { + usb4->margining->lanes = 0; + } else if (!strcmp(buf, "1")) { + usb4->margining->lanes = 1; + } else if (!strcmp(buf, "all")) { + /* Needs to be supported */ + if (both_lanes(usb4)) + usb4->margining->lanes = 7; + else + ret = -EINVAL; + } else { + ret = -EINVAL; + } + + mutex_unlock(&tb->lock); + +out_free: + free_page((unsigned long)buf); + return ret < 0 ? ret : count; +} + +static int margining_lanes_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + unsigned int lanes; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + lanes = usb4->margining->lanes; + if (both_lanes(usb4)) { + if (!lanes) + seq_puts(s, "[0] 1 all\n"); + else if (lanes == 1) + seq_puts(s, "0 [1] all\n"); + else + seq_puts(s, "0 1 [all]\n"); + } else { + if (!lanes) + seq_puts(s, "[0] 1\n"); + else + seq_puts(s, "0 [1]\n"); + } + + mutex_unlock(&tb->lock); + return 0; +} +DEBUGFS_ATTR_RW(margining_lanes); + +static ssize_t margining_mode_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + if (mutex_lock_interruptible(&tb->lock)) { + ret = -ERESTARTSYS; + goto out_free; + } + + if (!strcmp(buf, "software")) { + if (supports_software(usb4)) + usb4->margining->software = true; + else + ret = -EINVAL; + } else if (!strcmp(buf, "hardware")) { + if (supports_hardware(usb4)) + usb4->margining->software = false; + else + ret = -EINVAL; + } else { + ret = -EINVAL; + } + + mutex_unlock(&tb->lock); + +out_free: + free_page((unsigned long)buf); + return ret ? ret : count; +} + +static int margining_mode_show(struct seq_file *s, void *not_used) +{ + const struct tb_port *port = s->private; + const struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + const char *space = ""; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + if (supports_software(usb4)) { + if (usb4->margining->software) + seq_puts(s, "[software]"); + else + seq_puts(s, "software"); + space = " "; + } + if (supports_hardware(usb4)) { + if (usb4->margining->software) + seq_printf(s, "%shardware", space); + else + seq_printf(s, "%s[hardware]", space); + } + + mutex_unlock(&tb->lock); + + seq_puts(s, "\n"); + return 0; +} +DEBUGFS_ATTR_RW(margining_mode); + +static int margining_run_write(void *data, u64 val) +{ + struct tb_port *port = data; + struct usb4_port *usb4 = port->usb4; + struct tb_switch *sw = port->sw; + struct tb_margining *margining; + struct tb *tb = sw->tb; + int ret; + + if (val != 1) + return -EINVAL; + + pm_runtime_get_sync(&sw->dev); + + if (mutex_lock_interruptible(&tb->lock)) { + ret = -ERESTARTSYS; + goto out_rpm_put; + } + + /* + * CL states may interfere with lane margining so inform the user know + * and bail out. + */ + if (tb_port_is_clx_enabled(port, TB_CL1 | TB_CL2)) { + tb_port_warn(port, + "CL states are enabled, Disable them with clx=0 and re-connect\n"); + ret = -EINVAL; + goto out_unlock; + } + + margining = usb4->margining; + + if (margining->software) { + tb_port_dbg(port, "running software %s lane margining for lanes %u\n", + margining->time ? "time" : "voltage", margining->lanes); + ret = usb4_port_sw_margin(port, margining->lanes, margining->time, + margining->right_high, + USB4_MARGIN_SW_COUNTER_CLEAR); + if (ret) + goto out_unlock; + + ret = usb4_port_sw_margin_errors(port, &margining->results[0]); + } else { + tb_port_dbg(port, "running hardware %s lane margining for lanes %u\n", + margining->time ? "time" : "voltage", margining->lanes); + /* Clear the results */ + margining->results[0] = 0; + margining->results[1] = 0; + ret = usb4_port_hw_margin(port, margining->lanes, + margining->ber_level, margining->time, + margining->right_high, margining->results); + } + +out_unlock: + mutex_unlock(&tb->lock); +out_rpm_put: + pm_runtime_mark_last_busy(&sw->dev); + pm_runtime_put_autosuspend(&sw->dev); + + return ret; +} +DEFINE_DEBUGFS_ATTRIBUTE(margining_run_fops, NULL, margining_run_write, + "%llu\n"); + +static ssize_t margining_results_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + /* Just clear the results */ + usb4->margining->results[0] = 0; + usb4->margining->results[1] = 0; + + mutex_unlock(&tb->lock); + return count; +} + +static void voltage_margin_show(struct seq_file *s, + const struct tb_margining *margining, u8 val) +{ + unsigned int tmp, voltage; + + tmp = val & USB4_MARGIN_HW_RES_1_MARGIN_MASK; + voltage = tmp * margining->max_voltage_offset / margining->voltage_steps; + seq_printf(s, "%u mV (%u)", voltage, tmp); + if (val & USB4_MARGIN_HW_RES_1_EXCEEDS) + seq_puts(s, " exceeds maximum"); + seq_puts(s, "\n"); +} + +static void time_margin_show(struct seq_file *s, + const struct tb_margining *margining, u8 val) +{ + unsigned int tmp, interval; + + tmp = val & USB4_MARGIN_HW_RES_1_MARGIN_MASK; + interval = tmp * margining->max_time_offset / margining->time_steps; + seq_printf(s, "%u mUI (%u)", interval, tmp); + if (val & USB4_MARGIN_HW_RES_1_EXCEEDS) + seq_puts(s, " exceeds maximum"); + seq_puts(s, "\n"); +} + +static int margining_results_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb_margining *margining; + struct tb *tb = port->sw->tb; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + margining = usb4->margining; + /* Dump the raw results first */ + seq_printf(s, "0x%08x\n", margining->results[0]); + /* Only the hardware margining has two result dwords */ + if (!margining->software) { + unsigned int val; + + seq_printf(s, "0x%08x\n", margining->results[1]); + + if (margining->time) { + if (!margining->lanes || margining->lanes == 7) { + val = margining->results[1]; + seq_puts(s, "# lane 0 right time margin: "); + time_margin_show(s, margining, val); + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT; + seq_puts(s, "# lane 0 left time margin: "); + time_margin_show(s, margining, val); + } + if (margining->lanes == 1 || margining->lanes == 7) { + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT; + seq_puts(s, "# lane 1 right time margin: "); + time_margin_show(s, margining, val); + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT; + seq_puts(s, "# lane 1 left time margin: "); + time_margin_show(s, margining, val); + } + } else { + if (!margining->lanes || margining->lanes == 7) { + val = margining->results[1]; + seq_puts(s, "# lane 0 high voltage margin: "); + voltage_margin_show(s, margining, val); + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT; + seq_puts(s, "# lane 0 low voltage margin: "); + voltage_margin_show(s, margining, val); + } + if (margining->lanes == 1 || margining->lanes == 7) { + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT; + seq_puts(s, "# lane 1 high voltage margin: "); + voltage_margin_show(s, margining, val); + val = margining->results[1] >> + USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT; + seq_puts(s, "# lane 1 low voltage margin: "); + voltage_margin_show(s, margining, val); + } + } + } + + mutex_unlock(&tb->lock); + return 0; +} +DEBUGFS_ATTR_RW(margining_results); + +static ssize_t margining_test_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + if (mutex_lock_interruptible(&tb->lock)) { + ret = -ERESTARTSYS; + goto out_free; + } + + if (!strcmp(buf, "time") && supports_time(usb4)) + usb4->margining->time = true; + else if (!strcmp(buf, "voltage")) + usb4->margining->time = false; + else + ret = -EINVAL; + + mutex_unlock(&tb->lock); + +out_free: + free_page((unsigned long)buf); + return ret ? ret : count; +} + +static int margining_test_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + if (supports_time(usb4)) { + if (usb4->margining->time) + seq_puts(s, "voltage [time]\n"); + else + seq_puts(s, "[voltage] time\n"); + } else { + seq_puts(s, "[voltage]\n"); + } + + mutex_unlock(&tb->lock); + return 0; +} +DEBUGFS_ATTR_RW(margining_test); + +static ssize_t margining_margin_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + if (mutex_lock_interruptible(&tb->lock)) { + ret = -ERESTARTSYS; + goto out_free; + } + + if (usb4->margining->time) { + if (!strcmp(buf, "left")) + usb4->margining->right_high = false; + else if (!strcmp(buf, "right")) + usb4->margining->right_high = true; + else + ret = -EINVAL; + } else { + if (!strcmp(buf, "low")) + usb4->margining->right_high = false; + else if (!strcmp(buf, "high")) + usb4->margining->right_high = true; + else + ret = -EINVAL; + } + + mutex_unlock(&tb->lock); + +out_free: + free_page((unsigned long)buf); + return ret ? ret : count; +} + +static int margining_margin_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + + if (mutex_lock_interruptible(&tb->lock)) + return -ERESTARTSYS; + + if (usb4->margining->time) { + if (usb4->margining->right_high) + seq_puts(s, "left [right]\n"); + else + seq_puts(s, "[left] right\n"); + } else { + if (usb4->margining->right_high) + seq_puts(s, "low [high]\n"); + else + seq_puts(s, "[low] high\n"); + } + + mutex_unlock(&tb->lock); + return 0; +} +DEBUGFS_ATTR_RW(margining_margin); + +static void margining_port_init(struct tb_port *port) +{ + struct tb_margining *margining; + struct dentry *dir, *parent; + struct usb4_port *usb4; + char dir_name[10]; + unsigned int val; + int ret; + + usb4 = port->usb4; + if (!usb4) + return; + + snprintf(dir_name, sizeof(dir_name), "port%d", port->port); + parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); + + margining = kzalloc(sizeof(*margining), GFP_KERNEL); + if (!margining) + return; + + ret = usb4_port_margining_caps(port, margining->caps); + if (ret) { + kfree(margining); + return; + } + + usb4->margining = margining; + + /* Set the initial mode */ + if (supports_software(usb4)) + margining->software = true; + + val = (margining->caps[0] & USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK) >> + USB4_MARGIN_CAP_0_VOLTAGE_STEPS_SHIFT; + margining->voltage_steps = val; + val = (margining->caps[0] & USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK) >> + USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT; + margining->max_voltage_offset = 74 + val * 2; + + if (supports_time(usb4)) { + val = (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_STEPS_MASK) >> + USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT; + margining->time_steps = val; + val = (margining->caps[1] & USB4_MARGIN_CAP_1_TIME_OFFSET_MASK) >> + USB4_MARGIN_CAP_1_TIME_OFFSET_SHIFT; + /* + * Store it as mUI (milli Unit Interval) because we want + * to keep it as integer. + */ + margining->max_time_offset = 200 + 10 * val; + } + + dir = debugfs_create_dir("margining", parent); + if (supports_hardware(usb4)) { + val = (margining->caps[1] & USB4_MARGIN_CAP_1_MIN_BER_MASK) >> + USB4_MARGIN_CAP_1_MIN_BER_SHIFT; + margining->min_ber_level = val; + val = (margining->caps[1] & USB4_MARGIN_CAP_1_MAX_BER_MASK) >> + USB4_MARGIN_CAP_1_MAX_BER_SHIFT; + margining->max_ber_level = val; + + /* Set the default to minimum */ + margining->ber_level = margining->min_ber_level; + + debugfs_create_file("ber_level_contour", 0400, dir, port, + &margining_ber_level_fops); + } + debugfs_create_file("caps", 0400, dir, port, &margining_caps_fops); + debugfs_create_file("lanes", 0600, dir, port, &margining_lanes_fops); + debugfs_create_file("mode", 0600, dir, port, &margining_mode_fops); + debugfs_create_file("run", 0600, dir, port, &margining_run_fops); + debugfs_create_file("results", 0600, dir, port, &margining_results_fops); + debugfs_create_file("test", 0600, dir, port, &margining_test_fops); + if (independent_voltage_margins(usb4) || + (supports_time(usb4) && independent_time_margins(usb4))) + debugfs_create_file("margin", 0600, dir, port, &margining_margin_fops); +} + +static void margining_port_remove(struct tb_port *port) +{ + struct dentry *parent; + char dir_name[10]; + + if (!port->usb4) + return; + + snprintf(dir_name, sizeof(dir_name), "port%d", port->port); + parent = debugfs_lookup(dir_name, port->sw->debugfs_dir); + debugfs_remove_recursive(debugfs_lookup("margining", parent)); + + kfree(port->usb4->margining); + port->usb4->margining = NULL; +} + +static void margining_switch_init(struct tb_switch *sw) +{ + struct tb_port *upstream, *downstream; + struct tb_switch *parent_sw; + u64 route = tb_route(sw); + + if (!route) + return; + + upstream = tb_upstream_port(sw); + parent_sw = tb_switch_parent(sw); + downstream = tb_port_at(route, parent_sw); + + margining_port_init(downstream); + margining_port_init(upstream); +} + +static void margining_switch_remove(struct tb_switch *sw) +{ + struct tb_switch *parent_sw; + struct tb_port *downstream; + u64 route = tb_route(sw); + + if (!route) + return; + + /* + * Upstream is removed with the router itself but we need to + * remove the downstream port margining directory. + */ + parent_sw = tb_switch_parent(sw); + downstream = tb_port_at(route, parent_sw); + margining_port_remove(downstream); +} + +static void margining_xdomain_init(struct tb_xdomain *xd) +{ + struct tb_switch *parent_sw; + struct tb_port *downstream; + + parent_sw = tb_xdomain_parent(xd); + downstream = tb_port_at(xd->route, parent_sw); + + margining_port_init(downstream); +} + +static void margining_xdomain_remove(struct tb_xdomain *xd) +{ + struct tb_switch *parent_sw; + struct tb_port *downstream; + + parent_sw = tb_xdomain_parent(xd); + downstream = tb_port_at(xd->route, parent_sw); + margining_port_remove(downstream); +} +#else +static inline void margining_switch_init(struct tb_switch *sw) { } +static inline void margining_switch_remove(struct tb_switch *sw) { } +static inline void margining_xdomain_init(struct tb_xdomain *xd) { } +static inline void margining_xdomain_remove(struct tb_xdomain *xd) { } +#endif + static int port_clear_all_counters(struct tb_port *port) { u32 *buf; @@ -689,6 +1512,8 @@ void tb_switch_debugfs_init(struct tb_switch *sw) debugfs_create_file("counters", 0600, debugfs_dir, port, &counters_fops); } + + margining_switch_init(sw); } /** @@ -699,9 +1524,20 @@ void tb_switch_debugfs_init(struct tb_switch *sw) */ void tb_switch_debugfs_remove(struct tb_switch *sw) { + margining_switch_remove(sw); debugfs_remove_recursive(sw->debugfs_dir); } +void tb_xdomain_debugfs_init(struct tb_xdomain *xd) +{ + margining_xdomain_init(xd); +} + +void tb_xdomain_debugfs_remove(struct tb_xdomain *xd) +{ + margining_xdomain_remove(xd); +} + /** * tb_service_debugfs_init() - Add debugfs directory for service * @svc: Thunderbolt service pointer diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 99211f35a5cd..ec7b5f65804e 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -144,11 +144,9 @@ static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr, for (ret = 0, i = 0; i < tb->nboot_acl; i++) { if (!uuid_is_null(&uuids[i])) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%pUb", - &uuids[i]); + ret += sysfs_emit_at(buf, ret, "%pUb", &uuids[i]); - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s", - i < tb->nboot_acl - 1 ? "," : "\n"); + ret += sysfs_emit_at(buf, ret, "%s", i < tb->nboot_acl - 1 ? "," : "\n"); } out: @@ -247,7 +245,7 @@ static ssize_t deauthorization_show(struct device *dev, tb->security_level == TB_SECURITY_SECURE) deauthorization = !!tb->cm_ops->disapprove_switch; - return sprintf(buf, "%d\n", deauthorization); + return sysfs_emit(buf, "%d\n", deauthorization); } static DEVICE_ATTR_RO(deauthorization); @@ -270,7 +268,7 @@ static ssize_t security_show(struct device *dev, struct device_attribute *attr, if (tb->security_level < ARRAY_SIZE(tb_security_names)) name = tb_security_names[tb->security_level]; - return sprintf(buf, "%s\n", name); + return sysfs_emit(buf, "%s\n", name); } static DEVICE_ATTR_RO(security); diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 572b5896caa3..86521ebb2579 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -2518,6 +2518,9 @@ struct tb *icm_probe(struct tb_nhi *nhi) case PCI_DEVICE_ID_INTEL_ADL_NHI1: case PCI_DEVICE_ID_INTEL_RPL_NHI0: case PCI_DEVICE_ID_INTEL_RPL_NHI1: + case PCI_DEVICE_ID_INTEL_MTL_M_NHI0: + case PCI_DEVICE_ID_INTEL_MTL_P_NHI0: + case PCI_DEVICE_ID_INTEL_MTL_P_NHI1: icm->is_supported = icm_tgl_is_supported; icm->driver_ready = icm_icl_driver_ready; icm->set_uuid = icm_icl_set_uuid; diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index b5cd9673e15d..4dce2edd86ea 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1184,6 +1184,7 @@ static void nhi_check_iommu(struct tb_nhi *nhi) static int nhi_init_msi(struct tb_nhi *nhi) { struct pci_dev *pdev = nhi->pdev; + struct device *dev = &pdev->dev; int res, irq, nvec; /* In case someone left them on. */ @@ -1214,10 +1215,8 @@ static int nhi_init_msi(struct tb_nhi *nhi) res = devm_request_irq(&pdev->dev, irq, nhi_msi, IRQF_NO_SUSPEND, "thunderbolt", nhi); - if (res) { - dev_err(&pdev->dev, "request_irq failed, aborting\n"); - return res; - } + if (res) + return dev_err_probe(dev, res, "request_irq failed, aborting\n"); } return 0; @@ -1258,26 +1257,21 @@ static struct tb *nhi_select_cm(struct tb_nhi *nhi) static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct tb_nhi *nhi; struct tb *tb; int res; - if (!nhi_imr_valid(pdev)) { - dev_warn(&pdev->dev, "firmware image not valid, aborting\n"); - return -ENODEV; - } + if (!nhi_imr_valid(pdev)) + return dev_err_probe(dev, -ENODEV, "firmware image not valid, aborting\n"); res = pcim_enable_device(pdev); - if (res) { - dev_err(&pdev->dev, "cannot enable PCI device, aborting\n"); - return res; - } + if (res) + return dev_err_probe(dev, res, "cannot enable PCI device, aborting\n"); res = pcim_iomap_regions(pdev, 1 << 0, "thunderbolt"); - if (res) { - dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n"); - return res; - } + if (res) + return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n"); nhi = devm_kzalloc(&pdev->dev, sizeof(*nhi), GFP_KERNEL); if (!nhi) @@ -1288,7 +1282,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* cannot fail - table is allocated in pcim_iomap_regions */ nhi->iobase = pcim_iomap_table(pdev)[0]; nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff; - dev_dbg(&pdev->dev, "total paths: %d\n", nhi->hop_count); + dev_dbg(dev, "total paths: %d\n", nhi->hop_count); nhi->tx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count, sizeof(*nhi->tx_rings), GFP_KERNEL); @@ -1301,18 +1295,14 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) nhi_check_iommu(nhi); res = nhi_init_msi(nhi); - if (res) { - dev_err(&pdev->dev, "cannot enable MSI, aborting\n"); - return res; - } + if (res) + return dev_err_probe(dev, res, "cannot enable MSI, aborting\n"); spin_lock_init(&nhi->lock); res = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - if (res) { - dev_err(&pdev->dev, "failed to set DMA mask\n"); - return res; - } + if (res) + return dev_err_probe(dev, res, "failed to set DMA mask\n"); pci_set_master(pdev); @@ -1323,13 +1313,11 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) } tb = nhi_select_cm(nhi); - if (!tb) { - dev_err(&nhi->pdev->dev, + if (!tb) + return dev_err_probe(dev, -ENODEV, "failed to determine connection manager, aborting\n"); - return -ENODEV; - } - dev_dbg(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n"); + dev_dbg(dev, "NHI initialized, starting thunderbolt\n"); res = tb_domain_add(tb); if (res) { @@ -1433,6 +1421,7 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICL_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + /* Thunderbolt 4 */ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI0), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_NHI1), @@ -1449,6 +1438,12 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_M_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, /* Any USB4 compliant host */ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) }, diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h index 01190d9ced16..b0718020c6f5 100644 --- a/drivers/thunderbolt/nhi.h +++ b/drivers/thunderbolt/nhi.h @@ -75,6 +75,9 @@ extern const struct tb_nhi_ops icl_nhi_ops; #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE 0x15ef #define PCI_DEVICE_ID_INTEL_ADL_NHI0 0x463e #define PCI_DEVICE_ID_INTEL_ADL_NHI1 0x466d +#define PCI_DEVICE_ID_INTEL_MTL_M_NHI0 0x7eb2 +#define PCI_DEVICE_ID_INTEL_MTL_P_NHI0 0x7ec2 +#define PCI_DEVICE_ID_INTEL_MTL_P_NHI1 0x7ec3 #define PCI_DEVICE_ID_INTEL_ICL_NHI1 0x8a0d #define PCI_DEVICE_ID_INTEL_ICL_NHI0 0x8a17 #define PCI_DEVICE_ID_INTEL_TGL_NHI0 0x9a1b diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c index b3f310389378..3dd5f81bd629 100644 --- a/drivers/thunderbolt/nvm.c +++ b/drivers/thunderbolt/nvm.c @@ -12,19 +12,315 @@ #include "tb.h" +/* Intel specific NVM offsets */ +#define INTEL_NVM_DEVID 0x05 +#define INTEL_NVM_VERSION 0x08 +#define INTEL_NVM_CSS 0x10 +#define INTEL_NVM_FLASH_SIZE 0x45 + +/* ASMedia specific NVM offsets */ +#define ASMEDIA_NVM_DATE 0x1c +#define ASMEDIA_NVM_VERSION 0x28 + static DEFINE_IDA(nvm_ida); +/** + * struct tb_nvm_vendor_ops - Vendor specific NVM operations + * @read_version: Reads out NVM version from the flash + * @validate: Validates the NVM image before update (optional) + * @write_headers: Writes headers before the rest of the image (optional) + */ +struct tb_nvm_vendor_ops { + int (*read_version)(struct tb_nvm *nvm); + int (*validate)(struct tb_nvm *nvm); + int (*write_headers)(struct tb_nvm *nvm); +}; + +/** + * struct tb_nvm_vendor - Vendor to &struct tb_nvm_vendor_ops mapping + * @vendor: Vendor ID + * @vops: Vendor specific NVM operations + * + * Maps vendor ID to NVM vendor operations. If there is no mapping then + * NVM firmware upgrade is disabled for the device. + */ +struct tb_nvm_vendor { + u16 vendor; + const struct tb_nvm_vendor_ops *vops; +}; + +static int intel_switch_nvm_version(struct tb_nvm *nvm) +{ + struct tb_switch *sw = tb_to_switch(nvm->dev); + u32 val, nvm_size, hdr_size; + int ret; + + /* + * If the switch is in safe-mode the only accessible portion of + * the NVM is the non-active one where userspace is expected to + * write new functional NVM. + */ + if (sw->safe_mode) + return 0; + + ret = tb_switch_nvm_read(sw, INTEL_NVM_FLASH_SIZE, &val, sizeof(val)); + if (ret) + return ret; + + hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K; + nvm_size = (SZ_1M << (val & 7)) / 8; + nvm_size = (nvm_size - hdr_size) / 2; + + ret = tb_switch_nvm_read(sw, INTEL_NVM_VERSION, &val, sizeof(val)); + if (ret) + return ret; + + nvm->major = (val >> 16) & 0xff; + nvm->minor = (val >> 8) & 0xff; + nvm->active_size = nvm_size; + + return 0; +} + +static int intel_switch_nvm_validate(struct tb_nvm *nvm) +{ + struct tb_switch *sw = tb_to_switch(nvm->dev); + unsigned int image_size, hdr_size; + u16 ds_size, device_id; + u8 *buf = nvm->buf; + + image_size = nvm->buf_data_size; + + /* + * FARB pointer must point inside the image and must at least + * contain parts of the digital section we will be reading here. + */ + hdr_size = (*(u32 *)buf) & 0xffffff; + if (hdr_size + INTEL_NVM_DEVID + 2 >= image_size) + return -EINVAL; + + /* Digital section start should be aligned to 4k page */ + if (!IS_ALIGNED(hdr_size, SZ_4K)) + return -EINVAL; + + /* + * Read digital section size and check that it also fits inside + * the image. + */ + ds_size = *(u16 *)(buf + hdr_size); + if (ds_size >= image_size) + return -EINVAL; + + if (sw->safe_mode) + return 0; + + /* + * Make sure the device ID in the image matches the one + * we read from the switch config space. + */ + device_id = *(u16 *)(buf + hdr_size + INTEL_NVM_DEVID); + if (device_id != sw->config.device_id) + return -EINVAL; + + /* Skip headers in the image */ + nvm->buf_data_start = buf + hdr_size; + nvm->buf_data_size = image_size - hdr_size; + + return 0; +} + +static int intel_switch_nvm_write_headers(struct tb_nvm *nvm) +{ + struct tb_switch *sw = tb_to_switch(nvm->dev); + + if (sw->generation < 3) { + int ret; + + /* Write CSS headers first */ + ret = dma_port_flash_write(sw->dma_port, + DMA_PORT_CSS_ADDRESS, nvm->buf + INTEL_NVM_CSS, + DMA_PORT_CSS_MAX_SIZE); + if (ret) + return ret; + } + + return 0; +} + +static const struct tb_nvm_vendor_ops intel_switch_nvm_ops = { + .read_version = intel_switch_nvm_version, + .validate = intel_switch_nvm_validate, + .write_headers = intel_switch_nvm_write_headers, +}; + +static int asmedia_switch_nvm_version(struct tb_nvm *nvm) +{ + struct tb_switch *sw = tb_to_switch(nvm->dev); + u32 val; + int ret; + + ret = tb_switch_nvm_read(sw, ASMEDIA_NVM_VERSION, &val, sizeof(val)); + if (ret) + return ret; + + nvm->major = (val << 16) & 0xff0000; + nvm->major |= val & 0x00ff00; + nvm->major |= (val >> 16) & 0x0000ff; + + ret = tb_switch_nvm_read(sw, ASMEDIA_NVM_DATE, &val, sizeof(val)); + if (ret) + return ret; + + nvm->minor = (val << 16) & 0xff0000; + nvm->minor |= val & 0x00ff00; + nvm->minor |= (val >> 16) & 0x0000ff; + + /* ASMedia NVM size is fixed to 512k */ + nvm->active_size = SZ_512K; + + return 0; +} + +static const struct tb_nvm_vendor_ops asmedia_switch_nvm_ops = { + .read_version = asmedia_switch_nvm_version, +}; + +/* Router vendor NVM support table */ +static const struct tb_nvm_vendor switch_nvm_vendors[] = { + { 0x174c, &asmedia_switch_nvm_ops }, + { PCI_VENDOR_ID_INTEL, &intel_switch_nvm_ops }, + { 0x8087, &intel_switch_nvm_ops }, +}; + +static int intel_retimer_nvm_version(struct tb_nvm *nvm) +{ + struct tb_retimer *rt = tb_to_retimer(nvm->dev); + u32 val, nvm_size; + int ret; + + ret = tb_retimer_nvm_read(rt, INTEL_NVM_VERSION, &val, sizeof(val)); + if (ret) + return ret; + + nvm->major = (val >> 16) & 0xff; + nvm->minor = (val >> 8) & 0xff; + + ret = tb_retimer_nvm_read(rt, INTEL_NVM_FLASH_SIZE, &val, sizeof(val)); + if (ret) + return ret; + + nvm_size = (SZ_1M << (val & 7)) / 8; + nvm_size = (nvm_size - SZ_16K) / 2; + nvm->active_size = nvm_size; + + return 0; +} + +static int intel_retimer_nvm_validate(struct tb_nvm *nvm) +{ + struct tb_retimer *rt = tb_to_retimer(nvm->dev); + unsigned int image_size, hdr_size; + u8 *buf = nvm->buf; + u16 ds_size, device; + + image_size = nvm->buf_data_size; + + /* + * FARB pointer must point inside the image and must at least + * contain parts of the digital section we will be reading here. + */ + hdr_size = (*(u32 *)buf) & 0xffffff; + if (hdr_size + INTEL_NVM_DEVID + 2 >= image_size) + return -EINVAL; + + /* Digital section start should be aligned to 4k page */ + if (!IS_ALIGNED(hdr_size, SZ_4K)) + return -EINVAL; + + /* + * Read digital section size and check that it also fits inside + * the image. + */ + ds_size = *(u16 *)(buf + hdr_size); + if (ds_size >= image_size) + return -EINVAL; + + /* + * Make sure the device ID in the image matches the retimer + * hardware. + */ + device = *(u16 *)(buf + hdr_size + INTEL_NVM_DEVID); + if (device != rt->device) + return -EINVAL; + + /* Skip headers in the image */ + nvm->buf_data_start = buf + hdr_size; + nvm->buf_data_size = image_size - hdr_size; + + return 0; +} + +static const struct tb_nvm_vendor_ops intel_retimer_nvm_ops = { + .read_version = intel_retimer_nvm_version, + .validate = intel_retimer_nvm_validate, +}; + +/* Retimer vendor NVM support table */ +static const struct tb_nvm_vendor retimer_nvm_vendors[] = { + { 0x8087, &intel_retimer_nvm_ops }, +}; + /** * tb_nvm_alloc() - Allocate new NVM structure * @dev: Device owning the NVM * * Allocates new NVM structure with unique @id and returns it. In case - * of error returns ERR_PTR(). + * of error returns ERR_PTR(). Specifically returns %-EOPNOTSUPP if the + * NVM format of the @dev is not known by the kernel. */ struct tb_nvm *tb_nvm_alloc(struct device *dev) { + const struct tb_nvm_vendor_ops *vops = NULL; struct tb_nvm *nvm; - int ret; + int ret, i; + + if (tb_is_switch(dev)) { + const struct tb_switch *sw = tb_to_switch(dev); + + for (i = 0; i < ARRAY_SIZE(switch_nvm_vendors); i++) { + const struct tb_nvm_vendor *v = &switch_nvm_vendors[i]; + + if (v->vendor == sw->config.vendor_id) { + vops = v->vops; + break; + } + } + + if (!vops) { + tb_sw_dbg(sw, "router NVM format of vendor %#x unknown\n", + sw->config.vendor_id); + return ERR_PTR(-EOPNOTSUPP); + } + } else if (tb_is_retimer(dev)) { + const struct tb_retimer *rt = tb_to_retimer(dev); + + for (i = 0; i < ARRAY_SIZE(retimer_nvm_vendors); i++) { + const struct tb_nvm_vendor *v = &retimer_nvm_vendors[i]; + + if (v->vendor == rt->vendor) { + vops = v->vops; + break; + } + } + + if (!vops) { + dev_dbg(dev, "retimer NVM format of vendor %#x unknown\n", + rt->vendor); + return ERR_PTR(-EOPNOTSUPP); + } + } else { + return ERR_PTR(-EOPNOTSUPP); + } nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); if (!nvm) @@ -38,14 +334,85 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev) nvm->id = ret; nvm->dev = dev; + nvm->vops = vops; return nvm; } +/** + * tb_nvm_read_version() - Read and populate NVM version + * @nvm: NVM structure + * + * Uses vendor specific means to read out and fill in the existing + * active NVM version. Returns %0 in case of success and negative errno + * otherwise. + */ +int tb_nvm_read_version(struct tb_nvm *nvm) +{ + const struct tb_nvm_vendor_ops *vops = nvm->vops; + + if (vops && vops->read_version) + return vops->read_version(nvm); + + return -EOPNOTSUPP; +} + +/** + * tb_nvm_validate() - Validate new NVM image + * @nvm: NVM structure + * + * Runs vendor specific validation over the new NVM image and if all + * checks pass returns %0. As side effect updates @nvm->buf_data_start + * and @nvm->buf_data_size fields to match the actual data to be written + * to the NVM. + * + * If the validation does not pass then returns negative errno. + */ +int tb_nvm_validate(struct tb_nvm *nvm) +{ + const struct tb_nvm_vendor_ops *vops = nvm->vops; + unsigned int image_size; + u8 *buf = nvm->buf; + + if (!buf) + return -EINVAL; + if (!vops) + return -EOPNOTSUPP; + + /* Just do basic image size checks */ + image_size = nvm->buf_data_size; + if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) + return -EINVAL; + + /* + * Set the default data start in the buffer. The validate method + * below can change this if needed. + */ + nvm->buf_data_start = buf; + + return vops->validate ? vops->validate(nvm) : 0; +} + +/** + * tb_nvm_write_headers() - Write headers before the rest of the image + * @nvm: NVM structure + * + * If the vendor NVM format requires writing headers before the rest of + * the image, this function does that. Can be called even if the device + * does not need this. + * + * Returns %0 in case of success and negative errno otherwise. + */ +int tb_nvm_write_headers(struct tb_nvm *nvm) +{ + const struct tb_nvm_vendor_ops *vops = nvm->vops; + + return vops->write_headers ? vops->write_headers(nvm) : 0; +} + /** * tb_nvm_add_active() - Adds active NVMem device to NVM * @nvm: NVM structure - * @size: Size of the active NVM in bytes * @reg_read: Pointer to the function to read the NVM (passed directly to the * NVMem device) * @@ -54,7 +421,7 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev) * needed. The first parameter passed to @reg_read is @nvm structure. * Returns %0 in success and negative errno otherwise. */ -int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read) +int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read) { struct nvmem_config config; struct nvmem_device *nvmem; @@ -67,7 +434,7 @@ int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read config.id = nvm->id; config.stride = 4; config.word_size = 4; - config.size = size; + config.size = nvm->active_size; config.dev = nvm->dev; config.owner = THIS_MODULE; config.priv = nvm; @@ -109,17 +476,17 @@ int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, /** * tb_nvm_add_non_active() - Adds non-active NVMem device to NVM * @nvm: NVM structure - * @size: Size of the non-active NVM in bytes * @reg_write: Pointer to the function to write the NVM (passed directly * to the NVMem device) * * Registers new non-active NVmem device for @nvm. The @reg_write is called * directly from NVMem so it must handle possible concurrent access if * needed. The first parameter passed to @reg_write is @nvm structure. + * The size of the NVMem device is set to %NVM_MAX_SIZE. + * * Returns %0 in success and negative errno otherwise. */ -int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size, - nvmem_reg_write_t reg_write) +int tb_nvm_add_non_active(struct tb_nvm *nvm, nvmem_reg_write_t reg_write) { struct nvmem_config config; struct nvmem_device *nvmem; @@ -132,7 +499,7 @@ int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size, config.id = nvm->id; config.stride = 4; config.word_size = 4; - config.size = size; + config.size = NVM_MAX_SIZE; config.dev = nvm->dev; config.owner = THIS_MODULE; config.priv = nvm; diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c index 8c29bd556ae0..81252e31014a 100644 --- a/drivers/thunderbolt/retimer.c +++ b/drivers/thunderbolt/retimer.c @@ -16,8 +16,23 @@ #define TB_MAX_RETIMER_INDEX 6 -static int tb_retimer_nvm_read(void *priv, unsigned int offset, void *val, - size_t bytes) +/** + * tb_retimer_nvm_read() - Read contents of retimer NVM + * @rt: Retimer device + * @address: NVM address (in bytes) to start reading + * @buf: Data read from NVM is stored here + * @size: Number of bytes to read + * + * Reads retimer NVM and copies the contents to @buf. Returns %0 if the + * read was successful and negative errno in case of failure. + */ +int tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf, + size_t size) +{ + return usb4_port_retimer_nvm_read(rt->port, rt->index, address, buf, size); +} + +static int nvm_read(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_retimer *rt = tb_to_retimer(nvm->dev); @@ -30,7 +45,7 @@ static int tb_retimer_nvm_read(void *priv, unsigned int offset, void *val, goto out; } - ret = usb4_port_retimer_nvm_read(rt->port, rt->index, offset, val, bytes); + ret = tb_retimer_nvm_read(rt, offset, val, bytes); mutex_unlock(&rt->tb->lock); out: @@ -40,8 +55,7 @@ out: return ret; } -static int tb_retimer_nvm_write(void *priv, unsigned int offset, void *val, - size_t bytes) +static int nvm_write(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_retimer *rt = tb_to_retimer(nvm->dev); @@ -59,34 +73,23 @@ static int tb_retimer_nvm_write(void *priv, unsigned int offset, void *val, static int tb_retimer_nvm_add(struct tb_retimer *rt) { struct tb_nvm *nvm; - u32 val, nvm_size; int ret; nvm = tb_nvm_alloc(&rt->dev); - if (IS_ERR(nvm)) - return PTR_ERR(nvm); + if (IS_ERR(nvm)) { + ret = PTR_ERR(nvm) == -EOPNOTSUPP ? 0 : PTR_ERR(nvm); + goto err_nvm; + } - ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_VERSION, &val, - sizeof(val)); + ret = tb_nvm_read_version(nvm); if (ret) goto err_nvm; - nvm->major = val >> 16; - nvm->minor = val >> 8; - - ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_FLASH_SIZE, - &val, sizeof(val)); + ret = tb_nvm_add_active(nvm, nvm_read); if (ret) goto err_nvm; - nvm_size = (SZ_1M << (val & 7)) / 8; - nvm_size = (nvm_size - SZ_16K) / 2; - - ret = tb_nvm_add_active(nvm, nvm_size, tb_retimer_nvm_read); - if (ret) - goto err_nvm; - - ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, tb_retimer_nvm_write); + ret = tb_nvm_add_non_active(nvm, nvm_write); if (ret) goto err_nvm; @@ -94,59 +97,33 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt) return 0; err_nvm: - tb_nvm_free(nvm); + dev_dbg(&rt->dev, "NVM upgrade disabled\n"); + if (!IS_ERR(nvm)) + tb_nvm_free(nvm); + return ret; } static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt) { - unsigned int image_size, hdr_size; - const u8 *buf = rt->nvm->buf; - u16 ds_size, device; + unsigned int image_size; + const u8 *buf; int ret; + ret = tb_nvm_validate(rt->nvm); + if (ret) + return ret; + + buf = rt->nvm->buf_data_start; image_size = rt->nvm->buf_data_size; - if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) - return -EINVAL; - - /* - * FARB pointer must point inside the image and must at least - * contain parts of the digital section we will be reading here. - */ - hdr_size = (*(u32 *)buf) & 0xffffff; - if (hdr_size + NVM_DEVID + 2 >= image_size) - return -EINVAL; - - /* Digital section start should be aligned to 4k page */ - if (!IS_ALIGNED(hdr_size, SZ_4K)) - return -EINVAL; - - /* - * Read digital section size and check that it also fits inside - * the image. - */ - ds_size = *(u16 *)(buf + hdr_size); - if (ds_size >= image_size) - return -EINVAL; - - /* - * Make sure the device ID in the image matches the retimer - * hardware. - */ - device = *(u16 *)(buf + hdr_size + NVM_DEVID); - if (device != rt->device) - return -EINVAL; - - /* Skip headers in the image */ - buf += hdr_size; - image_size -= hdr_size; ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf, image_size); - if (!ret) - rt->nvm->flushed = true; + if (ret) + return ret; - return ret; + rt->nvm->flushed = true; + return 0; } static int tb_retimer_nvm_authenticate(struct tb_retimer *rt, bool auth_only) @@ -185,7 +162,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr, { struct tb_retimer *rt = tb_to_retimer(dev); - return sprintf(buf, "%#x\n", rt->device); + return sysfs_emit(buf, "%#x\n", rt->device); } static DEVICE_ATTR_RO(device); @@ -200,8 +177,10 @@ static ssize_t nvm_authenticate_show(struct device *dev, if (!rt->nvm) ret = -EAGAIN; + else if (rt->no_nvm_upgrade) + ret = -EOPNOTSUPP; else - ret = sprintf(buf, "%#x\n", rt->auth_status); + ret = sysfs_emit(buf, "%#x\n", rt->auth_status); mutex_unlock(&rt->tb->lock); @@ -276,7 +255,7 @@ static ssize_t nvm_version_show(struct device *dev, if (!rt->nvm) ret = -EAGAIN; else - ret = sprintf(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor); + ret = sysfs_emit(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor); mutex_unlock(&rt->tb->lock); return ret; @@ -288,7 +267,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, { struct tb_retimer *rt = tb_to_retimer(dev); - return sprintf(buf, "%#x\n", rt->vendor); + return sysfs_emit(buf, "%#x\n", rt->vendor); } static DEVICE_ATTR_RO(vendor); diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h index bda889ff3bda..5185cf3e4d97 100644 --- a/drivers/thunderbolt/sb_regs.h +++ b/drivers/thunderbolt/sb_regs.h @@ -26,10 +26,68 @@ enum usb4_sb_opcode { USB4_SB_OPCODE_NVM_BLOCK_WRITE = 0x574b4c42, /* "BLKW" */ USB4_SB_OPCODE_NVM_AUTH_WRITE = 0x48545541, /* "AUTH" */ USB4_SB_OPCODE_NVM_READ = 0x52524641, /* "AFRR" */ + USB4_SB_OPCODE_READ_LANE_MARGINING_CAP = 0x50434452, /* "RDCP" */ + USB4_SB_OPCODE_RUN_HW_LANE_MARGINING = 0x474d4852, /* "RHMG" */ + USB4_SB_OPCODE_RUN_SW_LANE_MARGINING = 0x474d5352, /* "RSMG" */ + USB4_SB_OPCODE_READ_SW_MARGIN_ERR = 0x57534452, /* "RDSW" */ }; #define USB4_SB_METADATA 0x09 #define USB4_SB_METADATA_NVM_AUTH_WRITE_MASK GENMASK(5, 0) #define USB4_SB_DATA 0x12 +/* USB4_SB_OPCODE_READ_LANE_MARGINING_CAP */ +#define USB4_MARGIN_CAP_0_MODES_HW BIT(0) +#define USB4_MARGIN_CAP_0_MODES_SW BIT(1) +#define USB4_MARGIN_CAP_0_2_LANES BIT(2) +#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK GENMASK(4, 3) +#define USB4_MARGIN_CAP_0_VOLTAGE_INDP_SHIFT 3 +#define USB4_MARGIN_CAP_0_VOLTAGE_MIN 0x0 +#define USB4_MARGIN_CAP_0_VOLTAGE_HL 0x1 +#define USB4_MARGIN_CAP_0_VOLTAGE_BOTH 0x2 +#define USB4_MARGIN_CAP_0_TIME BIT(5) +#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK GENMASK(12, 6) +#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_SHIFT 6 +#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK GENMASK(18, 13) +#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_SHIFT 13 +#define USB4_MARGIN_CAP_1_TIME_DESTR BIT(8) +#define USB4_MARGIN_CAP_1_TIME_INDP_MASK GENMASK(10, 9) +#define USB4_MARGIN_CAP_1_TIME_INDP_SHIFT 9 +#define USB4_MARGIN_CAP_1_TIME_MIN 0x0 +#define USB4_MARGIN_CAP_1_TIME_LR 0x1 +#define USB4_MARGIN_CAP_1_TIME_BOTH 0x2 +#define USB4_MARGIN_CAP_1_TIME_STEPS_MASK GENMASK(15, 11) +#define USB4_MARGIN_CAP_1_TIME_STEPS_SHIFT 11 +#define USB4_MARGIN_CAP_1_TIME_OFFSET_MASK GENMASK(20, 16) +#define USB4_MARGIN_CAP_1_TIME_OFFSET_SHIFT 16 +#define USB4_MARGIN_CAP_1_MIN_BER_MASK GENMASK(25, 21) +#define USB4_MARGIN_CAP_1_MIN_BER_SHIFT 21 +#define USB4_MARGIN_CAP_1_MAX_BER_MASK GENMASK(30, 26) +#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT 26 +#define USB4_MARGIN_CAP_1_MAX_BER_SHIFT 26 + +/* USB4_SB_OPCODE_RUN_HW_LANE_MARGINING */ +#define USB4_MARGIN_HW_TIME BIT(3) +#define USB4_MARGIN_HW_RH BIT(4) +#define USB4_MARGIN_HW_BER_MASK GENMASK(9, 5) +#define USB4_MARGIN_HW_BER_SHIFT 5 + +/* Applicable to all margin values */ +#define USB4_MARGIN_HW_RES_1_MARGIN_MASK GENMASK(6, 0) +#define USB4_MARGIN_HW_RES_1_EXCEEDS BIT(7) +/* Different lane margin shifts */ +#define USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT 8 +#define USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT 16 +#define USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT 24 + +/* USB4_SB_OPCODE_RUN_SW_LANE_MARGINING */ +#define USB4_MARGIN_SW_TIME BIT(3) +#define USB4_MARGIN_SW_RH BIT(4) +#define USB4_MARGIN_SW_COUNTER_MASK GENMASK(14, 13) +#define USB4_MARGIN_SW_COUNTER_SHIFT 13 +#define USB4_MARGIN_SW_COUNTER_NOP 0x0 +#define USB4_MARGIN_SW_COUNTER_CLEAR 0x1 +#define USB4_MARGIN_SW_COUNTER_START 0x2 +#define USB4_MARGIN_SW_COUNTER_STOP 0x3 + #endif diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 77d7f07ca075..60da5c23ccaf 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -19,8 +19,6 @@ /* Switch NVM support */ -#define NVM_CSS 0x10 - struct nvm_auth_status { struct list_head list; uuid_t uuid; @@ -102,70 +100,30 @@ static void nvm_clear_auth_status(const struct tb_switch *sw) static int nvm_validate_and_write(struct tb_switch *sw) { - unsigned int image_size, hdr_size; - const u8 *buf = sw->nvm->buf; - u16 ds_size; + unsigned int image_size; + const u8 *buf; int ret; - if (!buf) - return -EINVAL; + ret = tb_nvm_validate(sw->nvm); + if (ret) + return ret; + ret = tb_nvm_write_headers(sw->nvm); + if (ret) + return ret; + + buf = sw->nvm->buf_data_start; image_size = sw->nvm->buf_data_size; - if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) - return -EINVAL; - - /* - * FARB pointer must point inside the image and must at least - * contain parts of the digital section we will be reading here. - */ - hdr_size = (*(u32 *)buf) & 0xffffff; - if (hdr_size + NVM_DEVID + 2 >= image_size) - return -EINVAL; - - /* Digital section start should be aligned to 4k page */ - if (!IS_ALIGNED(hdr_size, SZ_4K)) - return -EINVAL; - - /* - * Read digital section size and check that it also fits inside - * the image. - */ - ds_size = *(u16 *)(buf + hdr_size); - if (ds_size >= image_size) - return -EINVAL; - - if (!sw->safe_mode) { - u16 device_id; - - /* - * Make sure the device ID in the image matches the one - * we read from the switch config space. - */ - device_id = *(u16 *)(buf + hdr_size + NVM_DEVID); - if (device_id != sw->config.device_id) - return -EINVAL; - - if (sw->generation < 3) { - /* Write CSS headers first */ - ret = dma_port_flash_write(sw->dma_port, - DMA_PORT_CSS_ADDRESS, buf + NVM_CSS, - DMA_PORT_CSS_MAX_SIZE); - if (ret) - return ret; - } - - /* Skip headers in the image */ - buf += hdr_size; - image_size -= hdr_size; - } if (tb_switch_is_usb4(sw)) ret = usb4_switch_nvm_write(sw, 0, buf, image_size); else ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); - if (!ret) - sw->nvm->flushed = true; - return ret; + if (ret) + return ret; + + sw->nvm->flushed = true; + return 0; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) @@ -300,14 +258,6 @@ static inline bool nvm_upgradeable(struct tb_switch *sw) return nvm_readable(sw); } -static inline int nvm_read(struct tb_switch *sw, unsigned int address, - void *buf, size_t size) -{ - if (tb_switch_is_usb4(sw)) - return usb4_switch_nvm_read(sw, address, buf, size); - return dma_port_flash_read(sw->dma_port, address, buf, size); -} - static int nvm_authenticate(struct tb_switch *sw, bool auth_only) { int ret; @@ -335,8 +285,26 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only) return ret; } -static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, - size_t bytes) +/** + * tb_switch_nvm_read() - Read router NVM + * @sw: Router whose NVM to read + * @address: Start address on the NVM + * @buf: Buffer where the read data is copied + * @size: Size of the buffer in bytes + * + * Reads from router NVM and returns the requested data in @buf. Locking + * is up to the caller. Returns %0 in success and negative errno in case + * of failure. + */ +int tb_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, + size_t size) +{ + if (tb_switch_is_usb4(sw)) + return usb4_switch_nvm_read(sw, address, buf, size); + return dma_port_flash_read(sw->dma_port, address, buf, size); +} + +static int nvm_read(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); @@ -349,7 +317,7 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, goto out; } - ret = nvm_read(sw, offset, val, bytes); + ret = tb_switch_nvm_read(sw, offset, val, bytes); mutex_unlock(&sw->tb->lock); out: @@ -359,8 +327,7 @@ out: return ret; } -static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, - size_t bytes) +static int nvm_write(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); @@ -384,28 +351,20 @@ static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, static int tb_switch_nvm_add(struct tb_switch *sw) { struct tb_nvm *nvm; - u32 val; int ret; if (!nvm_readable(sw)) return 0; - /* - * The NVM format of non-Intel hardware is not known so - * currently restrict NVM upgrade for Intel hardware. We may - * relax this in the future when we learn other NVM formats. - */ - if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL && - sw->config.vendor_id != 0x8087) { - dev_info(&sw->dev, - "NVM format of vendor %#x is not known, disabling NVM upgrade\n", - sw->config.vendor_id); - return 0; + nvm = tb_nvm_alloc(&sw->dev); + if (IS_ERR(nvm)) { + ret = PTR_ERR(nvm) == -EOPNOTSUPP ? 0 : PTR_ERR(nvm); + goto err_nvm; } - nvm = tb_nvm_alloc(&sw->dev); - if (IS_ERR(nvm)) - return PTR_ERR(nvm); + ret = tb_nvm_read_version(nvm); + if (ret) + goto err_nvm; /* * If the switch is in safe-mode the only accessible portion of @@ -413,31 +372,13 @@ static int tb_switch_nvm_add(struct tb_switch *sw) * write new functional NVM. */ if (!sw->safe_mode) { - u32 nvm_size, hdr_size; - - ret = nvm_read(sw, NVM_FLASH_SIZE, &val, sizeof(val)); - if (ret) - goto err_nvm; - - hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K; - nvm_size = (SZ_1M << (val & 7)) / 8; - nvm_size = (nvm_size - hdr_size) / 2; - - ret = nvm_read(sw, NVM_VERSION, &val, sizeof(val)); - if (ret) - goto err_nvm; - - nvm->major = val >> 16; - nvm->minor = val >> 8; - - ret = tb_nvm_add_active(nvm, nvm_size, tb_switch_nvm_read); + ret = tb_nvm_add_active(nvm, nvm_read); if (ret) goto err_nvm; } if (!sw->no_nvm_upgrade) { - ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, - tb_switch_nvm_write); + ret = tb_nvm_add_non_active(nvm, nvm_write); if (ret) goto err_nvm; } @@ -446,7 +387,11 @@ static int tb_switch_nvm_add(struct tb_switch *sw) return 0; err_nvm: - tb_nvm_free(nvm); + tb_sw_dbg(sw, "NVM upgrade disabled\n"); + sw->no_nvm_upgrade = true; + if (!IS_ERR(nvm)) + tb_nvm_free(nvm); + return ret; } @@ -1229,6 +1174,135 @@ int tb_port_update_credits(struct tb_port *port) return tb_port_do_update_credits(port->dual_link_port); } +static int __tb_port_pm_secondary_set(struct tb_port *port, bool secondary) +{ + u32 phy; + int ret; + + ret = tb_port_read(port, &phy, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_1, 1); + if (ret) + return ret; + + if (secondary) + phy |= LANE_ADP_CS_1_PMS; + else + phy &= ~LANE_ADP_CS_1_PMS; + + return tb_port_write(port, &phy, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_1, 1); +} + +static int tb_port_pm_secondary_enable(struct tb_port *port) +{ + return __tb_port_pm_secondary_set(port, true); +} + +static int tb_port_pm_secondary_disable(struct tb_port *port) +{ + return __tb_port_pm_secondary_set(port, false); +} + +/* Called for USB4 or Titan Ridge routers only */ +static bool tb_port_clx_supported(struct tb_port *port, unsigned int clx_mask) +{ + u32 val, mask = 0; + bool ret; + + /* Don't enable CLx in case of two single-lane links */ + if (!port->bonded && port->dual_link_port) + return false; + + /* Don't enable CLx in case of inter-domain link */ + if (port->xdomain) + return false; + + if (tb_switch_is_usb4(port->sw)) { + if (!usb4_port_clx_supported(port)) + return false; + } else if (!tb_lc_is_clx_supported(port)) { + return false; + } + + if (clx_mask & TB_CL1) { + /* CL0s and CL1 are enabled and supported together */ + mask |= LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT; + } + if (clx_mask & TB_CL2) + mask |= LANE_ADP_CS_0_CL2_SUPPORT; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_0, 1); + if (ret) + return false; + + return !!(val & mask); +} + +static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable) +{ + u32 phy, mask; + int ret; + + /* CL0s and CL1 are enabled and supported together */ + if (clx == TB_CL1) + mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE; + else + /* For now we support only CL0s and CL1. Not CL2 */ + return -EOPNOTSUPP; + + ret = tb_port_read(port, &phy, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_1, 1); + if (ret) + return ret; + + if (enable) + phy |= mask; + else + phy &= ~mask; + + return tb_port_write(port, &phy, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_1, 1); +} + +static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx) +{ + return __tb_port_clx_set(port, clx, false); +} + +static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx) +{ + return __tb_port_clx_set(port, clx, true); +} + +/** + * tb_port_is_clx_enabled() - Is given CL state enabled + * @port: USB4 port to check + * @clx_mask: Mask of CL states to check + * + * Returns true if any of the given CL states is enabled for @port. + */ +bool tb_port_is_clx_enabled(struct tb_port *port, unsigned int clx_mask) +{ + u32 val, mask = 0; + int ret; + + if (!tb_port_clx_supported(port, clx_mask)) + return false; + + if (clx_mask & TB_CL1) + mask |= LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE; + if (clx_mask & TB_CL2) + mask |= LANE_ADP_CS_1_CL2_ENABLE; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_phy + LANE_ADP_CS_1, 1); + if (ret) + return false; + + return !!(val & mask); +} + static int tb_port_start_lane_initialization(struct tb_port *port) { int ret; @@ -1620,7 +1694,7 @@ static ssize_t authorized_show(struct device *dev, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%u\n", sw->authorized); + return sysfs_emit(buf, "%u\n", sw->authorized); } static int disapprove_switch(struct device *dev, void *not_used) @@ -1730,7 +1804,7 @@ static ssize_t boot_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%u\n", sw->boot); + return sysfs_emit(buf, "%u\n", sw->boot); } static DEVICE_ATTR_RO(boot); @@ -1739,7 +1813,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%#x\n", sw->device); + return sysfs_emit(buf, "%#x\n", sw->device); } static DEVICE_ATTR_RO(device); @@ -1748,7 +1822,7 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%s\n", sw->device_name ? sw->device_name : ""); + return sysfs_emit(buf, "%s\n", sw->device_name ?: ""); } static DEVICE_ATTR_RO(device_name); @@ -1757,7 +1831,7 @@ generation_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%u\n", sw->generation); + return sysfs_emit(buf, "%u\n", sw->generation); } static DEVICE_ATTR_RO(generation); @@ -1771,9 +1845,9 @@ static ssize_t key_show(struct device *dev, struct device_attribute *attr, return restart_syscall(); if (sw->key) - ret = sprintf(buf, "%*phN\n", TB_SWITCH_KEY_SIZE, sw->key); + ret = sysfs_emit(buf, "%*phN\n", TB_SWITCH_KEY_SIZE, sw->key); else - ret = sprintf(buf, "\n"); + ret = sysfs_emit(buf, "\n"); mutex_unlock(&sw->tb->lock); return ret; @@ -1818,7 +1892,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%u.0 Gb/s\n", sw->link_speed); + return sysfs_emit(buf, "%u.0 Gb/s\n", sw->link_speed); } /* @@ -1833,7 +1907,7 @@ static ssize_t lanes_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%u\n", sw->link_width); + return sysfs_emit(buf, "%u\n", sw->link_width); } /* @@ -1850,7 +1924,7 @@ static ssize_t nvm_authenticate_show(struct device *dev, u32 status; nvm_get_auth_status(sw, &status); - return sprintf(buf, "%#x\n", status); + return sysfs_emit(buf, "%#x\n", status); } static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf, @@ -1866,6 +1940,11 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf, goto exit_rpm; } + if (sw->no_nvm_upgrade) { + ret = -EOPNOTSUPP; + goto exit_unlock; + } + /* If NVMem devices are not yet added */ if (!sw->nvm) { ret = -EAGAIN; @@ -1954,7 +2033,7 @@ static ssize_t nvm_version_show(struct device *dev, else if (!sw->nvm) ret = -EAGAIN; else - ret = sprintf(buf, "%x.%x\n", sw->nvm->major, sw->nvm->minor); + ret = sysfs_emit(buf, "%x.%x\n", sw->nvm->major, sw->nvm->minor); mutex_unlock(&sw->tb->lock); @@ -1967,7 +2046,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%#x\n", sw->vendor); + return sysfs_emit(buf, "%#x\n", sw->vendor); } static DEVICE_ATTR_RO(vendor); @@ -1976,7 +2055,7 @@ vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%s\n", sw->vendor_name ? sw->vendor_name : ""); + return sysfs_emit(buf, "%s\n", sw->vendor_name ?: ""); } static DEVICE_ATTR_RO(vendor_name); @@ -1985,7 +2064,7 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr, { struct tb_switch *sw = tb_to_switch(dev); - return sprintf(buf, "%pUb\n", sw->uuid); + return sysfs_emit(buf, "%pUb\n", sw->uuid); } static DEVICE_ATTR_RO(unique_id); @@ -2822,6 +2901,26 @@ static void tb_switch_credits_init(struct tb_switch *sw) tb_sw_info(sw, "failed to determine preferred buffer allocation, using defaults\n"); } +static int tb_switch_port_hotplug_enable(struct tb_switch *sw) +{ + struct tb_port *port; + + if (tb_switch_is_icm(sw)) + return 0; + + tb_switch_for_each_port(sw, port) { + int res; + + if (!port->cap_usb4) + continue; + + res = usb4_port_hotplug_enable(port); + if (res) + return res; + } + return 0; +} + /** * tb_switch_add() - Add a switch to the domain * @sw: Switch to add @@ -2891,6 +2990,10 @@ int tb_switch_add(struct tb_switch *sw) return ret; } + ret = tb_switch_port_hotplug_enable(sw); + if (ret) + return ret; + ret = device_add(&sw->dev); if (ret) { dev_err(&sw->dev, "failed to add device: %d\n", ret); @@ -3362,35 +3465,6 @@ struct tb_port *tb_switch_find_port(struct tb_switch *sw, return NULL; } -static int __tb_port_pm_secondary_set(struct tb_port *port, bool secondary) -{ - u32 phy; - int ret; - - ret = tb_port_read(port, &phy, TB_CFG_PORT, - port->cap_phy + LANE_ADP_CS_1, 1); - if (ret) - return ret; - - if (secondary) - phy |= LANE_ADP_CS_1_PMS; - else - phy &= ~LANE_ADP_CS_1_PMS; - - return tb_port_write(port, &phy, TB_CFG_PORT, - port->cap_phy + LANE_ADP_CS_1, 1); -} - -static int tb_port_pm_secondary_enable(struct tb_port *port) -{ - return __tb_port_pm_secondary_set(port, true); -} - -static int tb_port_pm_secondary_disable(struct tb_port *port) -{ - return __tb_port_pm_secondary_set(port, false); -} - static int tb_switch_pm_secondary_resolve(struct tb_switch *sw) { struct tb_switch *parent = tb_switch_parent(sw); @@ -3409,83 +3483,6 @@ static int tb_switch_pm_secondary_resolve(struct tb_switch *sw) return tb_port_pm_secondary_disable(down); } -/* Called for USB4 or Titan Ridge routers only */ -static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx) -{ - u32 mask, val; - bool ret; - - /* Don't enable CLx in case of two single-lane links */ - if (!port->bonded && port->dual_link_port) - return false; - - /* Don't enable CLx in case of inter-domain link */ - if (port->xdomain) - return false; - - if (tb_switch_is_usb4(port->sw)) { - if (!usb4_port_clx_supported(port)) - return false; - } else if (!tb_lc_is_clx_supported(port)) { - return false; - } - - switch (clx) { - case TB_CL1: - /* CL0s and CL1 are enabled and supported together */ - mask = LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT; - break; - - /* For now we support only CL0s and CL1. Not CL2 */ - case TB_CL2: - default: - return false; - } - - ret = tb_port_read(port, &val, TB_CFG_PORT, - port->cap_phy + LANE_ADP_CS_0, 1); - if (ret) - return false; - - return !!(val & mask); -} - -static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable) -{ - u32 phy, mask; - int ret; - - /* CL0s and CL1 are enabled and supported together */ - if (clx == TB_CL1) - mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE; - else - /* For now we support only CL0s and CL1. Not CL2 */ - return -EOPNOTSUPP; - - ret = tb_port_read(port, &phy, TB_CFG_PORT, - port->cap_phy + LANE_ADP_CS_1, 1); - if (ret) - return ret; - - if (enable) - phy |= mask; - else - phy &= ~mask; - - return tb_port_write(port, &phy, TB_CFG_PORT, - port->cap_phy + LANE_ADP_CS_1, 1); -} - -static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx) -{ - return __tb_port_clx_set(port, clx, false); -} - -static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx) -{ - return __tb_port_clx_set(port, clx, true); -} - static int __tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx) { struct tb_switch *parent = tb_switch_parent(sw); diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 9a277078338c..462845804427 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -105,6 +105,32 @@ static void tb_remove_dp_resources(struct tb_switch *sw) } } +static void tb_discover_dp_resource(struct tb *tb, struct tb_port *port) +{ + struct tb_cm *tcm = tb_priv(tb); + struct tb_port *p; + + list_for_each_entry(p, &tcm->dp_resources, list) { + if (p == port) + return; + } + + tb_port_dbg(port, "DP %s resource available discovered\n", + tb_port_is_dpin(port) ? "IN" : "OUT"); + list_add_tail(&port->list, &tcm->dp_resources); +} + +static void tb_discover_dp_resources(struct tb *tb) +{ + struct tb_cm *tcm = tb_priv(tb); + struct tb_tunnel *tunnel; + + list_for_each_entry(tunnel, &tcm->tunnel_list, list) { + if (tb_tunnel_is_dp(tunnel)) + tb_discover_dp_resource(tb, tunnel->dst_port); + } +} + static void tb_switch_discover_tunnels(struct tb_switch *sw, struct list_head *list, bool alloc_hopids) @@ -1416,8 +1442,11 @@ static int tb_start(struct tb *tb) * ICM firmware upgrade needs running firmware and in native * mode that is not available so disable firmware upgrade of the * root switch. + * + * However, USB4 routers support NVM firmware upgrade if they + * implement the necessary router operations. */ - tb->root_switch->no_nvm_upgrade = true; + tb->root_switch->no_nvm_upgrade = !tb_switch_is_usb4(tb->root_switch); /* All USB4 routers support runtime PM */ tb->root_switch->rpm = tb_switch_is_usb4(tb->root_switch); @@ -1446,6 +1475,8 @@ static int tb_start(struct tb *tb) tb_scan_switch(tb->root_switch); /* Find out tunnels created by the boot firmware */ tb_discover_tunnels(tb); + /* Add DP resources from the DP tunnels created by the boot firmware */ + tb_discover_dp_resources(tb); /* * If the boot firmware did not create USB 3.x tunnels create them * now for the whole topology. diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 0f067c06cba6..f9786976f5ec 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -23,11 +23,6 @@ #define NVM_MAX_SIZE SZ_512K #define NVM_DATA_DWORDS 16 -/* Intel specific NVM offsets */ -#define NVM_DEVID 0x05 -#define NVM_VERSION 0x08 -#define NVM_FLASH_SIZE 0x45 - /** * struct tb_nvm - Structure holding NVM information * @dev: Owner of the NVM @@ -35,28 +30,35 @@ * @minor: Minor version number of the active NVM portion * @id: Identifier used with both NVM portions * @active: Active portion NVMem device + * @active_size: Size in bytes of the active NVM * @non_active: Non-active portion NVMem device * @buf: Buffer where the NVM image is stored before it is written to * the actual NVM flash device + * @buf_data_start: Where the actual image starts after skipping + * possible headers * @buf_data_size: Number of bytes actually consumed by the new NVM * image * @authenticating: The device is authenticating the new NVM * @flushed: The image has been flushed to the storage area + * @vops: Router vendor specific NVM operations (optional) * * The user of this structure needs to handle serialization of possible * concurrent access. */ struct tb_nvm { struct device *dev; - u8 major; - u8 minor; + u32 major; + u32 minor; int id; struct nvmem_device *active; + size_t active_size; struct nvmem_device *non_active; void *buf; + void *buf_data_start; size_t buf_data_size; bool authenticating; bool flushed; + const struct tb_nvm_vendor_ops *vops; }; enum tb_nvm_write_ops { @@ -113,8 +115,8 @@ struct tb_switch_tmu { enum tb_clx { TB_CLX_DISABLE, /* CL0s and CL1 are enabled and supported together */ - TB_CL1, - TB_CL2, + TB_CL1 = BIT(0), + TB_CL2 = BIT(1), }; /** @@ -279,12 +281,16 @@ struct tb_port { * @can_offline: Does the port have necessary platform support to moved * it into offline mode and back * @offline: The port is currently in offline mode + * @margining: Pointer to margining structure if enabled */ struct usb4_port { struct device dev; struct tb_port *port; bool can_offline; bool offline; +#ifdef CONFIG_USB4_DEBUGFS_MARGINING + struct tb_margining *margining; +#endif }; /** @@ -296,6 +302,7 @@ struct usb4_port { * @device: Device ID of the retimer * @port: Pointer to the lane 0 adapter * @nvm: Pointer to the NVM if the retimer has one (%NULL otherwise) + * @no_nvm_upgrade: Prevent NVM upgrade of this retimer * @auth_status: Status of last NVM authentication */ struct tb_retimer { @@ -306,6 +313,7 @@ struct tb_retimer { u32 device; struct tb_port *port; struct tb_nvm *nvm; + bool no_nvm_upgrade; u32 auth_status; }; @@ -737,11 +745,13 @@ static inline void tb_domain_put(struct tb *tb) } struct tb_nvm *tb_nvm_alloc(struct device *dev); -int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read); +int tb_nvm_read_version(struct tb_nvm *nvm); +int tb_nvm_validate(struct tb_nvm *nvm); +int tb_nvm_write_headers(struct tb_nvm *nvm); +int tb_nvm_add_active(struct tb_nvm *nvm, nvmem_reg_read_t reg_read); int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, size_t bytes); -int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size, - nvmem_reg_write_t reg_write); +int tb_nvm_add_non_active(struct tb_nvm *nvm, nvmem_reg_write_t reg_write); void tb_nvm_free(struct tb_nvm *nvm); void tb_nvm_exit(void); @@ -755,6 +765,8 @@ int tb_nvm_write_data(unsigned int address, const void *buf, size_t size, unsigned int retries, write_block_fn write_next_block, void *write_block_data); +int tb_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, + size_t size); struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, u64 route); struct tb_switch *tb_switch_alloc_safe_mode(struct tb *tb, @@ -1035,6 +1047,7 @@ void tb_port_lane_bonding_disable(struct tb_port *port); int tb_port_wait_for_link_width(struct tb_port *port, int width, int timeout_msec); int tb_port_update_credits(struct tb_port *port); +bool tb_port_is_clx_enabled(struct tb_port *port, enum tb_clx clx); int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec); int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap); @@ -1132,6 +1145,13 @@ void tb_xdomain_remove(struct tb_xdomain *xd); struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, u8 depth); +static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd) +{ + return tb_to_switch(xd->dev.parent); +} + +int tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf, + size_t size); int tb_retimer_scan(struct tb_port *port, bool add); void tb_retimer_remove_all(struct tb_port *port); @@ -1174,6 +1194,7 @@ int usb4_switch_add_ports(struct tb_switch *sw); void usb4_switch_remove_ports(struct tb_switch *sw); int usb4_port_unlock(struct tb_port *port); +int usb4_port_hotplug_enable(struct tb_port *port); int usb4_port_configure(struct tb_port *port); void usb4_port_unconfigure(struct tb_port *port); int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd); @@ -1182,6 +1203,13 @@ int usb4_port_router_offline(struct tb_port *port); int usb4_port_router_online(struct tb_port *port); int usb4_port_enumerate_retimers(struct tb_port *port); bool usb4_port_clx_supported(struct tb_port *port); +int usb4_port_margining_caps(struct tb_port *port, u32 *caps); +int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes, + unsigned int ber_level, bool timing, bool right_high, + u32 *results); +int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing, + bool right_high, u32 counter); +int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors); int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index); int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf, @@ -1264,6 +1292,8 @@ void tb_debugfs_init(void); void tb_debugfs_exit(void); void tb_switch_debugfs_init(struct tb_switch *sw); void tb_switch_debugfs_remove(struct tb_switch *sw); +void tb_xdomain_debugfs_init(struct tb_xdomain *xd); +void tb_xdomain_debugfs_remove(struct tb_xdomain *xd); void tb_service_debugfs_init(struct tb_service *svc); void tb_service_debugfs_remove(struct tb_service *svc); #else @@ -1271,6 +1301,8 @@ static inline void tb_debugfs_init(void) { } static inline void tb_debugfs_exit(void) { } static inline void tb_switch_debugfs_init(struct tb_switch *sw) { } static inline void tb_switch_debugfs_remove(struct tb_switch *sw) { } +static inline void tb_xdomain_debugfs_init(struct tb_xdomain *xd) { } +static inline void tb_xdomain_debugfs_remove(struct tb_xdomain *xd) { } static inline void tb_service_debugfs_init(struct tb_service *svc) { } static inline void tb_service_debugfs_remove(struct tb_service *svc) { } #endif diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 166054110388..86319dca0f8c 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -308,6 +308,7 @@ struct tb_regs_port_header { #define ADP_CS_5 0x05 #define ADP_CS_5_LCA_MASK GENMASK(28, 22) #define ADP_CS_5_LCA_SHIFT 22 +#define ADP_CS_5_DHP BIT(31) /* TMU adapter registers */ #define TMU_ADP_CS_3 0x03 @@ -324,6 +325,7 @@ struct tb_regs_port_header { #define LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL 0x2 #define LANE_ADP_CS_0_CL0S_SUPPORT BIT(26) #define LANE_ADP_CS_0_CL1_SUPPORT BIT(27) +#define LANE_ADP_CS_0_CL2_SUPPORT BIT(28) #define LANE_ADP_CS_1 0x01 #define LANE_ADP_CS_1_TARGET_SPEED_MASK GENMASK(3, 0) #define LANE_ADP_CS_1_TARGET_SPEED_GEN3 0xc @@ -333,6 +335,7 @@ struct tb_regs_port_header { #define LANE_ADP_CS_1_TARGET_WIDTH_DUAL 0x3 #define LANE_ADP_CS_1_CL0S_ENABLE BIT(10) #define LANE_ADP_CS_1_CL1_ENABLE BIT(11) +#define LANE_ADP_CS_1_CL2_ENABLE BIT(12) #define LANE_ADP_CS_1_LD BIT(14) #define LANE_ADP_CS_1_LB BIT(15) #define LANE_ADP_CS_1_CURRENT_SPEED_MASK GENMASK(19, 16) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index a386228a44ee..f986854aa207 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -1046,6 +1046,26 @@ int usb4_port_unlock(struct tb_port *port) return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_4, 1); } +/** + * usb4_port_hotplug_enable() - Enables hotplug for a port + * @port: USB4 port to operate on + * + * Enables hot plug events on a given port. This is only intended + * to be used on lane, DP-IN, and DP-OUT adapters. + */ +int usb4_port_hotplug_enable(struct tb_port *port) +{ + int ret; + u32 val; + + ret = tb_port_read(port, &val, TB_CFG_PORT, ADP_CS_5, 1); + if (ret) + return ret; + + val &= ~ADP_CS_5_DHP; + return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1); +} + static int usb4_port_set_configured(struct tb_port *port, bool configured) { int ret; @@ -1386,6 +1406,126 @@ bool usb4_port_clx_supported(struct tb_port *port) return !!(val & PORT_CS_18_CPS); } +/** + * usb4_port_margining_caps() - Read USB4 port marginig capabilities + * @port: USB4 port + * @caps: Array with at least two elements to hold the results + * + * Reads the USB4 port lane margining capabilities into @caps. + */ +int usb4_port_margining_caps(struct tb_port *port, u32 *caps) +{ + int ret; + + ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_OPCODE_READ_LANE_MARGINING_CAP, 500); + if (ret) + return ret; + + return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_DATA, caps, sizeof(*caps) * 2); +} + +/** + * usb4_port_hw_margin() - Run hardware lane margining on port + * @port: USB4 port + * @lanes: Which lanes to run (must match the port capabilities). Can be + * %0, %1 or %7. + * @ber_level: BER level contour value + * @timing: Perform timing margining instead of voltage + * @right_high: Use Right/high margin instead of left/low + * @results: Array with at least two elements to hold the results + * + * Runs hardware lane margining on USB4 port and returns the result in + * @results. + */ +int usb4_port_hw_margin(struct tb_port *port, unsigned int lanes, + unsigned int ber_level, bool timing, bool right_high, + u32 *results) +{ + u32 val; + int ret; + + val = lanes; + if (timing) + val |= USB4_MARGIN_HW_TIME; + if (right_high) + val |= USB4_MARGIN_HW_RH; + if (ber_level) + val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) & + USB4_MARGIN_HW_BER_MASK; + + ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_METADATA, &val, sizeof(val)); + if (ret) + return ret; + + ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_OPCODE_RUN_HW_LANE_MARGINING, 2500); + if (ret) + return ret; + + return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_DATA, results, sizeof(*results) * 2); +} + +/** + * usb4_port_sw_margin() - Run software lane margining on port + * @port: USB4 port + * @lanes: Which lanes to run (must match the port capabilities). Can be + * %0, %1 or %7. + * @timing: Perform timing margining instead of voltage + * @right_high: Use Right/high margin instead of left/low + * @counter: What to do with the error counter + * + * Runs software lane margining on USB4 port. Read back the error + * counters by calling usb4_port_sw_margin_errors(). Returns %0 in + * success and negative errno otherwise. + */ +int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing, + bool right_high, u32 counter) +{ + u32 val; + int ret; + + val = lanes; + if (timing) + val |= USB4_MARGIN_SW_TIME; + if (right_high) + val |= USB4_MARGIN_SW_RH; + val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) & + USB4_MARGIN_SW_COUNTER_MASK; + + ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_METADATA, &val, sizeof(val)); + if (ret) + return ret; + + return usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500); +} + +/** + * usb4_port_sw_margin_errors() - Read the software margining error counters + * @port: USB4 port + * @errors: Error metadata is copied here. + * + * This reads back the software margining error counters from the port. + * Returns %0 in success and negative errno otherwise. + */ +int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors) +{ + int ret; + + ret = usb4_port_sb_op(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_OPCODE_READ_SW_MARGIN_ERR, 150); + if (ret) + return ret; + + return usb4_port_sb_read(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_METADATA, errors, sizeof(*errors)); +} + static inline int usb4_port_retimer_op(struct tb_port *port, u8 index, enum usb4_sb_opcode opcode, int timeout_msec) diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index c31c0d94d8b3..bbb248a2686f 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -877,7 +877,7 @@ static ssize_t key_show(struct device *dev, struct device_attribute *attr, * It should be null terminated but anything else is pretty much * allowed. */ - return sprintf(buf, "%*pE\n", (int)strlen(svc->key), svc->key); + return sysfs_emit(buf, "%*pE\n", (int)strlen(svc->key), svc->key); } static DEVICE_ATTR_RO(key); @@ -903,7 +903,7 @@ static ssize_t prtcid_show(struct device *dev, struct device_attribute *attr, { struct tb_service *svc = container_of(dev, struct tb_service, dev); - return sprintf(buf, "%u\n", svc->prtcid); + return sysfs_emit(buf, "%u\n", svc->prtcid); } static DEVICE_ATTR_RO(prtcid); @@ -912,7 +912,7 @@ static ssize_t prtcvers_show(struct device *dev, struct device_attribute *attr, { struct tb_service *svc = container_of(dev, struct tb_service, dev); - return sprintf(buf, "%u\n", svc->prtcvers); + return sysfs_emit(buf, "%u\n", svc->prtcvers); } static DEVICE_ATTR_RO(prtcvers); @@ -921,7 +921,7 @@ static ssize_t prtcrevs_show(struct device *dev, struct device_attribute *attr, { struct tb_service *svc = container_of(dev, struct tb_service, dev); - return sprintf(buf, "%u\n", svc->prtcrevs); + return sysfs_emit(buf, "%u\n", svc->prtcrevs); } static DEVICE_ATTR_RO(prtcrevs); @@ -930,7 +930,7 @@ static ssize_t prtcstns_show(struct device *dev, struct device_attribute *attr, { struct tb_service *svc = container_of(dev, struct tb_service, dev); - return sprintf(buf, "0x%08x\n", svc->prtcstns); + return sysfs_emit(buf, "0x%08x\n", svc->prtcstns); } static DEVICE_ATTR_RO(prtcstns); @@ -1131,11 +1131,6 @@ static int populate_properties(struct tb_xdomain *xd, return 0; } -static inline struct tb_switch *tb_xdomain_parent(struct tb_xdomain *xd) -{ - return tb_to_switch(xd->dev.parent); -} - static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd) { bool change = false; @@ -1440,6 +1435,8 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) if (xd->vendor_name && xd->device_name) dev_info(&xd->dev, "%s %s\n", xd->vendor_name, xd->device_name); + + tb_xdomain_debugfs_init(xd); } else { kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE); } @@ -1664,7 +1661,7 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%#x\n", xd->device); + return sysfs_emit(buf, "%#x\n", xd->device); } static DEVICE_ATTR_RO(device); @@ -1676,7 +1673,7 @@ device_name_show(struct device *dev, struct device_attribute *attr, char *buf) if (mutex_lock_interruptible(&xd->lock)) return -ERESTARTSYS; - ret = sprintf(buf, "%s\n", xd->device_name ? xd->device_name : ""); + ret = sysfs_emit(buf, "%s\n", xd->device_name ?: ""); mutex_unlock(&xd->lock); return ret; @@ -1688,7 +1685,7 @@ static ssize_t maxhopid_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%d\n", xd->remote_max_hopid); + return sysfs_emit(buf, "%d\n", xd->remote_max_hopid); } static DEVICE_ATTR_RO(maxhopid); @@ -1697,7 +1694,7 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%#x\n", xd->vendor); + return sysfs_emit(buf, "%#x\n", xd->vendor); } static DEVICE_ATTR_RO(vendor); @@ -1709,7 +1706,7 @@ vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf) if (mutex_lock_interruptible(&xd->lock)) return -ERESTARTSYS; - ret = sprintf(buf, "%s\n", xd->vendor_name ? xd->vendor_name : ""); + ret = sysfs_emit(buf, "%s\n", xd->vendor_name ?: ""); mutex_unlock(&xd->lock); return ret; @@ -1721,7 +1718,7 @@ static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%pUb\n", xd->remote_uuid); + return sysfs_emit(buf, "%pUb\n", xd->remote_uuid); } static DEVICE_ATTR_RO(unique_id); @@ -1730,7 +1727,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%u.0 Gb/s\n", xd->link_speed); + return sysfs_emit(buf, "%u.0 Gb/s\n", xd->link_speed); } static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL); @@ -1741,7 +1738,7 @@ static ssize_t lanes_show(struct device *dev, struct device_attribute *attr, { struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); - return sprintf(buf, "%u\n", xd->link_width); + return sysfs_emit(buf, "%u\n", xd->link_width); } static DEVICE_ATTR(rx_lanes, 0444, lanes_show, NULL); @@ -1940,6 +1937,8 @@ static int unregister_service(struct device *dev, void *data) */ void tb_xdomain_remove(struct tb_xdomain *xd) { + tb_xdomain_debugfs_remove(xd); + stop_handshake(xd); device_for_each_child_reverse(&xd->dev, xd, unregister_service); diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 81e7f64c1739..f52266766df9 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -94,7 +94,7 @@ static struct tty_driver *serial_driver; static unsigned char current_ctl_bits; static void change_speed(struct tty_struct *tty, struct serial_state *info, - struct ktermios *old); + const struct ktermios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -566,7 +566,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) * the specified baud rate for a serial port. */ static void change_speed(struct tty_struct *tty, struct serial_state *info, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct tty_port *port = &info->tport; int quot = 0, baud_base, baud; @@ -1169,7 +1169,7 @@ static int rs_ioctl(struct tty_struct *tty, return 0; } -static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void rs_set_termios(struct tty_struct *tty, const struct ktermios *old_termios) { struct serial_state *info = tty->driver_data; unsigned long flags; diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 32366caca662..7d49a872de48 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -29,7 +29,6 @@ /* General device driver settings */ -#define HVC_IUCV_MAGIC 0xc9e4c3e5 #define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS #define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) @@ -131,9 +130,9 @@ static struct iucv_handler hvc_iucv_handler = { */ static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) { - if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) + if (num > hvc_iucv_devices) return NULL; - return hvc_iucv_table[num - HVC_IUCV_MAGIC]; + return hvc_iucv_table[num]; } /** @@ -1072,8 +1071,8 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) priv->is_console = is_console; /* allocate hvc device */ - priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ - HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); + priv->hvc = hvc_alloc(id, /* PAGE_SIZE */ + id, &hvc_iucv_ops, 256); if (IS_ERR(priv->hvc)) { rc = PTR_ERR(priv->hvc); goto out_error_hvc; @@ -1371,7 +1370,7 @@ static int __init hvc_iucv_init(void) /* register the first terminal device as console * (must be done before allocating hvc terminal devices) */ - rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); + rc = hvc_instantiate(0, IUCV_HVC_CON_IDX, &hvc_iucv_ops); if (rc) { pr_err("Registering HVC terminal device as " "Linux console failed\n"); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 9b7e8246a464..4ba24963685e 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -69,6 +69,7 @@ #include #include #include +#include #include /* @@ -839,7 +840,7 @@ static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) hvcsd->p_partition_ID = pi->partition_ID; /* copy the null-term char too */ - strlcpy(hvcsd->p_location_code, pi->location_code, + strscpy(hvcsd->p_location_code, pi->location_code, sizeof(hvcsd->p_location_code)); } diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index f3c72ab1476c..35b6fddf0341 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -491,7 +491,7 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int); static unsigned int moxa_write_room(struct tty_struct *); static void moxa_flush_buffer(struct tty_struct *); static unsigned int moxa_chars_in_buffer(struct tty_struct *); -static void moxa_set_termios(struct tty_struct *, struct ktermios *); +static void moxa_set_termios(struct tty_struct *, const struct ktermios *); static void moxa_stop(struct tty_struct *); static void moxa_start(struct tty_struct *); static void moxa_hangup(struct tty_struct *); @@ -499,7 +499,7 @@ static int moxa_tiocmget(struct tty_struct *tty); static int moxa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void moxa_poll(struct timer_list *); -static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); +static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *); static void moxa_shutdown(struct tty_port *); static int moxa_carrier_raised(struct tty_port *); static void moxa_dtr_rts(struct tty_port *, int); @@ -1602,7 +1602,7 @@ static int moxa_tiocmset(struct tty_struct *tty, } static void moxa_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct moxa_port *ch = tty->driver_data; @@ -1761,7 +1761,8 @@ static void moxa_poll(struct timer_list *unused) /******************************************************************************/ -static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) +static void moxa_set_tty_param(struct tty_struct *tty, + const struct ktermios *old_termios) { register struct ktermios *ts = &tty->termios; struct moxa_port *ch = tty->driver_data; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 70b982b2c6b2..2436e0b10f9a 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -398,7 +398,7 @@ static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io) oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); mxser_set_must_xon1_value(io, 0x11); - if ((hwid = inb(io + UART_MCR)) != 0) { + if (inb(io + UART_MCR) != 0) { outb(oldmcr, io + UART_MCR); return MOXA_OTHER_UART; } @@ -571,7 +571,8 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_termios) +static void mxser_change_speed(struct tty_struct *tty, + const struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; unsigned cflag, cval; @@ -1348,7 +1349,8 @@ static void mxser_start(struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); } -static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void mxser_set_termios(struct tty_struct *tty, + const struct ktermios *old_termios) { struct mxser_port *info = tty->driver_data; unsigned long flags; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 01c112e2e214..5e516f5cac5a 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -63,6 +63,14 @@ static int debug; module_param(debug, int, 0600); +/* Module debug bits */ +#define DBG_DUMP BIT(0) /* Data transmission dump. */ +#define DBG_CD_ON BIT(1) /* Always assume CD line on. */ +#define DBG_DATA BIT(2) /* Data transmission details. */ +#define DBG_ERRORS BIT(3) /* Details for fail conditions. */ +#define DBG_TTY BIT(4) /* Transmission statistics for DLCI TTYs. */ +#define DBG_PAYLOAD BIT(5) /* Limits DBG_DUMP to payload frames. */ + /* Defaults: these are from the specification */ #define T1 10 /* 100mS */ @@ -164,6 +172,9 @@ struct gsm_dlci { struct net_device *net; /* network interface, if created */ }; +/* Total number of supported devices */ +#define GSM_TTY_MINORS 256 + /* DLCI 0, 62/63 are special or reserved see gsmtty_open */ #define NUM_DLCI 64 @@ -184,6 +195,11 @@ struct gsm_control { int error; /* Error if any */ }; +enum gsm_encoding { + GSM_BASIC_OPT, + GSM_ADV_OPT, +}; + enum gsm_mux_state { GSM_SEARCH, GSM_START, @@ -230,7 +246,7 @@ struct gsm_mux { unsigned int address; unsigned int count; bool escape; - int encoding; + enum gsm_encoding encoding; u8 control; u8 fcs; u8 *txframe; /* TX framing buffer */ @@ -527,7 +543,7 @@ static int gsm_register_devices(struct tty_driver *driver, unsigned int index) */ dev = tty_register_device(gsm_tty_driver, base + i, NULL); if (IS_ERR(dev)) { - if (debug & 8) + if (debug & DBG_ERRORS) pr_info("%s failed to register device minor %u", __func__, base + i); for (i--; i >= 1; i--) @@ -581,8 +597,12 @@ static void gsm_unregister_devices(struct tty_driver *driver, static void gsm_print_packet(const char *hdr, int addr, int cr, u8 control, const u8 *data, int dlen) { - if (!(debug & 1)) + if (!(debug & DBG_DUMP)) return; + /* Only show user payload frames if debug & DBG_PAYLOAD */ + if (!(debug & DBG_PAYLOAD) && addr != 0) + if ((control & ~PF) == UI || (control & ~PF) == UIH) + return; pr_info("%s %d) %c: ", hdr, addr, "RC"[cr]); @@ -693,7 +713,7 @@ static int gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) *dp++ = (addr << 2) | (ocr << 1) | EA; *dp++ = control; - if (gsm->encoding == 0) + if (gsm->encoding == GSM_BASIC_OPT) *dp++ = EA; /* Length of data = 0 */ *dp = 0xFF - gsm_fcs_add_block(INIT_FCS, msg->data, dp - msg->data); @@ -812,7 +832,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg) int len, ret; - if (gsm->encoding == 0) { + if (gsm->encoding == GSM_BASIC_OPT) { gsm->txframe[0] = GSM0_SOF; memcpy(gsm->txframe + 1, msg->data, msg->len); gsm->txframe[msg->len + 1] = GSM0_SOF; @@ -824,7 +844,7 @@ static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg) len += 2; } - if (debug & 4) + if (debug & DBG_DATA) gsm_hex_dump_bytes(__func__, gsm->txframe, len); gsm_print_packet("-->", msg->addr, gsm->initiator, msg->ctrl, msg->data, msg->len); @@ -964,7 +984,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) u8 *fcs = dp + msg->len; /* Fill in the header */ - if (gsm->encoding == 0) { + if (gsm->encoding == GSM_BASIC_OPT) { if (msg->len < 128) *--dp = (msg->len << 1) | EA; else { @@ -1305,6 +1325,31 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci) */ +/** + * gsm_control_command - send a command frame to a control + * @gsm: gsm channel + * @cmd: the command to use + * @data: data to follow encoded info + * @dlen: length of data + * + * Encode up and queue a UI/UIH frame containing our command. + */ +static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data, + int dlen) +{ + struct gsm_msg *msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype); + + if (msg == NULL) + return -ENOMEM; + + msg->data[0] = (cmd << 1) | CR | EA; /* Set C/R */ + msg->data[1] = (dlen << 1) | EA; + memcpy(msg->data + 2, data, dlen); + gsm_data_queue(gsm->dlci[0], msg); + + return 0; +} + /** * gsm_control_reply - send a response frame to a control * @gsm: gsm channel @@ -1407,18 +1452,12 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) unsigned int modem = 0; struct gsm_dlci *dlci; int len = clen; - int slen; + int cl = clen; const u8 *dp = data; struct tty_struct *tty; - while (gsm_read_ea(&addr, *dp++) == 0) { - len--; - if (len == 0) - return; - } - /* Must be at least one byte following the EA */ - len--; - if (len <= 0) + len = gsm_read_ea_val(&addr, data, cl); + if (len < 1) return; addr >>= 1; @@ -1427,15 +1466,20 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) return; dlci = gsm->dlci[addr]; - slen = len; - while (gsm_read_ea(&modem, *dp++) == 0) { - len--; - if (len == 0) - return; - } - len--; + /* Must be at least one byte following the EA */ + if ((cl - len) < 1) + return; + + dp += len; + cl -= len; + + /* get the modem status */ + len = gsm_read_ea_val(&modem, dp, cl); + if (len < 1) + return; + tty = tty_port_tty_get(&dlci->port); - gsm_process_modem(tty, dlci, modem, slen - len); + gsm_process_modem(tty, dlci, modem, cl); if (tty) { tty_wakeup(tty); tty_kref_put(tty); @@ -1611,13 +1655,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) { - struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 2, gsm->ftype); - if (msg == NULL) - return; - msg->data[0] = (ctrl->cmd << 1) | CR | EA; /* command */ - msg->data[1] = (ctrl->len << 1) | EA; - memcpy(msg->data + 2, ctrl->data, ctrl->len); - gsm_data_queue(gsm->dlci[0], msg); + gsm_control_command(gsm, ctrl->cmd, ctrl->data, ctrl->len); } /** @@ -1737,7 +1775,7 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control) static void gsm_dlci_close(struct gsm_dlci *dlci) { del_timer(&dlci->t1); - if (debug & 8) + if (debug & DBG_ERRORS) pr_debug("DLCI %d goes closed.\n", dlci->addr); dlci->state = DLCI_CLOSED; /* Prevent us from sending data before the link is up again */ @@ -1771,7 +1809,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) /* This will let a tty open continue */ dlci->state = DLCI_OPEN; dlci->constipated = false; - if (debug & 8) + if (debug & DBG_ERRORS) pr_debug("DLCI %d goes open.\n", dlci->addr); /* Send current modem state */ if (dlci->addr) @@ -1807,7 +1845,7 @@ static void gsm_dlci_t1(struct timer_list *t) gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else if (!dlci->addr && gsm->control == (DM | PF)) { - if (debug & 8) + if (debug & DBG_ERRORS) pr_info("DLCI %d opening in ADM mode.\n", dlci->addr); dlci->mode = DLCI_MODE_ADM; @@ -1910,11 +1948,10 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) struct tty_port *port = &dlci->port; struct tty_struct *tty; unsigned int modem = 0; - int len = clen; - int slen = 0; + int len; - if (debug & 16) - pr_debug("%d bytes for tty\n", len); + if (debug & DBG_TTY) + pr_debug("%d bytes for tty\n", clen); switch (dlci->adaption) { /* Unsupported types */ case 4: /* Packetised interruptible data */ @@ -1922,24 +1959,22 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) case 3: /* Packetised uininterruptible voice/data */ break; case 2: /* Asynchronous serial with line state in each frame */ - while (gsm_read_ea(&modem, *data++) == 0) { - len--; - slen++; - if (len == 0) - return; - } - len--; - slen++; + len = gsm_read_ea_val(&modem, data, clen); + if (len < 1) + return; tty = tty_port_tty_get(port); if (tty) { - gsm_process_modem(tty, dlci, modem, slen); + gsm_process_modem(tty, dlci, modem, len); tty_wakeup(tty); tty_kref_put(tty); } + /* Skip processed modem data */ + data += len; + clen -= len; fallthrough; case 1: /* Line state will go via DLCI 0 controls only */ default: - tty_insert_flip_string(port, data, len); + tty_insert_flip_string(port, data, clen); tty_flip_buffer_push(port); } } @@ -1960,24 +1995,27 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) { /* See what command is involved */ unsigned int command = 0; - while (len-- > 0) { - if (gsm_read_ea(&command, *data++) == 1) { - int clen = *data++; - len--; - /* FIXME: this is properly an EA */ - clen >>= 1; - /* Malformed command ? */ - if (clen > len) - return; - if (command & 1) - gsm_control_message(dlci->gsm, command, - data, clen); - else - gsm_control_response(dlci->gsm, command, - data, clen); - return; - } - } + unsigned int clen = 0; + unsigned int dlen; + + /* read the command */ + dlen = gsm_read_ea_val(&command, data, len); + len -= dlen; + data += dlen; + + /* read any control data */ + dlen = gsm_read_ea_val(&clen, data, len); + len -= dlen; + data += dlen; + + /* Malformed command? */ + if (clen > len) + return; + + if (command & 1) + gsm_control_message(dlci->gsm, command, data, clen); + else + gsm_control_response(dlci->gsm, command, data, clen); } /** @@ -1999,7 +2037,7 @@ static void gsm_kick_timeout(struct work_struct *work) sent = gsm_dlci_data_sweep(gsm); mutex_unlock(&gsm->tx_mutex); - if (sent && debug & 4) + if (sent && debug & DBG_DATA) pr_info("%s TX queue stalled\n", __func__); } @@ -2133,7 +2171,7 @@ static void gsm_queue(struct gsm_mux *gsm) if (gsm->fcs != GOOD_FCS) { gsm->bad_fcs++; - if (debug & 4) + if (debug & DBG_DATA) pr_debug("BAD FCS %02x\n", gsm->fcs); return; } @@ -2497,7 +2535,7 @@ static int gsm_activate_mux(struct gsm_mux *gsm) if (dlci == NULL) return -ENOMEM; - if (gsm->encoding == 0) + if (gsm->encoding == GSM_BASIC_OPT) gsm->receive = gsm0_receive; else gsm->receive = gsm1_receive; @@ -2614,7 +2652,7 @@ static struct gsm_mux *gsm_alloc_mux(void) gsm->n2 = N2; gsm->ftype = UIH; gsm->adaption = 1; - gsm->encoding = 1; + gsm->encoding = GSM_ADV_OPT; gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ gsm->mtu = 64; gsm->dead = true; /* Avoid early tty opens */ @@ -2716,7 +2754,7 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) gsm->initiator = c->initiator; gsm->mru = c->mru; gsm->mtu = c->mtu; - gsm->encoding = c->encapsulation; + gsm->encoding = c->encapsulation ? GSM_ADV_OPT : GSM_BASIC_OPT; gsm->adaption = c->adaption; gsm->n2 = c->n2; @@ -2760,7 +2798,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags); return -ENOSPC; } - if (debug & 4) + if (debug & DBG_DATA) gsm_hex_dump_bytes(__func__, data, len); return gsm->tty->ops->write(gsm->tty, data, len); } @@ -2846,7 +2884,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, struct gsm_mux *gsm = tty->disc_data; char flags = TTY_NORMAL; - if (debug & 4) + if (debug & DBG_DATA) gsm_hex_dump_bytes(__func__, cp, count); for (; count; count--, cp++) { @@ -2939,8 +2977,7 @@ static int gsmld_open(struct tty_struct *tty) tty->receive_room = 65536; /* Attach the initial passive connection */ - gsm->encoding = 1; - + gsm->encoding = GSM_ADV_OPT; gsmld_attach_gsm(tty, gsm); return 0; @@ -3336,7 +3373,7 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) struct gsm_control *ctrl; int len = 2; - if (dlci->gsm->encoding != 0) + if (dlci->gsm->encoding != GSM_BASIC_OPT) return 0; modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ @@ -3365,7 +3402,7 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk) /* Send convergence layer type 2 empty data frame. */ gsm_modem_upd_via_data(dlci, brk); return 0; - } else if (dlci->gsm->encoding == 0) { + } else if (dlci->gsm->encoding == GSM_BASIC_OPT) { /* Send as MSC control message. */ return gsm_modem_upd_via_msc(dlci, brk); } @@ -3382,15 +3419,15 @@ static int gsm_carrier_raised(struct tty_port *port) /* Not yet open so no carrier info */ if (dlci->state != DLCI_OPEN) return 0; - if (debug & 2) + if (debug & DBG_CD_ON) return 1; /* * Basic mode with control channel in ADM mode may not respond * to CMD_MSC at all and modem_rx is empty. */ - if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM && - !dlci->modem_rx) + if (gsm->encoding == GSM_BASIC_OPT && + gsm->dlci[0]->mode == DLCI_MODE_ADM && !dlci->modem_rx) return 1; return dlci->modem_rx & TIOCM_CD; @@ -3638,7 +3675,8 @@ static int gsmtty_ioctl(struct tty_struct *tty, } } -static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) +static void gsmtty_set_termios(struct tty_struct *tty, + const struct ktermios *old) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) @@ -3736,7 +3774,7 @@ static int __init gsm_init(void) return status; } - gsm_tty_driver = tty_alloc_driver(256, TTY_DRIVER_REAL_RAW | + gsm_tty_driver = tty_alloc_driver(GSM_TTY_MINORS, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); if (IS_ERR(gsm_tty_driver)) { pr_err("gsm_init: tty allocation failed.\n"); diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 94c1ec2dd754..46b09bfb6f3a 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -76,8 +76,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define HDLC_MAGIC 0x239e - #include #include #include @@ -98,7 +96,6 @@ #include #include -#include #include #include "tty.h" @@ -124,7 +121,6 @@ struct n_hdlc_buf_list { /** * struct n_hdlc - per device instance data structure - * @magic: magic value for structure * @tbusy: reentrancy flag for tx wakeup code * @woke_up: tx wakeup needs to be run again as it was called while @tbusy * @tx_buf_list: list of pending transmit frame buffers @@ -133,7 +129,6 @@ struct n_hdlc_buf_list { * @rx_free_buf_list: list unused received frame buffers */ struct n_hdlc { - int magic; bool tbusy; bool woke_up; struct n_hdlc_buf_list tx_buf_list; @@ -200,10 +195,6 @@ static void n_hdlc_tty_close(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty->disc_data; - if (n_hdlc->magic != HDLC_MAGIC) { - pr_warn("n_hdlc: trying to close unopened tty!\n"); - return; - } #if defined(TTY_NO_WRITE_SPLIT) clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags); #endif @@ -386,12 +377,6 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, pr_debug("%s() called count=%d\n", __func__, count); - /* verify line is using HDLC discipline */ - if (n_hdlc->magic != HDLC_MAGIC) { - pr_err("line not using HDLC discipline\n"); - return; - } - if (count > maxframe) { pr_debug("rx count>maxframesize, data discarded\n"); return; @@ -542,9 +527,6 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, pr_debug("%s() called count=%zd\n", __func__, count); - if (n_hdlc->magic != HDLC_MAGIC) - return -EIO; - /* verify frame size */ if (count > maxframe) { pr_debug("%s: truncating user packet from %zu to %d\n", @@ -609,10 +591,6 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, pr_debug("%s() called %d\n", __func__, cmd); - /* Verify the status of the device */ - if (n_hdlc->magic != HDLC_MAGIC) - return -EBADF; - switch (cmd) { case FIONREAD: /* report count of read data available */ @@ -673,9 +651,6 @@ static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, struct n_hdlc *n_hdlc = tty->disc_data; __poll_t mask = 0; - if (n_hdlc->magic != HDLC_MAGIC) - return 0; - /* * queue the current process into any wait queue that may awaken in the * future (read and write) @@ -739,9 +714,6 @@ static struct n_hdlc *n_hdlc_alloc(void) n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx"); n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx"); - /* Initialize the control block */ - n_hdlc->magic = HDLC_MAGIC; - return n_hdlc; } /* end of n_hdlc_alloc() */ diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 3afdd9033a9c..597019690ae6 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1758,7 +1758,7 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, * * Locking: Caller holds @tty->termios_rwsem */ -static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) +static void n_tty_set_termios(struct tty_struct *tty, const struct ktermios *old) { struct n_tty_data *ldata = tty->disc_data; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 752dab3356d7..07394fdaf522 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -240,7 +240,7 @@ out: } static void pty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { /* See if packet mode change of state. */ if (tty->link && tty->link->ctrl.packet) { diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 65d6af755567..c7d34823f715 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -243,7 +243,7 @@ static void serial21285_shutdown(struct uart_port *port) static void serial21285_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, quot, h_lcr, b; diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 8efdc271eb75..fa8ccf204d86 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -755,7 +755,7 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv, static void brcmstb_set_termios(struct uart_port *up, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_8250_port *p8250 = up_to_u8250p(up); struct brcmuart_priv *priv = up->private_data; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 2e83e7367441..94fbf0add2ce 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -298,10 +298,9 @@ static void serial8250_backup_timeout(struct timer_list *t) jiffies + uart_poll_timeout(&up->port) + HZ / 5); } -static int univ8250_setup_irq(struct uart_8250_port *up) +static void univ8250_setup_timer(struct uart_8250_port *up) { struct uart_port *port = &up->port; - int retval = 0; /* * The above check will only give an accurate result the first time @@ -322,10 +321,16 @@ static int univ8250_setup_irq(struct uart_8250_port *up) */ if (!port->irq) mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - else - retval = serial_link_irq_chain(up); +} - return retval; +static int univ8250_setup_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + if (port->irq) + return serial_link_irq_chain(up); + + return 0; } static void univ8250_release_irq(struct uart_8250_port *up) @@ -381,6 +386,7 @@ static struct uart_ops univ8250_port_ops; static const struct uart_8250_ops univ8250_driver_ops = { .setup_irq = univ8250_setup_irq, .release_irq = univ8250_release_irq, + .setup_timer = univ8250_setup_timer, }; static struct uart_8250_port serial8250_ports[UART_NR]; diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index a8dba4a0a8fb..b85c82616e8c 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -26,9 +26,7 @@ static void __dma_tx_complete(void *param) dma->tx_running = 0; - xmit->tail += dma->tx_size; - xmit->tail &= UART_XMIT_SIZE - 1; - p->port.icount.tx += dma->tx_size; + uart_xmit_advance(&p->port, dma->tx_size); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&p->port); @@ -107,8 +105,7 @@ int serial8250_tx_dma(struct uart_8250_port *p) dma_async_issue_pending(dma->txchan); serial8250_clear_THRI(p); - if (dma->tx_err) - dma->tx_err = 0; + dma->tx_err = 0; return 0; err: diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a604b42e4458..7db51781289e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -350,7 +350,7 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) } static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long newrate = tty_termios_baud_rate(termios) * 16; struct dw8250_data *d = to_dw8250_data(p->private_data); diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index dbe4d44f60d4..75f32f054ebb 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -92,7 +92,8 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, serial8250_do_set_divisor(p, baud, quot, quot_frac); } -void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, + const struct ktermios *old) { p->status &= ~UPSTAT_AUTOCTS; if (termios->c_cflag & CRTSCTS) diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 055bfdc87985..f13e91f2cace 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -47,7 +47,7 @@ struct dw8250_data { unsigned int uart_16550_compatible:1; }; -void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old); +void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old); void dw8250_setup_port(struct uart_port *p); static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 65b6b3cbaff6..e2aa2a1a02dd 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -278,7 +278,7 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) static void fintek_8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct fintek_8250 *pdata = port->private_data; unsigned int baud = tty_termios_baud_rate(termios); diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 4ba43bef9933..44cc755b1a29 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -70,7 +70,7 @@ static inline struct lpss8250 *to_lpss8250(struct dw8250_port_data *data) } static void byt_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); struct lpss8250 *lpss = to_lpss8250(p->private_data); diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index 737c4c31e8a0..f46ca13ff4aa 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -7,7 +7,6 @@ #include #include #include -#include #define MEN_UART_ID_Z025 0x19 #define MEN_UART_ID_Z057 0x39 diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index a2a03acb04ad..2cc78a4bf7a1 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -206,9 +206,8 @@ static void dnv_exit(struct mid8250 *mid) /*****************************************************************************/ -static void mid8250_set_termios(struct uart_port *p, - struct ktermios *termios, - struct ktermios *old) +static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios, + const struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); struct mid8250 *mid = p->private_data; diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 54051ec7b499..fb1d5ec0940e 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -291,7 +291,7 @@ static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { static const unsigned short fraction_L_mapping[] = { 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index f7fbef83583c..41b8c6b27136 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -342,6 +342,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up) omap8250_update_mdr1(up, priv); up->port.ops->set_mctrl(&up->port, up->port.mctrl); + + if (up->port.rs485.flags & SER_RS485_ENABLED) + serial8250_em485_stop_tx(up); } /* @@ -350,7 +353,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) */ static void omap_8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = up->port.private_data; @@ -984,9 +987,7 @@ static void omap_8250_dma_tx_complete(void *param) dma->tx_running = 0; - xmit->tail += dma->tx_size; - xmit->tail &= UART_XMIT_SIZE - 1; - p->port.icount.tx += dma->tx_size; + uart_xmit_advance(&p->port, dma->tx_size); if (priv->delayed_restore) { priv->delayed_restore = 0; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 6f66dc2ebacc..8e9f247590bd 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1232,6 +1232,10 @@ static void pci_oxsemi_tornado_set_mctrl(struct uart_port *port, serial8250_do_set_mctrl(port, mctrl); } +/* + * We require EFR features for clock programming, so set UPF_FULL_PROBE + * for full probing regardless of CONFIG_SERIAL_8250_16550A_VARIANTS setting. + */ static int pci_oxsemi_tornado_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *up, int idx) @@ -1239,6 +1243,7 @@ static int pci_oxsemi_tornado_setup(struct serial_private *priv, struct pci_dev *dev = priv->dev; if (pci_oxsemi_tornado_p(dev)) { + up->port.flags |= UPF_FULL_PROBE; up->port.get_divisor = pci_oxsemi_tornado_get_divisor; up->port.set_divisor = pci_oxsemi_tornado_set_divisor; up->port.set_mctrl = pci_oxsemi_tornado_set_mctrl; @@ -1627,7 +1632,6 @@ static int pci_fintek_init(struct pci_dev *dev) resource_size_t bar_data[3]; u8 config_base; struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) || !(pci_resource_flags(dev, 4) & IORESOURCE_IO) || @@ -1674,13 +1678,7 @@ static int pci_fintek_init(struct pci_dev *dev) pci_write_config_byte(dev, config_base + 0x06, dev->irq); - if (priv) { - /* re-apply RS232/485 mode when - * pciserial_resume_ports() - */ - port = serial8250_get_port(priv->line[i]); - uart_rs485_config(&port->port); - } else { + if (!priv) { /* First init without port data * force init to RS232 Mode */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 39b35a61958c..fe8662cd9402 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -600,7 +600,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); static int serial8250_em485_init(struct uart_8250_port *p) { if (p->em485) - return 0; + goto deassert_rts; p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); if (!p->em485) @@ -616,7 +616,9 @@ static int serial8250_em485_init(struct uart_8250_port *p) p->em485->active_timer = NULL; p->em485->tx_stopped = true; - p->rs485_stop_tx(p); +deassert_rts: + if (p->em485->tx_stopped) + p->rs485_stop_tx(p); return 0; } @@ -752,6 +754,14 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial8250_rpm_put(p); } +static void serial8250_clear_IER(struct uart_8250_port *up) +{ + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); +} + #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. @@ -1021,7 +1031,8 @@ static void autoconfig_16550a(struct uart_8250_port *up) up->port.type = PORT_16550A; up->capabilities |= UART_CAP_FIFO; - if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS)) + if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS) && + !(up->port.flags & UPF_FULL_PROBE)) return; /* @@ -1133,7 +1144,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * internal UARTs. * We're going to explicitly set the UUE bit to 0 before * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. + * already a 1 and maybe locked there before we even start. */ iersave = serial_in(up, UART_IER); serial_out(up, UART_IER, iersave & ~UART_IER_UUE); @@ -1329,10 +1340,7 @@ static void autoconfig(struct uart_8250_port *up) serial8250_out_MCR(up, save_mcr); serial8250_clear_fifos(up); serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); + serial8250_clear_IER(up); out_unlock: spin_unlock_irqrestore(&port->lock, flags); @@ -2042,6 +2050,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { + if (port->rs485.flags & SER_RS485_ENABLED) + return; + if (port->set_mctrl) port->set_mctrl(port, mctrl); else @@ -2142,10 +2153,7 @@ static void serial8250_put_poll_char(struct uart_port *port, * First save the IER then disable the interrupts */ ier = serial_port_in(port, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); + serial8250_clear_IER(up); wait_for_xmitr(up, UART_LSR_BOTH_EMPTY); /* @@ -2294,6 +2302,10 @@ int serial8250_do_startup(struct uart_port *port) if (port->irq && (up->port.flags & UPF_SHARE_IRQ)) up->port.irqflags |= IRQF_SHARED; + retval = up->ops->setup_irq(up); + if (retval) + goto out; + if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) { unsigned char iir1; @@ -2336,9 +2348,7 @@ int serial8250_do_startup(struct uart_port *port) } } - retval = up->ops->setup_irq(up); - if (retval) - goto out; + up->ops->setup_timer(up); /* * Now, initialize the UART @@ -2651,7 +2661,7 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int tolerance = port->uartclk / 100; unsigned int min; @@ -2737,7 +2747,7 @@ EXPORT_SYMBOL_GPL(serial8250_update_uartclk); void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_8250_port *up = up_to_u8250p(port); unsigned char cval; @@ -2875,7 +2885,7 @@ EXPORT_SYMBOL(serial8250_do_set_termios); static void serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { if (port->set_termios) port->set_termios(port, termios, old); @@ -3187,9 +3197,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (flags & UART_CONFIG_TYPE) autoconfig(up); - if (port->rs485.flags & SER_RS485_ENABLED) - uart_rs485_config(port); - /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; @@ -3314,8 +3321,13 @@ static void serial8250_console_restore(struct uart_8250_port *up) unsigned int baud, quot, frac = 0; termios.c_cflag = port->cons->cflag; - if (port->state->port.tty && termios.c_cflag == 0) + termios.c_ispeed = port->cons->ispeed; + termios.c_ospeed = port->cons->ospeed; + if (port->state->port.tty && termios.c_cflag == 0) { termios.c_cflag = port->state->port.tty->termios.c_cflag; + termios.c_ispeed = port->state->port.tty->termios.c_ispeed; + termios.c_ospeed = port->state->port.tty->termios.c_ospeed; + } baud = serial8250_get_baud_rate(port, &termios, NULL); quot = serial8250_get_divisor(port, baud, &frac); @@ -3383,11 +3395,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * First save the IER then disable the interrupts */ ier = serial_port_in(port, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); + serial8250_clear_IER(up); /* check scratch reg to see if port powered off during system sleep */ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b68f5f518971..113aafb5d9c3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -127,6 +127,7 @@ config SERIAL_SB1250_DUART_CONSOLE config SERIAL_ATMEL bool "AT91 on-chip serial port support" + depends on COMMON_CLK depends on ARCH_AT91 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB @@ -426,7 +427,7 @@ config SERIAL_PXA config SERIAL_PXA_NON8250 bool - depends on !SERIAL_8250 + depends on !SERIAL_8250 || COMPILE_TEST config SERIAL_PXA_CONSOLE bool "Console on PXA serial port (DEPRECATED)" @@ -1324,7 +1325,7 @@ config SERIAL_FSL_LPUART config SERIAL_FSL_LPUART_CONSOLE bool "Console on Freescale lpuart serial port" - depends on SERIAL_FSL_LPUART=y + depends on SERIAL_FSL_LPUART select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index cb791c5149a3..c2d154d78e54 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -9,6 +9,7 @@ * (C) Copyright 2010, Tobias Klauser */ +#include #include #include #include @@ -48,7 +49,6 @@ #define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200 #define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400 #define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000 -#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16 /* * Local per-uart structure. @@ -59,10 +59,19 @@ struct altera_jtaguart { unsigned long imr; /* Local IMR mirror */ }; +static unsigned int altera_jtaguart_tx_space(struct uart_port *port, u32 *ctlp) +{ + u32 ctl = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG); + + if (ctlp) + *ctlp = ctl; + + return FIELD_GET(ALTERA_JTAGUART_CONTROL_WSPACE_MSK, ctl); +} + static unsigned int altera_jtaguart_tx_empty(struct uart_port *port) { - return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0; + return altera_jtaguart_tx_space(port, NULL) ? TIOCSER_TEMT : 0; } static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port) @@ -106,8 +115,8 @@ static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) } static void altera_jtaguart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { /* Just copy the old termios settings back */ if (old) @@ -150,9 +159,7 @@ static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) pending = uart_circ_chars_pending(xmit); if (pending > 0) { - count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> - ALTERA_JTAGUART_CONTROL_WSPACE_OFF; + count = altera_jtaguart_tx_space(port, NULL); if (count > pending) count = pending; if (count > 0) { @@ -298,17 +305,17 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c) { - unsigned long status; unsigned long flags; + u32 status; spin_lock_irqsave(&port->lock, flags); - while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { + while (!altera_jtaguart_tx_space(port, &status)) { + spin_unlock_irqrestore(&port->lock, flags); + if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) { - spin_unlock_irqrestore(&port->lock, flags); return; /* no connection activity */ } - spin_unlock_irqrestore(&port->lock, flags); + cpu_relax(); spin_lock_irqsave(&port->lock, flags); } @@ -321,8 +328,7 @@ static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c unsigned long flags; spin_lock_irqsave(&port->lock, flags); - while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { + while (!altera_jtaguart_tx_space(port, NULL)) { spin_unlock_irqrestore(&port->lock, flags); cpu_relax(); spin_lock_irqsave(&port->lock, flags); diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 8b749ed557c6..82f2790de28d 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -175,7 +175,7 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) static void altera_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, baudclk; @@ -199,9 +199,8 @@ static void altera_uart_set_termios(struct uart_port *port, */ } -static void altera_uart_rx_chars(struct altera_uart *pp) +static void altera_uart_rx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; unsigned char ch, flag; unsigned short status; @@ -246,9 +245,8 @@ static void altera_uart_rx_chars(struct altera_uart *pp) tty_flip_buffer_push(&port->state->port); } -static void altera_uart_tx_chars(struct altera_uart *pp) +static void altera_uart_tx_chars(struct uart_port *port) { - struct uart_port *port = &pp->port; struct circ_buf *xmit = &port->state->xmit; if (port->x_char) { @@ -272,10 +270,8 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (xmit->head == xmit->tail) { - pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_update_ctrl_reg(pp); - } + if (uart_circ_empty(xmit)) + altera_uart_stop_tx(port); } static irqreturn_t altera_uart_interrupt(int irq, void *data) @@ -288,9 +284,9 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) spin_lock(&port->lock); if (isr & ALTERA_UART_STATUS_RRDY_MSK) - altera_uart_rx_chars(pp); + altera_uart_rx_chars(port); if (isr & ALTERA_UART_STATUS_TRDY_MSK) - altera_uart_tx_chars(pp); + altera_uart_tx_chars(port); spin_unlock(&port->lock); return IRQ_RETVAL(isr); diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index fae0b581ff42..af27fb8ec145 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -370,7 +370,7 @@ static void pl010_shutdown(struct uart_port *port) static void pl010_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int lcr_h, old_cr; unsigned long flags; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 15f0e4d88c5a..5cdced39eafd 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2030,7 +2030,7 @@ pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios) static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -2162,7 +2162,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, static void sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); @@ -2777,6 +2777,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) struct uart_amba_port *uap; struct vendor_data *vendor = id->data; int portnr, ret; + u32 val; portnr = pl011_find_free_port(); if (portnr < 0) @@ -2801,6 +2802,21 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.rs485_supported = pl011_rs485_supported; snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + if (device_property_read_u32(&dev->dev, "reg-io-width", &val) == 0) { + switch (val) { + case 1: + uap->port.iotype = UPIO_MEM; + break; + case 4: + uap->port.iotype = UPIO_MEM32; + break; + default: + dev_warn(&dev->dev, "unsupported reg-io-width (%d)\n", + val); + return -EINVAL; + } + } + ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); if (ret) return ret; diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 9ef82d870ff2..450f4edfda0f 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -228,7 +228,7 @@ static void apbuart_shutdown(struct uart_port *port) } static void apbuart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, const struct ktermios *old) { unsigned int cr; unsigned long flags; diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 32caeac12985..925484a42c82 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -283,7 +283,7 @@ static void ar933x_uart_get_scale_step(unsigned int clk, static void ar933x_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct ar933x_uart_port *up = container_of(port, struct ar933x_uart_port, port); @@ -583,6 +583,13 @@ static const struct uart_ops ar933x_uart_ops = { static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + + if (port->rs485.flags & SER_RS485_ENABLED) + gpiod_set_value(up->rts_gpiod, + !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND)); + return 0; } diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 2a09e92ef9ed..2a65ea2660e1 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -351,7 +351,7 @@ static void arc_serial_shutdown(struct uart_port *port) static void arc_serial_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct arc_uart_port *uart = to_arc_port(port); unsigned int baud, uartl, uarth, hw_val; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 7450d3853031..bd07f79a2df9 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ struct atmel_uart_char { struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ + struct clk *gclk; /* uart generic clock */ int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ u32 backup_imr; /* IMR saved during suspend */ int break_active; /* break being received */ @@ -150,6 +152,7 @@ struct atmel_uart_port { u32 rts_low; bool ms_irq_enabled; u32 rtor; /* address of receiver timeout register if it exists */ + bool is_usart; bool has_frac_baudrate; bool has_hw_timer; struct timer_list uart_timer; @@ -228,6 +231,11 @@ static inline int atmel_uart_is_half_duplex(struct uart_port *port) (port->iso7816.flags & SER_ISO7816_ENABLED); } +static inline int atmel_error_rate(int desired_value, int actual_value) +{ + return 100 - (desired_value * 100) / actual_value; +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -1825,6 +1833,7 @@ static void atmel_get_ip_name(struct uart_port *port) */ atmel_port->has_frac_baudrate = false; atmel_port->has_hw_timer = false; + atmel_port->is_usart = false; if (name == new_uart) { dev_dbg(port->dev, "Uart with hw timer"); @@ -1834,6 +1843,7 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "Usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { @@ -1863,6 +1873,7 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "This version is usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; break; case 0x203: @@ -2113,6 +2124,8 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * This is called on uart_close() or a suspend event. */ clk_disable_unprepare(atmel_port->clk); + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); break; default: dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); @@ -2122,19 +2135,25 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void atmel_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; + unsigned int old_mode, mode, imr, quot, div, cd, fp = 0; + unsigned int baud, actual_baud, gclk_rate; + int ret; /* save the current mode register */ mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ - mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | - ATMEL_US_PAR | ATMEL_US_USMODE); + if (atmel_port->is_usart) + mode &= ~(ATMEL_US_NBSTOP | ATMEL_US_PAR | ATMEL_US_CHRL | + ATMEL_US_USCLKS | ATMEL_US_USMODE); + else + mode &= ~(ATMEL_UA_BRSRCCK | ATMEL_US_PAR | ATMEL_UA_FILTER); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); @@ -2282,10 +2301,60 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, cd = uart_get_divisor(port, baud); } - if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + /* + * If the current value of the Clock Divisor surpasses the 16 bit + * ATMEL_US_CD mask and the IP is USART, switch to the Peripheral + * Clock implicitly divided by 8. + * If the IP is UART however, keep the highest possible value for + * the CD and avoid needless division of CD, since UART IP's do not + * support implicit division of the Peripheral Clock. + */ + if (atmel_port->is_usart && cd > ATMEL_US_CD) { cd /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; + } else { + cd = min_t(unsigned int, cd, ATMEL_US_CD); } + + /* + * If there is no Fractional Part, there is a high chance that + * we may be able to generate a baudrate closer to the desired one + * if we use the GCLK as the clock source driving the baudrate + * generator. + */ + if (!atmel_port->has_frac_baudrate) { + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); + gclk_rate = clk_round_rate(atmel_port->gclk, 16 * baud); + actual_baud = clk_get_rate(atmel_port->clk) / (16 * cd); + if (gclk_rate && abs(atmel_error_rate(baud, actual_baud)) > + abs(atmel_error_rate(baud, gclk_rate / 16))) { + clk_set_rate(atmel_port->gclk, 16 * baud); + ret = clk_prepare_enable(atmel_port->gclk); + if (ret) + goto gclk_fail; + + if (atmel_port->is_usart) { + mode &= ~ATMEL_US_USCLKS; + mode |= ATMEL_US_USCLKS_GCLK; + } else { + mode |= ATMEL_UA_BRSRCCK; + } + + /* + * Set the Clock Divisor for GCLK to 1. + * Since we were able to generate the smallest + * multiple of the desired baudrate times 16, + * then we surely can generate a bigger multiple + * with the exact error rate for an equally increased + * CD. Thus no need to take into account + * a higher value for CD. + */ + cd = 1; + } + } + +gclk_fail: quot = cd | fp << ATMEL_US_FP_OFFSET; if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) @@ -2881,6 +2950,12 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret) goto err; + atmel_port->gclk = devm_clk_get_optional(&pdev->dev, "gclk"); + if (IS_ERR(atmel_port->gclk)) { + ret = PTR_ERR(atmel_port->gclk); + goto err_clk_disable_unprepare; + } + ret = atmel_init_port(atmel_port, pdev); if (ret) goto err_clk_disable_unprepare; diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h index 0d8a0f9cc5c3..87f8f7996307 100644 --- a/drivers/tty/serial/atmel_serial.h +++ b/drivers/tty/serial/atmel_serial.h @@ -9,6 +9,8 @@ * Based on AT91RM9200 datasheet revision E. */ +#include + #ifndef ATMEL_SERIAL_H #define ATMEL_SERIAL_H @@ -39,39 +41,42 @@ #define ATMEL_US_MR 0x04 /* Mode Register */ #define ATMEL_US_USMODE GENMASK(3, 0) /* Mode of the USART */ -#define ATMEL_US_USMODE_NORMAL 0 -#define ATMEL_US_USMODE_RS485 1 -#define ATMEL_US_USMODE_HWHS 2 -#define ATMEL_US_USMODE_MODEM 3 -#define ATMEL_US_USMODE_ISO7816_T0 4 -#define ATMEL_US_USMODE_ISO7816_T1 6 -#define ATMEL_US_USMODE_IRDA 8 +#define ATMEL_US_USMODE_NORMAL FIELD_PREP(ATMEL_US_USMODE, 0) +#define ATMEL_US_USMODE_RS485 FIELD_PREP(ATMEL_US_USMODE, 1) +#define ATMEL_US_USMODE_HWHS FIELD_PREP(ATMEL_US_USMODE, 2) +#define ATMEL_US_USMODE_MODEM FIELD_PREP(ATMEL_US_USMODE, 3) +#define ATMEL_US_USMODE_ISO7816_T0 FIELD_PREP(ATMEL_US_USMODE, 4) +#define ATMEL_US_USMODE_ISO7816_T1 FIELD_PREP(ATMEL_US_USMODE, 6) +#define ATMEL_US_USMODE_IRDA FIELD_PREP(ATMEL_US_USMODE, 8) #define ATMEL_US_USCLKS GENMASK(5, 4) /* Clock Selection */ -#define ATMEL_US_USCLKS_MCK (0 << 4) -#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) -#define ATMEL_US_USCLKS_SCK (3 << 4) +#define ATMEL_US_USCLKS_MCK FIELD_PREP(ATMEL_US_USCLKS, 0) +#define ATMEL_US_USCLKS_MCK_DIV8 FIELD_PREP(ATMEL_US_USCLKS, 1) +#define ATMEL_US_USCLKS_GCLK FIELD_PREP(ATMEL_US_USCLKS, 2) +#define ATMEL_US_USCLKS_SCK FIELD_PREP(ATMEL_US_USCLKS, 3) +#define ATMEL_UA_FILTER BIT(4) #define ATMEL_US_CHRL GENMASK(7, 6) /* Character Length */ -#define ATMEL_US_CHRL_5 (0 << 6) -#define ATMEL_US_CHRL_6 (1 << 6) -#define ATMEL_US_CHRL_7 (2 << 6) -#define ATMEL_US_CHRL_8 (3 << 6) +#define ATMEL_US_CHRL_5 FIELD_PREP(ATMEL_US_CHRL, 0) +#define ATMEL_US_CHRL_6 FIELD_PREP(ATMEL_US_CHRL, 1) +#define ATMEL_US_CHRL_7 FIELD_PREP(ATMEL_US_CHRL, 2) +#define ATMEL_US_CHRL_8 FIELD_PREP(ATMEL_US_CHRL, 3) #define ATMEL_US_SYNC BIT(8) /* Synchronous Mode Select */ #define ATMEL_US_PAR GENMASK(11, 9) /* Parity Type */ -#define ATMEL_US_PAR_EVEN (0 << 9) -#define ATMEL_US_PAR_ODD (1 << 9) -#define ATMEL_US_PAR_SPACE (2 << 9) -#define ATMEL_US_PAR_MARK (3 << 9) -#define ATMEL_US_PAR_NONE (4 << 9) -#define ATMEL_US_PAR_MULTI_DROP (6 << 9) +#define ATMEL_US_PAR_EVEN FIELD_PREP(ATMEL_US_PAR, 0) +#define ATMEL_US_PAR_ODD FIELD_PREP(ATMEL_US_PAR, 1) +#define ATMEL_US_PAR_SPACE FIELD_PREP(ATMEL_US_PAR, 2) +#define ATMEL_US_PAR_MARK FIELD_PREP(ATMEL_US_PAR, 3) +#define ATMEL_US_PAR_NONE FIELD_PREP(ATMEL_US_PAR, 4) +#define ATMEL_US_PAR_MULTI_DROP FIELD_PREP(ATMEL_US_PAR, 6) #define ATMEL_US_NBSTOP GENMASK(13, 12) /* Number of Stop Bits */ -#define ATMEL_US_NBSTOP_1 (0 << 12) -#define ATMEL_US_NBSTOP_1_5 (1 << 12) -#define ATMEL_US_NBSTOP_2 (2 << 12) +#define ATMEL_US_NBSTOP_1 FIELD_PREP(ATMEL_US_NBSTOP, 0) +#define ATMEL_US_NBSTOP_1_5 FIELD_PREP(ATMEL_US_NBSTOP, 1) +#define ATMEL_US_NBSTOP_2 FIELD_PREP(ATMEL_US_NBSTOP, 2) +#define ATMEL_UA_BRSRCCK BIT(12) /* Clock Selection for UART */ #define ATMEL_US_CHMODE GENMASK(15, 14) /* Channel Mode */ -#define ATMEL_US_CHMODE_NORMAL (0 << 14) -#define ATMEL_US_CHMODE_ECHO (1 << 14) -#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) -#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) +#define ATMEL_US_CHMODE_NORMAL FIELD_PREP(ATMEL_US_CHMODE, 0) +#define ATMEL_US_CHMODE_ECHO FIELD_PREP(ATMEL_US_CHMODE, 1) +#define ATMEL_US_CHMODE_LOC_LOOP FIELD_PREP(ATMEL_US_CHMODE, 2) +#define ATMEL_US_CHMODE_REM_LOOP FIELD_PREP(ATMEL_US_CHMODE, 3) #define ATMEL_US_MSBF BIT(16) /* Bit Order */ #define ATMEL_US_MODE9 BIT(17) /* 9-bit Character Length */ #define ATMEL_US_CLKO BIT(18) /* Clock Output Select */ @@ -79,7 +84,7 @@ #define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */ #define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */ #define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */ -#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK) +#define ATMEL_US_MAX_ITER(n) FIELD_PREP(ATMEL_US_MAX_ITER_MASK, (n)) #define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */ #define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ @@ -131,19 +136,19 @@ #define ATMEL_US_CMPR 0x90 /* Comparaison Register */ #define ATMEL_US_FMR 0xa0 /* FIFO Mode Register */ -#define ATMEL_US_TXRDYM(data) (((data) & 0x3) << 0) /* TX Ready Mode */ -#define ATMEL_US_RXRDYM(data) (((data) & 0x3) << 4) /* RX Ready Mode */ +#define ATMEL_US_TXRDYM(data) FIELD_PREP(GENMASK(1, 0), (data)) /* TX Ready Mode */ +#define ATMEL_US_RXRDYM(data) FIELD_PREP(GENMASK(5, 4), (data)) /* RX Ready Mode */ #define ATMEL_US_ONE_DATA 0x0 #define ATMEL_US_TWO_DATA 0x1 #define ATMEL_US_FOUR_DATA 0x2 #define ATMEL_US_FRTSC BIT(7) /* FIFO RTS pin Control */ -#define ATMEL_US_TXFTHRES(thr) (((thr) & 0x3f) << 8) /* TX FIFO Threshold */ -#define ATMEL_US_RXFTHRES(thr) (((thr) & 0x3f) << 16) /* RX FIFO Threshold */ -#define ATMEL_US_RXFTHRES2(thr) (((thr) & 0x3f) << 24) /* RX FIFO Threshold2 */ +#define ATMEL_US_TXFTHRES(thr) FIELD_PREP(GENMASK(13, 8), (thr)) /* TX FIFO Threshold */ +#define ATMEL_US_RXFTHRES(thr) FIELD_PREP(GENMASK(21, 16), (thr)) /* RX FIFO Threshold */ +#define ATMEL_US_RXFTHRES2(thr) FIELD_PREP(GENMASK(29, 24), (thr)) /* RX FIFO Threshold2 */ #define ATMEL_US_FLR 0xa4 /* FIFO Level Register */ -#define ATMEL_US_TXFL(reg) (((reg) >> 0) & 0x3f) /* TX FIFO Level */ -#define ATMEL_US_RXFL(reg) (((reg) >> 16) & 0x3f) /* RX FIFO Level */ +#define ATMEL_US_TXFL(reg) FIELD_GET(GENMASK(5, 0), (reg)) /* TX FIFO Level */ +#define ATMEL_US_RXFL(reg) FIELD_GET(GENMASK(21, 16), (reg)) /* RX FIFO Level */ #define ATMEL_US_FIER 0xa8 /* FIFO Interrupt Enable Register */ #define ATMEL_US_FIDR 0xac /* FIFO Interrupt Disable Register */ diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 53b43174aa40..5d9737c2d1f2 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -492,9 +492,8 @@ static void bcm_uart_shutdown(struct uart_port *port) /* * serial core request to change current uart setting */ -static void bcm_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) +static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { unsigned int ctl, baud, quot, ier; unsigned long flags; diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index b9b66ad31a08..404b43a5ae33 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -251,7 +251,7 @@ static void uart_clps711x_shutdown(struct uart_port *port) static void uart_clps711x_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { u32 ubrlcr; unsigned int baud, quot; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index 8c582779cf22..0577618e78c0 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -87,7 +87,6 @@ struct uart_cpm_port { struct gpio_desc *gpios[NUM_GPIOS]; }; -extern int cpm_uart_nr; extern struct uart_cpm_port cpm_uart_ports[UART_NR]; /* these are located in their respective files */ diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index db07d6a5d764..b4369ed45ae2 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -484,12 +484,11 @@ static void cpm_uart_shutdown(struct uart_port *port) static void cpm_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { int baud; unsigned long flags; u16 cval, scval, prev_mode; - int bits, sbits; struct uart_cpm_port *pinfo = container_of(port, struct uart_cpm_port, port); smc_t __iomem *smcp = pinfo->smcp; @@ -515,28 +514,17 @@ static void cpm_uart_set_termios(struct uart_port *port, if (maxidl > 0x10) maxidl = 0x10; - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ cval = 0; scval = 0; - /* byte size */ - bits = tty_get_char_size(termios->c_cflag); - sbits = bits - 5; - if (termios->c_cflag & CSTOPB) { cval |= SMCMR_SL; /* Two stops */ scval |= SCU_PSMR_SL; - bits++; } if (termios->c_cflag & PARENB) { cval |= SMCMR_PEN; scval |= SCU_PSMR_PEN; - bits++; if (!(termios->c_cflag & PARODD)) { cval |= SMCMR_PM_EVEN; scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); @@ -580,12 +568,9 @@ static void cpm_uart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; if (IS_SMC(pinfo)) { + unsigned int bits = tty_get_frame_size(termios->c_cflag); + /* * MRBLR can be changed while an SMC/SCC is operating only * if it is done in a single bus cycle with one 16-bit move @@ -604,13 +589,17 @@ static void cpm_uart_set_termios(struct uart_port *port, */ prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN); /* Output in *one* operation, so we don't interrupt RX/TX if they - * were already enabled. */ - out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | - SMCMR_SM_UART | prev_mode); + * were already enabled. + * Character length programmed into the register is frame bits minus 1. + */ + out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits - 1) | cval | + SMCMR_SM_UART | prev_mode); } else { + unsigned int bits = tty_get_char_size(termios->c_cflag); + out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); out_be16(&pinfo->sccup->scc_maxidl, maxidl); - out_be16(&sccp->scc_psmr, (sbits << 12) | scval); + out_be16(&sccp->scc_psmr, (UART_LCR_WLEN(bits) << 12) | scval); } if (pinfo->clk) @@ -1214,12 +1203,6 @@ static int cpm_uart_init_port(struct device_node *np, pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; spin_lock_init(&pinfo->port.lock); - pinfo->port.irq = irq_of_parse_and_map(np, 0); - if (pinfo->port.irq == NO_IRQ) { - ret = -EINVAL; - goto out_pram; - } - for (i = 0; i < NUM_GPIOS; i++) { struct gpio_desc *gpiod; @@ -1229,7 +1212,7 @@ static int cpm_uart_init_port(struct device_node *np, if (IS_ERR(gpiod)) { ret = PTR_ERR(gpiod); - goto out_irq; + goto out_pram; } if (gpiod) { @@ -1255,8 +1238,6 @@ static int cpm_uart_init_port(struct device_node *np, return cpm_uart_request_port(&pinfo->port); -out_irq: - irq_dispose_mapping(pinfo->port.irq); out_pram: cpm_uart_unmap_pram(pinfo, pram); out_mem: @@ -1436,11 +1417,17 @@ static int cpm_uart_probe(struct platform_device *ofdev) /* initialize the device pointer for the port */ pinfo->port.dev = &ofdev->dev; - ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); - if (ret) - return ret; + pinfo->port.irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + if (!pinfo->port.irq) + return -EINVAL; - return uart_add_one_port(&cpm_reg, &pinfo->port); + ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); + if (!ret) + return uart_add_one_port(&cpm_reg, &pinfo->port); + + irq_dispose_mapping(pinfo->port.irq); + + return ret; } static int cpm_uart_remove(struct platform_device *ofdev) diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index af951e6a2ef4..0c0a62346f23 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -287,7 +287,7 @@ static void digicolor_uart_shutdown(struct uart_port *port) static void digicolor_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, divisor; u8 config = 0; diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 2e21acf39720..829b452daee9 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -559,7 +559,7 @@ static void dz_reset(struct dz_port *dport) } static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct dz_port *dport = to_dport(uport); unsigned long flags; @@ -592,9 +592,12 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600); bflag = dz_encode_baud_rate(baud); - if (bflag < 0) { /* Try to keep unchanged. */ - baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600); - bflag = dz_encode_baud_rate(baud); + if (bflag < 0) { + if (old_termios) { + /* Keep unchanged. */ + baud = tty_termios_baud_rate(old_termios); + bflag = dz_encode_baud_rate(baud); + } if (bflag < 0) { /* Resort to 9600. */ baud = 9600; bflag = DZ_B9600; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 88d08ba1ca83..a5f380584cda 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -67,7 +67,7 @@ static void __init earlycon_init(struct earlycon_device *device, if (*s) earlycon->index = simple_strtoul(s, NULL, 10); len = s - name; - strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); + strscpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name))); earlycon->data = &early_console_dev; } @@ -123,7 +123,7 @@ static int __init parse_options(struct earlycon_device *device, char *options) device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " ") + 1, (size_t)(sizeof(device->options))); - strlcpy(device->options, options, length); + strscpy(device->options, options, length); } return 0; @@ -304,7 +304,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match, if (options) { early_console_dev.baud = simple_strtoul(options, NULL, 0); - strlcpy(early_console_dev.options, options, + strscpy(early_console_dev.options, options, sizeof(early_console_dev.options)); } earlycon_init(&early_console_dev, match->name); diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 98bb0c315e13..84e8153e5420 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -401,7 +401,7 @@ static void linflex_shutdown(struct uart_port *port) static void linflex_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned long cr, old_cr, cr1; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index fbc4b071b330..67fa113f77d4 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1284,17 +1284,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) struct dma_slave_config dma_rx_sconfig = {}; struct circ_buf *ring = &sport->rx_ring; int ret, nent; - int bits, baud; struct tty_port *port = &sport->port.state->port; struct tty_struct *tty = port->tty; struct ktermios *termios = &tty->termios; struct dma_chan *chan = sport->dma_rx_chan; - - baud = tty_get_baud_rate(tty); - - bits = (termios->c_cflag & CSIZE) == CS7 ? 9 : 10; - if (termios->c_cflag & PARENB) - bits++; + unsigned int bits = tty_get_frame_size(termios->c_cflag); + unsigned int baud = tty_get_baud_rate(tty); /* * Calculate length of one DMA buffer size to keep latency below @@ -1776,6 +1771,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) if (sport->lpuart_dma_rx_use) { del_timer_sync(&sport->lpuart_timer); lpuart_dma_rx_free(&sport->port); + sport->lpuart_dma_rx_use = false; } if (sport->lpuart_dma_tx_use) { @@ -1784,6 +1780,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) sport->dma_tx_in_progress = false; dmaengine_terminate_all(sport->dma_tx_chan); } + sport->lpuart_dma_tx_use = false; } if (sport->dma_tx_chan) @@ -1833,7 +1830,7 @@ static void lpuart32_shutdown(struct uart_port *port) static void lpuart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; @@ -2073,7 +2070,7 @@ static void lpuart32_serial_setbrg(struct lpuart_port *sport, static void lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; @@ -2729,15 +2726,13 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_reset; - ret = uart_add_one_port(&lpuart_reg, &sport->port); - if (ret) - goto failed_attach_port; - ret = uart_get_rs485_mode(&sport->port); if (ret) goto failed_get_rs485; - uart_rs485_config(&sport->port); + ret = uart_add_one_port(&lpuart_reg, &sport->port); + if (ret) + goto failed_attach_port; ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, DRIVER_NAME, sport); @@ -2747,9 +2742,9 @@ static int lpuart_probe(struct platform_device *pdev) return 0; failed_irq_request: -failed_get_rs485: uart_remove_one_port(&lpuart_reg, &sport->port); failed_attach_port: +failed_get_rs485: failed_reset: lpuart_disable_clks(sport); return ret; @@ -2800,7 +2795,7 @@ static int __maybe_unused lpuart_suspend(struct device *dev) * EDMA driver during suspend will forcefully release any * non-idle DMA channels. If port wakeup is enabled or if port * is console port or 'no_console_suspend' is set the Rx DMA - * cannot resume as as expected, hence gracefully release the + * cannot resume as expected, hence gracefully release the * Rx DMA path before suspend and start Rx DMA path on resume. */ if (irq_wake) { diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 45df29947fe8..819f957b6b84 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1351,9 +1351,8 @@ static void icom_close(struct uart_port *port) kref_put(&icom_port->adapter->kref, icom_kref_release); } -static void icom_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) +static void icom_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old_termios) { struct icom_port *icom_port = to_icom_port(port); int baud; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 522445a8f666..05b432dc7a85 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -380,8 +380,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); - sport->port.mctrl |= TIOCM_RTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl); + mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); } /* called with port.lock taken and irqs caller dependent */ @@ -390,8 +389,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; - sport->port.mctrl &= ~TIOCM_RTS; - mctrl_gpio_set(sport->gpios, sport->port.mctrl); + mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); } static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) @@ -1620,7 +1618,7 @@ static void imx_uart_flush_buffer(struct uart_port *port) static void imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; @@ -2347,8 +2345,6 @@ static int imx_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "low-active RTS not possible when receiver is off, enabling receiver\n"); - uart_rs485_config(&sport->port); - /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 655e64b26852..dd0a8915ce4f 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -873,7 +873,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_ip22zilog_port *up = container_of(port, struct uart_ip22zilog_port, port); diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 0ea799bf8dbb..417a5b6bffc3 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -211,7 +211,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; default: - return -ENXIO; + rc = -ENXIO; + goto out_kfree_brd; } rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd); diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index cb58bdec2f43..222afc270c88 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -300,8 +300,8 @@ static void jsm_tty_close(struct uart_port *port) } static void jsm_tty_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) + struct ktermios *termios, + const struct ktermios *old_termios) { unsigned long lock_flags; struct jsm_channel *channel = diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index a3120c3347dd..c892f3c7d1ab 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -8,6 +8,7 @@ * Copyright (C) 2010 Thomas Langer, */ +#include #include #include #include @@ -93,7 +94,6 @@ #define ASCFSTAT_RXFFLMASK 0x003F #define ASCFSTAT_TXFFLMASK 0x3F00 #define ASCFSTAT_TXFREEMASK 0x3F000000 -#define ASCFSTAT_TXFREEOFF 24 static void lqasc_tx_chars(struct uart_port *port); static struct ltq_uart_port *lqasc_port[MAXPORTS]; @@ -139,6 +139,13 @@ lqasc_stop_tx(struct uart_port *port) return; } +static bool lqasc_tx_ready(struct uart_port *port) +{ + u32 fstat = __raw_readl(port->membase + LTQ_ASC_FSTAT); + + return FIELD_GET(ASCFSTAT_TXFREEMASK, fstat); +} + static void lqasc_start_tx(struct uart_port *port) { @@ -228,8 +235,7 @@ lqasc_tx_chars(struct uart_port *port) return; } - while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) & - ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { + while (lqasc_tx_ready(port)) { if (port->x_char) { writeb(port->x_char, port->membase + LTQ_ASC_TBUF); port->icount.tx++; @@ -405,8 +411,8 @@ lqasc_shutdown(struct uart_port *port) } static void -lqasc_set_termios(struct uart_port *port, - struct ktermios *new, struct ktermios *old) +lqasc_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { unsigned int cflag; unsigned int iflag; @@ -600,15 +606,12 @@ static const struct uart_ops lqasc_pops = { static void lqasc_console_putchar(struct uart_port *port, unsigned char ch) { - int fifofree; - if (!port->membase) return; - do { - fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT) - & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; - } while (fifofree == 0); + while (!lqasc_tx_ready(port)) + ; + writeb(ch, port->membase + LTQ_ASC_TBUF); } diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 328b50521f14..4c0604325ee9 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -178,7 +178,7 @@ static void liteuart_shutdown(struct uart_port *port) } static void liteuart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned long flags; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 93140cac1ca1..ed47f4768338 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -278,6 +278,13 @@ static void __serial_lpc32xx_rx(struct uart_port *port) static void serial_lpc32xx_stop_tx(struct uart_port *port); +static bool serial_lpc32xx_tx_ready(struct uart_port *port) +{ + u32 level = readl(LPC32XX_HSUART_LEVEL(port->membase)); + + return LPC32XX_HSU_TX_LEV(level) < 64; +} + static void __serial_lpc32xx_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; @@ -293,8 +300,7 @@ static void __serial_lpc32xx_tx(struct uart_port *port) goto exit_tx; /* Transfer data */ - while (LPC32XX_HSU_TX_LEV(readl( - LPC32XX_HSUART_LEVEL(port->membase))) < 64) { + while (serial_lpc32xx_tx_ready(port)) { writel((u32) xmit->buf[xmit->tail], LPC32XX_HSUART_FIFO(port->membase)); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -493,7 +499,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port) /* port->lock is not held. */ static void serial_lpc32xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, quot; diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 0b5f21fbb53d..c69602f356fd 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -418,7 +418,7 @@ static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) static void max3100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct max3100_port *s = container_of(port, struct max3100_port, diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 7cf81f692ac4..fbf6e2b3161c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -906,7 +906,7 @@ static void max310x_break_ctl(struct uart_port *port, int break_state) static void max310x_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int lcr = 0, flow = 0; int baud; diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index f4aaaadd0742..b1cd9a76dd93 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -192,7 +192,7 @@ static void mcf_shutdown(struct uart_port *port) /****************************************************************************/ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, baudclk; diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 12117b596e73..3690f5cf0f43 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -646,8 +646,8 @@ static void men_z135_shutdown(struct uart_port *port) } static void men_z135_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct men_z135_port *uart = to_men_z135(port); unsigned int baud; diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 6c8db19fd572..056243c12836 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -335,7 +335,7 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud) static void meson_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int cflags, iflags, baud; unsigned long flags; @@ -667,29 +667,6 @@ static struct uart_driver meson_uart_driver = { .cons = MESON_SERIAL_CONSOLE, }; -static inline struct clk *meson_uart_probe_clock(struct device *dev, - const char *id) -{ - struct clk *clk = NULL; - int ret; - - clk = devm_clk_get(dev, id); - if (IS_ERR(clk)) - return clk; - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(dev, "couldn't enable clk\n"); - return ERR_PTR(ret); - } - - devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - clk); - - return clk; -} - static int meson_uart_probe_clocks(struct platform_device *pdev, struct uart_port *port) { @@ -697,15 +674,15 @@ static int meson_uart_probe_clocks(struct platform_device *pdev, struct clk *clk_pclk = NULL; struct clk *clk_baud = NULL; - clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk"); + clk_pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); if (IS_ERR(clk_pclk)) return PTR_ERR(clk_pclk); - clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal"); + clk_xtal = devm_clk_get_enabled(&pdev->dev, "xtal"); if (IS_ERR(clk_xtal)) return PTR_ERR(clk_xtal); - clk_baud = meson_uart_probe_clock(&pdev->dev, "baud"); + clk_baud = devm_clk_get_enabled(&pdev->dev, "baud"); if (IS_ERR(clk_baud)) return PTR_ERR(clk_baud); diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index 347088bb380e..c15e0d84dc7e 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -298,7 +298,8 @@ static void mlb_usio_shutdown(struct uart_port *port) } static void mlb_usio_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { unsigned int escr, smr = MLB_USIO_SMR_SOE; unsigned long flags, baud, quot; diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 3f1986c89694..73362d4bc45d 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -101,7 +101,7 @@ struct psc_ops { void (*cw_restore_ints)(struct uart_port *port); unsigned int (*set_baudrate)(struct uart_port *port, struct ktermios *new, - struct ktermios *old); + const struct ktermios *old); int (*clock_alloc)(struct uart_port *port); void (*clock_relse)(struct uart_port *port); int (*clock)(struct uart_port *port, int enable); @@ -287,7 +287,7 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -305,7 +305,7 @@ static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -533,7 +533,7 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port) static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -880,7 +880,7 @@ static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc, static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud; unsigned int divisor; @@ -1167,7 +1167,7 @@ mpc52xx_uart_shutdown(struct uart_port *port) static void mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned char mr1, mr2; @@ -1364,7 +1364,7 @@ static const struct uart_ops mpc52xx_uart_ops = { /* Interrupt handling */ /* ======================================================================== */ -static inline unsigned int +static inline bool mpc52xx_uart_int_rx_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; @@ -1425,7 +1425,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) return psc_ops->raw_rx_rdy(port); } -static inline int +static inline bool mpc52xx_uart_int_tx_chars(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; @@ -1435,13 +1435,13 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) psc_ops->write_char(port, port->x_char); port->icount.tx++; port->x_char = 0; - return 1; + return true; } /* Nothing to do ? */ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { mpc52xx_uart_stop_tx(port); - return 0; + return false; } /* Send chars */ @@ -1460,23 +1460,23 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) /* Maybe we're done after all */ if (uart_circ_empty(xmit)) { mpc52xx_uart_stop_tx(port); - return 0; + return false; } - return 1; + return true; } static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port) { unsigned long pass = ISR_PASS_LIMIT; - unsigned int keepgoing; + bool keepgoing; u8 status; /* While we have stuff to do, we continue */ do { /* If we don't find anything to do, we stop */ - keepgoing = 0; + keepgoing = false; psc_ops->rx_clr_irq(port); if (psc_ops->rx_rdy(port)) @@ -1495,7 +1495,7 @@ mpc5xxx_uart_process_int(struct uart_port *port) /* Limit number of iteration */ if (!(--pass)) - keepgoing = 0; + keepgoing = false; } while (keepgoing); diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index 5e9429dcc51f..2e3e6cf16817 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -358,7 +358,7 @@ static void mps2_uart_shutdown(struct uart_port *port) static void mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, bauddiv; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 3159889ddae1..7dd19a281579 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1263,7 +1263,7 @@ static void msm_shutdown(struct uart_port *port) } static void msm_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct msm_port *msm_port = to_msm_port(port); struct msm_dma *dma = &msm_port->rx_dma; diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 0ba0f4d9459d..ed0e763f622a 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -289,7 +289,7 @@ static void mux_shutdown(struct uart_port *port) */ static void mux_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { } diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 65eaecd10b7c..ba16e1da6bd3 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -564,7 +564,7 @@ static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned in static void mvebu_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned long flags; unsigned int baud, min_baud, max_baud; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 1944daf8593a..d21a4f3ef2fe 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -959,7 +959,7 @@ err_out: #define CTS_AT_AUART() !mctrl_gpio_to_gpiod(s->gpios, UART_GPIO_CTS) static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct mxs_auart_port *s = to_auart_port(u); u32 ctrl, ctrl2, div; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0aa666e247d5..7d0d2718ef59 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -300,8 +300,7 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_OMAP_SCR, up->scr); res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; - if (up->rts_gpiod && - gpiod_get_value(up->rts_gpiod) != res) { + if (gpiod_get_value(up->rts_gpiod) != res) { if (port->rs485.delay_rts_after_send > 0) mdelay( port->rs485.delay_rts_after_send); @@ -337,19 +336,24 @@ static void serial_omap_stop_rx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } +static void serial_omap_put_char(struct uart_omap_port *up, unsigned char ch) +{ + serial_out(up, UART_TX, ch); + + if ((up->port.rs485.flags & SER_RS485_ENABLED) && + !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) + up->rs485_tx_filter_count++; +} + static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) { struct circ_buf *xmit = &up->port.state->xmit; int count; if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); + serial_omap_put_char(up, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; - if ((up->port.rs485.flags & SER_RS485_ENABLED) && - !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) - up->rs485_tx_filter_count++; - return; } if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { @@ -358,12 +362,9 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) } count = up->port.fifosize / 4; do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); + serial_omap_put_char(up, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); up->port.icount.tx++; - if ((up->port.rs485.flags & SER_RS485_ENABLED) && - !(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) - up->rs485_tx_filter_count++; if (uart_circ_empty(xmit)) break; @@ -397,7 +398,7 @@ static void serial_omap_start_tx(struct uart_port *port) /* if rts not already enabled */ res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; - if (up->rts_gpiod && gpiod_get_value(up->rts_gpiod) != res) { + if (gpiod_get_value(up->rts_gpiod) != res) { gpiod_set_value(up->rts_gpiod, res); if (port->rs485.delay_rts_before_send > 0) mdelay(port->rs485.delay_rts_before_send); @@ -802,7 +803,7 @@ static void serial_omap_uart_qos_work(struct work_struct *work) static void serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; @@ -1336,13 +1337,11 @@ serial_omap_config_rs485(struct uart_port *port, struct ktermios *termios, up->ier = 0; serial_out(up, UART_IER, 0); - if (up->rts_gpiod) { - /* enable / disable rts */ - val = (rs485->flags & SER_RS485_ENABLED) ? - SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; - val = (rs485->flags & val) ? 1 : 0; - gpiod_set_value(up->rts_gpiod, val); - } + /* enable / disable rts */ + val = (rs485->flags & SER_RS485_ENABLED) ? + SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; + val = (rs485->flags & val) ? 1 : 0; + gpiod_set_value(up->rts_gpiod, val); /* Enable interrupts */ up->ier = mode; @@ -1547,11 +1546,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, ret = PTR_ERR(up->rts_gpiod); if (ret == -EPROBE_DEFER) return ret; - /* - * FIXME: the code historically ignored any other error than - * -EPROBE_DEFER and just went on without GPIO. - */ + up->rts_gpiod = NULL; + up->port.rs485_supported = (const struct serial_rs485) { }; + if (rs485conf->flags & SER_RS485_ENABLED) { + dev_err(dev, "disabling RS-485 (rts-gpio missing in device tree)\n"); + memset(rs485conf, 0, sizeof(*rs485conf)); + } } else { gpiod_set_consumer_name(up->rts_gpiod, "omap-serial"); } diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 888e17e3f25f..fde39cc1145d 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -328,7 +328,7 @@ static void owl_uart_change_baudrate(struct owl_uart_port *owl_port, static void owl_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct owl_uart_port *owl_port = to_owl_uart_port(port); unsigned int baud; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 8a9065e4a903..c59ce7886579 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -898,9 +898,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) fifo_size--; } - bytes = min((int)CIRC_CNT(xmit->head, xmit->tail, - UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, - xmit->tail, UART_XMIT_SIZE)); + bytes = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (!bytes) { dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__); pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); @@ -1301,7 +1299,8 @@ static void pch_uart_shutdown(struct uart_port *port) *bits. Update read_status_mask and ignore_status_mask to indicate *the types of events we are interested in receiving. */ static void pch_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { int rtn; unsigned int baud, parity, bits, stb; diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index f418f1de66b3..2beada66c824 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -50,7 +50,7 @@ * @irq_rx_name: irq rx name * @irq_tx: virtual tx interrupt number * @irq_tx_name: irq tx name - * @cts_gpio: clear to send gpio + * @cts_gpiod: clear to send GPIO * @dev: device descriptor **/ struct pic32_sport { @@ -65,8 +65,7 @@ struct pic32_sport { const char *irq_tx_name; bool enable_tx_irq; - bool hw_flow_ctrl; - int cts_gpio; + struct gpio_desc *cts_gpiod; struct clk *clk; @@ -158,25 +157,16 @@ static void pic32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) PIC32_UART_MODE_LPBK); } -/* get the state of CTS input pin for this port */ -static unsigned int get_cts_state(struct pic32_sport *sport) -{ - /* read and invert UxCTS */ - if (gpio_is_valid(sport->cts_gpio)) - return !gpio_get_value(sport->cts_gpio); - - return 1; -} - /* serial core request to return the state of misc UART input pins */ static unsigned int pic32_uart_get_mctrl(struct uart_port *port) { struct pic32_sport *sport = to_pic32_sport(port); unsigned int mctrl = 0; - if (!sport->hw_flow_ctrl) + /* get the state of CTS input pin for this port */ + if (!sport->cts_gpiod) mctrl |= TIOCM_CTS; - else if (get_cts_state(sport)) + else if (gpiod_get_value(sport->cts_gpiod)) mctrl |= TIOCM_CTS; /* DSR and CD are not supported in PIC32, so return 1 @@ -609,7 +599,7 @@ static void pic32_uart_shutdown(struct uart_port *port) /* serial core request to change current uart setting */ static void pic32_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { struct pic32_sport *sport = to_pic32_sport(port); unsigned int baud; @@ -648,7 +638,7 @@ static void pic32_uart_set_termios(struct uart_port *port, PIC32_UART_MODE_PDSEL0); } /* if hw flow ctrl, then the pins must be specified in device tree */ - if ((new->c_cflag & CRTSCTS) && sport->hw_flow_ctrl) { + if ((new->c_cflag & CRTSCTS) && sport->cts_gpiod) { /* enable hardware flow control */ pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), PIC32_UART_MODE_UEN1); @@ -875,7 +865,8 @@ static struct uart_driver pic32_uart_driver = { static int pic32_uart_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct pic32_sport *sport; int uart_idx = 0; struct resource *res_mem; @@ -904,25 +895,10 @@ static int pic32_uart_probe(struct platform_device *pdev) /* Hardware flow control: gpios * !Note: Basically, CTS is needed for reading the status. */ - sport->hw_flow_ctrl = false; - sport->cts_gpio = of_get_named_gpio(np, "cts-gpios", 0); - if (gpio_is_valid(sport->cts_gpio)) { - sport->hw_flow_ctrl = true; - - ret = devm_gpio_request(sport->dev, - sport->cts_gpio, "CTS"); - if (ret) { - dev_err(&pdev->dev, - "error requesting CTS GPIO\n"); - goto err; - } - - ret = gpio_direction_input(sport->cts_gpio); - if (ret) { - dev_err(&pdev->dev, "error setting CTS GPIO\n"); - goto err; - } - } + sport->cts_gpiod = devm_gpiod_get_optional(dev, "cts", GPIOD_IN); + if (IS_ERR(sport->cts_gpiod)) + return dev_err_probe(dev, PTR_ERR(sport->cts_gpiod), "error requesting CTS GPIO\n"); + gpiod_set_consumer_name(sport->cts_gpiod, "CTS"); pic32_sports[uart_idx] = sport; port = &sport->port; @@ -943,7 +919,7 @@ static int pic32_uart_probe(struct platform_device *pdev) } #ifdef CONFIG_SERIAL_PIC32_CONSOLE - if (uart_console(port) && (pic32_console.flags & CON_ENABLED)) { + if (uart_console_enabled(port)) { /* The peripheral clock has been enabled by console_setup, * so disable it till the port is used. */ diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index f63257b8e872..fe2e4ec423f7 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1202,7 +1202,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long baud; @@ -1244,7 +1244,7 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, /* The port lock is not held. */ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pmac_port *uap = to_pmz(port); unsigned long flags; diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 9309ffd87c8e..2d25231fad84 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -423,7 +423,7 @@ static void serial_pxa_shutdown(struct uart_port *port) static void serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned char cval, fcr = 0; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index f4698a064a4d..83b66b73303a 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -22,6 +22,7 @@ #include #include #include +#include /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG 0x22c @@ -1005,7 +1006,8 @@ static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud, } static void qcom_geni_serial_set_termios(struct uart_port *uport, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { unsigned int baud; u32 bits_per_char; @@ -1524,7 +1526,7 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) * even with no_console_suspend */ if (uart_console(uport)) { - geni_icc_set_tag(&port->se, 0x3); + geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY); geni_icc_set_bw(&port->se); } return uart_suspend_port(private_data->drv, uport); @@ -1539,7 +1541,7 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) ret = uart_resume_port(private_data->drv, uport); if (uart_console(uport)) { - geni_icc_set_tag(&port->se, 0x7); + geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS); geni_icc_set_bw(&port->se); } return ret; diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index feb2054aba37..0e387e2144fa 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -238,7 +238,7 @@ static void rda_uart_change_baudrate(struct rda_uart_port *rda_port, static void rda_uart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct rda_uart_port *rda_port = to_rda_uart_port(port); unsigned long flags; diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 6689d8add8f7..b81afb06f1f4 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -370,9 +370,8 @@ static void __rp2_uart_set_termios(struct rp2_uart_port *up, up->ucode + RP2_RX_SWFLOW); } -static void rp2_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) +static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new, + const struct ktermios *old) { struct rp2_uart_port *up = port_to_up(port); unsigned long flags; diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index e64e42a19d1a..dd9e3253cab4 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -409,7 +409,7 @@ static void sa1100_shutdown(struct uart_port *port) static void sa1100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct sa1100_port *sport = container_of(port, struct sa1100_port, port); diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index b7a4b47ce74e..77d1363029f5 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1530,7 +1530,7 @@ static const u16 udivslot_table[16] = { static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { const struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index 2cf8533ef760..c5d2b6cdcb4a 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -531,7 +531,7 @@ static void sbd_init_port(struct sbd_port *sport) } static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct sbd_port *sport = to_sport(uport); unsigned int mode1 = 0, mode2 = 0, aux = 0; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index d983692c59e0..524921360ca7 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1015,7 +1015,7 @@ static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) static void sc16is7xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index c56de2e104d4..dd98509f52e5 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -636,7 +636,8 @@ static void sccnxp_break_ctl(struct uart_port *port, int break_state) } static void sccnxp_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct sccnxp_port *s = dev_get_drvdata(port->dev); unsigned long flags; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index a5748e41483b..b7170cb9a544 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1270,14 +1270,14 @@ static void tegra_uart_enable_ms(struct uart_port *u) } static void tegra_uart_set_termios(struct uart_port *u, - struct ktermios *termios, struct ktermios *oldtermios) + struct ktermios *termios, + const struct ktermios *oldtermios) { struct tegra_uart_port *tup = to_tegra_uport(u); unsigned int baud; unsigned long flags; unsigned int lcr; unsigned char char_bits; - int symb_bit = 1; struct clk *parent_clk = clk_get_parent(tup->uart_clk); unsigned long parent_clk_rate = clk_get_rate(parent_clk); int max_divider = (tup->cdata->support_clk_src_div) ? 0x7FFF : 0xFFFF; @@ -1304,7 +1304,6 @@ static void tegra_uart_set_termios(struct uart_port *u, termios->c_cflag &= ~CMSPAR; if ((termios->c_cflag & PARENB) == PARENB) { - symb_bit++; if (termios->c_cflag & PARODD) { lcr |= UART_LCR_PARITY; lcr &= ~UART_LCR_EPAR; @@ -1317,22 +1316,18 @@ static void tegra_uart_set_termios(struct uart_port *u, } char_bits = tty_get_char_size(termios->c_cflag); - symb_bit += char_bits; lcr &= ~UART_LCR_WLEN8; lcr |= UART_LCR_WLEN(char_bits); /* Stop bits */ - if (termios->c_cflag & CSTOPB) { + if (termios->c_cflag & CSTOPB) lcr |= UART_LCR_STOP; - symb_bit += 2; - } else { + else lcr &= ~UART_LCR_STOP; - symb_bit++; - } tegra_uart_write(tup, lcr, UART_LCR); tup->lcr_shadow = lcr; - tup->symb_bit = symb_bit; + tup->symb_bit = tty_get_frame_size(termios->c_cflag); /* Baud rate. */ baud = uart_get_baud_rate(u, termios, oldtermios, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 12c87cd201a7..179ee199df34 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -49,7 +49,7 @@ static struct lock_class_key port_lock_key; #define RS485_MAX_RTS_DELAY 100 /* msecs */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios); + const struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state); @@ -158,15 +158,10 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) unsigned long flags; unsigned int old; - if (port->rs485.flags & SER_RS485_ENABLED) { - set &= ~TIOCM_RTS; - clear &= ~TIOCM_RTS; - } - spin_lock_irqsave(&port->lock, flags); old = port->mctrl; port->mctrl = (old & ~clear) | set; - if (old != port->mctrl) + if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED)) port->ops->set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); } @@ -380,7 +375,7 @@ EXPORT_SYMBOL(uart_update_timeout); */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old, unsigned int min, unsigned int max) + const struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try; unsigned int baud; @@ -492,7 +487,7 @@ EXPORT_SYMBOL(uart_get_divisor); /* Caller holds port mutex */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct uart_port *uport = uart_port_check(state); struct ktermios *termios; @@ -1391,7 +1386,7 @@ static void uart_set_rs485_termination(struct uart_port *port, !!(rs485->flags & SER_RS485_TERMINATE_BUS)); } -int uart_rs485_config(struct uart_port *port) +static int uart_rs485_config(struct uart_port *port) { struct serial_rs485 *rs485 = &port->rs485; int ret; @@ -1405,7 +1400,6 @@ int uart_rs485_config(struct uart_port *port) return ret; } -EXPORT_SYMBOL_GPL(uart_rs485_config); static int uart_get_rs485_config(struct uart_port *port, struct serial_rs485 __user *rs485) @@ -1444,8 +1438,13 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &tty->termios, &rs485); - if (!ret) + if (!ret) { port->rs485 = rs485; + + /* Reset RTS and other mctrl lines when disabling RS485 */ + if (!(rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } spin_unlock_irqrestore(&port->lock, flags); if (ret) return ret; @@ -1619,7 +1618,7 @@ static void uart_set_ldisc(struct tty_struct *tty) } static void uart_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; struct uart_port *uport; @@ -2352,7 +2351,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) spin_lock_irq(&uport->lock); ops->stop_tx(uport); - ops->set_mctrl(uport, 0); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); /* save mctrl so it can be restored on resume */ mctrl = uport->mctrl; uport->mctrl = 0; @@ -2440,7 +2440,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) uart_change_pm(state, UART_PM_STATE_ON); spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, 0); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); spin_unlock_irq(&uport->lock); if (console_suspend_enabled || !uart_console(uport)) { /* Protected by port mutex for now */ @@ -2451,7 +2452,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (tty) uart_change_speed(tty, state, NULL); spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, uport->mctrl); + else + uart_rs485_config(uport); ops->start_tx(uport); spin_unlock_irq(&uport->lock); tty_port_set_initialized(port, 1); @@ -2497,7 +2501,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) "MMIO 0x%llx", (unsigned long long)port->mapbase); break; default: - strlcpy(address, "*unknown*", sizeof(address)); + strscpy(address, "*unknown*", sizeof(address)); break; } @@ -2558,10 +2562,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, */ spin_lock_irqsave(&port->lock, flags); port->mctrl &= TIOCM_DTR; - if (port->rs485.flags & SER_RS485_ENABLED && - !(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) - port->mctrl |= TIOCM_RTS; - port->ops->set_mctrl(port, port->mctrl); + if (!(port->rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + else + uart_rs485_config(port); spin_unlock_irqrestore(&port->lock, flags); /* diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 228e380db080..e12f1dc18c38 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -594,7 +594,7 @@ static void serial_txx9_shutdown(struct uart_port *up) static void serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int cval, fcr = 0; unsigned long flags; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 0075a1420005..62f773286d44 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1407,10 +1407,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work) spin_lock_irq(&port->lock); head = xmit->head; tail = xmit->tail; - buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1)); - s->tx_dma_len = min_t(unsigned int, - CIRC_CNT(head, tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE)); + buf = s->tx_dma_addr + tail; + s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE); if (!s->tx_dma_len) { /* Transmit buffer has been flushed */ spin_unlock_irq(&port->lock); @@ -2367,7 +2365,7 @@ static void sci_reset(struct uart_port *port) } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i, bits; unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0; diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 4b1d4fe8458e..7fb6760b5c37 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -646,7 +646,7 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb, static void sifive_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); unsigned long flags; diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 4329b9c9cbf0..342a87967631 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -771,9 +771,8 @@ static void sprd_shutdown(struct uart_port *port) devm_free_irq(port->dev, port->irq, port); } -static void sprd_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) +static void sprd_set_termios(struct uart_port *port, struct ktermios *termios, + const struct ktermios *old) { unsigned int baud, quot; unsigned int lcr = 0, fc; diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index cce42f4c9bc2..fcecea689a0d 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -500,7 +500,7 @@ static void asc_pm(struct uart_port *port, unsigned int state, } static void asc_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct asc_port *ascport = to_asc_port(port); struct gpio_desc *gpiod; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 2c85dbf165c4..dfdbcf092fac 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -37,7 +37,7 @@ /* Register offsets */ -static struct stm32_usart_info stm32f4_info = { +static struct stm32_usart_info __maybe_unused stm32f4_info = { .ofs = { .isr = 0x00, .rdr = 0x04, @@ -58,7 +58,7 @@ static struct stm32_usart_info stm32f4_info = { } }; -static struct stm32_usart_info stm32f7_info = { +static struct stm32_usart_info __maybe_unused stm32f7_info = { .ofs = { .cr1 = 0x00, .cr2 = 0x04, @@ -80,7 +80,7 @@ static struct stm32_usart_info stm32f7_info = { } }; -static struct stm32_usart_info stm32h7_info = { +static struct stm32_usart_info __maybe_unused stm32h7_info = { .ofs = { .cr1 = 0x00, .cr2 = 0x04, @@ -131,6 +131,53 @@ static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } +static unsigned int stm32_usart_tx_empty(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) + return TIOCSER_TEMT; + + return 0; +} + +static void stm32_usart_rs485_rts_enable(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; + + if (stm32_port->hw_flow_control || + !(rs485conf->flags & SER_RS485_ENABLED)) + return; + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } +} + +static void stm32_usart_rs485_rts_disable(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct serial_rs485 *rs485conf = &port->rs485; + + if (stm32_port->hw_flow_control || + !(rs485conf->flags & SER_RS485_ENABLED)) + return; + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl & ~TIOCM_RTS); + } else { + mctrl_gpio_set(stm32_port->gpios, + stm32_port->port.mctrl | TIOCM_RTS); + } +} + static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, u32 delay_DDE, u32 baud) { @@ -214,6 +261,12 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + /* Adjust RTS polarity in case it's driven in software */ + if (stm32_usart_tx_empty(port)) + stm32_usart_rs485_rts_disable(port); + else + stm32_usart_rs485_rts_enable(port); + return 0; } @@ -529,42 +582,6 @@ static void stm32_usart_tc_interrupt_disable(struct uart_port *port) stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TCIE); } -static void stm32_usart_rs485_rts_enable(struct uart_port *port) -{ - struct stm32_port *stm32_port = to_stm32_port(port); - struct serial_rs485 *rs485conf = &port->rs485; - - if (stm32_port->hw_flow_control || - !(rs485conf->flags & SER_RS485_ENABLED)) - return; - - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl | TIOCM_RTS); - } else { - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl & ~TIOCM_RTS); - } -} - -static void stm32_usart_rs485_rts_disable(struct uart_port *port) -{ - struct stm32_port *stm32_port = to_stm32_port(port); - struct serial_rs485 *rs485conf = &port->rs485; - - if (stm32_port->hw_flow_control || - !(rs485conf->flags & SER_RS485_ENABLED)) - return; - - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl & ~TIOCM_RTS); - } else { - mctrl_gpio_set(stm32_port->gpios, - stm32_port->port.mctrl | TIOCM_RTS); - } -} - static void stm32_usart_transmit_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -807,17 +824,6 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) return IRQ_HANDLED; } -static unsigned int stm32_usart_tx_empty(struct uart_port *port) -{ - struct stm32_port *stm32_port = to_stm32_port(port); - const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - - if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) - return TIOCSER_TEMT; - - return 0; -} - static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -1089,7 +1095,7 @@ static void stm32_usart_shutdown(struct uart_port *port) static void stm32_usart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index eafada8fb6fa..1938ba5e98c0 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -323,7 +323,7 @@ static void sunhv_shutdown(struct uart_port *port) /* port->lock is not held. */ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); unsigned int quot = uart_get_divisor(port, baud); diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index 60c73662f955..7afe61a0e72e 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -333,7 +333,7 @@ static void sunplus_shutdown(struct uart_port *port) static void sunplus_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *oldtermios) + const struct ktermios *oldtermios) { u32 ext, div, div_l, div_h, baud, lcr; u32 clk = port->uartclk; diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 6ea52293d9f3..99608b2a2b74 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -681,27 +681,23 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla unsigned int quot) { unsigned char dafo; - int bits, n, m; + int n, m; /* Byte size and parity */ switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; - case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; - case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; - case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + case CS5: dafo = SAB82532_DAFO_CHL5; break; + case CS6: dafo = SAB82532_DAFO_CHL6; break; + case CS7: dafo = SAB82532_DAFO_CHL7; break; + case CS8: dafo = SAB82532_DAFO_CHL8; break; /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + default: dafo = SAB82532_DAFO_CHL5; break; } - if (cflag & CSTOPB) { + if (cflag & CSTOPB) dafo |= SAB82532_DAFO_STOP; - bits++; - } - if (cflag & PARENB) { + if (cflag & PARENB) dafo |= SAB82532_DAFO_PARE; - bits++; - } if (cflag & PARODD) { dafo |= SAB82532_DAFO_PAR_ODD; @@ -776,7 +772,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla /* port->lock is not held. */ static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_sunsab_port *up = container_of(port, struct uart_sunsab_port, port); diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 84d545e5a8c7..9ea7e567540d 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -897,7 +897,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, static void sunsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { unsigned int baud, quot; @@ -1217,13 +1217,13 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) serio->id.type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "sukbd", sizeof(serio->name)); + strscpy(serio->name, "sukbd", sizeof(serio->name)); } else { serio->id.proto = SERIO_SUN; serio->id.extra = 1; - strlcpy(serio->name, "sums", sizeof(serio->name)); + strscpy(serio->name, "sums", sizeof(serio->name)); } - strlcpy(serio->phys, + strscpy(serio->phys, (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), sizeof(serio->phys)); diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index c14275d83b0b..87425290687d 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -938,7 +938,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, /* The port lock is not held. */ static void sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_sunzilog_port *up = container_of(port, struct uart_sunzilog_port, port); @@ -1307,13 +1307,13 @@ static void sunzilog_register_serio(struct uart_sunzilog_port *up) serio->id.type = SERIO_RS232; if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); + strscpy(serio->name, "zskbd", sizeof(serio->name)); } else { serio->id.proto = SERIO_SUN; serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); + strscpy(serio->name, "zsms", sizeof(serio->name)); } - strlcpy(serio->phys, + strscpy(serio->phys, ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ? "zs/serio0" : "zs/serio1"), sizeof(serio->phys)); diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index 889b701ba7c6..23500b342da7 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -126,7 +126,7 @@ static void tegra_tcu_uart_shutdown(struct uart_port *port) static void tegra_tcu_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) + const struct ktermios *old) { } diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 08941eabe7b1..bb19ed012def 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -275,8 +275,8 @@ static int get_bindex(int baud) } static void timbuart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { unsigned int baud; short bindex; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 880e2afbb97b..eca41ac5477c 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -314,8 +314,9 @@ static void ulite_shutdown(struct uart_port *port) clk_disable(pdata->clk); } -static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void ulite_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { unsigned long flags; struct uartlite_data *pdata = port->private_data; diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 3cc9ef08455c..82cf14dd3d43 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -843,7 +843,8 @@ static void qe_uart_shutdown(struct uart_port *port) * Set the serial port parameters. */ static void qe_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { struct uart_qe_port *qe_port = container_of(port, struct uart_qe_port, port); @@ -853,13 +854,6 @@ static void qe_uart_set_termios(struct uart_port *port, u16 upsmr = ioread16be(&uccp->upsmr); struct ucc_uart_pram __iomem *uccup = qe_port->uccup; u16 supsmr = ioread16be(&uccup->supsmr); - u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ /* byte size */ upsmr &= UCC_UART_UPSMR_CL_MASK; @@ -869,22 +863,18 @@ static void qe_uart_set_termios(struct uart_port *port, case CS5: upsmr |= UCC_UART_UPSMR_CL_5; supsmr |= UCC_UART_SUPSMR_CL_5; - char_length += 5; break; case CS6: upsmr |= UCC_UART_UPSMR_CL_6; supsmr |= UCC_UART_SUPSMR_CL_6; - char_length += 6; break; case CS7: upsmr |= UCC_UART_UPSMR_CL_7; supsmr |= UCC_UART_SUPSMR_CL_7; - char_length += 7; break; default: /* case CS8 */ upsmr |= UCC_UART_UPSMR_CL_8; supsmr |= UCC_UART_SUPSMR_CL_8; - char_length += 8; break; } @@ -892,13 +882,11 @@ static void qe_uart_set_termios(struct uart_port *port, if (termios->c_cflag & CSTOPB) { upsmr |= UCC_UART_UPSMR_SL; supsmr |= UCC_UART_SUPSMR_SL; - char_length++; /* + SL */ } if (termios->c_cflag & PARENB) { upsmr |= UCC_UART_UPSMR_PEN; supsmr |= UCC_UART_SUPSMR_PEN; - char_length++; /* + PEN */ if (!(termios->c_cflag & PARODD)) { upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | @@ -953,7 +941,7 @@ static void qe_uart_set_termios(struct uart_port *port, iowrite16be(upsmr, &uccp->upsmr); if (soft_uart) { iowrite16be(supsmr, &uccup->supsmr); - iowrite8(char_length, &uccup->rx_length); + iowrite8(tty_get_frame_size(termios->c_cflag), &uccup->rx_length); /* Soft-UART requires a 1X multiplier for TX */ qe_setbrg(qe_port->us_info.rx_clock, baud, 16); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 6f08136ce78a..10fbdb09965f 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -187,6 +187,13 @@ static void handle_rx(struct uart_port *port) tty_flip_buffer_push(tport); } +static unsigned int vt8500_tx_empty(struct uart_port *port) +{ + unsigned int idx = vt8500_read(port, VT8500_URFIDX) & 0x1f; + + return idx < 16 ? TIOCSER_TEMT : 0; +} + static void handle_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; @@ -201,7 +208,7 @@ static void handle_tx(struct uart_port *port) return; } - while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) { + while (vt8500_tx_empty(port)) { if (uart_circ_empty(xmit)) break; @@ -260,12 +267,6 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static unsigned int vt8500_tx_empty(struct uart_port *port) -{ - return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ? - TIOCSER_TEMT : 0; -} - static unsigned int vt8500_get_mctrl(struct uart_port *port) { unsigned int usr; @@ -355,7 +356,7 @@ static void vt8500_shutdown(struct uart_port *port) static void vt8500_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct vt8500_port *vt8500_port = container_of(port, struct vt8500_port, uart); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 9e01fe6c0ab8..2eff7cff57c4 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -2,7 +2,7 @@ /* * Cadence UART driver (found in Xilinx Zynq) * - * 2011 - 2014 (C) Xilinx Inc. + * Copyright (c) 2011 - 2014 Xilinx, Inc. * * This driver has originally been pushed by Xilinx using a Zynq-branding. This * still shows in the naming of this file, the kconfig symbols and some symbols @@ -361,6 +361,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } + isrstatus &= port->read_status_mask; + isrstatus &= ~port->ignore_status_mask; /* * Skip RX processing if RX is disabled as RXEMPTY will never be set * as read bytes will not be removed from the FIFO. @@ -675,7 +677,8 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) * @old: Values of the previously saved termios structure */ static void cdns_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) + struct ktermios *termios, + const struct ktermios *old) { u32 cval = 0; unsigned int baud, minbaud, maxbaud; @@ -1130,8 +1133,35 @@ static struct uart_driver cdns_uart_uart_driver; */ static void cdns_uart_console_putchar(struct uart_port *port, unsigned char ch) { - while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) + unsigned int ctrl_reg; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_CR); + if (!(ctrl_reg & CDNS_UART_CR_TX_DIS)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for Enable\n"); + return; + } cpu_relax(); + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { + ctrl_reg = readl(port->membase + CDNS_UART_SR); + + if (!(ctrl_reg & CDNS_UART_SR_TXFULL)) + break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for TX fifo\n"); + return; + } + cpu_relax(); + } writel(ch, port->membase + CDNS_UART_FIFO); } @@ -1329,12 +1359,20 @@ static int cdns_uart_resume(struct device *device) unsigned long flags; u32 ctrl_reg; int may_wake; + int ret; may_wake = device_may_wakeup(device); if (console_suspend_enabled && uart_console(port) && !may_wake) { - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; + + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } spin_lock_irqsave(&port->lock, flags); @@ -1383,9 +1421,17 @@ static int __maybe_unused cdns_runtime_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); struct cdns_uart *cdns_uart = port->private_data; + int ret; - clk_enable(cdns_uart->pclk); - clk_enable(cdns_uart->uartclk); + ret = clk_enable(cdns_uart->pclk); + if (ret) + return ret; + + ret = clk_enable(cdns_uart->uartclk); + if (ret) { + clk_disable(cdns_uart->pclk); + return ret; + } return 0; }; @@ -1551,6 +1597,8 @@ static int cdns_uart_probe(struct platform_device *pdev) port->dev = &pdev->dev; port->uartclk = clk_get_rate(cdns_uart_data->uartclk); port->private_data = cdns_uart_data; + port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; cdns_uart_data->port = port; platform_set_drvdata(pdev, port); diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 5bc58591665a..688db7d8b748 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -846,7 +846,7 @@ static void zs_reset(struct zs_port *zport) } static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct zs_port *zport = to_zport(uport); struct zs_scc *scc = zport->scc; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 9bc2a9265277..25e9befdda3a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -91,7 +91,6 @@ static char *driver_name = "SyncLink GT"; static char *slgt_driver_name = "synclink_gt"; static char *tty_dev_prefix = "ttySLG"; MODULE_LICENSE("GPL"); -#define MGSL_MAGIC 0x5401 #define MAX_DEVICES 32 static const struct pci_device_id pci_table[] = { @@ -215,8 +214,6 @@ struct slgt_info { struct slgt_info *next_device; /* device list link */ - int magic; - char device_name[25]; struct pci_dev *pdev; @@ -554,10 +551,6 @@ static inline int sanity_check(struct slgt_info *info, char *devname, const char printk("null struct slgt_info for (%s) in %s\n", devname, name); return 1; } - if (info->magic != MGSL_MAGIC) { - printk("bad magic number struct slgt_info (%s) in %s\n", devname, name); - return 1; - } #else if (!info) return 1; @@ -707,7 +700,8 @@ static void hangup(struct tty_struct *tty) wake_up_interruptible(&info->port.open_wait); } -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void set_termios(struct tty_struct *tty, + const struct ktermios *old_termios) { struct slgt_info *info = tty->driver_data; unsigned long flags; @@ -3498,7 +3492,6 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev } else { tty_port_init(&info->port); info->port.ops = &slgt_port_ops; - info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->base_clock = 14745600; diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index f310a8274df1..1c08c9b67b16 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -73,7 +73,7 @@ void tty_buffer_set_lock_subclass(struct tty_port *port); bool tty_buffer_restart_work(struct tty_port *port); bool tty_buffer_cancel_work(struct tty_port *port); void tty_buffer_flush_work(struct tty_port *port); -speed_t tty_termios_input_baud_rate(struct ktermios *termios); +speed_t tty_termios_input_baud_rate(const struct ktermios *termios); void tty_ldisc_hangup(struct tty_struct *tty, bool reset); int tty_ldisc_reinit(struct tty_struct *tty, int disc); long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 3cd99ed7c710..f9b49939c27b 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -49,13 +49,13 @@ static int n_baud_table = ARRAY_SIZE(baud_table); * * Convert termios baud rate data into a speed. This should be called * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. Device drivers can call this - * function but should use ->c_[io]speed directly as they are updated. + * structure. Device drivers can call this function but should use + * ->c_[io]speed directly as they are updated. * * Locking: none */ -speed_t tty_termios_baud_rate(struct ktermios *termios) +speed_t tty_termios_baud_rate(const struct ktermios *termios) { unsigned int cbaud; @@ -67,11 +67,7 @@ speed_t tty_termios_baud_rate(struct ktermios *termios) if (cbaud & CBAUDEX) { cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~CBAUDEX; - else - cbaud += 15; + cbaud += 15; } return cbaud >= n_baud_table ? 0 : baud_table[cbaud]; } @@ -83,30 +79,26 @@ EXPORT_SYMBOL(tty_termios_baud_rate); * * Convert termios baud rate data into a speed. This should be called * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. Device drivers can call this - * function but should use ->c_[io]speed directly as they are updated. + * structure. Device drivers can call this function but should use + * ->c_[io]speed directly as they are updated. * * Locking: none */ -speed_t tty_termios_input_baud_rate(struct ktermios *termios) +speed_t tty_termios_input_baud_rate(const struct ktermios *termios) { unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; if (cbaud == B0) return tty_termios_baud_rate(termios); - /* Magic token for arbitrary speed via c_ispeed*/ + /* Magic token for arbitrary speed via c_ispeed */ if (cbaud == BOTHER) return termios->c_ispeed; if (cbaud & CBAUDEX) { cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~(CBAUDEX << IBSHIFT); - else - cbaud += 15; + cbaud += 15; } return cbaud >= n_baud_table ? 0 : baud_table[cbaud]; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 82a8855981f7..de06c3c2ff70 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -99,8 +99,8 @@ #include #include #include - #include +#include #include #include @@ -170,7 +170,6 @@ static void free_tty_struct(struct tty_struct *tty) tty_ldisc_deinit(tty); put_device(tty->dev); kvfree(tty->write_buf); - tty->magic = 0xDEADDEAD; kfree(tty); } @@ -265,11 +264,6 @@ static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, imajor(inode), iminor(inode), routine); return 1; } - if (tty->magic != TTY_MAGIC) { - pr_warn("(%d:%d): %s: bad magic number\n", - imajor(inode), iminor(inode), routine); - return 1; - } #endif return 0; } @@ -1533,7 +1527,6 @@ static void release_one_tty(struct work_struct *work) if (tty->ops->cleanup) tty->ops->cleanup(tty); - tty->magic = 0; tty_driver_kref_put(driver); module_put(owner); @@ -3093,7 +3086,6 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) return NULL; kref_init(&tty->kref); - tty->magic = TTY_MAGIC; if (tty_ldisc_init(tty)) { kfree(tty); return NULL; @@ -3329,7 +3321,6 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, return ERR_PTR(-ENOMEM); kref_init(&driver->kref); - driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; driver->owner = owner; driver->flags = flags; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 2a76b330e108..ce511557b98b 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "tty.h" #include @@ -219,7 +220,7 @@ EXPORT_SYMBOL(tty_wait_until_sent); * Termios Helper Methods */ -static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old) +static void unset_locked_termios(struct tty_struct *tty, const struct ktermios *old) { struct ktermios *termios = &tty->termios; struct ktermios *locked = &tty->termios_locked; @@ -249,7 +250,7 @@ static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old) * in some cases where only minimal reconfiguration is supported */ -void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) +void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old) { /* The bits a dumb device handles in software. Smart devices need to always provide a set_termios method */ @@ -374,6 +375,80 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) } EXPORT_SYMBOL_GPL(tty_set_termios); + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +__weak int user_termio_to_kernel_termios(struct ktermios *termios, + struct termio __user *termio) +{ + struct termio v; + + if (copy_from_user(&v, termio, sizeof(struct termio))) + return -EFAULT; + + termios->c_iflag = (0xffff0000 & termios->c_iflag) | v.c_iflag; + termios->c_oflag = (0xffff0000 & termios->c_oflag) | v.c_oflag; + termios->c_cflag = (0xffff0000 & termios->c_cflag) | v.c_cflag; + termios->c_lflag = (0xffff0000 & termios->c_lflag) | v.c_lflag; + termios->c_line = (0xffff0000 & termios->c_lflag) | v.c_line; + memcpy(termios->c_cc, v.c_cc, NCC); + return 0; +} + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +__weak int kernel_termios_to_user_termio(struct termio __user *termio, + struct ktermios *termios) +{ + struct termio v; + memset(&v, 0, sizeof(struct termio)); + v.c_iflag = termios->c_iflag; + v.c_oflag = termios->c_oflag; + v.c_cflag = termios->c_cflag; + v.c_lflag = termios->c_lflag; + v.c_line = termios->c_line; + memcpy(v.c_cc, termios->c_cc, NCC); + return copy_to_user(termio, &v, sizeof(struct termio)); +} + +#ifdef TCGETS2 +__weak int user_termios_to_kernel_termios(struct ktermios *k, + struct termios2 __user *u) +{ + return copy_from_user(k, u, sizeof(struct termios2)); +} +__weak int kernel_termios_to_user_termios(struct termios2 __user *u, + struct ktermios *k) +{ + return copy_to_user(u, k, sizeof(struct termios2)); +} +__weak int user_termios_to_kernel_termios_1(struct ktermios *k, + struct termios __user *u) +{ + return copy_from_user(k, u, sizeof(struct termios)); +} +__weak int kernel_termios_to_user_termios_1(struct termios __user *u, + struct ktermios *k) +{ + return copy_to_user(u, k, sizeof(struct termios)); +} + +#else + +__weak int user_termios_to_kernel_termios(struct ktermios *k, + struct termios __user *u) +{ + return copy_from_user(k, u, sizeof(struct termios)); +} +__weak int kernel_termios_to_user_termios(struct termios __user *u, + struct ktermios *k) +{ + return copy_to_user(u, k, sizeof(struct termios)); +} +#endif /* TCGETS2 */ + /** * set_termios - set termios values for a tty * @tty: terminal device diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 393518a24cfe..784e46a0a3b1 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -14,8 +14,6 @@ void tty_lock(struct tty_struct *tty) { - if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) - return; tty_kref_get(tty); mutex_lock(&tty->legacy_mutex); } @@ -25,8 +23,6 @@ int tty_lock_interruptible(struct tty_struct *tty) { int ret; - if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) - return -EIO; tty_kref_get(tty); ret = mutex_lock_interruptible(&tty->legacy_mutex); if (ret) @@ -36,8 +32,6 @@ int tty_lock_interruptible(struct tty_struct *tty) void tty_unlock(struct tty_struct *tty) { - if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty)) - return; mutex_unlock(&tty->legacy_mutex); tty_kref_put(tty); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index e11383ae1e7e..34ba6e54789a 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 0b669c82ddc9..981d2bfcf9a5 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -154,10 +154,10 @@ static void console_callback(struct work_struct *ignored); static void con_driver_unregister_callback(struct work_struct *ignored); static void blank_screen_t(struct timer_list *unused); static void set_palette(struct vc_data *vc); +static void unblank_screen(void); #define vt_get_kmsg_redirect() vt_kmsg_redirect(-1) -static int printable; /* Is console ready for printing? */ int default_utf8 = true; module_param(default_utf8, int, S_IRUGO | S_IWUSR); int global_cursor_default = -1; @@ -3084,9 +3084,9 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) ushort start_x, cnt; int kmsg_console; - /* console busy or not yet initialized */ - if (!printable) - return; + WARN_CONSOLE_UNLOCKED(); + + /* this protects against concurrent oops only */ if (!spin_trylock(&printing_lock)) return; @@ -3537,7 +3537,6 @@ static int __init con_init(void) pr_info("Console: %s %s %dx%d\n", vc->vc_can_do_color ? "colour" : "mono", display_desc, vc->vc_cols, vc->vc_rows); - printable = 1; console_unlock(); @@ -4452,7 +4451,7 @@ EXPORT_SYMBOL(do_unblank_screen); * call it with 1 as an argument and so force a mode restore... that may kill * X or at least garbage the screen but would also make the Oops visible... */ -void unblank_screen(void) +static void unblank_screen(void) { do_unblank_screen(0); } diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 362217189ef3..1cdb8758ae01 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1026,7 +1026,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, /* public fields */ instance->driver = driver; - strlcpy(instance->driver_name, driver->driver_name, + strscpy(instance->driver_name, driver->driver_name, sizeof(instance->driver_name)); instance->usb_dev = usb_dev; diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index dc068e940ed5..2bc5d094548b 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -110,8 +110,6 @@ static int cdns3_plat_probe(struct platform_device *pdev) cdns->wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup"); if (cdns->wakeup_irq == -EPROBE_DEFER) return cdns->wakeup_irq; - else if (cdns->wakeup_irq == 0) - return -EINVAL; if (cdns->wakeup_irq < 0) { dev_dbg(dev, "couldn't get wakeup irq\n"); diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 661818e8fed6..c815824a0b2d 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -34,26 +34,26 @@ config USB_CHIPIDEA_HOST ChipIdea driver. config USB_CHIPIDEA_PCI - tristate "Enable PCI glue driver" if EMBEDDED + tristate "Enable PCI glue driver" if EXPERT depends on USB_PCI depends on NOP_USB_XCEIV default USB_CHIPIDEA config USB_CHIPIDEA_MSM - tristate "Enable MSM hsusb glue driver" if EMBEDDED + tristate "Enable MSM hsusb glue driver" if EXPERT default USB_CHIPIDEA config USB_CHIPIDEA_IMX - tristate "Enable i.MX USB glue driver" if EMBEDDED + tristate "Enable i.MX USB glue driver" if EXPERT depends on OF default USB_CHIPIDEA config USB_CHIPIDEA_GENERIC - tristate "Enable generic USB2 glue driver" if EMBEDDED + tristate "Enable generic USB2 glue driver" if EXPERT default USB_CHIPIDEA config USB_CHIPIDEA_TEGRA - tristate "Enable Tegra USB glue driver" if EMBEDDED + tristate "Enable Tegra USB glue driver" if EXPERT depends on OF default USB_CHIPIDEA diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 89e1d82d739b..dc86b12060b5 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -30,6 +30,7 @@ static const struct ci_hdrc_platform_data ci_default_pdata = { static const struct ci_hdrc_platform_data ci_zynq_pdata = { .capoffset = DEF_CAPOFFSET, + .flags = CI_HDRC_PHY_VBUS_CONTROL, }; static const struct ci_hdrc_platform_data ci_zevio_pdata = { diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index bdc3885c0d49..bc3634a54c6b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -63,6 +63,13 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) priv->enabled = enable; } + if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL) { + if (enable) + usb_phy_vbus_on(ci->usb_phy); + else + usb_phy_vbus_off(ci->usb_phy); + } + if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { /* * Marvell 28nm HSIC PHY requires forcing the port to HS mode. diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 61b157b9c662..ada78daba6df 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -471,6 +471,10 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) return; } } + + if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL) + usb_phy_vbus_on(ci->usb_phy); + /* Disable data pulse irq */ hw_write_otgsc(ci, OTGSC_DPIE, 0); @@ -480,6 +484,9 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) if (ci->platdata->reg_vbus) regulator_disable(ci->platdata->reg_vbus); + if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL) + usb_phy_vbus_off(ci->usb_phy); + fsm->a_bus_drop = 1; fsm->a_bus_req = 0; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index cc637c4599e1..36bf051b345b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -51,7 +51,7 @@ static DEFINE_IDR(acm_minors); static DEFINE_MUTEX(acm_minors_lock); static void acm_tty_set_termios(struct tty_struct *tty, - struct ktermios *termios_old); + const struct ktermios *termios_old); /* * acm_minors accessors @@ -1049,7 +1049,7 @@ static int acm_tty_ioctl(struct tty_struct *tty, } static void acm_tty_set_termios(struct tty_struct *tty, - struct ktermios *termios_old) + const struct ktermios *termios_old) { struct acm *acm = tty->driver_data; struct ktermios *termios = &tty->termios; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index eebe782380fb..1f0951be15ab 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -958,7 +958,7 @@ static void wdm_wwan_rx(struct wdm_device *desc, int length) if (!skb) return; - memcpy(skb_put(skb, length), desc->inbuf, length); + skb_put_data(skb, desc->inbuf, length); wwan_port_rx(port, skb); /* inbuf has been copied, it is safe to check for outstanding data */ diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c index 075f6b1b2a1a..f204cec8d380 100644 --- a/drivers/usb/common/debug.c +++ b/drivers/usb/common/debug.c @@ -208,30 +208,28 @@ static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size) snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue); } -/** - * usb_decode_ctrl - Returns human readable representation of control request. - * @str: buffer to return a human-readable representation of control request. - * This buffer should have about 200 bytes. - * @size: size of str buffer. - * @bRequestType: matches the USB bmRequestType field - * @bRequest: matches the USB bRequest field - * @wValue: matches the USB wValue field (CPU byte order) - * @wIndex: matches the USB wIndex field (CPU byte order) - * @wLength: matches the USB wLength field (CPU byte order) - * - * Function returns decoded, formatted and human-readable description of - * control request packet. - * - * The usage scenario for this is for tracepoints, so function as a return - * use the same value as in parameters. This approach allows to use this - * function in TP_printk - * - * Important: wValue, wIndex, wLength parameters before invoking this function - * should be processed by le16_to_cpu macro. - */ -const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, - __u8 bRequest, __u16 wValue, __u16 wIndex, - __u16 wLength) +static void usb_decode_ctrl_generic(char *str, size_t size, __u8 bRequestType, + __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) +{ + u8 recip = bRequestType & USB_RECIP_MASK; + u8 type = bRequestType & USB_TYPE_MASK; + + snprintf(str, size, + "Type=%s Recipient=%s Dir=%s bRequest=%u wValue=%u wIndex=%u wLength=%u", + (type == USB_TYPE_STANDARD) ? "Standard" : + (type == USB_TYPE_VENDOR) ? "Vendor" : + (type == USB_TYPE_CLASS) ? "Class" : "Unknown", + (recip == USB_RECIP_DEVICE) ? "Device" : + (recip == USB_RECIP_INTERFACE) ? "Interface" : + (recip == USB_RECIP_ENDPOINT) ? "Endpoint" : "Unknown", + (bRequestType & USB_DIR_IN) ? "IN" : "OUT", + bRequest, wValue, wIndex, wLength); +} + +static void usb_decode_ctrl_standard(char *str, size_t size, __u8 bRequestType, + __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) { switch (bRequest) { case USB_REQ_GET_STATUS: @@ -272,14 +270,48 @@ const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, usb_decode_set_isoch_delay(wValue, str, size); break; default: - snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x", - bRequestType, bRequest, - (u8)(cpu_to_le16(wValue) & 0xff), - (u8)(cpu_to_le16(wValue) >> 8), - (u8)(cpu_to_le16(wIndex) & 0xff), - (u8)(cpu_to_le16(wIndex) >> 8), - (u8)(cpu_to_le16(wLength) & 0xff), - (u8)(cpu_to_le16(wLength) >> 8)); + usb_decode_ctrl_generic(str, size, bRequestType, bRequest, + wValue, wIndex, wLength); + break; + } +} + +/** + * usb_decode_ctrl - Returns human readable representation of control request. + * @str: buffer to return a human-readable representation of control request. + * This buffer should have about 200 bytes. + * @size: size of str buffer. + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (CPU byte order) + * @wIndex: matches the USB wIndex field (CPU byte order) + * @wLength: matches the USB wLength field (CPU byte order) + * + * Function returns decoded, formatted and human-readable description of + * control request packet. + * + * The usage scenario for this is for tracepoints, so function as a return + * use the same value as in parameters. This approach allows to use this + * function in TP_printk + * + * Important: wValue, wIndex, wLength parameters before invoking this function + * should be processed by le16_to_cpu macro. + */ +const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, + __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength) +{ + switch (bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: + usb_decode_ctrl_standard(str, size, bRequestType, bRequest, + wValue, wIndex, wLength); + break; + case USB_TYPE_VENDOR: + case USB_TYPE_CLASS: + default: + usb_decode_ctrl_generic(str, size, bRequestType, bRequest, + wValue, wIndex, wLength); + break; } return str; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 0a4f441aff8f..d7c8461976ce 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -233,7 +233,7 @@ err: return 0; } -static int ulpi_regs_read(struct seq_file *seq, void *data) +static int ulpi_regs_show(struct seq_file *seq, void *data) { struct ulpi *ulpi = seq->private; @@ -269,21 +269,7 @@ static int ulpi_regs_read(struct seq_file *seq, void *data) return 0; } - -static int ulpi_regs_open(struct inode *inode, struct file *f) -{ - struct ulpi *ulpi = inode->i_private; - - return single_open(f, ulpi_regs_read, ulpi); -} - -static const struct file_operations ulpi_regs_ops = { - .owner = THIS_MODULE, - .open = ulpi_regs_open, - .release = single_release, - .read = seq_read, - .llseek = seq_lseek -}; +DEFINE_SHOW_ATTRIBUTE(ulpi_regs); #define ULPI_ROOT debugfs_lookup(KBUILD_MODNAME, NULL) @@ -316,7 +302,7 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) } root = debugfs_create_dir(dev_name(dev), ULPI_ROOT); - debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_ops); + debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops); dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n", ulpi->id.vendor, ulpi->id.product); diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index b39c9f1c375d..e20874caba36 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -208,10 +208,8 @@ static int usb_conn_probe(struct platform_device *pdev) if (PTR_ERR(info->vbus) == -ENODEV) info->vbus = NULL; - if (IS_ERR(info->vbus)) { - ret = PTR_ERR(info->vbus); - return dev_err_probe(dev, ret, "failed to get vbus :%d\n", ret); - } + if (IS_ERR(info->vbus)) + return dev_err_probe(dev, PTR_ERR(info->vbus), "failed to get vbus\n"); info->role_sw = usb_role_switch_get(dev); if (IS_ERR(info->role_sw)) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b5b85bf80329..837f3e57f580 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1434,7 +1434,7 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg) if (!intf || !intf->dev.driver) ret = -ENODATA; else { - strlcpy(gd.driver, intf->dev.driver->name, + strscpy(gd.driver, intf->dev.driver->name, sizeof(gd.driver)); ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 482dae72ef1c..9b77f49b3560 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -157,7 +157,6 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, /** * usb_hcd_pci_probe - initialize PCI-based HCDs * @dev: USB Host Controller being probed - * @id: pci hotplug id connecting controller to HCD framework * @driver: USB HC driver handle * * Context: task context, might sleep @@ -170,8 +169,7 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, * * Return: 0 if successful. */ -int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, - const struct hc_driver *driver) +int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver) { struct usb_hcd *hcd; int retval; @@ -180,9 +178,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, if (usb_disabled()) return -ENODEV; - if (!id) - return -EINVAL; - if (!driver) return -EINVAL; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 94b305bbd621..faeaace0d197 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1474,7 +1474,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, urb->sg, urb->num_sgs, dir); - if (n <= 0) + if (!n) ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_SG; @@ -2158,21 +2158,14 @@ static struct urb *request_single_step_set_feature_urb( { struct urb *urb; struct usb_hcd *hcd = bus_to_hcd(udev->bus); - struct usb_host_endpoint *ep; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return NULL; urb->pipe = usb_rcvctrlpipe(udev, 0); - ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) { - usb_free_urb(urb); - return NULL; - } - urb->ep = ep; + urb->ep = &udev->ep0; urb->dev = udev; urb->setup_packet = (void *)dr; urb->transfer_buffer = buf; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index f99a65a64588..0722d2131305 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -388,6 +388,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* Kingston DataTraveler 3.0 */ { USB_DEVICE(0x0951, 0x1666), .driver_info = USB_QUIRK_NO_LPM }, + /* NVIDIA Jetson devices in Force Recovery mode */ + { USB_DEVICE(0x0955, 0x7018), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7019), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7418), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7721), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7c18), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7e19), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x0955, 0x7f21), .driver_info = USB_QUIRK_RESET_RESUME }, + /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, @@ -437,6 +446,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1532, 0x0116), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */ + { USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */ { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index dc4fc72ab1b6..5635e4d7ec88 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -3,36 +3,6 @@ * core.c - DesignWare HS OTG Controller common routines * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 0683852e47e4..40cf2880d7e5 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -3,36 +3,6 @@ * core.h - DesignWare HS OTG Controller common declarations * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __DWC2_CORE_H__ diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index a5c52b237e72..158ede753854 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -3,36 +3,6 @@ * core_intr.c - DesignWare HS OTG Controller common interrupt handling * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index aaf7b9fc4d34..657f1f659ffa 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3,36 +3,6 @@ * hcd.c - DesignWare HS OTG Controller host-mode routines * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index ea02ee63ac6d..b7254d94fdc3 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -3,37 +3,8 @@ * hcd.h - DesignWare HS OTG Controller host-mode declarations * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #ifndef __DWC2_HCD_H__ #define __DWC2_HCD_H__ diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c index a858b5f9c1d6..6b4d825e97a2 100644 --- a/drivers/usb/dwc2/hcd_ddma.c +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -3,36 +3,6 @@ * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index d5f4ec1b73b1..c9740caa5974 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -3,36 +3,6 @@ * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 24beff610cf2..0a1145592fc7 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -3,36 +3,6 @@ * hcd_queue.c - DesignWare HS OTG Controller host queuing routines * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 6b16fbf98bc6..13abdd5f6752 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -3,36 +3,6 @@ * hw.h - DesignWare HS OTG Controller hardware definitions * * Copyright 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __DWC2_HW_H__ diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index fdb8a42fff86..8eab5f38b110 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -1,36 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) 2004-2016 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index a93559b4ecdb..b7306ed8be4c 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -3,36 +3,6 @@ * pci.c - DesignWare HS OTG Controller PCI driver * * Copyright (C) 2004-2013 Synopsys, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index fd0ccf6f3ec5..ec4ace0107f5 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -3,36 +3,6 @@ * platform.c - DesignWare HS OTG Controller platform driver * * Copyright (C) Matthijs Kooijman - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d0237b30c9be..ea51624461b5 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -86,7 +85,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) * mode. If the controller supports DRD but the dr_mode is not * specified or set to OTG, then set the mode to peripheral. */ - if (mode == USB_DR_MODE_OTG && !dwc->edev && + if (mode == USB_DR_MODE_OTG && (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) || !device_property_read_bool(dwc->dev, "usb-role-switch")) && !DWC3_VER_IS_PRIOR(DWC3, 330A)) @@ -408,6 +407,10 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj) | FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1) | FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1); + + if (dwc->gfladj_refclk_lpm_sel) + reg |= DWC3_GFLADJ_REFCLK_LPM_SEL; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } @@ -789,7 +792,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc) else reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; - if (dwc->dis_u2_freeclk_exists_quirk) + if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); @@ -1180,6 +1183,21 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); } + /* + * When configured in HOST mode, after issuing U3/L2 exit controller + * fails to send proper CRC checksum in CRC5 feild. Because of this + * behaviour Transaction Error is generated, resulting in reset and + * re-enumeration of usb device attached. All the termsel, xcvrsel, + * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1 + * will correct this problem. This option is to support certain + * legacy ULPI PHYs. + */ + if (dwc->resume_hs_terminations) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); + reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST; + dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); + } + if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); @@ -1523,8 +1541,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-del-phy-power-chg-quirk"); dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev, "snps,dis-tx-ipgap-linecheck-quirk"); + dwc->resume_hs_terminations = device_property_read_bool(dev, + "snps,resume-hs-terminations"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); + dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, + "snps,gfladj-refclk-lpm-sel-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); @@ -1668,46 +1690,6 @@ static void dwc3_check_params(struct dwc3 *dwc) } } -static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) -{ - struct device *dev = dwc->dev; - struct device_node *np_phy; - struct extcon_dev *edev = NULL; - const char *name; - - if (device_property_read_bool(dev, "extcon")) - return extcon_get_edev_by_phandle(dev, 0); - - /* - * Device tree platforms should get extcon via phandle. - * On ACPI platforms, we get the name from a device property. - * This device property is for kernel internal use only and - * is expected to be set by the glue code. - */ - if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) - return extcon_get_extcon_dev(name); - - /* - * Try to get an extcon device from the USB PHY controller's "port" - * node. Check if it has the "port" node first, to avoid printing the - * error message from underlying code, as it's a valid case: extcon - * device (and "port" node) may be missing in case of "usb-role-switch" - * or OTG mode. - */ - np_phy = of_parse_phandle(dev->of_node, "phys", 0); - if (of_graph_is_present(np_phy)) { - struct device_node *np_conn; - - np_conn = of_graph_get_remote_node(np_phy, -1, -1); - if (np_conn) - edev = extcon_find_edev_by_node(np_conn); - of_node_put(np_conn); - } - of_node_put(np_phy); - - return edev; -} - static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1753,8 +1735,10 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_get_properties(dwc); dwc->reset = devm_reset_control_array_get_optional_shared(dev); - if (IS_ERR(dwc->reset)) - return PTR_ERR(dwc->reset); + if (IS_ERR(dwc->reset)) { + ret = PTR_ERR(dwc->reset); + goto put_usb_psy; + } if (dev->of_node) { /* @@ -1764,45 +1748,57 @@ static int dwc3_probe(struct platform_device *pdev) * check for them to retain backwards compatibility. */ dwc->bus_clk = devm_clk_get_optional(dev, "bus_early"); - if (IS_ERR(dwc->bus_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); + if (IS_ERR(dwc->bus_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + goto put_usb_psy; + } if (dwc->bus_clk == NULL) { dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk"); - if (IS_ERR(dwc->bus_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); + if (IS_ERR(dwc->bus_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + goto put_usb_psy; + } } dwc->ref_clk = devm_clk_get_optional(dev, "ref"); - if (IS_ERR(dwc->ref_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); + if (IS_ERR(dwc->ref_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + goto put_usb_psy; + } if (dwc->ref_clk == NULL) { dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk"); - if (IS_ERR(dwc->ref_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); + if (IS_ERR(dwc->ref_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + goto put_usb_psy; + } } dwc->susp_clk = devm_clk_get_optional(dev, "suspend"); - if (IS_ERR(dwc->susp_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); + if (IS_ERR(dwc->susp_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + goto put_usb_psy; + } if (dwc->susp_clk == NULL) { dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk"); - if (IS_ERR(dwc->susp_clk)) - return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); + if (IS_ERR(dwc->susp_clk)) { + ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + goto put_usb_psy; + } } } ret = reset_control_deassert(dwc->reset); if (ret) - return ret; + goto put_usb_psy; ret = dwc3_clk_enable(dwc); if (ret) @@ -1844,13 +1840,6 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } - dwc->edev = dwc3_get_extcon(dwc); - if (IS_ERR(dwc->edev)) { - ret = PTR_ERR(dwc->edev); - dev_err_probe(dwc->dev, ret, "failed to get extcon\n"); - goto err3; - } - ret = dwc3_get_dr_mode(dwc); if (ret) goto err3; @@ -1909,7 +1898,7 @@ disable_clks: dwc3_clk_disable(dwc); assert_reset: reset_control_assert(dwc->reset); - +put_usb_psy: if (dwc->usb_psy) power_supply_put(dwc->usb_psy); @@ -1977,9 +1966,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) case DWC3_GCTL_PRTCAP_DEVICE: if (pm_runtime_suspended(dwc->dev)) break; - spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_suspend(dwc); - spin_unlock_irqrestore(&dwc->lock, flags); synchronize_irq(dwc->irq_gadget); dwc3_core_exit(dwc); break; @@ -2040,9 +2027,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) return ret; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); - spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); - spin_unlock_irqrestore(&dwc->lock, flags); break; case DWC3_GCTL_PRTCAP_HOST: if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4fe4287dc934..8f9959ba9fd4 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -263,6 +263,7 @@ #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) +#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ #define DWC3_GSTS_OTG_IP BIT(10) @@ -391,6 +392,7 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f #define DWC3_GFLADJ_REFCLK_FLADJ_MASK GENMASK(21, 8) +#define DWC3_GFLADJ_REFCLK_LPM_SEL BIT(23) #define DWC3_GFLADJ_240MHZDECR GENMASK(30, 24) #define DWC3_GFLADJ_240MHZDECR_PLS1 BIT(31) @@ -1096,6 +1098,8 @@ struct dwc3_scratchpad_array { * change quirk. * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate * check during HS transmit. + * @resume-hs-terminations: Set if we enable quirk for fixing improper crc + * generation after resume from suspend. * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk @@ -1311,7 +1315,9 @@ struct dwc3 { unsigned dis_u2_freeclk_exists_quirk:1; unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; + unsigned resume_hs_terminations:1; unsigned parkmode_disable_ss_quirk:1; + unsigned gfladj_refclk_lpm_sel:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; @@ -1560,6 +1566,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, u32 param); void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc); +void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index d223c54115f4..48b44b88dc25 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -278,7 +278,7 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size, break; case DWC3_DEPEVT_XFERINPROGRESS: scnprintf(str + len, size - len, - "Transfer In Progress [%d] (%c%c%c)", + "Transfer In Progress [%08x] (%c%c%c)", event->parameters, status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_IOC ? 'I' : 'i', @@ -286,7 +286,7 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size, break; case DWC3_DEPEVT_XFERNOTREADY: len += scnprintf(str + len, size - len, - "Transfer Not Ready [%d]%s", + "Transfer Not Ready [%08x]%s", event->parameters, status & DEPEVT_STATUS_TRANSFER_ACTIVE ? " (Active)" : " (Not Active)"); diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 039bf241769a..8cad9e7d3368 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -438,6 +439,51 @@ static int dwc3_drd_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + struct device_node *np_phy; + struct extcon_dev *edev = NULL; + const char *name; + + if (device_property_read_bool(dev, "extcon")) + return extcon_get_edev_by_phandle(dev, 0); + + /* + * Device tree platforms should get extcon via phandle. + * On ACPI platforms, we get the name from a device property. + * This device property is for kernel internal use only and + * is expected to be set by the glue code. + */ + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { + edev = extcon_get_extcon_dev(name); + if (!edev) + return ERR_PTR(-EPROBE_DEFER); + + return edev; + } + + /* + * Try to get an extcon device from the USB PHY controller's "port" + * node. Check if it has the "port" node first, to avoid printing the + * error message from underlying code, as it's a valid case: extcon + * device (and "port" node) may be missing in case of "usb-role-switch" + * or OTG mode. + */ + np_phy = of_parse_phandle(dev->of_node, "phys", 0); + if (of_graph_is_present(np_phy)) { + struct device_node *np_conn; + + np_conn = of_graph_get_remote_node(np_phy, -1, -1); + if (np_conn) + edev = extcon_find_edev_by_node(np_conn); + of_node_put(np_conn); + } + of_node_put(np_phy); + + return edev; +} + #if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) #define ROLE_SWITCH 1 static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, @@ -542,6 +588,10 @@ int dwc3_drd_init(struct dwc3 *dwc) device_property_read_bool(dwc->dev, "usb-role-switch")) return dwc3_setup_role_switch(dwc); + dwc->edev = dwc3_get_extcon(dwc); + if (IS_ERR(dwc->edev)) + return PTR_ERR(dwc->edev); + if (dwc->edev) { dwc->edev_nb.notifier_call = dwc3_drd_notifier; ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 4ee4ca09873a..fb14511b1e10 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -40,9 +40,10 @@ #define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee #define PCI_DEVICE_ID_INTEL_TGPH 0x43ee #define PCI_DEVICE_ID_INTEL_JSP 0x4dee -#define PCI_DEVICE_ID_INTEL_ADL 0x465e -#define PCI_DEVICE_ID_INTEL_ADLP 0x51ee -#define PCI_DEVICE_ID_INTEL_ADLM 0x54ee +#define PCI_DEVICE_ID_INTEL_ADL 0x460e +#define PCI_DEVICE_ID_INTEL_ADL_PCH 0x51ee +#define PCI_DEVICE_ID_INTEL_ADLN 0x465e +#define PCI_DEVICE_ID_INTEL_ADLN_PCH 0x54ee #define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1 #define PCI_DEVICE_ID_INTEL_RPL 0x460e #define PCI_DEVICE_ID_INTEL_RPLS 0x7a61 @@ -448,10 +449,13 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLP), + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLM), + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index d3f3937d7005..7c40f3ffc054 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -243,6 +243,7 @@ static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom) */ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom) { + enum usb_device_speed max_speed; struct device *dev = qcom->dev; int ret; @@ -252,7 +253,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom) qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr"); if (IS_ERR(qcom->icc_path_ddr)) { dev_err(dev, "failed to get usb-ddr path: %ld\n", - PTR_ERR(qcom->icc_path_ddr)); + PTR_ERR(qcom->icc_path_ddr)); return PTR_ERR(qcom->icc_path_ddr); } @@ -263,21 +264,20 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom) return PTR_ERR(qcom->icc_path_apps); } - if (usb_get_maximum_speed(&qcom->dwc3->dev) >= USB_SPEED_SUPER || - usb_get_maximum_speed(&qcom->dwc3->dev) == USB_SPEED_UNKNOWN) + max_speed = usb_get_maximum_speed(&qcom->dwc3->dev); + if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) { ret = icc_set_bw(qcom->icc_path_ddr, - USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW); - else + USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW); + } else { ret = icc_set_bw(qcom->icc_path_ddr, - USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW); - + USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW); + } if (ret) { dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret); return ret; } - ret = icc_set_bw(qcom->icc_path_apps, - APPS_USB_AVG_BW, APPS_USB_PEAK_BW); + ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW); if (ret) { dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret); return ret; @@ -1007,10 +1007,6 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { static const struct of_device_id dwc3_qcom_of_match[] = { { .compatible = "qcom,dwc3" }, - { .compatible = "qcom,msm8996-dwc3" }, - { .compatible = "qcom,msm8998-dwc3" }, - { .compatible = "qcom,sdm660-dwc3" }, - { .compatible = "qcom,sdm845-dwc3" }, { } }; MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index 67b237c7a76a..8607d4c23283 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -47,6 +47,7 @@ struct dwc3_xlnx { struct device *dev; void __iomem *regs; int (*pltfm_init)(struct dwc3_xlnx *data); + struct phy *usb3_phy; }; static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask) @@ -100,13 +101,12 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) struct device *dev = priv_data->dev; struct reset_control *crst, *hibrst, *apbrst; struct gpio_desc *reset_gpio; - struct phy *usb3_phy; int ret = 0; u32 reg; - usb3_phy = devm_phy_optional_get(dev, "usb3-phy"); - if (IS_ERR(usb3_phy)) { - ret = PTR_ERR(usb3_phy); + priv_data->usb3_phy = devm_phy_optional_get(dev, "usb3-phy"); + if (IS_ERR(priv_data->usb3_phy)) { + ret = PTR_ERR(priv_data->usb3_phy); dev_err_probe(dev, ret, "failed to get USB3 PHY\n"); goto err; @@ -121,7 +121,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) * in use but the usb3-phy entry is missing from the device tree. * Therefore, skip these operations in this case. */ - if (!usb3_phy) + if (!priv_data->usb3_phy) goto skip_usb3_phy; crst = devm_reset_control_get_exclusive(dev, "usb_crst"); @@ -166,9 +166,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) goto err; } - ret = phy_init(usb3_phy); + ret = phy_init(priv_data->usb3_phy); if (ret < 0) { - phy_exit(usb3_phy); + phy_exit(priv_data->usb3_phy); goto err; } @@ -196,9 +196,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) goto err; } - ret = phy_power_on(usb3_phy); + ret = phy_power_on(priv_data->usb3_phy); if (ret < 0) { - phy_exit(usb3_phy); + phy_exit(priv_data->usb3_phy); goto err; } @@ -322,7 +322,7 @@ static int dwc3_xlnx_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused dwc3_xlnx_suspend_common(struct device *dev) +static int __maybe_unused dwc3_xlnx_runtime_suspend(struct device *dev) { struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); @@ -331,7 +331,7 @@ static int __maybe_unused dwc3_xlnx_suspend_common(struct device *dev) return 0; } -static int __maybe_unused dwc3_xlnx_resume_common(struct device *dev) +static int __maybe_unused dwc3_xlnx_runtime_resume(struct device *dev) { struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); @@ -346,8 +346,45 @@ static int __maybe_unused dwc3_xlnx_runtime_idle(struct device *dev) return 0; } -static UNIVERSAL_DEV_PM_OPS(dwc3_xlnx_dev_pm_ops, dwc3_xlnx_suspend_common, - dwc3_xlnx_resume_common, dwc3_xlnx_runtime_idle); +static int __maybe_unused dwc3_xlnx_suspend(struct device *dev) +{ + struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); + + phy_exit(priv_data->usb3_phy); + + /* Disable the clocks */ + clk_bulk_disable(priv_data->num_clocks, priv_data->clks); + + return 0; +} + +static int __maybe_unused dwc3_xlnx_resume(struct device *dev) +{ + struct dwc3_xlnx *priv_data = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_enable(priv_data->num_clocks, priv_data->clks); + if (ret) + return ret; + + ret = phy_init(priv_data->usb3_phy); + if (ret < 0) + return ret; + + ret = phy_power_on(priv_data->usb3_phy); + if (ret < 0) { + phy_exit(priv_data->usb3_phy); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops dwc3_xlnx_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_xlnx_suspend, dwc3_xlnx_resume) + SET_RUNTIME_PM_OPS(dwc3_xlnx_runtime_suspend, + dwc3_xlnx_runtime_resume, dwc3_xlnx_runtime_idle) +}; static struct platform_driver dwc3_xlnx_driver = { .probe = dwc3_xlnx_probe, diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 197af63f8d05..61de693461da 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -197,7 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); - if (!dep->endpoint.desc || !dwc->pullups_connected) { + if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", dep->name); ret = -ESHUTDOWN; @@ -293,7 +293,10 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) continue; dwc3_ep->flags &= ~DWC3_EP_DELAY_STOP; - dwc3_stop_active_transfer(dwc3_ep, true, true); + if (dwc->connected) + dwc3_stop_active_transfer(dwc3_ep, true, true); + else + dwc3_remove_requests(dwc, dwc3_ep, -ESHUTDOWN); } } @@ -815,7 +818,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, int ret = -EINVAL; u32 len; - if (!dwc->gadget_driver || !dwc->connected) + if (!dwc->gadget_driver || !dwc->softconnect || !dwc->connected) goto out; trace_dwc3_ctrl_req(ctrl); @@ -1118,6 +1121,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, { switch (event->status) { case DEPEVT_STATUS_CONTROL_DATA: + if (!dwc->softconnect || !dwc->connected) + return; /* * We already have a DATA transfer in the controller's cache, * if we receive a XferNotReady(DATA) we will ignore it, unless diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index eca945feeec3..079cd333632e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -366,7 +366,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, dwc3_writel(dep->regs, DWC3_DEPCMD, cmd); - if (!(cmd & DWC3_DEPCMD_CMDACT)) { + if (!(cmd & DWC3_DEPCMD_CMDACT) || + (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER && + !(cmd & DWC3_DEPCMD_CMDIOC))) { ret = 0; goto skip_status; } @@ -965,29 +967,33 @@ out: return 0; } -static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) +void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status) { struct dwc3_request *req; dwc3_stop_active_transfer(dep, true, false); + /* If endxfer is delayed, avoid unmapping requests */ + if (dep->flags & DWC3_EP_DELAY_STOP) + return; + /* - giveback all requests to gadget driver */ while (!list_empty(&dep->started_list)) { req = next_request(&dep->started_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + dwc3_gadget_giveback(dep, req, status); } while (!list_empty(&dep->pending_list)) { req = next_request(&dep->pending_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + dwc3_gadget_giveback(dep, req, status); } while (!list_empty(&dep->cancelled_list)) { req = next_request(&dep->cancelled_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + dwc3_gadget_giveback(dep, req, status); } } @@ -1005,6 +1011,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; u32 reg; + u32 mask; trace_dwc3_gadget_ep_disable(dep); @@ -1022,11 +1029,19 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->endpoint.desc = NULL; } - dwc3_remove_requests(dwc, dep); + dwc3_remove_requests(dwc, dep, -ECONNRESET); dep->stream_capable = false; dep->type = 0; - dep->flags &= DWC3_EP_TXFIFO_RESIZED; + mask = DWC3_EP_TXFIFO_RESIZED; + /* + * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is + * set. Do not clear DEP flags, so that the end transfer command will + * be reattempted during the next SETUP stage. + */ + if (dep->flags & DWC3_EP_DELAY_STOP) + mask |= (DWC3_EP_DELAY_STOP | DWC3_EP_TRANSFER_STARTED); + dep->flags &= mask; return 0; } @@ -2340,7 +2355,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) if (!dep) continue; - dwc3_remove_requests(dwc, dep); + dwc3_remove_requests(dwc, dep, -ESHUTDOWN); } } @@ -2440,7 +2455,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg; - u32 timeout = 500; + u32 timeout = 2000; if (pm_runtime_suspended(dwc->dev)) return 0; @@ -2473,6 +2488,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc3_gadget_dctl_write_safe(dwc, reg); do { + usleep_range(1000, 2000); reg = dwc3_readl(dwc->regs, DWC3_DSTS); reg &= DWC3_DSTS_DEVCTRLHLT; } while (--timeout && !(!is_on ^ !reg)); @@ -2501,6 +2517,9 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) if (dwc->ep0state != EP0_SETUP_PHASE) { int ret; + if (dwc->delayed_status) + dwc3_ep0_send_delayed_status(dwc); + reinit_completion(&dwc->ep0_in_setup); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2568,6 +2587,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) return 0; } + synchronize_irq(dwc->irq_gadget); + if (!is_on) { ret = dwc3_gadget_soft_disconnect(dwc); } else { @@ -2718,6 +2739,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; + dep->flags = 0; ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); @@ -2725,6 +2747,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) } dep = dwc->eps[1]; + dep->flags = 0; ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); @@ -3568,7 +3591,7 @@ static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep, * streams are updated, and the device controller will not be * triggered to generate ERDY to move the next stream data. To * workaround this and maintain compatibility with various - * hosts, force to reinitate the stream until the host is ready + * hosts, force to reinitiate the stream until the host is ready * instead of waiting for the host to prime the endpoint. */ if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) { @@ -3596,11 +3619,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; if (!(dep->flags & DWC3_EP_ENABLED)) { - if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) + if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; /* Handle only EPCMDCMPLT when EP disabled */ - if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) + if ((event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) && + !(epnum <= 1 && event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE)) return; } @@ -3695,7 +3719,7 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, * timeout. Delay issuing the End Transfer command until the Setup TRB is * prepared. */ - if (dwc->ep0state != EP0_SETUP_PHASE && !dwc->delayed_status) { + if (dwc->ep0state != EP0_SETUP_PHASE) { dep->flags |= DWC3_EP_DELAY_STOP; return; } @@ -3763,13 +3787,24 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_INITU2ENA; dwc3_gadget_dctl_write_safe(dwc, reg); + dwc->connected = false; + dwc3_disconnect_gadget(dwc); dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); - dwc->connected = false; + if (dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + dwc3_ep0_stall_and_restart(dwc); + } } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) @@ -3867,6 +3902,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) u8 lanes = 1; u8 speed; + if (!dwc->softconnect) + return; + reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; @@ -4129,7 +4167,7 @@ static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, unsigned int is_ss = evtinfo & BIT(4); /* - * WORKAROUND: DWC3 revison 2.20a with hibernation support + * WORKAROUND: DWC3 revision 2.20a with hibernation support * have a known issue which can cause USB CV TD.9.23 to fail * randomly. * @@ -4507,12 +4545,17 @@ void dwc3_gadget_exit(struct dwc3 *dwc) int dwc3_gadget_suspend(struct dwc3 *dwc) { + unsigned long flags; + if (!dwc->gadget_driver) return 0; dwc3_gadget_run_stop(dwc, false, false); + + spin_lock_irqsave(&dwc->lock, flags); dwc3_disconnect_gadget(dwc); __dwc3_gadget_stop(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; } diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index cb998ba50fea..1975aec8d36d 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -241,7 +241,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, __entry->enqueue = dep->trb_enqueue; __entry->dequeue = dep->trb_dequeue; ), - TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)", + TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x sofn %08x (%c%c%c%c:%c%c:%s)", __get_str(name), __entry->trb, __entry->enqueue, __entry->dequeue, __entry->bph, __entry->bpl, ({char *s; @@ -267,6 +267,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, s = ""; } s; }), DWC3_TRB_SIZE_LENGTH(__entry->size), __entry->ctrl, + DWC3_TRB_CTRL_GET_SID_SOFN(__entry->ctrl), __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h', __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l', __entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c', diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e0fa4b186ec6..73dc10a77cde 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2645,10 +2645,10 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, unsigned i = 0; vla_group(d); vla_item(d, struct usb_gadget_strings *, stringtabs, - lang_count + 1); + size_add(lang_count, 1)); vla_item(d, struct usb_gadget_strings, stringtab, lang_count); vla_item(d, struct usb_string, strings, - lang_count*(needed_count+1)); + size_mul(lang_count, (needed_count + 1))); char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); @@ -3700,7 +3700,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) existing = _ffs_do_find_dev(name); if (!existing) - strlcpy(dev->name, name, ARRAY_SIZE(dev->name)); + strscpy(dev->name, name, ARRAY_SIZE(dev->name)); else if (existing != dev) ret = -EBUSY; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 925e99f9775c..3abf7f586e2a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2662,11 +2662,16 @@ static ssize_t forced_eject_store(struct device *dev, } static DEVICE_ATTR_RW(nofua); -/* mode wil be set in fsg_lun_attr_is_visible() */ -static DEVICE_ATTR(ro, 0, ro_show, ro_store); -static DEVICE_ATTR(file, 0, file_show, file_store); static DEVICE_ATTR_WO(forced_eject); +/* + * Mode of the ro and file attribute files will be overridden in + * fsg_lun_dev_is_visible() depending on if this is a cdrom, or if it is a + * removable device. + */ +static DEVICE_ATTR_RW(ro); +static DEVICE_ATTR_RW(file); + /****************************** FSG COMMON ******************************/ static void fsg_lun_release(struct device *dev) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index dc8f078f918c..c36bcfa0e9b4 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -450,39 +450,35 @@ struct ndp_parser_opts { unsigned next_ndp_index; }; -#define INIT_NDP16_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH16_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth16), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \ - .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), \ - .ndplen_align = 4, \ - .dgram_item_len = 1, \ - .block_length = 1, \ - .ndp_index = 1, \ - .reserved1 = 0, \ - .reserved2 = 0, \ - .next_ndp_index = 1, \ - } +static const struct ndp_parser_opts ndp16_opts = { + .nth_sign = USB_CDC_NCM_NTH16_SIGN, + .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, + .nth_size = sizeof(struct usb_cdc_ncm_nth16), + .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), + .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), + .ndplen_align = 4, + .dgram_item_len = 1, + .block_length = 1, + .ndp_index = 1, + .reserved1 = 0, + .reserved2 = 0, + .next_ndp_index = 1, +}; - -#define INIT_NDP32_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH32_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth32), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \ - .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), \ - .ndplen_align = 8, \ - .dgram_item_len = 2, \ - .block_length = 2, \ - .ndp_index = 2, \ - .reserved1 = 1, \ - .reserved2 = 2, \ - .next_ndp_index = 2, \ - } - -static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; -static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS; +static const struct ndp_parser_opts ndp32_opts = { + .nth_sign = USB_CDC_NCM_NTH32_SIGN, + .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, + .nth_size = sizeof(struct usb_cdc_ncm_nth32), + .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), + .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), + .ndplen_align = 8, + .dgram_item_len = 2, + .block_length = 2, + .ndp_index = 2, + .reserved1 = 1, + .reserved2 = 2, + .next_ndp_index = 2, +}; static inline void put_ncm(__le16 **p, unsigned size, unsigned val) { diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index abec5c58f525..a881c69b1f2b 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -89,7 +89,7 @@ struct printer_dev { u8 printer_cdev_open; wait_queue_head_t wait; unsigned q_len; - char *pnp_string; /* We don't own memory! */ + char **pnp_string; /* We don't own memory! */ struct usb_function function; }; @@ -1000,16 +1000,16 @@ static int printer_func_setup(struct usb_function *f, if ((wIndex>>8) != dev->interface) break; - if (!dev->pnp_string) { + if (!*dev->pnp_string) { value = 0; break; } - value = strlen(dev->pnp_string); + value = strlen(*dev->pnp_string); buf[0] = (value >> 8) & 0xFF; buf[1] = value & 0xFF; - memcpy(buf + 2, dev->pnp_string, value); + memcpy(buf + 2, *dev->pnp_string, value); DBG(dev, "1284 PNP String: %x %s\n", value, - dev->pnp_string); + *dev->pnp_string); break; case GET_PORT_STATUS: /* Get Port Status */ @@ -1475,7 +1475,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) kref_init(&dev->kref); ++opts->refcnt; dev->minor = opts->minor; - dev->pnp_string = opts->pnp_string; + dev->pnp_string = &opts->pnp_string; dev->q_len = opts->q_len; mutex_unlock(&opts->lock); diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 8e17ac831be0..658e2e21fdd0 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -2306,7 +2306,7 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc); -static int tcm_init(void) +static int __init tcm_init(void) { int ret; @@ -2322,7 +2322,7 @@ static int tcm_init(void) } module_init(tcm_init); -static void tcm_exit(void) +static void __exit tcm_exit(void) { target_unregister_template(&usbg_ops); usb_function_unregister(&tcmusb_func); diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 71669e0e4d00..6e196e06181e 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -421,7 +421,7 @@ uvc_register_video(struct uvc_device *uvc) int ret; /* TODO reference counting. */ - memset(&uvc->vdev, 0, sizeof(uvc->video)); + memset(&uvc->vdev, 0, sizeof(uvc->vdev)); uvc->vdev.v4l2_dev = &uvc->v4l2_dev; uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; uvc->vdev.fops = &uvc_v4l2_fops; @@ -430,7 +430,7 @@ uvc_register_video(struct uvc_device *uvc) uvc->vdev.vfl_dir = VFL_DIR_TX; uvc->vdev.lock = &uvc->video.mutex; uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); + strscpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); video_set_drvdata(&uvc->vdev, uvc); @@ -888,6 +888,7 @@ static void uvc_free(struct usb_function *f) struct uvc_device *uvc = to_uvc(f); struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, func_inst); + config_item_put(&uvc->header->item); --opts->refcnt; kfree(uvc); } @@ -897,10 +898,14 @@ static void uvc_function_unbind(struct usb_configuration *c, { struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); + struct uvc_video *video = &uvc->video; long wait_ret = 1; uvcg_info(f, "%s()\n", __func__); + if (video->async_wq) + destroy_workqueue(video->async_wq); + /* * If we know we're connected via v4l2, then there should be a cleanup * of the device from userspace either via UVC_EVENT_DISCONNECT or @@ -941,6 +946,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) struct uvc_device *uvc; struct f_uvc_opts *opts; struct uvc_descriptor_header **strm_cls; + struct config_item *streaming, *header, *h; uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); if (uvc == NULL) @@ -973,6 +979,28 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->desc.fs_streaming = opts->fs_streaming; uvc->desc.hs_streaming = opts->hs_streaming; uvc->desc.ss_streaming = opts->ss_streaming; + + streaming = config_group_find_item(&opts->func_inst.group, "streaming"); + if (!streaming) + goto err_config; + + header = config_group_find_item(to_config_group(streaming), "header"); + config_item_put(streaming); + if (!header) + goto err_config; + + h = config_group_find_item(to_config_group(header), "h"); + config_item_put(header); + if (!h) + goto err_config; + + uvc->header = to_uvcg_streaming_header(h); + if (!uvc->header->linked) { + mutex_unlock(&opts->lock); + kfree(uvc); + return ERR_PTR(-EBUSY); + } + ++opts->refcnt; mutex_unlock(&opts->lock); @@ -988,6 +1016,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->func.bind_deactivated = true; return &uvc->func; + +err_config: + mutex_unlock(&opts->lock); + kfree(uvc); + return ERR_PTR(-ENOENT); } DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 713efd9aefde..29bf8664bf58 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -869,7 +869,7 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser); static inline int rndis_get_nr(void) { - return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL); + return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL); } static inline void rndis_put_nr(int nr) @@ -1105,7 +1105,7 @@ static int rndis_proc_show(struct seq_file *m, void *v) "used : %s\n" "state : %s\n" "medium : 0x%08X\n" - "speed : %d\n" + "speed : %u\n" "cable : %s\n" "vendor ID : 0x%08X\n" "vendor : %s\n", diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 7887def05dc2..e06022873df1 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -144,10 +144,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) { struct eth_dev *dev = netdev_priv(net); - strlcpy(p->driver, "g_ether", sizeof(p->driver)); - strlcpy(p->version, UETH__VERSION, sizeof(p->version)); - strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); - strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + strscpy(p->driver, "g_ether", sizeof(p->driver)); + strscpy(p->version, UETH__VERSION, sizeof(p->version)); + strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); + strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); } /* REVISIT can also support: diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 6f68cbeeee7c..7538279f9817 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1443,7 +1443,7 @@ void gserial_resume(struct gserial *gser) } EXPORT_SYMBOL_GPL(gserial_resume); -static int userial_init(void) +static int __init userial_init(void) { struct tty_driver *driver; unsigned i; @@ -1496,7 +1496,7 @@ fail: } module_init(userial_init); -static void userial_cleanup(void) +static void __exit userial_cleanup(void) { tty_unregister_driver(gs_tty_driver); tty_driver_kref_put(gs_tty_driver); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 58e383afdd44..40226b1f7e14 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -88,6 +88,7 @@ struct uvc_video { struct usb_ep *ep; struct work_struct pump; + struct workqueue_struct *async_wq; /* Frame parameters */ u8 bpp; @@ -133,6 +134,8 @@ struct uvc_device { bool func_connected; wait_queue_head_t func_connected_queue; + struct uvcg_streaming_header *header; + /* Descriptors */ struct { const struct uvc_descriptor_header * const *fs_control; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index fd8f73bb726d..c4ed48d6b8a4 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -18,12 +18,161 @@ #include #include #include +#include #include "f_uvc.h" #include "uvc.h" #include "uvc_queue.h" #include "uvc_video.h" #include "uvc_v4l2.h" +#include "uvc_configfs.h" + +static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat) +{ + char guid[16] = UVC_GUID_FORMAT_MJPEG; + struct uvc_format_desc *format; + struct uvcg_uncompressed *unc; + + if (uformat->type == UVCG_UNCOMPRESSED) { + unc = to_uvcg_uncompressed(&uformat->group.cg_item); + if (!unc) + return ERR_PTR(-EINVAL); + + memcpy(guid, unc->desc.guidFormat, sizeof(guid)); + } + + format = uvc_format_by_guid(guid); + if (!format) + return ERR_PTR(-EINVAL); + + return format; +} + +static int uvc_v4l2_get_bytesperline(struct uvcg_format *uformat, + struct uvcg_frame *uframe) +{ + struct uvcg_uncompressed *u; + + if (uformat->type == UVCG_UNCOMPRESSED) { + u = to_uvcg_uncompressed(&uformat->group.cg_item); + if (!u) + return 0; + + return u->desc.bBitsPerPixel * uframe->frame.w_width / 8; + } + + return 0; +} + +static int uvc_get_frame_size(struct uvcg_format *uformat, + struct uvcg_frame *uframe) +{ + unsigned int bpl = uvc_v4l2_get_bytesperline(uformat, uframe); + + return bpl ? bpl * uframe->frame.w_height : + uframe->frame.dw_max_video_frame_buffer_size; +} + +static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index) +{ + struct uvcg_format_ptr *format; + struct uvcg_format *uformat = NULL; + int i = 1; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (index == i) { + uformat = format->fmt; + break; + } + i++; + } + + return uformat; +} + +static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc, + struct uvcg_format *uformat, + int index) +{ + struct uvcg_format_ptr *format; + struct uvcg_frame_ptr *frame; + struct uvcg_frame *uframe = NULL; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (format->fmt->type != uformat->type) + continue; + list_for_each_entry(frame, &format->fmt->frames, entry) { + if (index == frame->frm->frame.b_frame_index) { + uframe = frame->frm; + break; + } + } + } + + return uframe; +} + +static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc, + u32 pixelformat) +{ + struct uvcg_format_ptr *format; + struct uvcg_format *uformat = NULL; + + list_for_each_entry(format, &uvc->header->formats, entry) { + struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt); + + if (fmtdesc->fcc == pixelformat) { + uformat = format->fmt; + break; + } + } + + return uformat; +} + +static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc, + struct uvcg_format *uformat, + u16 rw, u16 rh) +{ + struct uvc_video *video = &uvc->video; + struct uvcg_format_ptr *format; + struct uvcg_frame_ptr *frame; + struct uvcg_frame *uframe = NULL; + unsigned int d, maxd; + + /* Find the closest image size. The distance between image sizes is + * the size in pixels of the non-overlapping regions between the + * requested size and the frame-specified size. + */ + maxd = (unsigned int)-1; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (format->fmt->type != uformat->type) + continue; + + list_for_each_entry(frame, &format->fmt->frames, entry) { + u16 w, h; + + w = frame->frm->frame.w_width; + h = frame->frm->frame.w_height; + + d = min(w, rw) * min(h, rh); + d = w*h + rw*rh - 2*d; + if (d < maxd) { + maxd = d; + uframe = frame->frm; + } + + if (maxd == 0) + break; + } + } + + if (!uframe) + uvcg_dbg(&video->uvc->func, "Unsupported size %ux%u\n", rw, rh); + + return uframe; +} /* -------------------------------------------------------------------------- * Requests handling @@ -67,9 +216,9 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) struct uvc_device *uvc = video_get_drvdata(vdev); struct usb_composite_dev *cdev = uvc->func.config->cdev; - strlcpy(cap->driver, "g_uvc", sizeof(cap->driver)); - strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), + strscpy(cap->driver, "g_uvc", sizeof(cap->driver)); + strscpy(cap->card, cdev->gadget->name, sizeof(cap->card)); + strscpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof(cap->bus_info)); return 0; } @@ -134,6 +283,139 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) return 0; } +static int +uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_video *video = &uvc->video; + struct uvcg_format *uformat; + struct uvcg_frame *uframe; + u8 *fcc; + + if (fmt->type != video->queue.queue.type) + return -EINVAL; + + fcc = (u8 *)&fmt->fmt.pix.pixelformat; + uvcg_dbg(&uvc->func, "Trying format 0x%08x (%c%c%c%c): %ux%u\n", + fmt->fmt.pix.pixelformat, + fcc[0], fcc[1], fcc[2], fcc[3], + fmt->fmt.pix.width, fmt->fmt.pix.height); + + uformat = find_format_by_pix(uvc, fmt->fmt.pix.pixelformat); + if (!uformat) + return -EINVAL; + + uframe = find_closest_frame_by_size(uvc, uformat, + fmt->fmt.pix.width, fmt->fmt.pix.height); + if (!uframe) + return -EINVAL; + + fmt->fmt.pix.width = uframe->frame.w_width; + fmt->fmt.pix.height = uframe->frame.w_height; + fmt->fmt.pix.field = V4L2_FIELD_NONE; + fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe); + fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe); + fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + fmt->fmt.pix.priv = 0; + + return 0; +} + +static int +uvc_v4l2_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvcg_format *uformat = NULL; + struct uvcg_frame *uframe = NULL; + struct uvcg_frame_ptr *frame; + + uformat = find_format_by_pix(uvc, fival->pixel_format); + if (!uformat) + return -EINVAL; + + list_for_each_entry(frame, &uformat->frames, entry) { + if (frame->frm->frame.w_width == fival->width && + frame->frm->frame.w_height == fival->height) { + uframe = frame->frm; + break; + } + } + if (!uframe) + return -EINVAL; + + if (fival->index >= uframe->frame.b_frame_interval_type) + return -EINVAL; + + fival->discrete.numerator = + uframe->dw_frame_interval[fival->index]; + + /* TODO: handle V4L2_FRMIVAL_TYPE_STEPWISE */ + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.denominator = 10000000; + v4l2_simplify_fraction(&fival->discrete.numerator, + &fival->discrete.denominator, 8, 333); + + return 0; +} + +static int +uvc_v4l2_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvcg_format *uformat = NULL; + struct uvcg_frame *uframe = NULL; + + uformat = find_format_by_pix(uvc, fsize->pixel_format); + if (!uformat) + return -EINVAL; + + if (fsize->index >= uformat->num_frames) + return -EINVAL; + + uframe = find_frame_by_index(uvc, uformat, fsize->index + 1); + if (!uframe) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = uframe->frame.w_width; + fsize->discrete.height = uframe->frame.w_height; + + return 0; +} + +static int +uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_format_desc *fmtdesc; + struct uvcg_format *uformat; + + if (f->index >= uvc->header->num_fmt) + return -EINVAL; + + uformat = find_format_by_index(uvc, f->index + 1); + if (!uformat) + return -EINVAL; + + if (uformat->type != UVCG_UNCOMPRESSED) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + + fmtdesc = to_uvc_format(uformat); + f->pixelformat = fmtdesc->fcc; + + strscpy(f->description, fmtdesc->name, sizeof(f->description)); + f->description[strlen(fmtdesc->name) - 1] = 0; + + return 0; +} + static int uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) { @@ -170,7 +452,7 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) return ret; if (uvc->state == UVC_STATE_STREAMING) - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); return ret; } @@ -298,8 +580,12 @@ uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio, const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = { .vidioc_querycap = uvc_v4l2_querycap, + .vidioc_try_fmt_vid_out = uvc_v4l2_try_format, .vidioc_g_fmt_vid_out = uvc_v4l2_get_format, .vidioc_s_fmt_vid_out = uvc_v4l2_set_format, + .vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals, + .vidioc_enum_framesizes = uvc_v4l2_enum_framesizes, + .vidioc_enum_fmt_vid_out = uvc_v4l2_enum_format, .vidioc_reqbufs = uvc_v4l2_reqbufs, .vidioc_querybuf = uvc_v4l2_querybuf, .vidioc_qbuf = uvc_v4l2_qbuf, diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index c00ce0e91f5d..bb037fcc90e6 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -277,7 +277,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock_irqrestore(&video->req_lock, flags); if (uvc->state == UVC_STATE_STREAMING) - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); } static int @@ -485,7 +485,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable) video->req_int_count = 0; - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); return ret; } @@ -499,6 +499,11 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) spin_lock_init(&video->req_lock); INIT_WORK(&video->pump, uvcg_video_pump); + /* Allocate a work queue for asynchronous video pump handler. */ + video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!video->async_wq) + return -EINVAL; + video->uvc = uvc; video->fcc = V4L2_PIX_FMT_YUYV; video->bpp = 16; diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 728987280373..a9a7b3fc60ec 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -994,7 +994,7 @@ static const struct usb_gadget_ops at91_udc_ops = { .udc_stop = at91_stop, /* - * VBUS-powered devices may also also want to support bigger + * VBUS-powered devices may also want to support bigger * power budgets after an appropriate SET_CONFIGURATION. */ /* .vbus_power = at91_vbus_power, */ @@ -1779,12 +1779,14 @@ static void at91udc_of_init(struct at91_udc *udc, struct device_node *np) if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0) board->vbus_polled = 1; - board->vbus_pin = gpiod_get_from_of_node(np, "atmel,vbus-gpio", 0, - GPIOD_IN, "udc_vbus"); + board->vbus_pin = fwnode_gpiod_get_index(of_fwnode_handle(np), + "atmel,vbus", 0, GPIOD_IN, + "udc_vbus"); if (IS_ERR(board->vbus_pin)) board->vbus_pin = NULL; - board->pullup_pin = gpiod_get_from_of_node(np, "atmel,pullup-gpio", 0, + board->pullup_pin = fwnode_gpiod_get_index(of_fwnode_handle(np), + "atmel,pullup", 0, GPIOD_ASIS, "udc_pullup"); if (IS_ERR(board->pullup_pin)) board->pullup_pin = NULL; diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index c97cd4bc817c..84605a4d0715 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -91,7 +91,7 @@ module_param(dma_mode, ushort, 0644); * mode 2 == ep-a 1k, ep-b 1k, ep-c 512db * mode 3 == ep-a 1k, ep-b disabled, ep-c 512db */ -static ushort fifo_mode = 0; +static ushort fifo_mode; module_param(fifo_mode, ushort, 0644); /* @@ -100,7 +100,7 @@ module_param(fifo_mode, ushort, 0644); * USB suspend requests will be ignored. This is acceptable for * self-powered devices. For bus powered devices set this to 1. */ -static ushort enable_suspend = 0; +static ushort enable_suspend; module_param(enable_suspend, ushort, 0644); static void assert_out_naking(struct net2272_ep *ep, const char *where) diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index 61cabb9de6ae..bea346e362b2 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2234,7 +2234,7 @@ static int proc_otg_show(struct seq_file *s) char *ctrl_name = "(UNKNOWN)"; tmp = omap_readl(OTG_REV); - ctrl_name = "tranceiver_ctrl"; + ctrl_name = "transceiver_ctrl"; trans = omap_readw(USB_TRANSCEIVER_CTRL); seq_printf(s, "\nOTG rev %d.%d, %s %05x\n", tmp >> 4, tmp & 0xf, ctrl_name, trans); @@ -2558,7 +2558,7 @@ omap_ep_setup(char *name, u8 addr, u8 type, /* set up driver data structures */ BUG_ON(strlen(name) >= sizeof ep->name); - strlcpy(ep->name, name, sizeof ep->name); + strscpy(ep->name, name, sizeof(ep->name)); INIT_LIST_HEAD(&ep->queue); INIT_LIST_HEAD(&ep->iso); ep->bEndpointAddress = addr; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 648be3fd476a..615ba0a6fbee 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -38,16 +39,16 @@ #define USB3_USB20_CON 0x204 #define USB3_USB30_CON 0x208 #define USB3_USB_STA 0x210 -#define USB3_DRD_CON 0x218 +#define USB3_DRD_CON(p) ((p)->is_rzv2m ? 0x400 : 0x218) #define USB3_USB_INT_STA_1 0x220 #define USB3_USB_INT_STA_2 0x224 #define USB3_USB_INT_ENA_1 0x228 #define USB3_USB_INT_ENA_2 0x22c #define USB3_STUP_DAT_0 0x230 #define USB3_STUP_DAT_1 0x234 -#define USB3_USB_OTG_STA 0x268 -#define USB3_USB_OTG_INT_STA 0x26c -#define USB3_USB_OTG_INT_ENA 0x270 +#define USB3_USB_OTG_STA(p) ((p)->is_rzv2m ? 0x410 : 0x268) +#define USB3_USB_OTG_INT_STA(p) ((p)->is_rzv2m ? 0x414 : 0x26c) +#define USB3_USB_OTG_INT_ENA(p) ((p)->is_rzv2m ? 0x418 : 0x270) #define USB3_P0_MOD 0x280 #define USB3_P0_CON 0x288 #define USB3_P0_STA 0x28c @@ -135,6 +136,8 @@ #define USB_STA_VBUS_STA BIT(0) /* DRD_CON */ +#define DRD_CON_PERI_RST BIT(31) /* rzv2m only */ +#define DRD_CON_HOST_RST BIT(30) /* rzv2m only */ #define DRD_CON_PERI_CON BIT(24) #define DRD_CON_VBOUT BIT(0) @@ -155,7 +158,7 @@ #define USB_INT_2_PIPE(n) BIT(n) /* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */ -#define USB_OTG_IDMON BIT(4) +#define USB_OTG_IDMON(p) ((p)->is_rzv2m ? BIT(0) : BIT(4)) /* P0_MOD */ #define P0_MOD_DIR BIT(6) @@ -255,7 +258,7 @@ #define USB3_EP0_SS_MAX_PACKET_SIZE 512 #define USB3_EP0_HSFS_MAX_PACKET_SIZE 64 #define USB3_EP0_BUF_SIZE 8 -#define USB3_MAX_NUM_PIPES 6 /* This includes PIPE 0 */ +#define USB3_MAX_NUM_PIPES(p) ((p)->is_rzv2m ? 16 : 6) /* This includes PIPE 0 */ #define USB3_WAIT_US 3 #define USB3_DMA_NUM_SETTING_AREA 4 /* @@ -326,10 +329,13 @@ struct renesas_usb3_priv { int num_ramif; int ramsize_per_pipe; /* unit = bytes */ bool workaround_for_vbus; /* if true, don't check vbus signal */ + bool is_rzv2m; /* if true, RZ/V2M SoC */ }; struct renesas_usb3 { void __iomem *reg; + struct reset_control *drd_rstc; + struct reset_control *usbp_rstc; struct usb_gadget gadget; struct usb_gadget_driver *driver; @@ -363,6 +369,7 @@ struct renesas_usb3 { bool forced_b_device; bool start_to_connect; bool role_sw_by_connector; + bool is_rzv2m; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -467,7 +474,7 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num) static bool usb3_is_host(struct renesas_usb3 *usb3) { - return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON); + return !(usb3_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON); } static void usb3_init_axi_bridge(struct renesas_usb3 *usb3) @@ -674,10 +681,20 @@ static void renesas_usb3_role_work(struct work_struct *work) static void usb3_set_mode(struct renesas_usb3 *usb3, bool host) { + if (usb3->is_rzv2m) { + if (host) { + usb3_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3)); + usb3_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3)); + } else { + usb3_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3)); + usb3_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3)); + } + } + if (host) - usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON); + usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3)); else - usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON); + usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3)); } static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host) @@ -693,9 +710,9 @@ static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host) static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable) { if (enable) - usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON); + usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3)); else - usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON); + usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3)); } static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) @@ -716,7 +733,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) static bool usb3_is_a_device(struct renesas_usb3 *usb3) { - return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON); + return !(usb3_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3)); } static void usb3_check_id(struct renesas_usb3 *usb3) @@ -739,8 +756,8 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3) usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL | USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP, USB3_USB_COM_CON); - usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA); - usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA); + usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3)); + usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3)); usb3_check_id(usb3); usb3_check_vbus(usb3); @@ -750,7 +767,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3) { usb3_disconnect(usb3); usb3_write(usb3, 0, USB3_P0_INT_ENA); - usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA); + usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3)); usb3_write(usb3, 0, USB3_USB_INT_ENA_1); usb3_write(usb3, 0, USB3_USB_INT_ENA_2); usb3_write(usb3, 0, USB3_AXI_INT_ENA); @@ -2005,9 +2022,15 @@ static void usb3_irq_idmon_change(struct renesas_usb3 *usb3) usb3_check_id(usb3); } -static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta) +static void usb3_irq_otg_int(struct renesas_usb3 *usb3) { - if (otg_int_sta & USB_OTG_IDMON) + u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA(usb3)); + + otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA(usb3)); + if (otg_int_sta) + usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3)); + + if (otg_int_sta & USB_OTG_IDMON(usb3)) usb3_irq_idmon_change(usb3); } @@ -2015,7 +2038,6 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3) { u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1); u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2); - u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA); int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1); if (int_sta_1) { @@ -2027,11 +2049,8 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3) if (int_sta_2) usb3_irq_epc_int_2(usb3, int_sta_2); - otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA); - if (otg_int_sta) { - usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA); - usb3_irq_otg_int(usb3, otg_int_sta); - } + if (!usb3->is_rzv2m) + usb3_irq_otg_int(usb3); } static void usb3_irq_dma_int(struct renesas_usb3 *usb3, u32 dma_sta) @@ -2085,6 +2104,15 @@ static irqreturn_t renesas_usb3_irq(int irq, void *_usb3) return ret; } +static irqreturn_t renesas_usb3_otg_irq(int irq, void *_usb3) +{ + struct renesas_usb3 *usb3 = _usb3; + + usb3_irq_otg_int(usb3); + + return IRQ_HANDLED; +} + static void usb3_write_pn_mod(struct renesas_usb3_ep *usb3_ep, const struct usb_endpoint_descriptor *desc) { @@ -2571,6 +2599,8 @@ static int renesas_usb3_remove(struct platform_device *pdev) usb_role_switch_unregister(usb3->role_sw); usb_del_gadget_udc(&usb3->gadget); + reset_control_assert(usb3->usbp_rstc); + reset_control_assert(usb3->drd_rstc); renesas_usb3_dma_free_prd(usb3, &pdev->dev); __renesas_usb3_ep_free_request(usb3->ep0_req); @@ -2589,8 +2619,8 @@ static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev, usb3->num_usb3_eps = priv->ramsize_per_ramif * priv->num_ramif * 2 / priv->ramsize_per_pipe + 1; - if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES) - usb3->num_usb3_eps = USB3_MAX_NUM_PIPES; + if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES(usb3)) + usb3->num_usb3_eps = USB3_MAX_NUM_PIPES(usb3); usb3->usb3_ep = devm_kcalloc(dev, usb3->num_usb3_eps, sizeof(*usb3_ep), @@ -2707,6 +2737,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { .workaround_for_vbus = true, }; +static const struct renesas_usb3_priv renesas_usb3_priv_rzv2m = { + .ramsize_per_ramif = SZ_16K, + .num_ramif = 1, + .ramsize_per_pipe = SZ_4K, + .is_rzv2m = true, +}; + static const struct of_device_id usb3_of_match[] = { { .compatible = "renesas,r8a774c0-usb3-peri", @@ -2717,6 +2754,9 @@ static const struct of_device_id usb3_of_match[] = { }, { .compatible = "renesas,r8a77990-usb3-peri", .data = &renesas_usb3_priv_r8a77990, + }, { + .compatible = "renesas,rzv2m-usb3-peri", + .data = &renesas_usb3_priv_rzv2m, }, { .compatible = "renesas,rcar-gen3-usb3-peri", .data = &renesas_usb3_priv_gen3, @@ -2748,7 +2788,7 @@ static struct usb_role_switch_desc renesas_usb3_role_switch_desc = { static int renesas_usb3_probe(struct platform_device *pdev) { struct renesas_usb3 *usb3; - int irq, ret; + int irq, drd_irq, ret; const struct renesas_usb3_priv *priv; const struct soc_device_attribute *attr; @@ -2762,10 +2802,18 @@ static int renesas_usb3_probe(struct platform_device *pdev) if (irq < 0) return irq; + if (priv->is_rzv2m) { + drd_irq = platform_get_irq_byname(pdev, "drd"); + if (drd_irq < 0) + return drd_irq; + } + usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); if (!usb3) return -ENOMEM; + usb3->is_rzv2m = priv->is_rzv2m; + usb3->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(usb3->reg)) return PTR_ERR(usb3->reg); @@ -2787,6 +2835,14 @@ static int renesas_usb3_probe(struct platform_device *pdev) if (ret < 0) return ret; + if (usb3->is_rzv2m) { + ret = devm_request_irq(&pdev->dev, drd_irq, + renesas_usb3_otg_irq, 0, + dev_name(&pdev->dev), usb3); + if (ret < 0) + return ret; + } + INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work); usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable); if (IS_ERR(usb3->extcon)) @@ -2817,10 +2873,27 @@ static int renesas_usb3_probe(struct platform_device *pdev) goto err_add_udc; } + usb3->drd_rstc = devm_reset_control_get_optional_shared(&pdev->dev, + "drd_reset"); + if (IS_ERR(usb3->drd_rstc)) { + ret = PTR_ERR(usb3->drd_rstc); + goto err_add_udc; + } + + usb3->usbp_rstc = devm_reset_control_get_optional_shared(&pdev->dev, + "aresetn_p"); + if (IS_ERR(usb3->usbp_rstc)) { + ret = PTR_ERR(usb3->usbp_rstc); + goto err_add_udc; + } + + reset_control_deassert(usb3->drd_rstc); + reset_control_deassert(usb3->usbp_rstc); + pm_runtime_enable(&pdev->dev); ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget); if (ret < 0) - goto err_add_udc; + goto err_reset; ret = device_create_file(&pdev->dev, &dev_attr_role); if (ret < 0) @@ -2858,6 +2931,10 @@ static int renesas_usb3_probe(struct platform_device *pdev) err_dev_create: usb_del_gadget_udc(&usb3->gadget); +err_reset: + reset_control_assert(usb3->usbp_rstc); + reset_control_assert(usb3->drd_rstc); + err_add_udc: renesas_usb3_dma_free_prd(usb3, &pdev->dev); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index c6625aeb7bca..8c57b191e52b 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -1419,8 +1419,7 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) { dprintk(DEBUG_NORMAL, "%s()\n", __func__); - if (udc_info && (udc_info->udc_command || - gpio_is_valid(udc_info->pullup_pin))) { + if (udc_info && (udc_info->udc_command || udc->pullup_gpiod)) { if (is_on) s3c2410_udc_enable(udc); @@ -1467,9 +1466,7 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev) dprintk(DEBUG_NORMAL, "%s()\n", __func__); - value = gpio_get_value(udc_info->vbus_pin) ? 1 : 0; - if (udc_info->vbus_pin_inverted) - value = !value; + value = gpiod_get_value(dev->vbus_gpiod); if (value != dev->vbus) s3c2410_udc_vbus_session(&dev->gadget, value); @@ -1504,14 +1501,15 @@ static const struct usb_gadget_ops s3c2410_ops = { .udc_stop = s3c2410_udc_stop, }; -static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) +static void s3c2410_udc_command(struct s3c2410_udc *udc, + enum s3c2410_udc_cmd_e cmd) { if (!udc_info) return; if (udc_info->udc_command) { udc_info->udc_command(cmd); - } else if (gpio_is_valid(udc_info->pullup_pin)) { + } else if (udc->pullup_gpiod) { int value; switch (cmd) { @@ -1524,9 +1522,8 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) default: return; } - value ^= udc_info->pullup_pin_inverted; - gpio_set_value(udc_info->pullup_pin, value); + gpiod_set_value(udc->pullup_gpiod, value); } } @@ -1551,7 +1548,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev) udc_write(0x1F, S3C2410_UDC_EP_INT_REG); /* Good bye, cruel world */ - s3c2410_udc_command(S3C2410_UDC_P_DISABLE); + s3c2410_udc_command(dev, S3C2410_UDC_P_DISABLE); /* Set speed to unknown */ dev->gadget.speed = USB_SPEED_UNKNOWN; @@ -1613,7 +1610,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); /* time to say "hello, world" */ - s3c2410_udc_command(S3C2410_UDC_P_ENABLE); + s3c2410_udc_command(dev, S3C2410_UDC_P_ENABLE); } static int s3c2410_udc_start(struct usb_gadget *g, @@ -1802,14 +1799,15 @@ static int s3c2410_udc_probe(struct platform_device *pdev) dev_dbg(dev, "got irq %i\n", irq_usbd); - if (udc_info && udc_info->vbus_pin > 0) { - retval = gpio_request(udc_info->vbus_pin, "udc vbus"); - if (retval < 0) { - dev_err(dev, "cannot claim vbus pin\n"); - goto err_int; - } + udc->vbus_gpiod = gpiod_get_optional(dev, "vbus", GPIOD_IN); + if (IS_ERR(udc->vbus_gpiod)) { + retval = PTR_ERR(udc->vbus_gpiod); + goto err_int; + } + if (udc->vbus_gpiod) { + gpiod_set_consumer_name(udc->vbus_gpiod, "udc vbus"); - irq = gpio_to_irq(udc_info->vbus_pin); + irq = gpiod_to_irq(udc->vbus_gpiod); if (irq < 0) { dev_err(dev, "no irq for gpio vbus pin\n"); retval = irq; @@ -1833,16 +1831,12 @@ static int s3c2410_udc_probe(struct platform_device *pdev) udc->vbus = 1; } - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) { - - retval = gpio_request_one(udc_info->pullup_pin, - udc_info->vbus_pin_inverted ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - "udc pullup"); - if (retval) - goto err_vbus_irq; + udc->pullup_gpiod = gpiod_get_optional(dev, "pullup", GPIOD_OUT_LOW); + if (IS_ERR(udc->pullup_gpiod)) { + retval = PTR_ERR(udc->pullup_gpiod); + goto err_vbus_irq; } + gpiod_set_consumer_name(udc->pullup_gpiod, "udc pullup"); retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) @@ -1856,15 +1850,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev) return 0; err_add_udc: - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) - gpio_free(udc_info->pullup_pin); err_vbus_irq: - if (udc_info && udc_info->vbus_pin > 0) - free_irq(gpio_to_irq(udc_info->vbus_pin), udc); + if (udc->vbus_gpiod) + free_irq(gpiod_to_irq(udc->vbus_gpiod), udc); err_gpio_claim: - if (udc_info && udc_info->vbus_pin > 0) - gpio_free(udc_info->vbus_pin); err_int: free_irq(irq_usbd, udc); err_udc_clk: @@ -1885,7 +1874,6 @@ err_usb_bus_clk: static int s3c2410_udc_remove(struct platform_device *pdev) { struct s3c2410_udc *udc = platform_get_drvdata(pdev); - unsigned int irq; dev_dbg(&pdev->dev, "%s()\n", __func__); @@ -1895,14 +1883,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev) usb_del_gadget_udc(&udc->gadget); debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root)); - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) - gpio_free(udc_info->pullup_pin); - - if (udc_info && udc_info->vbus_pin > 0) { - irq = gpio_to_irq(udc_info->vbus_pin); - free_irq(irq, udc); - } + if (udc->vbus_gpiod) + free_irq(gpiod_to_irq(udc->vbus_gpiod), udc); free_irq(irq_usbd, udc); @@ -1926,14 +1908,18 @@ static int s3c2410_udc_remove(struct platform_device *pdev) static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) { - s3c2410_udc_command(S3C2410_UDC_P_DISABLE); + struct s3c2410_udc *udc = platform_get_drvdata(pdev); + + s3c2410_udc_command(udc, S3C2410_UDC_P_DISABLE); return 0; } static int s3c2410_udc_resume(struct platform_device *pdev) { - s3c2410_udc_command(S3C2410_UDC_P_ENABLE); + struct s3c2410_udc *udc = platform_get_drvdata(pdev); + + s3c2410_udc_command(udc, S3C2410_UDC_P_ENABLE); return 0; } diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h index 135a5bff3c74..cdbf202e5ee8 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.h +++ b/drivers/usb/gadget/udc/s3c2410_udc.h @@ -83,6 +83,9 @@ struct s3c2410_udc { u32 port_status; int ep0state; + struct gpio_desc *vbus_gpiod; + struct gpio_desc *pullup_gpiod; + unsigned got_irq : 1; unsigned req_std : 1; diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 3c37effdfa64..76919d7570d2 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2,7 +2,7 @@ /* * NVIDIA Tegra XUSB device mode controller * - * Copyright (c) 2013-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2015, Google Inc. */ @@ -702,6 +702,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc) pm_runtime_get_sync(xudc->dev); + tegra_phy_xusb_utmi_pad_power_on(xudc->curr_utmi_phy); + err = phy_power_on(xudc->curr_utmi_phy); if (err < 0) dev_err(xudc->dev, "UTMI power on failed: %d\n", err); @@ -756,6 +758,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) /* Make sure interrupt handler has completed before powergating. */ synchronize_irq(xudc->irq); + tegra_phy_xusb_utmi_pad_power_down(xudc->curr_utmi_phy); + err = phy_power_off(xudc->curr_utmi_phy); if (err < 0) dev_err(xudc->dev, "UTMI PHY power off failed: %d\n", err); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index fd9264cf6c87..247568bc17a2 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -205,12 +205,12 @@ config USB_EHCI_FSL Variation of ARC USB block used in some Freescale chips. config USB_EHCI_HCD_NPCM7XX - tristate "Support for Nuvoton NPCM7XX on-chip EHCI USB controller" - depends on (USB_EHCI_HCD && ARCH_NPCM7XX) || COMPILE_TEST - default y if (USB_EHCI_HCD && ARCH_NPCM7XX) + tristate "Support for Nuvoton NPCM on-chip EHCI USB controller" + depends on (USB_EHCI_HCD && ARCH_NPCM) || COMPILE_TEST + default y if (USB_EHCI_HCD && ARCH_NPCM) help Enables support for the on-chip EHCI controller on - Nuvoton NPCM7XX chips. + Nuvoton NPCM chips. config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 05d41fd65f25..8b775e7bab06 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -25,8 +25,6 @@ #define DRIVER_DESC "EHCI Atmel driver" -static const char hcd_name[] = "ehci-atmel"; - #define EHCI_INSNREG(index) ((index) * 4 + 0x90) #define EHCI_INSNREG08_HSIC_EN BIT(2) @@ -239,7 +237,6 @@ static int __init ehci_atmel_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides); return platform_driver_register(&ehci_atmel_driver); } diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 1a9b7572e17f..a333231616f4 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,7 +32,6 @@ (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) -static const char hcd_name[] = "ehci-exynos"; static struct hc_driver __read_mostly exynos_ehci_hc_driver; #define PHY_NUMBER 3 @@ -132,20 +131,13 @@ static void exynos_ehci_phy_disable(struct device *dev) static void exynos_setup_vbus_gpio(struct device *dev) { + struct gpio_desc *gpio; int err; - int gpio; - if (!dev->of_node) - return; - - gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return; - - err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, - "ehci_vbus_gpio"); + gpio = devm_gpiod_get_optional(dev, "samsung,vbus", GPIOD_OUT_HIGH); + err = PTR_ERR_OR_ZERO(gpio); if (err) - dev_err(dev, "can't request ehci vbus gpio %d", gpio); + dev_err(dev, "can't request ehci vbus gpio: %d\n", err); } static int exynos_ehci_probe(struct platform_device *pdev) @@ -347,7 +339,6 @@ static int __init ehci_exynos_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides); return platform_driver_register(&exynos_ehci_driver); } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 896c0d107f72..9cea785934e5 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -722,8 +722,6 @@ static int __init ehci_fsl_init(void) if (usb_disabled()) return -ENODEV; - pr_info(DRV_NAME ": " DRIVER_DESC "\n"); - ehci_init_driver(&fsl_ehci_hc_driver, &ehci_fsl_overrides); fsl_ehci_hc_driver.product_desc = diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 684164fa9716..a1930db0da1c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1351,7 +1351,6 @@ static int __init ehci_hcd_init(void) if (usb_disabled()) return -ENODEV; - printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c index 6b5a7a873e01..63af1a827fcb 100644 --- a/drivers/usb/host/ehci-npcm7xx.c +++ b/drivers/usb/host/ehci-npcm7xx.c @@ -22,19 +22,8 @@ #include "ehci.h" -#include -#include - #define DRIVER_DESC "EHCI npcm7xx driver" -static const char hcd_name[] = "npcm7xx-ehci"; - -#define USB2PHYCTL_OFFSET 0x144 - -#define IPSRST2_OFFSET 0x24 -#define IPSRST3_OFFSET 0x34 - - static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver; static int __maybe_unused ehci_npcm7xx_drv_suspend(struct device *dev) @@ -60,52 +49,12 @@ static int npcm7xx_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; - struct regmap *gcr_regmap; - struct regmap *rst_regmap; const struct hc_driver *driver = &ehci_npcm7xx_hc_driver; int irq; int retval; dev_dbg(&pdev->dev, "initializing npcm7xx ehci USB Controller\n"); - gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); - if (IS_ERR(gcr_regmap)) { - dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-gcr\n", - __func__); - return PTR_ERR(gcr_regmap); - } - - rst_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst"); - if (IS_ERR(rst_regmap)) { - dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n", - __func__); - return PTR_ERR(rst_regmap); - } - - /********* phy init ******/ - // reset usb host - regmap_update_bits(rst_regmap, IPSRST2_OFFSET, - (0x1 << 26), (0x1 << 26)); - regmap_update_bits(rst_regmap, IPSRST3_OFFSET, - (0x1 << 25), (0x1 << 25)); - regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET, - (0x1 << 28), 0); - - udelay(1); - - // enable phy - regmap_update_bits(rst_regmap, IPSRST3_OFFSET, - (0x1 << 25), 0); - - udelay(50); // enable phy - - regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET, - (0x1 << 28), (0x1 << 28)); - - // enable host - regmap_update_bits(rst_regmap, IPSRST2_OFFSET, - (0x1 << 26), 0); - if (usb_disabled()) return -ENODEV; @@ -191,8 +140,6 @@ static int __init ehci_npcm7xx_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_npcm7xx_hc_driver, NULL); return platform_driver_register(&npcm7xx_ehci_hcd_driver); } diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 8c45bc17a580..7dd984722a7f 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -284,8 +284,6 @@ static int __init ehci_omap_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides); return platform_driver_register(&ehci_hcd_omap_driver); } diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 3626758b3e2a..a3454a3ea4e0 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -65,8 +65,6 @@ struct orion_ehci_hcd { struct phy *phy; }; -static const char hcd_name[] = "ehci-orion"; - static struct hc_driver __read_mostly ehci_orion_hc_driver; /* @@ -361,8 +359,6 @@ static int __init ehci_orion_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_orion_hc_driver, &orion_overrides); return platform_driver_register(&ehci_orion_driver); } diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 9937c5a7efc2..17f8b6ea0c35 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -382,7 +382,7 @@ static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { if (is_bypassed_id(pdev)) return -ENODEV; - return usb_hcd_pci_probe(pdev, id, &ehci_pci_hc_driver); + return usb_hcd_pci_probe(pdev, &ehci_pci_hc_driver); } static void ehci_pci_remove(struct pci_dev *pdev) @@ -423,8 +423,6 @@ static int __init ehci_pci_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_pci_hc_driver, &pci_overrides); /* Entries for the PCI suspend/resume callbacks are special */ diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 6924f0316e9a..fe497c876d76 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -53,8 +53,6 @@ struct ehci_platform_priv { struct delayed_work poll_work; }; -static const char hcd_name[] = "ehci-platform"; - static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); @@ -529,8 +527,6 @@ static int __init ehci_platform_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); return platform_driver_register(&ehci_platform_driver); } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 807e64991e3e..666f5c4db25a 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -645,7 +645,7 @@ qh_urb_transaction ( token |= (1 /* "in" */ << 8); /* else it's already initted to "out" pid (0 << 8) */ - maxpacket = usb_maxpacket(urb->dev, urb->pipe); + maxpacket = usb_endpoint_maxp(&urb->ep->desc); /* * buffer gets wrapped in one or more qtds; @@ -1218,7 +1218,7 @@ static int ehci_submit_single_step_set_feature( token |= (1 /* "in" */ << 8); /*This is IN stage*/ - maxpacket = usb_maxpacket(urb->dev, urb->pipe); + maxpacket = usb_endpoint_maxp(&urb->ep->desc); qtd_fill(ehci, qtd, buf, len, token, maxpacket); diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 3694e450a11a..c4ddd1022f60 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -24,8 +24,6 @@ #define DRIVER_DESC "EHCI SPEAr driver" -static const char hcd_name[] = "SPEAr-ehci"; - struct spear_ehci { struct clk *clk; }; @@ -167,8 +165,6 @@ static int __init ehci_spear_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides); return platform_driver_register(&spear_ehci_hcd_driver); } diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c index f74433aac948..f731dc98c533 100644 --- a/drivers/usb/host/ehci-st.c +++ b/drivers/usb/host/ehci-st.c @@ -42,8 +42,6 @@ struct st_ehci_platform_priv { #define hcd_to_ehci_priv(h) \ ((struct st_ehci_platform_priv *)hcd_to_ehci(h)->priv) -static const char hcd_name[] = "ehci-st"; - #define EHCI_CAPS_SIZE 0x10 #define AHB2STBUS_INSREG01 (EHCI_CAPS_SIZE + 0x84) @@ -346,8 +344,6 @@ static int __init ehci_platform_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); return platform_driver_register(&ehci_platform_driver); } diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 2ba09c3fbc2f..95a44462bed0 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -25,8 +25,8 @@ #include #include #include -#include #include +#include #include #include #include "fhci.h" @@ -150,15 +150,15 @@ int fhci_ioports_check_bus_state(struct fhci_hcd *fhci) u8 bits = 0; /* check USBOE,if transmitting,exit */ - if (!gpio_get_value(fhci->gpios[GPIO_USBOE])) + if (!gpiod_get_value(fhci->gpiods[GPIO_USBOE])) return -1; /* check USBRP */ - if (gpio_get_value(fhci->gpios[GPIO_USBRP])) + if (gpiod_get_value(fhci->gpiods[GPIO_USBRP])) bits |= 0x2; /* check USBRN */ - if (gpio_get_value(fhci->gpios[GPIO_USBRN])) + if (gpiod_get_value(fhci->gpiods[GPIO_USBRN])) bits |= 0x1; return bits; @@ -630,40 +630,23 @@ static int of_fhci_probe(struct platform_device *ofdev) /* GPIOs and pins */ for (i = 0; i < NUM_GPIOS; i++) { - int gpio; - enum of_gpio_flags flags; + if (i < GPIO_SPEED) + fhci->gpiods[i] = devm_gpiod_get_index(dev, + NULL, i, GPIOD_IN); - gpio = of_get_gpio_flags(node, i, &flags); - fhci->gpios[i] = gpio; - fhci->alow_gpios[i] = flags & OF_GPIO_ACTIVE_LOW; + else + fhci->gpiods[i] = devm_gpiod_get_index_optional(dev, + NULL, i, GPIOD_OUT_LOW); - if (!gpio_is_valid(gpio)) { - if (i < GPIO_SPEED) { - dev_err(dev, "incorrect GPIO%d: %d\n", - i, gpio); - goto err_gpios; - } else { - dev_info(dev, "assuming board doesn't have " - "%s gpio\n", i == GPIO_SPEED ? - "speed" : "power"); - continue; - } - } - - ret = gpio_request(gpio, dev_name(dev)); - if (ret) { - dev_err(dev, "failed to request gpio %d", i); + if (IS_ERR(fhci->gpiods[i])) { + dev_err(dev, "incorrect GPIO%d: %ld\n", + i, PTR_ERR(fhci->gpiods[i])); goto err_gpios; } - - if (i >= GPIO_SPEED) { - ret = gpio_direction_output(gpio, 0); - if (ret) { - dev_err(dev, "failed to set gpio %d as " - "an output\n", i); - i++; - goto err_gpios; - } + if (!fhci->gpiods[i]) { + dev_info(dev, "assuming board doesn't have " + "%s gpio\n", i == GPIO_SPEED ? + "speed" : "power"); } } @@ -766,10 +749,6 @@ err_pins: while (--j >= 0) qe_pin_free(fhci->pins[j]); err_gpios: - while (--i >= 0) { - if (gpio_is_valid(fhci->gpios[i])) - gpio_free(fhci->gpios[i]); - } cpm_muram_free(pram_addr); err_pram: iounmap(hcd->regs); @@ -782,18 +761,12 @@ static int fhci_remove(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct fhci_hcd *fhci = hcd_to_fhci(hcd); - int i; int j; usb_remove_hcd(hcd); free_irq(fhci->timer->irq, hcd); gtm_put_timer16(fhci->timer); cpm_muram_free(cpm_muram_offset(fhci->pram)); - for (i = 0; i < NUM_GPIOS; i++) { - if (!gpio_is_valid(fhci->gpios[i])) - continue; - gpio_free(fhci->gpios[i]); - } for (j = 0; j < NUM_PINS; j++) qe_pin_free(fhci->pins[j]); fhci_dfs_destroy(fhci); diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c index c359dcdb9b13..5f48660ebdfa 100644 --- a/drivers/usb/host/fhci-hub.c +++ b/drivers/usb/host/fhci-hub.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "fhci.h" @@ -38,13 +38,12 @@ static u8 root_hub_des[] = { static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on) { - int gpio = fhci->gpios[gpio_nr]; - bool alow = fhci->alow_gpios[gpio_nr]; + struct gpio_desc *gpiod = fhci->gpiods[gpio_nr]; - if (!gpio_is_valid(gpio)) + if (!gpiod) return; - gpio_set_value(gpio, on ^ alow); + gpiod_set_value(gpiod, on); mdelay(5); } @@ -129,9 +128,9 @@ void fhci_io_port_generate_reset(struct fhci_hcd *fhci) { fhci_dbg(fhci, "-> %s\n", __func__); - gpio_direction_output(fhci->gpios[GPIO_USBOE], 0); - gpio_direction_output(fhci->gpios[GPIO_USBTP], 0); - gpio_direction_output(fhci->gpios[GPIO_USBTN], 0); + gpiod_direction_output(fhci->gpiods[GPIO_USBOE], 0); + gpiod_direction_output(fhci->gpiods[GPIO_USBTP], 0); + gpiod_direction_output(fhci->gpiods[GPIO_USBTN], 0); mdelay(5); diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h index 81fbc019a9b3..1f57b0989485 100644 --- a/drivers/usb/host/fhci.h +++ b/drivers/usb/host/fhci.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -242,8 +243,7 @@ struct fhci_hcd { enum qe_clock fullspeed_clk; enum qe_clock lowspeed_clk; struct qe_pin *pins[NUM_PINS]; - int gpios[NUM_GPIOS]; - bool alow_gpios[NUM_GPIOS]; + struct gpio_desc *gpiods[NUM_GPIOS]; struct qe_usb_ctlr __iomem *regs; /* I/O memory used to communicate */ struct fhci_pram __iomem *pram; /* Parameter RAM */ diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index f8c111e08a0d..3d1dbcf4c073 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5692,7 +5692,6 @@ static int __init fotg210_hcd_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 98326465e2dc..533537ef3c21 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -62,8 +62,6 @@ struct ohci_at91_priv { #define DRIVER_DESC "OHCI Atmel driver" -static const char hcd_name[] = "ohci-atmel"; - static struct hc_driver __read_mostly ohci_at91_hc_driver; static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = { @@ -699,7 +697,6 @@ static int __init ohci_at91_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); ohci_init_driver(&ohci_at91_hc_driver, &ohci_at91_drv_overrides); /* diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 1371b0c249ec..d4818e8d652b 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -551,7 +551,6 @@ static int __init ohci_da8xx_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", DRV_NAME); ohci_init_driver(&ohci_da8xx_hc_driver, &da8xx_overrides); /* diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 5f5e8a64c8e2..8d7977fd5d3b 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -21,7 +21,6 @@ #define DRIVER_DESC "OHCI Exynos driver" -static const char hcd_name[] = "ohci-exynos"; static struct hc_driver __read_mostly exynos_ohci_hc_driver; #define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv) @@ -310,7 +309,6 @@ static int __init ohci_exynos_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides); return platform_driver_register(&exynos_ohci_driver); } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c4c821c2288c..0457dd9f6c19 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1276,7 +1276,6 @@ static int __init ohci_hcd_mod_init(void) if (usb_disabled()) return -ENODEV; - printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); pr_debug ("%s: block sizes: ed %zd td %zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 106a6bcefb08..5b32e683e367 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -275,8 +275,6 @@ static int __init ohci_nxp_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_nxp_hc_driver, NULL); return platform_driver_register(&ohci_hcd_nxp_driver); } diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index f5bc9c8bdc9a..cb29701df911 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -423,8 +423,6 @@ static int __init ohci_omap_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides); return platform_driver_register(&ohci_hcd_omap_driver); } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 41efe927d8f3..d7b4f40f9ff4 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -282,7 +282,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); static int ohci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { - return usb_hcd_pci_probe(dev, id, &ohci_pci_hc_driver); + return usb_hcd_pci_probe(dev, &ohci_pci_hc_driver); } /* pci driver glue; this is a "new style" PCI driver module */ @@ -306,8 +306,6 @@ static int __init ohci_pci_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides); #ifdef CONFIG_PM diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 0adae6265127..a84305091c43 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -41,8 +41,6 @@ struct ohci_platform_priv { struct reset_control *resets; }; -static const char hcd_name[] = "ohci-platform"; - static int ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -289,7 +287,7 @@ static int ohci_platform_suspend(struct device *dev) return ret; } -static int ohci_platform_resume(struct device *dev) +static int ohci_platform_resume_common(struct device *dev, bool hibernated) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_ohci_pdata *pdata = dev_get_platdata(dev); @@ -301,7 +299,7 @@ static int ohci_platform_resume(struct device *dev) return err; } - ohci_resume(hcd, false); + ohci_resume(hcd, hibernated); pm_runtime_disable(dev); pm_runtime_set_active(dev); @@ -309,6 +307,16 @@ static int ohci_platform_resume(struct device *dev) return 0; } + +static int ohci_platform_resume(struct device *dev) +{ + return ohci_platform_resume_common(dev, false); +} + +static int ohci_platform_restore(struct device *dev) +{ + return ohci_platform_resume_common(dev, true); +} #endif /* CONFIG_PM_SLEEP */ static const struct of_device_id ohci_platform_ids[] = { @@ -325,8 +333,16 @@ static const struct platform_device_id ohci_platform_table[] = { }; MODULE_DEVICE_TABLE(platform, ohci_platform_table); -static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend, - ohci_platform_resume); +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops ohci_platform_pm_ops = { + .suspend = ohci_platform_suspend, + .resume = ohci_platform_resume, + .freeze = ohci_platform_suspend, + .thaw = ohci_platform_resume, + .poweroff = ohci_platform_suspend, + .restore = ohci_platform_restore, +}; +#endif static struct platform_driver ohci_platform_driver = { .id_table = ohci_platform_table, @@ -335,7 +351,9 @@ static struct platform_driver ohci_platform_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ohci-platform", +#ifdef CONFIG_PM_SLEEP .pm = &ohci_platform_pm_ops, +#endif .of_match_table = ohci_platform_ids, .probe_type = PROBE_PREFER_ASYNCHRONOUS, } @@ -346,8 +364,6 @@ static int __init ohci_platform_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides); return platform_driver_register(&ohci_platform_driver); } diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index ab4f610a0140..a1dad8745622 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -114,8 +114,6 @@ #define PXA_UHC_MAX_PORTNUM 3 -static const char hcd_name[] = "ohci-pxa27x"; - static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; struct pxa27x_ohci { @@ -608,8 +606,6 @@ static int __init ohci_pxa27x_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control; diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 12264c048601..85a0a9ae0095 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -39,8 +39,6 @@ #define DRIVER_DESC "OHCI S3C2410 driver" -static const char hcd_name[] = "ohci-s3c2410"; - static struct clk *clk; static struct clk *usb_clk; @@ -474,7 +472,6 @@ static int __init ohci_s3c2410_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); ohci_init_driver(&ohci_s3c2410_hc_driver, NULL); /* diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 9b81f420656d..196951a27f3f 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -23,7 +23,6 @@ #define DRIVER_DESC "OHCI SPEAr driver" -static const char hcd_name[] = "SPEAr-ohci"; struct spear_ohci { struct clk *clk; }; @@ -179,8 +178,6 @@ static int __init ohci_spear_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_spear_hc_driver, &spear_overrides); return platform_driver_register(&spear_ohci_hcd_driver); } diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c index ac796ccd93ef..82eef3c62e11 100644 --- a/drivers/usb/host/ohci-st.c +++ b/drivers/usb/host/ohci-st.c @@ -40,8 +40,6 @@ struct st_ohci_platform_priv { #define hcd_to_ohci_priv(h) \ ((struct st_ohci_platform_priv *)hcd_to_ohci(h)->priv) -static const char hcd_name[] = "ohci-st"; - static int st_ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -324,8 +322,6 @@ static int __init ohci_platform_init(void) if (usb_disabled()) return -ENODEV; - pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides); return platform_driver_register(&ohci_platform_driver); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index d879d6af5710..95240c9c45bd 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3190,7 +3190,6 @@ static int __init u132_hcd_init(void) u132_exiting = 0; if (usb_disabled()) return -ENODEV; - printk(KERN_INFO "driver %s\n", hcd_name); workqueue = create_singlethread_workqueue("u132"); if (!workqueue) return -ENOMEM; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d90b869f5f40..c22b51af83fc 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -867,8 +867,6 @@ static int __init uhci_hcd_init(void) if (usb_disabled()) return -ENODEV; - printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n", - ignore_oc ? ", overcurrent ignored" : ""); set_bit(USB_UHCI_LOADED, &usb_hcds_loaded); #ifdef CONFIG_DYNAMIC_DEBUG diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 9b88745d247f..3592f757fe05 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids); static int uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { - return usb_hcd_pci_probe(dev, id, &uhci_driver); + return usb_hcd_pci_probe(dev, &uhci_driver); } static struct pci_driver uhci_pci_driver = { diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index e61155fa6379..f1367b53b260 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -988,7 +988,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->driver = driver; if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) - return NULL; + goto err; INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8c19e151a945..9e56aa28efcd 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -641,7 +641,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, num_stream_ctxs, &stream_info->ctx_array_dma, mem_flags); if (!stream_info->stream_ctx_array) - goto cleanup_ctx; + goto cleanup_ring_array; memset(stream_info->stream_ctx_array, 0, sizeof(struct xhci_stream_ctx)*num_stream_ctxs); @@ -702,6 +702,11 @@ cleanup_rings: } xhci_free_command(xhci, stream_info->free_streams_command); cleanup_ctx: + xhci_free_stream_ctx(xhci, + stream_info->num_stream_ctxs, + stream_info->stream_ctx_array, + stream_info->ctx_array_dma); +cleanup_ring_array: kfree(stream_info->stream_rings); cleanup_info: kfree(stream_info); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index dce6c0ec8d34..40228a3d77a0 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -431,7 +431,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) * to say USB 2.0, but I'm not sure what the implications would be in * the other parts of the HCD code. */ - retval = usb_hcd_pci_probe(dev, id, &xhci_pci_hc_driver); + retval = usb_hcd_pci_probe(dev, &xhci_pci_hc_driver); if (retval) goto put_runtime_pm; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index a8641b6536ee..5fb55bf19493 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -123,7 +123,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { }; static const struct xhci_plat_priv xhci_plat_brcm = { - .quirks = XHCI_RESET_ON_RESUME, + .quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS, }; static const struct of_device_id usb_xhci_of_match[] = { @@ -437,7 +437,16 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev) * xhci_suspend() needs `do_wakeup` to know whether host is allowed * to do wakeup during suspend. */ - return xhci_suspend(xhci, device_may_wakeup(dev)); + ret = xhci_suspend(xhci, device_may_wakeup(dev)); + if (ret) + return ret; + + if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { + clk_disable_unprepare(xhci->clk); + clk_disable_unprepare(xhci->reg_clk); + } + + return 0; } static int __maybe_unused xhci_plat_resume(struct device *dev) @@ -446,6 +455,11 @@ static int __maybe_unused xhci_plat_resume(struct device *dev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ret; + if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { + clk_prepare_enable(xhci->clk); + clk_prepare_enable(xhci->reg_clk); + } + ret = xhci_priv_resume_quirk(hcd); if (ret) return ret; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 38649284ff88..5176765c4013 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1183,7 +1183,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* re-initialize the HC on Restore Error, or Host Controller Error */ if (temp & (STS_SRE | STS_HCE)) { reinit_xhc = true; - xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp); + if (!xhci->broken_suspend) + xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp); } if (reinit_xhc) { @@ -1482,7 +1483,7 @@ EXPORT_SYMBOL_GPL(xhci_get_endpoint_index); /* The reverse operation to xhci_get_endpoint_index. Calculate the USB endpoint * address from the XHCI endpoint index. */ -unsigned int xhci_get_endpoint_address(unsigned int ep_index) +static unsigned int xhci_get_endpoint_address(unsigned int ep_index) { unsigned int number = DIV_ROUND_UP(ep_index, 2); unsigned int direction = ep_index % 2 ? USB_DIR_OUT : USB_DIR_IN; @@ -4095,7 +4096,8 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) slot_id = command->slot_id; if (!slot_id || command->status != COMP_SUCCESS) { - xhci_err(xhci, "Error while assigning device slot ID\n"); + xhci_err(xhci, "Error while assigning device slot ID: %s\n", + xhci_trb_comp_code_string(command->status)); xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n", HCS_MAX_SLOTS( readl(&xhci->cap_regs->hcs_params1))); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7caa0db5e826..c0964fe8ac12 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1807,8 +1807,6 @@ struct xhci_hcd { struct xhci_erst erst; /* Scratchpad */ struct xhci_scratchpad *scratchpad; - /* Store LPM test failed devices' information */ - struct list_head lpm_failed_devs; /* slot enabling and address device helpers */ /* these are not thread safe so use mutex */ @@ -1827,7 +1825,6 @@ struct xhci_hcd { /* Host controller watchdog timer structures */ unsigned int xhc_state; unsigned long run_graceperiod; - u32 command; struct s3_save s3; /* Host controller is dying - not responding to commands. "I'm not dead yet!" * @@ -1899,6 +1896,7 @@ struct xhci_hcd { #define XHCI_NO_SOFT_RETRY BIT_ULL(40) #define XHCI_BROKEN_D3COLD BIT_ULL(41) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42) +#define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43) unsigned int num_active_eps; unsigned int limit_active_eps; @@ -2041,7 +2039,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, struct usb_device *udev); unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); -unsigned int xhci_get_endpoint_address(unsigned int ep_index); unsigned int xhci_last_valid_endpoint(u32 added_ctxs); void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); void xhci_update_tt_active_eps(struct xhci_hcd *xhci, diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index e9437a176518..ea39243efee3 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -177,10 +177,6 @@ static int idmouse_create_image(struct usb_idmouse *dev) bytes_read += bulk_read; } - /* reset the device */ -reset: - ftip_command(dev, FTIP_RELEASE, 0, 0); - /* check for valid image */ /* right border should be black (0x00) */ for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH) @@ -192,6 +188,10 @@ reset: if (dev->bulk_in_buffer[bytes_read] != 0xFF) return -EAGAIN; + /* reset the device */ +reset: + ftip_command(dev, FTIP_RELEASE, 0, 0); + /* should be IMGSIZE == 65040 */ dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n", bytes_read); diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 04c4e3fed094..54337d72bb9f 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -400,7 +400,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, { struct device *dev = hub->dev; struct device_node *np = dev->of_node; - int len, err; + int len; u32 property_u32 = 0; const char *cproperty_char; char str[USB251XB_STRING_BUFSIZE / 2]; @@ -416,13 +416,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->skip_config = 0; hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (PTR_ERR(hub->gpio_reset) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(hub->gpio_reset)) { - err = PTR_ERR(hub->gpio_reset); - dev_err(dev, "unable to request GPIO reset pin (%d)\n", err); - return err; - } + if (IS_ERR(hub->gpio_reset)) + return dev_err_probe(dev, PTR_ERR(hub->gpio_reset), + "unable to request GPIO reset pin\n"); if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1)) hub->vendor_id = USB251XB_DEF_VENDOR_ID; @@ -547,7 +543,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; cproperty_char = of_get_property(np, "manufacturer", NULL); - strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, + strscpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, sizeof(str)); hub->manufacturer_len = strlen(str) & 0xFF; memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE); @@ -557,7 +553,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, USB251XB_STRING_BUFSIZE); cproperty_char = of_get_property(np, "product", NULL); - strlcpy(str, cproperty_char ? : data->product_str, sizeof(str)); + strscpy(str, cproperty_char ? : data->product_str, sizeof(str)); hub->product_len = strlen(str) & 0xFF; memset(hub->product, 0, USB251XB_STRING_BUFSIZE); len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); @@ -566,7 +562,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, USB251XB_STRING_BUFSIZE); cproperty_char = of_get_property(np, "serial", NULL); - strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, + strscpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, sizeof(str)); hub->serial_len = strlen(str) & 0xFF; memset(hub->serial, 0, USB251XB_STRING_BUFSIZE); diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 3c9fa663475f..c70ca475c7c7 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -160,6 +160,7 @@ static int usb3503_probe(struct usb3503 *hub) struct usb3503_platform_data *pdata = dev_get_platdata(dev); struct device_node *np = dev->of_node; int err; + bool is_clk_enabled = false; u32 mode = USB3503_MODE_HUB; const u32 *property; enum gpiod_flags flags; @@ -217,6 +218,7 @@ static int usb3503_probe(struct usb3503 *hub) return err; } + is_clk_enabled = true; property = of_get_property(np, "disabled-ports", &len); if (property && (len / sizeof(u32)) > 0) { int i; @@ -236,20 +238,26 @@ static int usb3503_probe(struct usb3503 *hub) else flags = GPIOD_OUT_HIGH; hub->intn = devm_gpiod_get_optional(dev, "intn", flags); - if (IS_ERR(hub->intn)) - return PTR_ERR(hub->intn); + if (IS_ERR(hub->intn)) { + err = PTR_ERR(hub->intn); + goto err_clk; + } if (hub->intn) gpiod_set_consumer_name(hub->intn, "usb3503 intn"); hub->connect = devm_gpiod_get_optional(dev, "connect", GPIOD_OUT_LOW); - if (IS_ERR(hub->connect)) - return PTR_ERR(hub->connect); + if (IS_ERR(hub->connect)) { + err = PTR_ERR(hub->connect); + goto err_clk; + } if (hub->connect) gpiod_set_consumer_name(hub->connect, "usb3503 connect"); hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(hub->reset)) - return PTR_ERR(hub->reset); + if (IS_ERR(hub->reset)) { + err = PTR_ERR(hub->reset); + goto err_clk; + } if (hub->reset) { /* Datasheet defines a hardware reset to be at least 100us */ usleep_range(100, 10000); @@ -265,6 +273,11 @@ static int usb3503_probe(struct usb3503 *hub) (hub->mode == USB3503_MODE_HUB) ? "hub" : "standby"); return 0; + +err_clk: + if (is_clk_enabled) + clk_disable_unprepare(hub->clk); + return err; } static int usb3503_i2c_probe(struct i2c_client *i2c, diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 0be8efcda15d..b00d92db5dfd 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -502,7 +502,7 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, #else struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; - int rlen; + int rlen = 0; int i; if (!usbdev) @@ -563,7 +563,7 @@ static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buff { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; - int rlen; + int rlen = 0; int i; if (!usbdev) @@ -581,7 +581,7 @@ static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, siz { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; - int rlen; + int rlen = 0; int i; if (!usbdev) @@ -614,7 +614,7 @@ static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; - int rlen; + int rlen = 0; int i; if (!usbdev) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index f48a23adbc35..094e812e9e69 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1268,6 +1268,11 @@ static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) { /* don't do anything here: "fault" will set up page table entries */ vma->vm_ops = &mon_bin_vm_ops; + + if (vma->vm_flags & VM_WRITE) + return -EPERM; + + vma->vm_flags &= ~VM_MAYWRITE; vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; vma->vm_private_data = filp->private_data; mon_bin_vma_open(vma); diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 0ca173af87bb..a3a6282893d0 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -978,8 +978,6 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) goto irq_err; } - device_init_wakeup(dev, true); - /* power down device IP for power saving by default */ mtu3_stop(mtu); diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 4cb65346789d..d78ae52b4e26 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -356,6 +356,8 @@ static int mtu3_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); + device_init_wakeup(dev, true); + ret = ssusb_rscs_init(ssusb); if (ret) goto comm_init_err; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index fd4ae2dd24e5..a4e55b0c52cf 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -523,11 +523,9 @@ static int da8xx_probe(struct platform_device *pdev) } glue->phy = devm_phy_get(&pdev->dev, "usb-phy"); - if (IS_ERR(glue->phy)) { - if (PTR_ERR(glue->phy) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get phy\n"); - return PTR_ERR(glue->phy); - } + if (IS_ERR(glue->phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(glue->phy), + "failed to get phy\n"); glue->dev = &pdev->dev; glue->clk = clk; diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index 417c30bff9ca..d1e4e0deb753 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -105,7 +105,6 @@ static int jz4740_musb_init(struct musb *musb) .driver_data = glue, .fwnode = dev_fwnode(dev), }; - int err; glue->musb = musb; @@ -113,12 +112,9 @@ static int jz4740_musb_init(struct musb *musb) musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); else musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - if (IS_ERR(musb->xceiv)) { - err = PTR_ERR(musb->xceiv); - if (err != -EPROBE_DEFER) - dev_err(dev, "No transceiver configured: %d\n", err); - return err; - } + if (IS_ERR(musb->xceiv)) + return dev_err_probe(dev, PTR_ERR(musb->xceiv), + "No transceiver configured\n"); glue->role_sw = usb_role_switch_register(dev, &role_sw_desc); if (IS_ERR(glue->role_sw)) { diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index bbbcfd49fb35..03027c6fa3ab 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2595,9 +2595,7 @@ fail2: musb_platform_exit(musb); fail1: - if (status != -EPROBE_DEFER) - dev_err(musb->controller, - "%s failed with status %d\n", __func__, status); + dev_err_probe(musb->controller, status, "%s failed\n", __func__); musb_free(musb); diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index c963cb8565f2..9589243e8951 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -718,10 +718,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) dc = dma_request_chan(dev->parent, str); if (IS_ERR(dc)) { - ret = PTR_ERR(dc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request %s: %d.\n", - str, ret); + ret = dev_err_probe(dev, PTR_ERR(dc), + "Failed to request %s.\n", str); goto err; } diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index daada4b66a92..6704a62a1665 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -760,6 +760,9 @@ static void rxstate(struct musb *musb, struct musb_request *req) musb_writew(epio, MUSB_RXCSR, csr); buffer_aint_mapped: + fifo_count = min_t(unsigned int, + request->length - request->actual, + (unsigned int)fifo_count); musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 961c858fb349..7f9a999cd5ff 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -743,31 +743,20 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { glue->rst = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(glue->rst)) { - if (PTR_ERR(glue->rst) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(&pdev->dev, "Error getting reset %ld\n", - PTR_ERR(glue->rst)); - return PTR_ERR(glue->rst); - } + if (IS_ERR(glue->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(glue->rst), + "Error getting reset\n"); } glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); - if (IS_ERR(glue->extcon)) { - if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(&pdev->dev, "Invalid or missing extcon\n"); - return PTR_ERR(glue->extcon); - } + if (IS_ERR(glue->extcon)) + return dev_err_probe(&pdev->dev, PTR_ERR(glue->extcon), + "Invalid or missing extcon\n"); glue->phy = devm_phy_get(&pdev->dev, "usb"); - if (IS_ERR(glue->phy)) { - if (PTR_ERR(glue->phy) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(&pdev->dev, "Error getting phy %ld\n", - PTR_ERR(glue->phy)); - return PTR_ERR(glue->phy); - } + if (IS_ERR(glue->phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(glue->phy), + "Error getting phy\n"); glue->usb_phy = usb_phy_generic_register(); if (IS_ERR(glue->usb_phy)) { diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 34b9f8140187..3dc5c04e7cbf 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -230,12 +230,9 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop) err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); } - if (err == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (err) { - dev_err(dev, "Error requesting RESET or VBUS GPIO\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, + "Error requesting RESET or VBUS GPIO\n"); if (nop->gpiod_reset) gpiod_direction_output(nop->gpiod_reset, 1); diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c index 4025da20b3fd..f16adcacdce3 100644 --- a/drivers/usb/phy/phy-jz4770.c +++ b/drivers/usb/phy/phy-jz4770.c @@ -321,27 +321,18 @@ static int jz4770_phy_probe(struct platform_device *pdev) } priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - err = PTR_ERR(priv->clk); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock\n"); - return err; - } + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "Failed to get clock\n"); priv->vcc_supply = devm_regulator_get(dev, "vcc"); - if (IS_ERR(priv->vcc_supply)) { - err = PTR_ERR(priv->vcc_supply); - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get regulator\n"); - return err; - } + if (IS_ERR(priv->vcc_supply)) + return dev_err_probe(dev, PTR_ERR(priv->vcc_supply), + "Failed to get regulator\n"); err = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(dev, "Unable to register PHY\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, "Unable to register PHY\n"); return devm_add_action_or_reset(dev, ingenic_usb_phy_remove, &priv->phy); } diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 8a262c5a0408..d2836ef5d15c 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -144,8 +144,8 @@ #define MXS_PHY_NEED_IP_FIX BIT(3) /* Minimum and maximum values for device tree entries */ -#define MXS_PHY_TX_CAL45_MIN 30 -#define MXS_PHY_TX_CAL45_MAX 55 +#define MXS_PHY_TX_CAL45_MIN 35 +#define MXS_PHY_TX_CAL45_MAX 54 #define MXS_PHY_TX_D_CAL_MIN 79 #define MXS_PHY_TX_D_CAL_MAX 119 diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 68cd4b68e3a2..f0240107edb1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1440,16 +1440,22 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return err; } - gpiod = devm_gpiod_get_from_of_node(&pdev->dev, np, - "nvidia,phy-reset-gpio", - 0, GPIOD_OUT_HIGH, - "ulpi_phy_reset_b"); + gpiod = devm_gpiod_get(&pdev->dev, "nvidia,phy-reset", + GPIOD_OUT_HIGH); err = PTR_ERR_OR_ZERO(gpiod); if (err) { dev_err(&pdev->dev, "Request failed for reset GPIO: %d\n", err); return err; } + + err = gpiod_set_consumer_name(gpiod, "ulpi_phy_reset_b"); + if (err) { + dev_err(&pdev->dev, + "Failed to set up reset GPIO name: %d\n", err); + return err; + } + tegra_phy->reset_gpio = gpiod; phy = devm_otg_ulpi_create(&pdev->dev, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 39eaa7b97c40..9452291f1703 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -189,7 +189,7 @@ static void ark3116_port_remove(struct usb_serial_port *port) static void ark3116_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 8107e4b5b03b..9331a562dac0 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -44,7 +44,8 @@ static void belkin_sa_close(struct usb_serial_port *port); static void belkin_sa_read_int_callback(struct urb *urb); static void belkin_sa_process_read_urb(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios * old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); static int belkin_sa_tiocmget(struct tty_struct *tty); static int belkin_sa_tiocmset(struct tty_struct *tty, @@ -273,7 +274,8 @@ static void belkin_sa_process_read_urb(struct urb *urb) } static void belkin_sa_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct belkin_sa_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index af01a462cc43..6e1b87e67304 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -106,7 +106,7 @@ struct ch341_private { static void ch341_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios); + const struct ktermios *old_termios); static int ch341_control_out(struct usb_device *dev, u8 request, u16 value, u16 index) @@ -482,7 +482,8 @@ err_kill_interrupt_urb: * tty->termios contains the new setting to be used. */ static void ch341_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct ch341_private *priv = usb_get_serial_port_data(port); unsigned baud_rate; diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index b97aa40ca4d1..da19a5fa414f 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -189,8 +189,8 @@ static int usb_console_setup(struct console *co, char *options) info->port = NULL; usb_autopm_put_interface(serial->interface); error_get_interface: - usb_serial_put(serial); mutex_unlock(&serial->disc_mutex); + usb_serial_put(serial); return retval; } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a34957c4b64c..3bcec419f463 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -31,9 +31,9 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, - struct ktermios *); + const struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, - struct ktermios*); + const struct ktermios *); static bool cp210x_tx_empty(struct usb_serial_port *port); static int cp210x_tiocmget(struct tty_struct *); static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); @@ -1040,7 +1040,8 @@ static speed_t cp210x_get_actual_rate(speed_t baud) * otherwise. */ static void cp210x_change_speed(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct cp210x_serial_private *priv = usb_get_serial_data(serial); @@ -1122,7 +1123,8 @@ static bool cp210x_termios_change(const struct ktermios *a, const struct ktermio } static void cp210x_set_flow_control(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct cp210x_serial_private *priv = usb_get_serial_data(port->serial); struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -1232,7 +1234,8 @@ out_unlock: } static void cp210x_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct cp210x_serial_private *priv = usb_get_serial_data(port->serial); u16 bits; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 5fbcc155e8f5..1e0c028c5ec9 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -125,7 +125,8 @@ static void cypress_send(struct usb_serial_port *port); static unsigned int cypress_write_room(struct tty_struct *tty); static void cypress_earthmate_init_termios(struct tty_struct *tty); static void cypress_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static int cypress_tiocmget(struct tty_struct *tty); static int cypress_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); @@ -859,7 +860,8 @@ static void cypress_earthmate_init_termios(struct tty_struct *tty) } static void cypress_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index af65eb863d70..45d688e9b93f 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -215,7 +215,8 @@ static int digi_transmit_idle(struct usb_serial_port *port, static void digi_rx_throttle(struct tty_struct *tty); static void digi_rx_unthrottle(struct tty_struct *tty); static void digi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); static void digi_break_ctl(struct tty_struct *tty, int break_state); static int digi_tiocmget(struct tty_struct *tty); static int digi_tiocmset(struct tty_struct *tty, unsigned int set, @@ -649,7 +650,8 @@ static void digi_rx_unthrottle(struct tty_struct *tty) static void digi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct digi_port *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index d9f20256a6a8..2dd58cd9f0cc 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -603,7 +603,8 @@ static int f81232_port_disable(struct usb_serial_port *port) } static void f81232_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct f81232_private *priv = usb_get_serial_port_data(port); u8 new_lcr = 0; diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index d789c1ec87b3..ddfcd72eb0ae 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -944,8 +944,8 @@ static int f81534_calc_num_ports(struct usb_serial *serial, } static void f81534_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { u8 new_lcr = 0; int status; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 52d59be92034..05e28a5ce42b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -47,10 +47,27 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober , Andreas Mohr, Johan Hovold " #define DRIVER_DESC "USB FTDI Serial Converters Driver" +enum ftdi_chip_type { + SIO, + FT232A, + FT232B, + FT2232C, + FT232R, + FT232H, + FT2232H, + FT4232H, + FT4232HA, + FT232HP, + FT233HP, + FT2232HP, + FT2233HP, + FT4232HP, + FT4233HP, + FTX, +}; struct ftdi_private { enum ftdi_chip_type chip_type; - /* type of device, either SIO or FT8U232AM */ int baud_base; /* baud base clock for divisor setting */ int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the @@ -62,8 +79,7 @@ struct ftdi_private { unsigned long last_dtr_rts; /* saved modem control outputs */ char prev_status; /* Used for TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ - u16 interface; /* FT2232C, FT2232H or FT4232H port interface - (0 for FT232/245) */ + u16 channel; /* channel index, or 0 for legacy types */ speed_t force_baud; /* if non-zero, force the baud rate to this value */ @@ -84,8 +100,7 @@ struct ftdi_private { #endif }; -/* struct ftdi_sio_quirk is used by devices requiring special attention. */ -struct ftdi_sio_quirk { +struct ftdi_quirk { int (*probe)(struct usb_serial *); /* Special settings for probed ports. */ void (*port_probe)(struct ftdi_private *); @@ -98,27 +113,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); -static const struct ftdi_sio_quirk ftdi_jtag_quirk = { +static const struct ftdi_quirk ftdi_jtag_quirk = { .probe = ftdi_jtag_probe, }; -static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = { +static const struct ftdi_quirk ftdi_NDI_device_quirk = { .probe = ftdi_NDI_device_setup, }; -static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { +static const struct ftdi_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; -static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { +static const struct ftdi_quirk ftdi_HE_TIRA1_quirk = { .port_probe = ftdi_HE_TIRA1_setup, }; -static const struct ftdi_sio_quirk ftdi_stmclite_quirk = { +static const struct ftdi_quirk ftdi_stmclite_quirk = { .probe = ftdi_stmclite_probe, }; -static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = { +static const struct ftdi_quirk ftdi_8u2232c_quirk = { .probe = ftdi_8u2232c_probe, }; @@ -180,6 +195,13 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT2233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT2232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4232HA_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -1061,15 +1083,22 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); static const char *ftdi_chip_name[] = { - [SIO] = "SIO", /* the serial part of FT8U100AX */ - [FT8U232AM] = "FT8U232AM", - [FT232BM] = "FT232BM", - [FT2232C] = "FT2232C", - [FT232RL] = "FT232RL", - [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H", - [FT232H] = "FT232H", - [FTX] = "FT-X" + [SIO] = "SIO", /* the serial part of FT8U100AX */ + [FT232A] = "FT232A", + [FT232B] = "FT232B", + [FT2232C] = "FT2232C/D", + [FT232R] = "FT232R", + [FT232H] = "FT232H", + [FT2232H] = "FT2232H", + [FT4232H] = "FT4232H", + [FT4232HA] = "FT4232HA", + [FT232HP] = "FT232HP", + [FT233HP] = "FT233HP", + [FT2232HP] = "FT2232HP", + [FT2233HP] = "FT2233HP", + [FT4232HP] = "FT4232HP", + [FT4233HP] = "FT4233HP", + [FTX] = "FT-X", }; @@ -1078,74 +1107,12 @@ static const char *ftdi_chip_name[] = { #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) /* End TIOCMIWAIT */ -/* function prototypes for a FTDI serial converter */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static int ftdi_sio_port_probe(struct usb_serial_port *port); -static void ftdi_sio_port_remove(struct usb_serial_port *port); -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_dtr_rts(struct usb_serial_port *port, int on); -static void ftdi_process_read_urb(struct urb *urb); -static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); static void ftdi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int ftdi_tiocmget(struct tty_struct *tty); -static int ftdi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int ftdi_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss); -static int set_serial_info(struct tty_struct *tty, - struct serial_struct *ss); -static void ftdi_break_ctl(struct tty_struct *tty, int break_state); -static bool ftdi_tx_empty(struct usb_serial_port *port); + struct usb_serial_port *port, + const struct ktermios *old_termios); static int ftdi_get_modem_status(struct usb_serial_port *port, unsigned char status[2]); -static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); -static unsigned short int ftdi_232am_baud_to_divisor(int baud); -static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base); -static u32 ftdi_232bm_baud_to_divisor(int baud); -static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); -static u32 ftdi_2232h_baud_to_divisor(int baud); - -static struct usb_serial_driver ftdi_sio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ftdi_sio", - }, - .description = "FTDI USB Serial Device", - .id_table = id_table_combined, - .num_ports = 1, - .bulk_in_size = 512, - .bulk_out_size = 256, - .probe = ftdi_sio_probe, - .port_probe = ftdi_sio_port_probe, - .port_remove = ftdi_sio_port_remove, - .open = ftdi_open, - .dtr_rts = ftdi_dtr_rts, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .process_read_urb = ftdi_process_read_urb, - .prepare_write_buffer = ftdi_prepare_write_buffer, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .ioctl = ftdi_ioctl, - .get_serial = get_serial_info, - .set_serial = set_serial_info, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .tx_empty = ftdi_tx_empty, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ftdi_sio_device, NULL -}; - - #define WDR_TIMEOUT 5000 /* default urb timeout */ #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ @@ -1261,7 +1228,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - value, priv->interface, + value, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) { dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n", @@ -1307,7 +1274,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, if (!baud) baud = 9600; switch (priv->chip_type) { - case SIO: /* SIO chip */ + case SIO: switch (baud) { case 300: div_value = ftdi_sio_b300; break; case 600: div_value = ftdi_sio_b600; break; @@ -1319,8 +1286,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, case 38400: div_value = ftdi_sio_b38400; break; case 57600: div_value = ftdi_sio_b57600; break; case 115200: div_value = ftdi_sio_b115200; break; - } /* baud */ - if (div_value == 0) { + default: dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", __func__, baud); div_value = ftdi_sio_b9600; @@ -1328,7 +1294,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT8U232AM: /* 8U232AM chip */ + case FT232A: if (baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { @@ -1338,10 +1304,10 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT232BM: /* FT232BM chip */ - case FT2232C: /* FT2232C chip */ - case FT232RL: /* FT232RL chip */ - case FTX: /* FT-X series */ + case FT232B: + case FT2232C: + case FT232R: + case FTX: if (baud <= 3000000) { u16 product_id = le16_to_cpu( port->serial->dev->descriptor.idProduct); @@ -1361,9 +1327,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; - case FT2232H: /* FT2232H chip */ - case FT4232H: /* FT4232H chip */ - case FT232H: /* FT232H chip */ + default: if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { @@ -1375,7 +1339,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; - } /* priv->chip_type */ + } if (div_okay) { dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n", @@ -1398,13 +1362,8 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) index_value = get_ftdi_divisor(tty, port); value = (u16)index_value; index = (u16)(index_value >> 16); - if (priv->chip_type == FT2232C || priv->chip_type == FT2232H || - priv->chip_type == FT4232H || priv->chip_type == FT232H || - priv->chip_type == FTX) { - /* Probably the BM type needs the MSB of the encoded fractional - * divider also moved like for the chips above. Any infos? */ - index = (u16)((index << 8) | priv->interface); - } + if (priv->channel) + index = (u16)((index << 8) | priv->channel); rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1422,7 +1381,7 @@ static int write_latency_timer(struct usb_serial_port *port) int rv; int l = priv->latency; - if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + if (priv->chip_type == SIO || priv->chip_type == FT232A) return -EINVAL; if (priv->flags & ASYNC_LOW_LATENCY) @@ -1434,7 +1393,7 @@ static int write_latency_timer(struct usb_serial_port *port) usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - l, priv->interface, + l, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); @@ -1450,7 +1409,7 @@ static int _read_latency_timer(struct usb_serial_port *port) rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST, FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, - priv->interface, &buf, 1, WDR_TIMEOUT, + priv->channel, &buf, 1, WDR_TIMEOUT, GFP_KERNEL); if (rv == 0) rv = buf; @@ -1463,7 +1422,7 @@ static int read_latency_timer(struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int rv; - if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + if (priv->chip_type == SIO || priv->chip_type == FT232A) return -EINVAL; rv = _read_latency_timer(port); @@ -1538,90 +1497,97 @@ static int get_lsr_info(struct usb_serial_port *port, return 0; } - -/* Determine type of FTDI chip based on USB config and descriptor. */ -static void ftdi_determine_type(struct usb_serial_port *port) +static int ftdi_determine_type(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct usb_device *udev = serial->dev; - unsigned version; - unsigned interfaces; - - /* Assume it is not the original SIO device for now. */ - priv->baud_base = 48000000 / 2; + unsigned int version, ifnum; version = le16_to_cpu(udev->descriptor.bcdDevice); - interfaces = udev->actconfig->desc.bNumInterfaces; - dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__, - version, interfaces); - if (interfaces > 1) { - struct usb_interface *intf = serial->interface; - int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - /* Multiple interfaces.*/ - if (version == 0x0800) { - priv->chip_type = FT4232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else if (version == 0x0700) { - priv->chip_type = FT2232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else - priv->chip_type = FT2232C; + /* Assume Hi-Speed type */ + priv->baud_base = 120000000 / 2; + priv->channel = CHANNEL_A + ifnum; - /* Determine interface code. */ - if (ifnum == 0) - priv->interface = INTERFACE_A; - else if (ifnum == 1) - priv->interface = INTERFACE_B; - else if (ifnum == 2) - priv->interface = INTERFACE_C; - else if (ifnum == 3) - priv->interface = INTERFACE_D; - - /* BM-type devices have a bug where bcdDevice gets set - * to 0x200 when iSerialNumber is 0. */ - if (version < 0x500) { - dev_dbg(&port->dev, - "%s: something fishy - bcdDevice too low for multi-interface device\n", - __func__); - } - } else if (version < 0x200) { - /* Old device. Assume it's the original SIO. */ - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - } else if (version < 0x400) { - /* Assume it's an FT8U232AM (or FT8U245AM) */ - priv->chip_type = FT8U232AM; + switch (version) { + case 0x200: + priv->chip_type = FT232A; + priv->baud_base = 48000000 / 2; + priv->channel = 0; /* - * It might be a BM type because of the iSerialNumber bug. - * If iSerialNumber==0 and the latency timer is readable, - * assume it is BM type. + * FT232B devices have a bug where bcdDevice gets set to 0x200 + * when iSerialNumber is 0. Assume it is an FT232B in case the + * latency timer is readable. */ if (udev->descriptor.iSerialNumber == 0 && _read_latency_timer(port) >= 0) { - dev_dbg(&port->dev, - "%s: has latency timer so not an AM type\n", - __func__); - priv->chip_type = FT232BM; + priv->chip_type = FT232B; } - } else if (version < 0x600) { - /* Assume it's an FT232BM (or FT245BM) */ - priv->chip_type = FT232BM; - } else if (version < 0x900) { - /* Assume it's an FT232RL */ - priv->chip_type = FT232RL; - } else if (version < 0x1000) { - /* Assume it's an FT232H */ + break; + case 0x400: + priv->chip_type = FT232B; + priv->baud_base = 48000000 / 2; + priv->channel = 0; + break; + case 0x500: + priv->chip_type = FT2232C; + priv->baud_base = 48000000 / 2; + break; + case 0x600: + priv->chip_type = FT232R; + priv->baud_base = 48000000 / 2; + priv->channel = 0; + break; + case 0x700: + priv->chip_type = FT2232H; + break; + case 0x800: + priv->chip_type = FT4232H; + break; + case 0x900: priv->chip_type = FT232H; - } else { - /* Assume it's an FT-X series device */ + break; + case 0x1000: priv->chip_type = FTX; + priv->baud_base = 48000000 / 2; + break; + case 0x2800: + priv->chip_type = FT2233HP; + break; + case 0x2900: + priv->chip_type = FT4233HP; + break; + case 0x3000: + priv->chip_type = FT2232HP; + break; + case 0x3100: + priv->chip_type = FT4232HP; + break; + case 0x3200: + priv->chip_type = FT233HP; + break; + case 0x3300: + priv->chip_type = FT232HP; + break; + case 0x3600: + priv->chip_type = FT4232HA; + break; + default: + if (version < 0x200) { + priv->chip_type = SIO; + priv->baud_base = 12000000 / 16; + priv->channel = 0; + } else { + dev_err(&port->dev, "unknown device type: 0x%02x\n", version); + return -ENODEV; + } } dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); + + return 0; } @@ -1720,7 +1686,7 @@ static ssize_t event_char_store(struct device *dev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, + v, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) { dev_dbg(&port->dev, "Unable to write event character: %i\n", rv); @@ -1731,51 +1697,42 @@ static ssize_t event_char_store(struct device *dev, } static DEVICE_ATTR_WO(event_char); -static int create_sysfs_attrs(struct usb_serial_port *port) +static struct attribute *ftdi_attrs[] = { + &dev_attr_event_char.attr, + &dev_attr_latency_timer.attr, + NULL +}; + +static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { + struct device *dev = kobj_to_dev(kobj); + struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - int retval = 0; + enum ftdi_chip_type type = priv->chip_type; - /* XXX I've no idea if the original SIO supports the event_char - * sysfs parameter, so I'm playing it safe. */ - if (priv->chip_type != SIO) { - dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]); - retval = device_create_file(&port->dev, &dev_attr_event_char); - if ((!retval) && - (priv->chip_type == FT232BM || - priv->chip_type == FT2232C || - priv->chip_type == FT232RL || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX)) { - retval = device_create_file(&port->dev, - &dev_attr_latency_timer); - } - } - return retval; -} - -static void remove_sysfs_attrs(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - /* XXX see create_sysfs_attrs */ - if (priv->chip_type != SIO) { - device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || - priv->chip_type == FT2232C || - priv->chip_type == FT232RL || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX) { - device_remove_file(&port->dev, &dev_attr_latency_timer); - } + if (attr == &dev_attr_event_char.attr) { + if (type == SIO) + return 0; } + if (attr == &dev_attr_latency_timer.attr) { + if (type == SIO || type == FT232A) + return 0; + } + + return attr->mode; } +static const struct attribute_group ftdi_group = { + .attrs = ftdi_attrs, + .is_visible = ftdi_is_visible, +}; + +static const struct attribute_group *ftdi_groups[] = { + &ftdi_group, + NULL +}; + #ifdef CONFIG_GPIOLIB static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) @@ -1794,7 +1751,7 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_BITMODE_REQUEST, FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val, - priv->interface, NULL, 0, WDR_TIMEOUT); + priv->channel, NULL, 0, WDR_TIMEOUT); if (result < 0) { dev_err(&serial->interface->dev, "bitmode request failed for value 0x%04x: %d\n", @@ -1858,7 +1815,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) result = usb_control_msg_recv(serial->dev, 0, FTDI_SIO_READ_PINS_REQUEST, FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, - priv->interface, &buf, 1, WDR_TIMEOUT, + priv->channel, &buf, 1, WDR_TIMEOUT, GFP_KERNEL); if (result == 0) result = buf; @@ -2143,7 +2100,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port) case FT232H: result = ftdi_gpio_init_ft232h(port); break; - case FT232RL: + case FT232R: result = ftdi_gpio_init_ft232r(port); break; case FTX: @@ -2213,12 +2170,9 @@ static void ftdi_gpio_remove(struct usb_serial_port *port) { } * *************************************************************************** */ -/* Probe function to check for special devices */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id) +static int ftdi_probe(struct usb_serial *serial, const struct usb_device_id *id) { - const struct ftdi_sio_quirk *quirk = - (struct ftdi_sio_quirk *)id->driver_info; + const struct ftdi_quirk *quirk = (struct ftdi_quirk *)id->driver_info; if (quirk && quirk->probe) { int ret = quirk->probe(serial); @@ -2231,10 +2185,10 @@ static int ftdi_sio_probe(struct usb_serial *serial, return 0; } -static int ftdi_sio_port_probe(struct usb_serial_port *port) +static int ftdi_port_probe(struct usb_serial_port *port) { + const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial); struct ftdi_private *priv; - const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); int result; priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); @@ -2248,12 +2202,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); - ftdi_determine_type(port); + result = ftdi_determine_type(port); + if (result) + goto err_free; + ftdi_set_max_packet_size(port); if (read_latency_timer(port) < 0) priv->latency = 16; write_latency_timer(port); - create_sysfs_attrs(port); result = ftdi_gpio_init(port); if (result < 0) { @@ -2263,6 +2219,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) } return 0; + +err_free: + kfree(priv); + + return result; } /* Setup for the USB-UIRT device, which requires hardwired @@ -2373,14 +2334,12 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) return 0; } -static void ftdi_sio_port_remove(struct usb_serial_port *port) +static void ftdi_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); ftdi_gpio_remove(port); - remove_sysfs_attrs(port); - kfree(priv); } @@ -2394,7 +2353,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - priv->interface, NULL, 0, WDR_TIMEOUT); + priv->channel, NULL, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would lose speed settings, etc. @@ -2417,7 +2376,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, NULL, 0, + 0, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(&port->dev, "error from flowcontrol urb\n"); } @@ -2610,7 +2569,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value , priv->interface, + value, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n", __func__, break_state); @@ -2640,7 +2599,8 @@ static bool ftdi_tx_empty(struct usb_serial_port *port) * WARNING: set_termios calls this with old_termios in kernel space */ static void ftdi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; struct device *ddev = &port->dev; @@ -2746,7 +2706,7 @@ no_skip: if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value , priv->interface, + value, priv->channel, NULL, 0, WDR_SHORT_TIMEOUT) < 0) { dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n", __func__); @@ -2759,7 +2719,7 @@ no_data_parity_stop_changes: if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(ddev, "%s error from disable flowcontrol urb\n", __func__); @@ -2793,7 +2753,7 @@ no_c_cflag_changes: index = FTDI_SIO_DISABLE_FLOW_CTRL; } - index |= priv->interface; + index |= priv->channel; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -2821,33 +2781,19 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, if (!buf) return -ENOMEM; /* - * The 8U232AM returns a two byte value (the SIO a 1 byte value) in - * the same format as the data returned from the in point. + * The device returns a two byte value (the SIO a 1 byte value) in the + * same format as the data returned from the IN endpoint. */ - switch (priv->chip_type) { - case SIO: + if (priv->chip_type == SIO) len = 1; - break; - case FT8U232AM: - case FT232BM: - case FT2232C: - case FT232RL: - case FT2232H: - case FT4232H: - case FT232H: - case FTX: + else len = 2; - break; - default: - ret = -EFAULT; - goto out; - } ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, + 0, priv->channel, buf, len, WDR_TIMEOUT); /* NOTE: We allow short responses and handle that below. */ @@ -2917,6 +2863,41 @@ static int ftdi_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static struct usb_serial_driver ftdi_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ftdi_sio", + .dev_groups = ftdi_groups, + }, + .description = "FTDI USB Serial Device", + .id_table = id_table_combined, + .num_ports = 1, + .bulk_in_size = 512, + .bulk_out_size = 256, + .probe = ftdi_probe, + .port_probe = ftdi_port_probe, + .port_remove = ftdi_port_remove, + .open = ftdi_open, + .dtr_rts = ftdi_dtr_rts, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, + .process_read_urb = ftdi_process_read_urb, + .prepare_write_buffer = ftdi_prepare_write_buffer, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .ioctl = ftdi_ioctl, + .get_serial = get_serial_info, + .set_serial = set_serial_info, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .tx_empty = ftdi_tx_empty, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &ftdi_device, NULL +}; module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index be1641e0408b..55ea61264f91 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -40,11 +40,11 @@ #define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ #define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ -/* Interface indices for FT2232, FT2232H and FT4232H devices */ -#define INTERFACE_A 1 -#define INTERFACE_B 2 -#define INTERFACE_C 3 -#define INTERFACE_D 4 +/* Channel indices for FT2232, FT2232H and FT4232H devices */ +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 /* @@ -153,18 +153,6 @@ * not supported by the FT8U232AM). */ -enum ftdi_chip_type { - SIO = 1, - FT8U232AM = 2, - FT232BM = 3, - FT2232C = 4, - FT232RL = 5, - FT2232H = 6, - FT4232H = 7, - FT232H = 8, - FTX = 9, -}; - enum ftdi_sio_baudrate { ftdi_sio_b300 = 0, ftdi_sio_b600 = 1, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 31c8ccabbbb7..e2099445db70 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -25,6 +25,13 @@ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ #define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ #define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ +#define FTDI_FT2233HP_PID 0x6040 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4233HP_PID 0x6041 /* Quad channel hi-speed device with PD */ +#define FTDI_FT2232HP_PID 0x6042 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4232HP_PID 0x6043 /* Quad channel hi-speed device with PD */ +#define FTDI_FT233HP_PID 0x6044 /* Dual channel hi-speed device with PD */ +#define FTDI_FT232HP_PID 0x6045 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4232HA_PID 0x6048 /* Quad channel automotive grade hi-speed device */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index ffa622539a25..3a4c0febf335 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -281,7 +281,7 @@ static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, - struct ktermios *old_termios); + const struct ktermios *old_termios); static int send_cmd_write_uart_register(struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); static int write_cmd_usb(struct edgeport_port *edge_port, @@ -1441,7 +1441,8 @@ static void edge_unthrottle(struct tty_struct *tty) * the termios structure *****************************************************************************/ static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); @@ -2325,7 +2326,7 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, *****************************************************************************/ static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, struct ktermios *old_termios) + struct edgeport_port *edge_port, const struct ktermios *old_termios) { struct device *dev = &edge_port->port->dev; struct edgeport_serial *edge_serial = diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index feba2a8d1233..bc3c24ea42c1 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -221,7 +221,8 @@ static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); static int do_download_mode(struct edgeport_serial *serial, @@ -2210,7 +2211,7 @@ static int restart_read(struct edgeport_port *edge_port) } static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, struct ktermios *old_termios) + struct edgeport_port *edge_port, const struct ktermios *old_termios) { struct device *dev = &edge_port->port->dev; struct ump_uart_config *config; @@ -2351,7 +2352,8 @@ static void change_port_settings(struct tty_struct *tty, } static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 7b44dbea95cd..82f108134e6f 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -51,7 +51,8 @@ static unsigned int ir_write_room(struct tty_struct *tty); static void ir_write_bulk_callback(struct urb *urb); static void ir_process_read_urb(struct urb *urb); static void ir_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); /* Not that this lot means you can only have one per system */ static u8 ir_baud; @@ -376,7 +377,8 @@ static void ir_process_read_urb(struct urb *urb) } static void ir_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_device *udev = port->serial->dev; unsigned char *transfer_buffer; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 0be3b5e1eaf3..77cba71bcccb 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -879,7 +879,8 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, } static void iuu_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { const u32 supported_mask = CMSPAR|PARENB|PARODD; struct iuu_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 1cfcd805f286..2966e0c4941e 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -616,7 +616,8 @@ static void keyspan_break_ctl(struct tty_struct *tty, int break_state) static void keyspan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { int baud_rate, device_port; struct keyspan_port_private *p_priv; diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 3e7628becdcd..6fd15cd9e1eb 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -321,7 +321,8 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) } static void keyspan_pda_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; speed_t speed; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index edcc57bd9b5e..394b3189e003 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -56,7 +56,8 @@ static void klsi_105_port_remove(struct usb_serial_port *port); static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); static void klsi_105_close(struct usb_serial_port *port); static void klsi_105_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static int klsi_105_tiocmget(struct tty_struct *tty); static void klsi_105_process_read_urb(struct urb *urb); static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, @@ -366,7 +367,7 @@ static void klsi_105_process_read_urb(struct urb *urb) static void klsi_105_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 4ed8b8b0a361..5e775f68fcb8 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -62,7 +62,8 @@ static int kobil_tiocmset(struct tty_struct *tty, static void kobil_read_int_callback(struct urb *urb); static void kobil_write_int_callback(struct urb *urb); static void kobil_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old); static void kobil_init_termios(struct tty_struct *tty); static const struct usb_device_id id_table[] = { @@ -474,7 +475,8 @@ static int kobil_tiocmset(struct tty_struct *tty, } static void kobil_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old) + struct usb_serial_port *port, + const struct ktermios *old) { struct kobil_private *priv; int result; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index ecd5b921e374..d3852feb81a4 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -45,7 +45,8 @@ static void mct_u232_close(struct usb_serial_port *port); static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); static void mct_u232_read_int_callback(struct urb *urb); static void mct_u232_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); static int mct_u232_tiocmget(struct tty_struct *tty); static int mct_u232_tiocmset(struct tty_struct *tty, @@ -593,7 +594,7 @@ exit: static void mct_u232_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 23ccbba716c7..1d1f85fabc28 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1356,7 +1356,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, */ static void change_port_settings(struct tty_struct *tty, struct moschip_port *mos7720_port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct usb_serial_port *port; struct usb_serial *serial; @@ -1494,7 +1494,8 @@ static void change_port_settings(struct tty_struct *tty, * termios structure. */ static void mos7720_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { int status; struct moschip_port *mos7720_port; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 925067a7978d..6b12bb4648b8 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1188,7 +1188,8 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_change_port_settings(struct tty_struct *tty, - struct moschip_port *mos7840_port, struct ktermios *old_termios) + struct moschip_port *mos7840_port, + const struct ktermios *old_termios) { struct usb_serial_port *port = mos7840_port->port; int baud; @@ -1330,7 +1331,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, static void mos7840_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int status; diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index eb45a9b0005c..faa0eedfe245 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -760,7 +760,7 @@ static int mxuport_tiocmget(struct tty_struct *tty) } static int mxuport_set_termios_flow(struct tty_struct *tty, - struct ktermios *old_termios, + const struct ktermios *old_termios, struct usb_serial_port *port, struct usb_serial *serial) { @@ -834,7 +834,7 @@ out: static void mxuport_set_termios(struct tty_struct *tty, struct usb_serial_port *port, - struct ktermios *old_termios) + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; u8 *buf; diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index a5caedbe72e2..6365cfe5402c 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -119,7 +119,8 @@ struct oti6858_control_pkt { static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port); static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static void oti6858_init_termios(struct tty_struct *tty); static void oti6858_read_int_callback(struct urb *urb); static void oti6858_read_bulk_callback(struct urb *urb); @@ -395,7 +396,8 @@ static void oti6858_init_termios(struct tty_struct *tty) } static void oti6858_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 40b1ab3d284d..8949c1891164 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -789,7 +789,8 @@ static bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_ty } static void pl2303_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_serial_private *spriv = usb_get_serial_data(serial); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 586ef5551e76..b1e844bf31f8 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -177,6 +177,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ {DEVICE_SWI(0x413c, 0x81b5)}, /* Dell Wireless 5811e QDL */ {DEVICE_SWI(0x413c, 0x81b6)}, /* Dell Wireless 5811e QDL */ + {DEVICE_SWI(0x413c, 0x81c2)}, /* Dell Wireless 5811e */ {DEVICE_SWI(0x413c, 0x81cb)}, /* Dell Wireless 5816e QDL */ {DEVICE_SWI(0x413c, 0x81cc)}, /* Dell Wireless 5816e */ {DEVICE_SWI(0x413c, 0x81cf)}, /* Dell Wireless 5819 */ diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 36b1e064e51f..6fca40ace83a 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -261,8 +261,8 @@ static int qt2_calc_num_ports(struct usb_serial *serial, } static void qt2_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; struct qt2_port_private *port_priv; diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 7039dc918827..09a972a838ee 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -283,7 +283,8 @@ static void spcp8x5_init_termios(struct tty_struct *tty) } static void spcp8x5_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 181e302136a5..1e1888b66305 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -214,8 +214,8 @@ out: kfree(data); static void ssu100_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; struct ktermios *termios = &tty->termios; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 18c0bd853392..b99f78224846 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -314,7 +314,8 @@ static bool ti_tx_empty(struct usb_serial_port *port); static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); static void ti_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); static int ti_tiocmget(struct tty_struct *tty); static int ti_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); @@ -892,7 +893,8 @@ static void ti_unthrottle(struct tty_struct *tty) } static void ti_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct ti_port *tport = usb_get_serial_port_data(port); struct ti_uart_config *config; diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c index 63d4a784ae45..c47439bd90fa 100644 --- a/drivers/usb/serial/upd78f0730.c +++ b/drivers/usb/serial/upd78f0730.c @@ -296,8 +296,8 @@ static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty) } static void upd78f0730_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct device *dev = &port->dev; struct upd78f0730_line_control request; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e35bea2235c1..164521ee10c6 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -519,7 +519,8 @@ static int serial_ioctl(struct tty_struct *tty, return retval; } -static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) +static void serial_set_termios(struct tty_struct *tty, + const struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 332fb92ae575..7f82d40753ee 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -82,7 +82,8 @@ static void whiteheat_close(struct usb_serial_port *port); static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss); static void whiteheat_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + struct usb_serial_port *port, + const struct ktermios *old_termios); static int whiteheat_tiocmget(struct tty_struct *tty); static int whiteheat_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); @@ -442,7 +443,8 @@ static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *s static void whiteheat_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { firm_setup_port(tty); } diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 6853cd56d8dc..f3811e060a44 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -104,7 +104,8 @@ static int xr21v141x_uart_enable(struct usb_serial_port *port); static int xr21v141x_uart_disable(struct usb_serial_port *port); static int xr21v141x_fifo_reset(struct usb_serial_port *port); static void xr21v141x_set_line_settings(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); struct xr_type { int reg_width; @@ -133,8 +134,8 @@ struct xr_type { int (*disable)(struct usb_serial_port *port); int (*fifo_reset)(struct usb_serial_port *port); void (*set_line_settings)(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios); + struct usb_serial_port *port, + const struct ktermios *old_termios); }; enum xr_type_id { @@ -622,8 +623,8 @@ static int xr21v141x_set_baudrate(struct tty_struct *tty, struct usb_serial_port } static void xr_set_flow_mode(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; @@ -674,7 +675,8 @@ static void xr_set_flow_mode(struct tty_struct *tty, } static void xr21v141x_set_line_settings(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct ktermios *termios = &tty->termios; u8 bits = 0; @@ -732,7 +734,8 @@ static void xr21v141x_set_line_settings(struct tty_struct *tty, } static void xr_cdc_set_line_coding(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct xr_data *data = usb_get_serial_port_data(port); struct usb_host_interface *alt = port->serial->interface->cur_altsetting; @@ -809,7 +812,8 @@ static void xr_cdc_set_line_coding(struct tty_struct *tty, } static void xr_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct xr_data *data = usb_get_serial_port_data(port); diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 1db2eefeea22..01f3c2779ccf 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -201,7 +201,7 @@ static int onetouch_connect_input(struct us_data *ss) onetouch->dev = input_dev; if (udev->manufacturer) - strlcpy(onetouch->name, udev->manufacturer, + strscpy(onetouch->name, udev->manufacturer, sizeof(onetouch->name)); if (udev->product) { if (udev->manufacturer) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 4993227ab293..20dcbccb290b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1275,12 +1275,6 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, USB_SC_RBC, USB_PR_BULK, NULL, 0 ), -UNUSUAL_DEV(0x090c, 0x1000, 0x1100, 0x1100, - "Samsung", - "Flash Drive FIT", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64), - /* aeb */ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, "Feiya", diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index e205f409589a..b8f3b75fd7eb 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1105,7 +1105,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, int ret; struct device_node *node; - node = of_find_node_by_name(dev->of_node, "orientation_switch"); + node = of_get_child_by_name(dev->of_node, "orientation_switch"); if (!node) return 0; @@ -1115,7 +1115,7 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, return ret; } - node = of_find_node_by_name(dev->of_node, "mode_switch"); + node = of_get_child_by_name(dev->of_node, "mode_switch"); if (!node) { dev_err(dev, "no typec mux exist"); ret = -ENODEV; diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 464330776cd6..941735c73161 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -29,7 +29,7 @@ static int switch_fwnode_match(struct device *dev, const void *fwnode) if (!is_typec_switch_dev(dev)) return 0; - return dev_fwnode(dev) == fwnode; + return device_match_fwnode(dev, fwnode); } static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, @@ -259,7 +259,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode) if (!is_typec_mux_dev(dev)) return 0; - return dev_fwnode(dev) == fwnode; + return device_match_fwnode(dev, fwnode); } static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, diff --git a/drivers/usb/typec/qcom-pmic-typec.c b/drivers/usb/typec/qcom-pmic-typec.c index a0454a80c4a2..432ea62f1bab 100644 --- a/drivers/usb/typec/qcom-pmic-typec.c +++ b/drivers/usb/typec/qcom-pmic-typec.c @@ -195,9 +195,8 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) qcom_usb->role_sw = fwnode_usb_role_switch_get(dev_fwnode(qcom_usb->dev)); if (IS_ERR(qcom_usb->role_sw)) { - if (PTR_ERR(qcom_usb->role_sw) != -EPROBE_DEFER) - dev_err(dev, "failed to get role switch\n"); - ret = PTR_ERR(qcom_usb->role_sw); + ret = dev_err_probe(dev, PTR_ERR(qcom_usb->role_sw), + "failed to get role switch\n"); goto err_typec_port; } diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c index 2003731f1bee..ee94dbbe4745 100644 --- a/drivers/usb/typec/retimer.c +++ b/drivers/usb/typec/retimer.c @@ -31,7 +31,7 @@ static bool dev_name_ends_with(struct device *dev, const char *suffix) static int retimer_fwnode_match(struct device *dev, const void *fwnode) { - return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer"); + return device_match_fwnode(dev, fwnode) && dev_name_ends_with(dev, "-retimer"); } static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data) diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index 8638f1d39896..494b371151e0 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -750,11 +750,8 @@ static int stusb160x_probe(struct i2c_client *client) if (client->irq) { chip->role_sw = fwnode_usb_role_switch_get(fwnode); if (IS_ERR(chip->role_sw)) { - ret = PTR_ERR(chip->role_sw); - if (ret != -EPROBE_DEFER) - dev_err(chip->dev, - "Failed to get usb role switch: %d\n", - ret); + ret = dev_err_probe(chip->dev, PTR_ERR(chip->role_sw), + "Failed to get usb role switch\n"); goto port_unregister; } diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 073fd2ea5e0b..e6b88ca4a4b9 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,17 @@ config TYPEC_MT6360 USB Type-C. It works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_TCPCI_MT6370 + tristate "MediaTek MT6370 Type-C driver" + depends on MFD_MT6370 + help + MediaTek MT6370 is a multi-functional IC that includes + USB Type-C. It works with Type-C Port Controller Manager + to provide USB PD and USB Type-C functionalities. + + This driver can also be built as a module. The module + will be called "tcpci_mt6370". + config TYPEC_TCPCI_MAXIM tristate "Maxim TCPCI based Type-C chip driver" help diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index 7d499f3569fd..906d9dced8e7 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -6,4 +6,5 @@ typec_wcove-y := wcove.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o +obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 5e9348f28d50..721b2a548084 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -151,7 +151,7 @@ static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, if (fusb302_log_full(chip)) { chip->logbuffer_head = max(chip->logbuffer_head - 1, 0); - strlcpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); + strscpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); } if (chip->logbuffer_head < 0 || @@ -1743,9 +1743,8 @@ static int fusb302_probe(struct i2c_client *client, chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev); if (IS_ERR(chip->tcpm_port)) { fwnode_handle_put(chip->tcpc_dev.fwnode); - ret = PTR_ERR(chip->tcpm_port); - if (ret != -EPROBE_DEFER) - dev_err(dev, "cannot register tcpm port, ret=%d", ret); + ret = dev_err_probe(dev, PTR_ERR(chip->tcpm_port), + "cannot register tcpm port\n"); goto destroy_workqueue; } diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index f00810d198a8..b2bfcebe218f 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -27,11 +27,6 @@ #define VPPS_VALID_MIN_MV 100 #define VSINKDISCONNECT_PD_MIN_PERCENT 90 -#define tcpc_presenting_rd(reg, cc) \ - (!(TCPC_ROLE_CTRL_DRP & (reg)) && \ - (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \ - (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT))) - struct tcpci { struct device *dev; @@ -218,23 +213,6 @@ static int tcpci_start_toggling(struct tcpc_dev *tcpc, TCPC_CMD_LOOK4CONNECTION); } -static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) -{ - switch (cc) { - case 0x1: - return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA; - case 0x2: - return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD; - case 0x3: - if (sink) - return TYPEC_CC_RP_3_0; - fallthrough; - case 0x0: - default: - return TYPEC_CC_OPEN; - } -} - static int tcpci_get_cc(struct tcpc_dev *tcpc, enum typec_cc_status *cc1, enum typec_cc_status *cc2) { diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c new file mode 100644 index 000000000000..c5bb201a5163 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MT6370_REG_SYSCTRL8 0x9B + +#define MT6370_AUTOIDLE_MASK BIT(3) + +#define MT6370_VENDOR_ID 0x29CF +#define MT6370_TCPC_DID_A 0x2170 + +struct mt6370_priv { + struct device *dev; + struct regulator *vbus; + struct tcpci *tcpci; + struct tcpci_data tcpci_data; +}; + +static const struct reg_sequence mt6370_reg_init[] = { + REG_SEQ(0xA0, 0x1, 1000), + REG_SEQ(0x81, 0x38, 0), + REG_SEQ(0x82, 0x82, 0), + REG_SEQ(0xBA, 0xFC, 0), + REG_SEQ(0xBB, 0x50, 0), + REG_SEQ(0x9E, 0x8F, 0), + REG_SEQ(0xA1, 0x5, 0), + REG_SEQ(0xA2, 0x4, 0), + REG_SEQ(0xA3, 0x4A, 0), + REG_SEQ(0xA4, 0x01, 0), + REG_SEQ(0x95, 0x01, 0), + REG_SEQ(0x80, 0x71, 0), + REG_SEQ(0x9B, 0x3A, 1000), +}; + +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data) +{ + u16 did; + int ret; + + ret = regmap_register_patch(data->regmap, mt6370_reg_init, + ARRAY_SIZE(mt6370_reg_init)); + if (ret) + return ret; + + ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16)); + if (ret) + return ret; + + if (did == MT6370_TCPC_DID_A) + return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80); + + return 0; +} + +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data, + bool enable) +{ + return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8, + MT6370_AUTOIDLE_MASK, + enable ? 0 : MT6370_AUTOIDLE_MASK); +} + +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data, + bool source, bool sink) +{ + struct mt6370_priv *priv = container_of(data, struct mt6370_priv, + tcpci_data); + int ret; + + ret = regulator_is_enabled(priv->vbus); + if (ret < 0) + return ret; + + if (ret && !source) + return regulator_disable(priv->vbus); + + if (!ret && source) + return regulator_enable(priv->vbus); + + return 0; +} + +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id) +{ + struct mt6370_priv *priv = dev_id; + + return tcpci_irq(priv->tcpci); +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + struct regmap *regmap = priv->tcpci_data.regmap; + u16 vid; + int ret; + + ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16)); + if (ret) + return ret; + + if (vid != MT6370_VENDOR_ID) + return dev_err_probe(priv->dev, -ENODEV, + "Vendor ID not correct 0x%02x\n", vid); + + return 0; +} + +static void mt6370_unregister_tcpci_port(void *tcpci) +{ + tcpci_unregister_port(tcpci); +} + +static int mt6370_tcpc_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + struct device *dev = &pdev->dev; + int irq, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->tcpci_data.regmap) + return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + return ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get irq\n"); + + /* Assign TCPCI feature and ops */ + priv->tcpci_data.auto_discharge_disconnect = 1; + priv->tcpci_data.init = mt6370_tcpc_init; + priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn; + + priv->vbus = devm_regulator_get_optional(dev, "vbus"); + if (!IS_ERR(priv->vbus)) + priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus; + + priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data); + if (IS_ERR(priv->tcpci)) + return dev_err_probe(dev, PTR_ERR(priv->tcpci), + "Failed to register tcpci port\n"); + + ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port, priv->tcpci); + if (ret) + return ret; + + ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler, + IRQF_ONESHOT, dev_name(dev), priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to allocate irq\n"); + + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, irq); + + return 0; +} + +static int mt6370_tcpc_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + + return 0; +} + +static const struct of_device_id mt6370_tcpc_devid_table[] = { + { .compatible = "mediatek,mt6370-tcpc" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table); + +static struct platform_driver mt6370_tcpc_driver = { + .driver = { + .name = "mt6370-tcpc", + .of_match_table = mt6370_tcpc_devid_table, + }, + .probe = mt6370_tcpc_probe, + .remove = mt6370_tcpc_remove, +}; +module_platform_driver(mt6370_tcpc_driver); + +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index c1327713f06d..7b217c712c11 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -5,6 +5,7 @@ * Richtek RT1711H Type-C Chip Driver */ +#include #include #include #include @@ -13,16 +14,27 @@ #include #include #include +#include #define RT1711H_VID 0x29CF #define RT1711H_PID 0x1711 +#define RT1711H_DID 0x2171 +#define RT1715_DID 0x2173 + +#define RT1711H_PHYCTRL1 0x80 +#define RT1711H_PHYCTRL2 0x81 + +#define RT1711H_RTCTRL4 0x93 +/* rx threshold of rd/rp: 1b0 for level 0.4V/0.7V, 1b1 for 0.35V/0.75V */ +#define RT1711H_BMCIO_RXDZSEL BIT(0) #define RT1711H_RTCTRL8 0x9B - /* Autoidle timeout = (tout * 2 + 1) * 6.4ms */ #define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \ (((ck300) << 7) | ((ship_off) << 5) | \ ((auto_idle) << 3) | ((tout) & 0x07)) +#define RT1711H_AUTOIDLEEN BIT(3) +#define RT1711H_ENEXTMSG BIT(4) #define RT1711H_RTCTRL11 0x9E @@ -35,10 +47,17 @@ #define RT1711H_RTCTRL15 0xA2 #define RT1711H_RTCTRL16 0xA3 +#define RT1711H_RTCTRL18 0xAF +/* 1b0 as fixed rx threshold of rd/rp 0.55V, 1b1 depends on RTCRTL4[0] */ +#define BMCIO_RXDZEN BIT(0) + struct rt1711h_chip { struct tcpci_data data; struct tcpci *tcpci; struct device *dev; + struct regulator *vbus; + bool src_en; + u16 did; }; static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val) @@ -75,8 +94,9 @@ static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata) static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) { - int ret; struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); + struct regmap *regmap = chip->data.regmap; + int ret; /* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */ ret = rt1711h_write8(chip, RT1711H_RTCTRL8, @@ -84,6 +104,14 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) if (ret < 0) return ret; + /* Enable PD30 extended message for RT1715 */ + if (chip->did == RT1715_DID) { + ret = regmap_update_bits(regmap, RT1711H_RTCTRL8, + RT1711H_ENEXTMSG, RT1711H_ENEXTMSG); + if (ret < 0) + return ret; + } + /* I2C reset : (val + 1) * 12.5ms */ ret = rt1711h_write8(chip, RT1711H_RTCTRL11, RT1711H_RTCTRL11_SET(1, 0x0F)); @@ -101,7 +129,37 @@ static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata) return ret; /* dcSRC.DRP : 33% */ - return rt1711h_write16(chip, RT1711H_RTCTRL16, 330); + ret = rt1711h_write16(chip, RT1711H_RTCTRL16, 330); + if (ret < 0) + return ret; + + /* Enable phy discard retry, retry count 7, rx filter deglitch 100 us */ + ret = rt1711h_write8(chip, RT1711H_PHYCTRL1, 0xF1); + if (ret < 0) + return ret; + + /* Decrease wait time of BMC-encoded 1 bit from 2.67us to 2.55us */ + /* wait time : (val * .4167) us */ + return rt1711h_write8(chip, RT1711H_PHYCTRL2, 62); +} + +static int rt1711h_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, + bool src, bool snk) +{ + struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); + int ret; + + if (chip->src_en == src) + return 0; + + if (src) + ret = regulator_enable(chip->vbus); + else + ret = regulator_disable(chip->vbus); + + if (!ret) + chip->src_en = src; + return ret; } static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, @@ -109,8 +167,55 @@ static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata, { struct rt1711h_chip *chip = tdata_to_rt1711h(tdata); - return rt1711h_write8(chip, RT1711H_RTCTRL8, - RT1711H_RTCTRL8_SET(0, 1, !enable, 2)); + return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL8, + RT1711H_AUTOIDLEEN, enable ? 0 : RT1711H_AUTOIDLEEN); +} + +/* + * Selects the CC PHY noise filter voltage level according to the remote current + * CC voltage level. + * + * @status: The port's current cc status read from IC + * Return 0 if writes succeed; failure code otherwise + */ +static inline int rt1711h_init_cc_params(struct rt1711h_chip *chip, u8 status) +{ + int ret, cc1, cc2; + u8 role = 0; + u32 rxdz_en, rxdz_sel; + + ret = rt1711h_read8(chip, TCPC_ROLE_CTRL, &role); + if (ret < 0) + return ret; + + cc1 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC1_SHIFT) & + TCPC_CC_STATUS_CC1_MASK, + status & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role, CC1)); + cc2 = tcpci_to_typec_cc((status >> TCPC_CC_STATUS_CC2_SHIFT) & + TCPC_CC_STATUS_CC2_MASK, + status & TCPC_CC_STATUS_TERM || + tcpc_presenting_rd(role, CC2)); + + if ((cc1 >= TYPEC_CC_RP_1_5 && cc2 < TYPEC_CC_RP_DEF) || + (cc2 >= TYPEC_CC_RP_1_5 && cc1 < TYPEC_CC_RP_DEF)) { + rxdz_en = BMCIO_RXDZEN; + if (chip->did == RT1715_DID) + rxdz_sel = RT1711H_BMCIO_RXDZSEL; + else + rxdz_sel = 0; + } else { + rxdz_en = 0; + rxdz_sel = RT1711H_BMCIO_RXDZSEL; + } + + ret = regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL18, + BMCIO_RXDZEN, rxdz_en); + if (ret < 0) + return ret; + + return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL4, + RT1711H_BMCIO_RXDZSEL, rxdz_sel); } static int rt1711h_start_drp_toggling(struct tcpci *tcpci, @@ -173,6 +278,8 @@ static irqreturn_t rt1711h_irq(int irq, void *dev_id) /* Clear cc change event triggered by starting toggling */ if (status & TCPC_CC_STATUS_TOGGLING) rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS); + else + rt1711h_init_cc_params(chip, status); } out: @@ -191,7 +298,7 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip) return 0; } -static int rt1711h_check_revision(struct i2c_client *i2c) +static int rt1711h_check_revision(struct i2c_client *i2c, struct rt1711h_chip *chip) { int ret; @@ -209,7 +316,15 @@ static int rt1711h_check_revision(struct i2c_client *i2c) dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret); return -ENODEV; } - return 0; + ret = i2c_smbus_read_word_data(i2c, TCPC_BCD_DEV); + if (ret < 0) + return ret; + if (ret != chip->did) { + dev_err(&i2c->dev, "did is not correct, 0x%04x\n", ret); + return -ENODEV; + } + dev_dbg(&i2c->dev, "did is 0x%04x\n", ret); + return ret; } static int rt1711h_probe(struct i2c_client *client, @@ -218,16 +333,18 @@ static int rt1711h_probe(struct i2c_client *client, int ret; struct rt1711h_chip *chip; - ret = rt1711h_check_revision(client); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->did = (size_t)device_get_match_data(&client->dev); + + ret = rt1711h_check_revision(client, chip); if (ret < 0) { dev_err(&client->dev, "check vid/pid fail\n"); return ret; } - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - chip->data.regmap = devm_regmap_init_i2c(client, &rt1711h_regmap_config); if (IS_ERR(chip->data.regmap)) @@ -245,7 +362,12 @@ static int rt1711h_probe(struct i2c_client *client, if (ret < 0) return ret; + chip->vbus = devm_regulator_get(&client->dev, "vbus"); + if (IS_ERR(chip->vbus)) + return PTR_ERR(chip->vbus); + chip->data.init = rt1711h_init; + chip->data.set_vbus = rt1711h_set_vbus; chip->data.set_vconn = rt1711h_set_vconn; chip->data.start_drp_toggling = rt1711h_start_drp_toggling; chip->tcpci = tcpci_register_port(chip->dev, &chip->data); @@ -272,13 +394,15 @@ static void rt1711h_remove(struct i2c_client *client) static const struct i2c_device_id rt1711h_id[] = { { "rt1711h", 0 }, + { "rt1715", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt1711h_id); #ifdef CONFIG_OF static const struct of_device_id rt1711h_of_match[] = { - { .compatible = "richtek,rt1711h", }, + { .compatible = "richtek,rt1711h", .data = (void *)RT1711H_DID }, + { .compatible = "richtek,rt1715", .data = (void *)RT1715_DID }, {}, }; MODULE_DEVICE_TABLE(of, rt1711h_of_match); diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 6364f0d467ea..74fb5a4c6f21 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1067,11 +1067,9 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) cap->fwnode = ucsi_find_fwnode(con); con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode); - if (IS_ERR(con->usb_role_sw)) { - dev_err(ucsi->dev, "con%d: failed to get usb role switch\n", - con->num); - return PTR_ERR(con->usb_role_sw); - } + if (IS_ERR(con->usb_role_sw)) + return dev_err_probe(ucsi->dev, PTR_ERR(con->usb_role_sw), + "con%d: failed to get usb role switch\n", con->num); /* Delay other interactions with the con until registration is complete */ mutex_lock(&con->lock); diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 349756335362..835f1c4372ba 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -125,6 +125,11 @@ struct version_format { #define CCG_FW_BUILD_NVIDIA (('n' << 8) | 'v') #define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10)) +/* Firmware for Tegra doesn't support UCSI ALT command, built + * for NVIDIA has known issue of reporting wrong capability info + */ +#define CCG_FW_BUILD_NVIDIA_TEGRA (('g' << 8) | 'n') + /* Altmode offset for NVIDIA Function Test Board (FTB) */ #define NVIDIA_FTB_DP_OFFSET (2) #define NVIDIA_FTB_DBG_OFFSET (3) @@ -513,6 +518,7 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); + struct ucsi_capability *cap; struct ucsi_altmode *alt; int ret; @@ -536,6 +542,12 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, ucsi_ccg_nvidia_altmode(uc, alt); } break; + case UCSI_GET_CAPABILITY: + if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) { + cap = val; + cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS; + } + break; default: break; } diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 16289ff583b4..7b92f0c8de70 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -599,7 +599,7 @@ static int ucsi_stm32g0_probe_bootloader(struct ucsi *ucsi) g0->i2c_bl = i2c_new_dummy_device(g0->client->adapter, STM32G0_I2C_BL_ADDR); if (IS_ERR(g0->i2c_bl)) { ret = dev_err_probe(g0->dev, PTR_ERR(g0->i2c_bl), - "Failed to register booloader I2C address\n"); + "Failed to register bootloader I2C address\n"); return ret; } } diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 77a5b3f8736a..e8c3131a8543 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -100,7 +100,7 @@ static int add_match_busid(char *busid) for (i = 0; i < MAX_BUSID; i++) { spin_lock(&busid_table[i].busid_lock); if (!busid_table[i].name[0]) { - strlcpy(busid_table[i].name, busid, BUSID_SIZE); + strscpy(busid_table[i].name, busid, BUSID_SIZE); if ((busid_table[i].status != STUB_BUSID_ALLOC) && (busid_table[i].status != STUB_BUSID_REMOV)) busid_table[i].status = STUB_BUSID_ADDED; diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 5dd41e8215e0..fc01b31bbb87 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -464,7 +464,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, int nents; int num_urbs = 1; int pipe = get_pipe(sdev, pdu); - int use_sg = pdu->u.cmd_submit.transfer_flags & URB_DMA_MAP_SG; + int use_sg = pdu->u.cmd_submit.transfer_flags & USBIP_URB_DMA_MAP_SG; int support_sg = 1; int np = 0; int ret, i; @@ -514,7 +514,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, num_urbs = nents; priv->completed_urbs = 0; pdu->u.cmd_submit.transfer_flags &= - ~URB_DMA_MAP_SG; + ~USBIP_URB_DMA_MAP_SG; } } else { buffer = kzalloc(buf_len, GFP_KERNEL); diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index 2ab99244bc31..053a2bca4c47 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -344,6 +344,91 @@ static unsigned int tweak_transfer_flags(unsigned int flags) return flags; } +/* + * USBIP driver packs URB transfer flags in PDUs that are exchanged + * between Server (usbip_host) and Client (vhci_hcd). URB_* flags + * are internal to kernel and could change. Where as USBIP URB flags + * exchanged in PDUs are USBIP user API must not change. + * + * USBIP_URB* flags are exported as explicit API and client and server + * do mapping from kernel flags to USBIP_URB*. Details as follows: + * + * Client tx path (USBIP_CMD_SUBMIT): + * - Maps URB_* to USBIP_URB_* when it sends USBIP_CMD_SUBMIT packet. + * + * Server rx path (USBIP_CMD_SUBMIT): + * - Maps USBIP_URB_* to URB_* when it receives USBIP_CMD_SUBMIT packet. + * + * Flags aren't included in USBIP_CMD_UNLINK and USBIP_RET_SUBMIT packets + * and no special handling is needed for them in the following cases: + * - Server rx path (USBIP_CMD_UNLINK) + * - Client rx path & Server tx path (USBIP_RET_SUBMIT) + * + * Code paths: + * usbip_pack_pdu() is the common routine that handles packing pdu from + * urb and unpack pdu to an urb. + * + * usbip_pack_cmd_submit() and usbip_pack_ret_submit() handle + * USBIP_CMD_SUBMIT and USBIP_RET_SUBMIT respectively. + * + * usbip_map_urb_to_usbip() and usbip_map_usbip_to_urb() are used + * by usbip_pack_cmd_submit() and usbip_pack_ret_submit() to map + * flags. + */ + +struct urb_to_usbip_flags { + u32 urb_flag; + u32 usbip_flag; +}; + +#define NUM_USBIP_FLAGS 17 + +static const struct urb_to_usbip_flags flag_map[NUM_USBIP_FLAGS] = { + {URB_SHORT_NOT_OK, USBIP_URB_SHORT_NOT_OK}, + {URB_ISO_ASAP, USBIP_URB_ISO_ASAP}, + {URB_NO_TRANSFER_DMA_MAP, USBIP_URB_NO_TRANSFER_DMA_MAP}, + {URB_ZERO_PACKET, USBIP_URB_ZERO_PACKET}, + {URB_NO_INTERRUPT, USBIP_URB_NO_INTERRUPT}, + {URB_FREE_BUFFER, USBIP_URB_FREE_BUFFER}, + {URB_DIR_IN, USBIP_URB_DIR_IN}, + {URB_DIR_OUT, USBIP_URB_DIR_OUT}, + {URB_DIR_MASK, USBIP_URB_DIR_MASK}, + {URB_DMA_MAP_SINGLE, USBIP_URB_DMA_MAP_SINGLE}, + {URB_DMA_MAP_PAGE, USBIP_URB_DMA_MAP_PAGE}, + {URB_DMA_MAP_SG, USBIP_URB_DMA_MAP_SG}, + {URB_MAP_LOCAL, USBIP_URB_MAP_LOCAL}, + {URB_SETUP_MAP_SINGLE, USBIP_URB_SETUP_MAP_SINGLE}, + {URB_SETUP_MAP_LOCAL, USBIP_URB_SETUP_MAP_LOCAL}, + {URB_DMA_SG_COMBINED, USBIP_URB_DMA_SG_COMBINED}, + {URB_ALIGNED_TEMP_BUFFER, USBIP_URB_ALIGNED_TEMP_BUFFER}, +}; + +static unsigned int urb_to_usbip(unsigned int flags) +{ + unsigned int map_flags = 0; + int loop; + + for (loop = 0; loop < NUM_USBIP_FLAGS; loop++) { + if (flags & flag_map[loop].urb_flag) + map_flags |= flag_map[loop].usbip_flag; + } + + return map_flags; +} + +static unsigned int usbip_to_urb(unsigned int flags) +{ + unsigned int map_flags = 0; + int loop; + + for (loop = 0; loop < NUM_USBIP_FLAGS; loop++) { + if (flags & flag_map[loop].usbip_flag) + map_flags |= flag_map[loop].urb_flag; + } + + return map_flags; +} + static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, int pack) { @@ -354,14 +439,14 @@ static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, * will be discussed when usbip is ported to other operating systems. */ if (pack) { - spdu->transfer_flags = - tweak_transfer_flags(urb->transfer_flags); + /* map after tweaking the urb flags */ + spdu->transfer_flags = urb_to_usbip(tweak_transfer_flags(urb->transfer_flags)); spdu->transfer_buffer_length = urb->transfer_buffer_length; spdu->start_frame = urb->start_frame; spdu->number_of_packets = urb->number_of_packets; spdu->interval = urb->interval; } else { - urb->transfer_flags = spdu->transfer_flags; + urb->transfer_flags = usbip_to_urb(spdu->transfer_flags); urb->transfer_buffer_length = spdu->transfer_buffer_length; urb->start_frame = spdu->start_frame; urb->number_of_packets = spdu->number_of_packets; diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 950c63fa4d0b..ddb3fc258df9 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -1121,7 +1121,7 @@ void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, } EXPORT_SYMBOL_GPL(debugfs_print_regs32); -static int debugfs_show_regset32(struct seq_file *s, void *data) +static int debugfs_regset32_show(struct seq_file *s, void *data) { struct debugfs_regset32 *regset = s->private; @@ -1136,17 +1136,7 @@ static int debugfs_show_regset32(struct seq_file *s, void *data) return 0; } -static int debugfs_open_regset32(struct inode *inode, struct file *file) -{ - return single_open(file, debugfs_show_regset32, inode->i_private); -} - -static const struct file_operations fops_regset32 = { - .open = debugfs_open_regset32, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(debugfs_regset32); /** * debugfs_create_regset32 - create a debugfs file that returns register values @@ -1167,7 +1157,7 @@ void debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset) { - debugfs_create_file(name, mode, parent, regset, &fops_regset32); + debugfs_create_file(name, mode, parent, regset, &debugfs_regset32_fops); } EXPORT_SYMBOL_GPL(debugfs_create_regset32); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 232cfdf095ae..2e8e112b1993 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -82,6 +82,8 @@ struct debugfs_mount_opts { kuid_t uid; kgid_t gid; umode_t mode; + /* Opt_* bitfield. */ + unsigned int opts; }; enum { @@ -111,6 +113,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) kgid_t gid; char *p; + opts->opts = 0; opts->mode = DEBUGFS_DEFAULT_MODE; while ((p = strsep(&data, ",")) != NULL) { @@ -145,24 +148,44 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) * but traditionally debugfs has ignored all mount options */ } + + opts->opts |= BIT(token); } return 0; } -static int debugfs_apply_options(struct super_block *sb) +static void _debugfs_apply_options(struct super_block *sb, bool remount) { struct debugfs_fs_info *fsi = sb->s_fs_info; struct inode *inode = d_inode(sb->s_root); struct debugfs_mount_opts *opts = &fsi->mount_opts; - inode->i_mode &= ~S_IALLUGO; - inode->i_mode |= opts->mode; + /* + * On remount, only reset mode/uid/gid if they were provided as mount + * options. + */ - inode->i_uid = opts->uid; - inode->i_gid = opts->gid; + if (!remount || opts->opts & BIT(Opt_mode)) { + inode->i_mode &= ~S_IALLUGO; + inode->i_mode |= opts->mode; + } - return 0; + if (!remount || opts->opts & BIT(Opt_uid)) + inode->i_uid = opts->uid; + + if (!remount || opts->opts & BIT(Opt_gid)) + inode->i_gid = opts->gid; +} + +static void debugfs_apply_options(struct super_block *sb) +{ + _debugfs_apply_options(sb, false); +} + +static void debugfs_apply_options_remount(struct super_block *sb) +{ + _debugfs_apply_options(sb, true); } static int debugfs_remount(struct super_block *sb, int *flags, char *data) @@ -175,7 +198,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data) if (err) goto fail; - debugfs_apply_options(sb); + debugfs_apply_options_remount(sb); fail: return err; diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 1cc88ba6de90..3990f3e270cb 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -472,6 +472,16 @@ static void kernfs_drain(struct kernfs_node *kn) lockdep_assert_held_write(&root->kernfs_rwsem); WARN_ON_ONCE(kernfs_active(kn)); + /* + * Skip draining if already fully drained. This avoids draining and its + * lockdep annotations for nodes which have never been activated + * allowing embedding kernfs_remove() in create error paths without + * worrying about draining. + */ + if (atomic_read(&kn->active) == KN_DEACTIVATED_BIAS && + !kernfs_should_drain_open_files(kn)) + return; + up_write(&root->kernfs_rwsem); if (kernfs_lockdep(kn)) { @@ -480,7 +490,6 @@ static void kernfs_drain(struct kernfs_node *kn) lock_contended(&kn->dep_map, _RET_IP_); } - /* but everyone should wait for draining */ wait_event(root->deactivate_waitq, atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); @@ -489,7 +498,8 @@ static void kernfs_drain(struct kernfs_node *kn) rwsem_release(&kn->dep_map, _RET_IP_); } - kernfs_drain_open_files(kn); + if (kernfs_should_drain_open_files(kn)) + kernfs_drain_open_files(kn); down_write(&root->kernfs_rwsem); } @@ -695,13 +705,7 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root, goto err_unlock; } - /* - * ACTIVATED is protected with kernfs_mutex but it was clear when - * @kn was added to idr and we just wanna see it set. No need to - * grab kernfs_mutex. - */ - if (unlikely(!(kn->flags & KERNFS_ACTIVATED) || - !atomic_inc_not_zero(&kn->count))) + if (unlikely(!kernfs_active(kn) || !atomic_inc_not_zero(&kn->count))) goto err_unlock; spin_unlock(&kernfs_idr_lock); @@ -743,10 +747,7 @@ int kernfs_add_one(struct kernfs_node *kn) goto out_unlock; ret = -ENOENT; - if (parent->flags & KERNFS_EMPTY_DIR) - goto out_unlock; - - if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) + if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR)) goto out_unlock; kn->hash = kernfs_name_hash(kn->name, kn->ns); @@ -1304,6 +1305,21 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, return pos->parent; } +static void kernfs_activate_one(struct kernfs_node *kn) +{ + lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem); + + kn->flags |= KERNFS_ACTIVATED; + + if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) + return; + + WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb)); + WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); + + atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); +} + /** * kernfs_activate - activate a node which started deactivated * @kn: kernfs_node whose subtree is to be activated @@ -1325,15 +1341,42 @@ void kernfs_activate(struct kernfs_node *kn) down_write(&root->kernfs_rwsem); pos = NULL; - while ((pos = kernfs_next_descendant_post(pos, kn))) { - if (pos->flags & KERNFS_ACTIVATED) - continue; + while ((pos = kernfs_next_descendant_post(pos, kn))) + kernfs_activate_one(pos); - WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb)); - WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS); + up_write(&root->kernfs_rwsem); +} - atomic_sub(KN_DEACTIVATED_BIAS, &pos->active); - pos->flags |= KERNFS_ACTIVATED; +/** + * kernfs_show - show or hide a node + * @kn: kernfs_node to show or hide + * @show: whether to show or hide + * + * If @show is %false, @kn is marked hidden and deactivated. A hidden node is + * ignored in future activaitons. If %true, the mark is removed and activation + * state is restored. This function won't implicitly activate a new node in a + * %KERNFS_ROOT_CREATE_DEACTIVATED root which hasn't been activated yet. + * + * To avoid recursion complexities, directories aren't supported for now. + */ +void kernfs_show(struct kernfs_node *kn, bool show) +{ + struct kernfs_root *root = kernfs_root(kn); + + if (WARN_ON_ONCE(kernfs_type(kn) == KERNFS_DIR)) + return; + + down_write(&root->kernfs_rwsem); + + if (show) { + kn->flags &= ~KERNFS_HIDDEN; + if (kn->flags & KERNFS_ACTIVATED) + kernfs_activate_one(kn); + } else { + kn->flags |= KERNFS_HIDDEN; + if (kernfs_active(kn)) + atomic_add(KN_DEACTIVATED_BIAS, &kn->active); + kernfs_drain(kn); } up_write(&root->kernfs_rwsem); @@ -1358,34 +1401,27 @@ static void __kernfs_remove(struct kernfs_node *kn) pr_debug("kernfs %s: removing\n", kn->name); - /* prevent any new usage under @kn by deactivating all nodes */ + /* prevent new usage by marking all nodes removing and deactivating */ pos = NULL; - while ((pos = kernfs_next_descendant_post(pos, kn))) + while ((pos = kernfs_next_descendant_post(pos, kn))) { + pos->flags |= KERNFS_REMOVING; if (kernfs_active(pos)) atomic_add(KN_DEACTIVATED_BIAS, &pos->active); + } /* deactivate and unlink the subtree node-by-node */ do { pos = kernfs_leftmost_descendant(kn); /* - * kernfs_drain() drops kernfs_rwsem temporarily and @pos's + * kernfs_drain() may drop kernfs_rwsem temporarily and @pos's * base ref could have been put by someone else by the time * the function returns. Make sure it doesn't go away * underneath us. */ kernfs_get(pos); - /* - * Drain iff @kn was activated. This avoids draining and - * its lockdep annotations for nodes which have never been - * activated and allows embedding kernfs_remove() in create - * error paths without worrying about draining. - */ - if (kn->flags & KERNFS_ACTIVATED) - kernfs_drain(pos); - else - WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); + kernfs_drain(pos); /* * kernfs_unlink_sibling() succeeds once per node. Use it @@ -1585,8 +1621,11 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, down_write(&root->kernfs_rwsem); kn = kernfs_find_ns(parent, name, ns); - if (kn) + if (kn) { + kernfs_get(kn); __kernfs_remove(kn); + kernfs_put(kn); + } up_write(&root->kernfs_rwsem); diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index b3ec34386b43..9ab6c92e02da 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -23,6 +23,8 @@ struct kernfs_open_node { atomic_t event; wait_queue_head_t poll; struct list_head files; /* goes through kernfs_open_file.list */ + unsigned int nr_mmapped; + unsigned int nr_to_release; }; /* @@ -57,31 +59,17 @@ static inline struct mutex *kernfs_open_file_mutex_lock(struct kernfs_node *kn) } /** - * kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn. - * - * @of: associated kernfs_open_file instance. - * @kn: target kernfs_node. - * - * Fetch and return ->attr.open of @kn if @of->list is non empty. - * If @of->list is not empty we can safely assume that @of is on - * @kn->attr.open->files list and this guarantees that @kn->attr.open - * will not vanish i.e. dereferencing outside RCU read-side critical - * section is safe here. - * - * The caller needs to make sure that @of->list is not empty. + * of_on - Return the kernfs_open_node of the specified kernfs_open_file + * @of: taret kernfs_open_file */ -static struct kernfs_open_node * -kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn) +static struct kernfs_open_node *of_on(struct kernfs_open_file *of) { - struct kernfs_open_node *on; - - on = rcu_dereference_check(kn->attr.open, !list_empty(&of->list)); - - return on; + return rcu_dereference_protected(of->kn->attr.open, + !list_empty(&of->list)); } /** - * kernfs_deref_open_node_protected - Get kernfs_open_node corresponding to @kn + * kernfs_deref_open_node_locked - Get kernfs_open_node corresponding to @kn * * @kn: target kernfs_node. * @@ -96,7 +84,7 @@ kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn) * The caller needs to make sure that kernfs_open_file_mutex is held. */ static struct kernfs_open_node * -kernfs_deref_open_node_protected(struct kernfs_node *kn) +kernfs_deref_open_node_locked(struct kernfs_node *kn) { return rcu_dereference_protected(kn->attr.open, lockdep_is_held(kernfs_open_file_mutex_ptr(kn))); @@ -207,12 +195,8 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v) static int kernfs_seq_show(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; - struct kernfs_open_node *on = kernfs_deref_open_node(of, of->kn); - if (!on) - return -EINVAL; - - of->event = atomic_read(&on->event); + of->event = atomic_read(&of_on(of)->event); return of->kn->attr.ops->seq_show(sf, v); } @@ -235,7 +219,6 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) struct kernfs_open_file *of = kernfs_of(iocb->ki_filp); ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE); const struct kernfs_ops *ops; - struct kernfs_open_node *on; char *buf; buf = of->prealloc_buf; @@ -257,14 +240,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) goto out_free; } - on = kernfs_deref_open_node(of, of->kn); - if (!on) { - len = -EINVAL; - mutex_unlock(&of->mutex); - goto out_free; - } - - of->event = atomic_read(&on->event); + of->event = atomic_read(&of_on(of)->event); ops = kernfs_ops(of->kn); if (ops->read) @@ -553,6 +529,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) rc = 0; of->mmapped = true; + of_on(of)->nr_mmapped++; of->vm_ops = vma->vm_ops; vma->vm_ops = &kernfs_vm_ops; out_put: @@ -580,31 +557,30 @@ out_unlock: static int kernfs_get_open_node(struct kernfs_node *kn, struct kernfs_open_file *of) { - struct kernfs_open_node *on, *new_on = NULL; - struct mutex *mutex = NULL; + struct kernfs_open_node *on; + struct mutex *mutex; mutex = kernfs_open_file_mutex_lock(kn); - on = kernfs_deref_open_node_protected(kn); + on = kernfs_deref_open_node_locked(kn); - if (on) { - list_add_tail(&of->list, &on->files); - mutex_unlock(mutex); - return 0; - } else { + if (!on) { /* not there, initialize a new one */ - new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); - if (!new_on) { + on = kzalloc(sizeof(*on), GFP_KERNEL); + if (!on) { mutex_unlock(mutex); return -ENOMEM; } - atomic_set(&new_on->event, 1); - init_waitqueue_head(&new_on->poll); - INIT_LIST_HEAD(&new_on->files); - list_add_tail(&of->list, &new_on->files); - rcu_assign_pointer(kn->attr.open, new_on); + atomic_set(&on->event, 1); + init_waitqueue_head(&on->poll); + INIT_LIST_HEAD(&on->files); + rcu_assign_pointer(kn->attr.open, on); } - mutex_unlock(mutex); + list_add_tail(&of->list, &on->files); + if (kn->flags & KERNFS_HAS_RELEASE) + on->nr_to_release++; + + mutex_unlock(mutex); return 0; } @@ -613,6 +589,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn, * * @kn: target kernfs_node * @of: associated kernfs_open_file + * @open_failed: ->open() failed, cancel ->release() * * Unlink @of from list of @kn's associated open files. If list of * associated open files becomes empty, disassociate and free @@ -622,21 +599,30 @@ static int kernfs_get_open_node(struct kernfs_node *kn, * None. */ static void kernfs_unlink_open_file(struct kernfs_node *kn, - struct kernfs_open_file *of) + struct kernfs_open_file *of, + bool open_failed) { struct kernfs_open_node *on; - struct mutex *mutex = NULL; + struct mutex *mutex; mutex = kernfs_open_file_mutex_lock(kn); - on = kernfs_deref_open_node_protected(kn); + on = kernfs_deref_open_node_locked(kn); if (!on) { mutex_unlock(mutex); return; } - if (of) + if (of) { + if (kn->flags & KERNFS_HAS_RELEASE) { + WARN_ON_ONCE(of->released == open_failed); + if (open_failed) + on->nr_to_release--; + } + if (of->mmapped) + on->nr_mmapped--; list_del(&of->list); + } if (list_empty(&on->files)) { rcu_assign_pointer(kn->attr.open, NULL); @@ -763,7 +749,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file) return 0; err_put_node: - kernfs_unlink_open_file(kn, of); + kernfs_unlink_open_file(kn, of, true); err_seq_release: seq_release(inode, file); err_free: @@ -795,6 +781,7 @@ static void kernfs_release_file(struct kernfs_node *kn, */ kn->attr.ops->release(of); of->released = true; + of_on(of)->nr_to_release--; } } @@ -802,15 +789,16 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp) { struct kernfs_node *kn = inode->i_private; struct kernfs_open_file *of = kernfs_of(filp); - struct mutex *mutex = NULL; if (kn->flags & KERNFS_HAS_RELEASE) { + struct mutex *mutex; + mutex = kernfs_open_file_mutex_lock(kn); kernfs_release_file(kn, of); mutex_unlock(mutex); } - kernfs_unlink_open_file(kn, of); + kernfs_unlink_open_file(kn, of, false); seq_release(inode, filp); kfree(of->prealloc_buf); kfree(of); @@ -818,28 +806,33 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp) return 0; } +bool kernfs_should_drain_open_files(struct kernfs_node *kn) +{ + struct kernfs_open_node *on; + bool ret; + + /* + * @kn being deactivated guarantees that @kn->attr.open can't change + * beneath us making the lockless test below safe. + */ + WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); + + rcu_read_lock(); + on = rcu_dereference(kn->attr.open); + ret = on && (on->nr_mmapped || on->nr_to_release); + rcu_read_unlock(); + + return ret; +} + void kernfs_drain_open_files(struct kernfs_node *kn) { struct kernfs_open_node *on; struct kernfs_open_file *of; - struct mutex *mutex = NULL; - - if (!(kn->flags & (KERNFS_HAS_MMAP | KERNFS_HAS_RELEASE))) - return; - - /* - * lockless opportunistic check is safe below because no one is adding to - * ->attr.open at this point of time. This check allows early bail out - * if ->attr.open is already NULL. kernfs_unlink_open_file makes - * ->attr.open NULL only while holding kernfs_open_file_mutex so below - * check under kernfs_open_file_mutex_ptr(kn) will ensure bailing out if - * ->attr.open became NULL while waiting for the mutex. - */ - if (!rcu_access_pointer(kn->attr.open)) - return; + struct mutex *mutex; mutex = kernfs_open_file_mutex_lock(kn); - on = kernfs_deref_open_node_protected(kn); + on = kernfs_deref_open_node_locked(kn); if (!on) { mutex_unlock(mutex); return; @@ -848,13 +841,17 @@ void kernfs_drain_open_files(struct kernfs_node *kn) list_for_each_entry(of, &on->files, list) { struct inode *inode = file_inode(of->file); - if (kn->flags & KERNFS_HAS_MMAP) + if (of->mmapped) { unmap_mapping_range(inode->i_mapping, 0, 0, 1); + of->mmapped = false; + on->nr_mmapped--; + } if (kn->flags & KERNFS_HAS_RELEASE) kernfs_release_file(kn, of); } + WARN_ON_ONCE(on->nr_mmapped || on->nr_to_release); mutex_unlock(mutex); } @@ -874,11 +871,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn) */ __poll_t kernfs_generic_poll(struct kernfs_open_file *of, poll_table *wait) { - struct kernfs_node *kn = kernfs_dentry_node(of->file->f_path.dentry); - struct kernfs_open_node *on = kernfs_deref_open_node(of, kn); - - if (!on) - return EPOLLERR; + struct kernfs_open_node *on = of_on(of); poll_wait(of->file, &on->poll, wait); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 3ae214d02d44..fc5821effd97 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -157,6 +157,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, */ extern const struct file_operations kernfs_file_fops; +bool kernfs_should_drain_open_files(struct kernfs_node *kn); void kernfs_drain_open_files(struct kernfs_node *kn); /* diff --git a/include/asm-generic/termios-base.h b/include/asm-generic/termios-base.h deleted file mode 100644 index 59c5a3bd4a6e..000000000000 --- a/include/asm-generic/termios-base.h +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* termios.h: generic termios/termio user copying/translation - */ - -#ifndef _ASM_GENERIC_TERMIOS_BASE_H -#define _ASM_GENERIC_TERMIOS_BASE_H - -#include - -#ifndef __ARCH_TERMIO_GETPUT - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -static inline int user_termio_to_kernel_termios(struct ktermios *termios, - struct termio __user *termio) -{ - unsigned short tmp; - - if (get_user(tmp, &termio->c_iflag) < 0) - goto fault; - termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; - - if (get_user(tmp, &termio->c_oflag) < 0) - goto fault; - termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; - - if (get_user(tmp, &termio->c_cflag) < 0) - goto fault; - termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; - - if (get_user(tmp, &termio->c_lflag) < 0) - goto fault; - termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; - - if (get_user(termios->c_line, &termio->c_line) < 0) - goto fault; - - if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) - goto fault; - - return 0; - - fault: - return -EFAULT; -} - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) -{ - if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || - put_user(termios->c_oflag, &termio->c_oflag) < 0 || - put_user(termios->c_cflag, &termio->c_cflag) < 0 || - put_user(termios->c_lflag, &termio->c_lflag) < 0 || - put_user(termios->c_line, &termio->c_line) < 0 || - copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) - return -EFAULT; - - return 0; -} - -#ifndef user_termios_to_kernel_termios -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) -#endif - -#ifndef kernel_termios_to_user_termios -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) -#endif - -#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) - -#endif /* __ARCH_TERMIO_GETPUT */ - -#endif /* _ASM_GENERIC_TERMIOS_BASE_H */ diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h deleted file mode 100644 index b1398d0d4a1d..000000000000 --- a/include/asm-generic/termios.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_GENERIC_TERMIOS_H -#define _ASM_GENERIC_TERMIOS_H - - -#include -#include - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -static inline int user_termio_to_kernel_termios(struct ktermios *termios, - const struct termio __user *termio) -{ - unsigned short tmp; - - if (get_user(tmp, &termio->c_iflag) < 0) - goto fault; - termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; - - if (get_user(tmp, &termio->c_oflag) < 0) - goto fault; - termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; - - if (get_user(tmp, &termio->c_cflag) < 0) - goto fault; - termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; - - if (get_user(tmp, &termio->c_lflag) < 0) - goto fault; - termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; - - if (get_user(termios->c_line, &termio->c_line) < 0) - goto fault; - - if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) - goto fault; - - return 0; - - fault: - return -EFAULT; -} - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) -{ - if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || - put_user(termios->c_oflag, &termio->c_oflag) < 0 || - put_user(termios->c_cflag, &termio->c_cflag) < 0 || - put_user(termios->c_lflag, &termio->c_lflag) < 0 || - put_user(termios->c_line, &termio->c_line) < 0 || - copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) - return -EFAULT; - - return 0; -} - -#ifdef TCGETS2 -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios2 __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios2)); -} - -static inline int kernel_termios_to_user_termios(struct termios2 __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios2)); -} - -static inline int user_termios_to_kernel_termios_1(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios_1(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#else /* TCGETS2 */ -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#endif /* TCGETS2 */ - -#endif /* _ASM_GENERIC_TERMIOS_H */ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index a232f518d98a..c15de165ec8f 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -353,6 +353,9 @@ *(__tracepoints) \ /* implement dynamic printk debug */ \ . = ALIGN(8); \ + __start___dyndbg_classes = .; \ + KEEP(*(__dyndbg_classes)) \ + __stop___dyndbg_classes = .; \ __start___dyndbg = .; \ KEEP(*(__dyndbg)) \ __stop___dyndbg = .; \ diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 22fabdeed297..a44fb7ef257f 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -31,11 +31,12 @@ #include #include #include +#include #include /* Do *not* use outside of drm_print.[ch]! */ -extern unsigned int __drm_debug; +extern unsigned long __drm_debug; /** * DOC: print @@ -275,55 +276,75 @@ static inline struct drm_printer drm_err_printer(const char *prefix) * */ enum drm_debug_category { + /* These names must match those in DYNAMIC_DEBUG_CLASSBITS */ /** * @DRM_UT_CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, * drm_memory.c, ... */ - DRM_UT_CORE = 0x01, + DRM_UT_CORE, /** * @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915, * radeon, ... macro. */ - DRM_UT_DRIVER = 0x02, + DRM_UT_DRIVER, /** * @DRM_UT_KMS: Used in the modesetting code. */ - DRM_UT_KMS = 0x04, + DRM_UT_KMS, /** * @DRM_UT_PRIME: Used in the prime code. */ - DRM_UT_PRIME = 0x08, + DRM_UT_PRIME, /** * @DRM_UT_ATOMIC: Used in the atomic code. */ - DRM_UT_ATOMIC = 0x10, + DRM_UT_ATOMIC, /** * @DRM_UT_VBL: Used for verbose debug message in the vblank code. */ - DRM_UT_VBL = 0x20, + DRM_UT_VBL, /** * @DRM_UT_STATE: Used for verbose atomic state debugging. */ - DRM_UT_STATE = 0x40, + DRM_UT_STATE, /** * @DRM_UT_LEASE: Used in the lease code. */ - DRM_UT_LEASE = 0x80, + DRM_UT_LEASE, /** * @DRM_UT_DP: Used in the DP code. */ - DRM_UT_DP = 0x100, + DRM_UT_DP, /** * @DRM_UT_DRMRES: Used in the drm managed resources code. */ - DRM_UT_DRMRES = 0x200, + DRM_UT_DRMRES }; -static inline bool drm_debug_enabled(enum drm_debug_category category) +static inline bool drm_debug_enabled_raw(enum drm_debug_category category) { - return unlikely(__drm_debug & category); + return unlikely(__drm_debug & BIT(category)); } +#define drm_debug_enabled_instrumented(category) \ + ({ \ + pr_debug("todo: is this frequent enough to optimize ?\n"); \ + drm_debug_enabled_raw(category); \ + }) + +#if defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) +/* + * the drm.debug API uses dyndbg, so each drm_*dbg macro/callsite gets + * a descriptor, and only enabled callsites are reachable. They use + * the private macro to avoid re-testing the enable-bit. + */ +#define __drm_debug_enabled(category) true +#define drm_debug_enabled(category) drm_debug_enabled_instrumented(category) +#else +#define __drm_debug_enabled(category) drm_debug_enabled_raw(category) +#define drm_debug_enabled(category) drm_debug_enabled_raw(category) +#endif + /* * struct device based logging * @@ -333,9 +354,10 @@ static inline bool drm_debug_enabled(enum drm_debug_category category) __printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, const char *format, ...); -__printf(3, 4) -void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, - const char *format, ...); +struct _ddebug; +__printf(4, 5) +void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev, + enum drm_debug_category category, const char *format, ...); /** * DRM_DEV_ERROR() - Error output. @@ -383,6 +405,15 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, } \ }) +#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) +#define drm_dev_dbg(dev, cat, fmt, ...) \ + __drm_dev_dbg(NULL, dev, cat, fmt, ##__VA_ARGS__) +#else +#define drm_dev_dbg(dev, cat, fmt, ...) \ + _dynamic_func_call_cls(cat, fmt, __drm_dev_dbg, \ + dev, cat, fmt, ##__VA_ARGS__) +#endif + /** * DRM_DEV_DEBUG() - Debug output for generic drm code * @@ -457,7 +488,7 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, #define drm_dbg_core(drm, fmt, ...) \ drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_CORE, fmt, ##__VA_ARGS__) -#define drm_dbg(drm, fmt, ...) \ +#define drm_dbg_driver(drm, fmt, ...) \ drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRIVER, fmt, ##__VA_ARGS__) #define drm_dbg_kms(drm, fmt, ...) \ drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_KMS, fmt, ##__VA_ARGS__) @@ -476,6 +507,7 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, #define drm_dbg_drmres(drm, fmt, ...) \ drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRMRES, fmt, ##__VA_ARGS__) +#define drm_dbg(drm, fmt, ...) drm_dbg_driver(drm, fmt, ##__VA_ARGS__) /* * printk based logging @@ -483,11 +515,19 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, * Prefer drm_device based logging over device or prink based logging. */ -__printf(2, 3) -void __drm_dbg(enum drm_debug_category category, const char *format, ...); +__printf(3, 4) +void ___drm_dbg(struct _ddebug *desc, enum drm_debug_category category, const char *format, ...); __printf(1, 2) void __drm_err(const char *format, ...); +#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) +#define __drm_dbg(fmt, ...) ___drm_dbg(NULL, fmt, ##__VA_ARGS__) +#else +#define __drm_dbg(cat, fmt, ...) \ + _dynamic_func_call_cls(cat, fmt, ___drm_dbg, \ + cat, fmt, ##__VA_ARGS__) +#endif + /* Macros to make printk easier */ #define _DRM_PRINTK(once, level, fmt, ...) \ diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h index f48c9acf251e..6b901b342348 100644 --- a/include/dt-bindings/phy/phy.h +++ b/include/dt-bindings/phy/phy.h @@ -22,5 +22,6 @@ #define PHY_TYPE_QSGMII 9 #define PHY_TYPE_DPHY 10 #define PHY_TYPE_CPHY 11 +#define PHY_TYPE_USXGMII 12 #endif /* _DT_BINDINGS_PHY */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index ac5d0515680e..b0914aa26506 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -114,6 +114,7 @@ int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_rm_cftypes(struct cftype *cfts); void cgroup_file_notify(struct cgroup_file *cfile); +void cgroup_file_show(struct cgroup_file *cfile, bool show); int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h index a6b7bc707356..77ea602c287c 100644 --- a/include/linux/dma/hsu.h +++ b/include/linux/dma/hsu.h @@ -8,11 +8,13 @@ #ifndef _DMA_HSU_H #define _DMA_HSU_H -#include -#include +#include +#include +#include #include +struct device; struct hsu_dma; /** diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index dce631e678dd..41682278d2e8 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -6,6 +6,8 @@ #include #endif +#include + /* * An instance of this structure is created in a special * ELF section at every dynamic debug callsite. At runtime, @@ -21,6 +23,9 @@ struct _ddebug { const char *filename; const char *format; unsigned int lineno:18; +#define CLS_BITS 6 + unsigned int class_id:CLS_BITS; +#define _DPRINTK_CLASS_DFLT ((1 << CLS_BITS) - 1) /* * The flags field controls the behaviour at the callsite. * The bits here are changed dynamically when the user @@ -51,15 +56,82 @@ struct _ddebug { #endif } __attribute__((aligned(8))); +enum class_map_type { + DD_CLASS_TYPE_DISJOINT_BITS, + /** + * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, one per bit. + * expecting hex input. Built for drm.debug, basis for other types. + */ + DD_CLASS_TYPE_LEVEL_NUM, + /** + * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N. + * N turns on just bits N-1 .. 0, so N=0 turns all bits off. + */ + DD_CLASS_TYPE_DISJOINT_NAMES, + /** + * DD_CLASS_TYPE_DISJOINT_NAMES: input is a CSV of [+-]CLASS_NAMES, + * classes are independent, like _DISJOINT_BITS. + */ + DD_CLASS_TYPE_LEVEL_NAMES, + /** + * DD_CLASS_TYPE_LEVEL_NAMES: input is a CSV of [+-]CLASS_NAMES, + * intended for names like: INFO,DEBUG,TRACE, with a module prefix + * avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug + */ +}; +struct ddebug_class_map { + struct list_head link; + struct module *mod; + const char *mod_name; /* needed for builtins */ + const char **class_names; + const int length; + const int base; /* index of 1st .class_id, allows split/shared space */ + enum class_map_type map_type; +}; + +/** + * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module + * @_var: a struct ddebug_class_map, passed to module_param_cb + * @_type: enum class_map_type, chooses bits/verbose, numeric/symbolic + * @_base: offset of 1st class-name. splits .class_id space + * @classes: class-names used to control class'd prdbgs + */ +#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...) \ + static const char *_var##_classnames[] = { __VA_ARGS__ }; \ + static struct ddebug_class_map __aligned(8) __used \ + __section("__dyndbg_classes") _var = { \ + .mod = THIS_MODULE, \ + .mod_name = KBUILD_MODNAME, \ + .base = _base, \ + .map_type = _maptype, \ + .length = NUM_TYPE_ARGS(char*, __VA_ARGS__), \ + .class_names = _var##_classnames, \ + } +#define NUM_TYPE_ARGS(eltype, ...) \ + (sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype)) + +/* encapsulate linker provided built-in (or module) dyndbg data */ +struct _ddebug_info { + struct _ddebug *descs; + struct ddebug_class_map *classes; + unsigned int num_descs; + unsigned int num_classes; +}; + +struct ddebug_class_param { + union { + unsigned long *bits; + unsigned int *lvl; + }; + char flags[8]; + const struct ddebug_class_map *map; +}; #if defined(CONFIG_DYNAMIC_DEBUG_CORE) -/* exported for module authors to exercise >control */ -int dynamic_debug_exec_queries(const char *query, const char *modname); +int ddebug_add_module(struct _ddebug_info *dyndbg, const char *modname); -int ddebug_add_module(struct _ddebug *tab, unsigned int n, - const char *modname); extern int ddebug_remove_module(const char *mod_name); extern __printf(2, 3) void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...); @@ -87,7 +159,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, const struct ib_device *ibdev, const char *fmt, ...); -#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \ +#define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt) \ static struct _ddebug __aligned(8) \ __section("__dyndbg") name = { \ .modname = KBUILD_MODNAME, \ @@ -96,8 +168,14 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, .format = (fmt), \ .lineno = __LINE__, \ .flags = _DPRINTK_FLAGS_DEFAULT, \ + .class_id = cls, \ _DPRINTK_KEY_INIT \ - } + }; \ + BUILD_BUG_ON_MSG(cls > _DPRINTK_CLASS_DFLT, \ + "classid value overflow") + +#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \ + DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, _DPRINTK_CLASS_DFLT, fmt) #ifdef CONFIG_JUMP_LABEL @@ -128,17 +206,34 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, #endif /* CONFIG_JUMP_LABEL */ -#define __dynamic_func_call(id, fmt, func, ...) do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \ - if (DYNAMIC_DEBUG_BRANCH(id)) \ - func(&id, ##__VA_ARGS__); \ -} while (0) - -#define __dynamic_func_call_no_desc(id, fmt, func, ...) do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \ +/* + * Factory macros: ($prefix)dynamic_func_call($suffix) + * + * Lower layer (with __ prefix) gets the callsite metadata, and wraps + * the func inside a debug-branch/static-key construct. Upper layer + * (with _ prefix) does the UNIQUE_ID once, so that lower can ref the + * name/label multiple times, and tie the elements together. + * Multiple flavors: + * (|_cls): adds in _DPRINT_CLASS_DFLT as needed + * (|_no_desc): former gets callsite descriptor as 1st arg (for prdbgs) + */ +#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do { \ + DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \ if (DYNAMIC_DEBUG_BRANCH(id)) \ - func(__VA_ARGS__); \ + func(&id, ##__VA_ARGS__); \ } while (0) +#define __dynamic_func_call(id, fmt, func, ...) \ + __dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt, \ + func, ##__VA_ARGS__) + +#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do { \ + DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \ + if (DYNAMIC_DEBUG_BRANCH(id)) \ + func(__VA_ARGS__); \ +} while (0) +#define __dynamic_func_call_no_desc(id, fmt, func, ...) \ + __dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT, \ + fmt, func, ##__VA_ARGS__) /* * "Factory macro" for generating a call to func, guarded by a @@ -148,22 +243,33 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, * the varargs. Note that fmt is repeated in invocations of this * macro. */ +#define _dynamic_func_call_cls(cls, fmt, func, ...) \ + __dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__) #define _dynamic_func_call(fmt, func, ...) \ - __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__) + _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__) + /* * A variant that does the same, except that the descriptor is not * passed as the first argument to the function; it is only called * with precisely the macro's varargs. */ -#define _dynamic_func_call_no_desc(fmt, func, ...) \ - __dynamic_func_call_no_desc(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__) +#define _dynamic_func_call_cls_no_desc(cls, fmt, func, ...) \ + __dynamic_func_call_cls_no_desc(__UNIQUE_ID(ddebug), cls, fmt, \ + func, ##__VA_ARGS__) +#define _dynamic_func_call_no_desc(fmt, func, ...) \ + _dynamic_func_call_cls_no_desc(_DPRINTK_CLASS_DFLT, fmt, \ + func, ##__VA_ARGS__) + +#define dynamic_pr_debug_cls(cls, fmt, ...) \ + _dynamic_func_call_cls(cls, fmt, __dynamic_pr_debug, \ + pr_fmt(fmt), ##__VA_ARGS__) #define dynamic_pr_debug(fmt, ...) \ - _dynamic_func_call(fmt, __dynamic_pr_debug, \ + _dynamic_func_call(fmt, __dynamic_pr_debug, \ pr_fmt(fmt), ##__VA_ARGS__) #define dynamic_dev_dbg(dev, fmt, ...) \ - _dynamic_func_call(fmt,__dynamic_dev_dbg, \ + _dynamic_func_call(fmt, __dynamic_dev_dbg, \ dev, fmt, ##__VA_ARGS__) #define dynamic_netdev_dbg(dev, fmt, ...) \ @@ -181,14 +287,24 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, KERN_DEBUG, prefix_str, prefix_type, \ rowsize, groupsize, buf, len, ascii) +struct kernel_param; +int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp); +int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp); + +/* for test only, generally expect drm.debug style macro wrappers */ +#define __pr_debug_cls(cls, fmt, ...) do { \ + BUILD_BUG_ON_MSG(!__builtin_constant_p(cls), \ + "expecting constant class int/enum"); \ + dynamic_pr_debug_cls(cls, fmt, ##__VA_ARGS__); \ + } while (0) + #else /* !CONFIG_DYNAMIC_DEBUG_CORE */ #include #include #include -static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n, - const char *modname) +static inline int ddebug_add_module(struct _ddebug_info *dinfo, const char *modname) { return 0; } @@ -201,7 +317,7 @@ static inline int ddebug_remove_module(const char *mod) static inline int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *modname) { - if (strstr(param, "dyndbg")) { + if (!strcmp(param, "dyndbg")) { /* avoid pr_warn(), which wants pr_fmt() fully defined */ printk(KERN_WARNING "dyndbg param is supported only in " "CONFIG_DYNAMIC_DEBUG builds\n"); @@ -221,12 +337,14 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val, rowsize, groupsize, buf, len, ascii); \ } while (0) -static inline int dynamic_debug_exec_queries(const char *query, const char *modname) -{ - pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n"); - return 0; -} +struct kernel_param; +static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) +{ return 0; } +static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp) +{ return 0; } #endif /* !CONFIG_DYNAMIC_DEBUG_CORE */ +extern const struct kernel_param_ops param_ops_dyndbg_classes; + #endif diff --git a/include/linux/io.h b/include/linux/io.h index 5fc800390fe4..308f4f0cfb93 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -59,8 +59,6 @@ void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset, resource_size_t size); void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, resource_size_t size); -void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset, - resource_size_t size); void devm_iounmap(struct device *dev, void __iomem *addr); int check_signature(const volatile void __iomem *io_addr, const unsigned char *signature, int length); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 367044d7708c..73f5c120def8 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -108,10 +108,12 @@ enum kernfs_node_flag { KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, KERNFS_LOCKDEP = 0x0100, + KERNFS_HIDDEN = 0x0200, KERNFS_SUICIDAL = 0x0400, KERNFS_SUICIDED = 0x0800, KERNFS_EMPTY_DIR = 0x1000, KERNFS_HAS_RELEASE = 0x2000, + KERNFS_REMOVING = 0x4000, }; /* @flags for kernfs_create_root() */ @@ -429,6 +431,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target); void kernfs_activate(struct kernfs_node *kn); +void kernfs_show(struct kernfs_node *kn, bool show); void kernfs_remove(struct kernfs_node *kn); void kernfs_break_active_protection(struct kernfs_node *kn); void kernfs_unbreak_active_protection(struct kernfs_node *kn); diff --git a/include/linux/phy/pcie.h b/include/linux/phy/pcie.h new file mode 100644 index 000000000000..e7ac81764576 --- /dev/null +++ b/include/linux/phy/pcie.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + */ +#ifndef __PHY_PCIE_H +#define __PHY_PCIE_H + +#define PHY_MODE_PCIE_RC 20 +#define PHY_MODE_PCIE_EP 21 +#define PHY_MODE_PCIE_BIFURCATION 22 + +#endif diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h index 3a35e74cdc61..70998e6dd6fd 100644 --- a/include/linux/phy/tegra/xusb.h +++ b/include/linux/phy/tegra/xusb.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. */ #ifndef PHY_TEGRA_XUSB_H @@ -21,6 +21,8 @@ int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, unsigned int port, bool enable); int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl, bool val); +void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy); +void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy); int tegra_phy_xusb_utmi_port_reset(struct phy *phy); int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl, unsigned int port); diff --git a/include/linux/platform_data/dma-hsu.h b/include/linux/platform_data/dma-hsu.h index c65b412b2b33..611bae193c1c 100644 --- a/include/linux/platform_data/dma-hsu.h +++ b/include/linux/platform_data/dma-hsu.h @@ -8,7 +8,7 @@ #ifndef _PLATFORM_DATA_DMA_HSU_H #define _PLATFORM_DATA_DMA_HSU_H -#include +struct device; struct hsu_dma_slave { struct device *dma_dev; diff --git a/include/linux/platform_data/usb-s3c2410_udc.h b/include/linux/platform_data/usb-s3c2410_udc.h index 07394819d03b..c0fbe1fe3426 100644 --- a/include/linux/platform_data/usb-s3c2410_udc.h +++ b/include/linux/platform_data/usb-s3c2410_udc.h @@ -22,12 +22,6 @@ enum s3c2410_udc_cmd_e { struct s3c2410_udc_mach_info { void (*udc_command)(enum s3c2410_udc_cmd_e); void (*vbus_draw)(unsigned int ma); - - unsigned int pullup_pin; - unsigned int pullup_pin_inverted; - - unsigned int vbus_pin; - unsigned char vbus_pin_inverted; }; extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *); diff --git a/include/linux/property.h b/include/linux/property.h index a5b429d623f6..117cc200c656 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -32,7 +32,7 @@ enum dev_dma_attr { DEV_DMA_COHERENT, }; -struct fwnode_handle *dev_fwnode(struct device *dev); +struct fwnode_handle *dev_fwnode(const struct device *dev); bool device_property_present(struct device *dev, const char *propname); int device_property_read_u8_array(struct device *dev, const char *propname, @@ -387,7 +387,7 @@ bool device_dma_supported(struct device *dev); enum dev_dma_attr device_get_dma_attr(struct device *dev); -const void *device_get_match_data(struct device *dev); +const void *device_get_match_data(const struct device *dev); int device_get_phy_mode(struct device *dev); int fwnode_get_phy_mode(struct fwnode_handle *fwnode); diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 3368c261ab62..66f624fc618c 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 8c7b793aa4d7..19376bee9667 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -32,7 +32,7 @@ struct plat_serial8250_port { void (*serial_out)(struct uart_port *, int, int); void (*set_termios)(struct uart_port *, struct ktermios *new, - struct ktermios *old); + const struct ktermios *old); void (*set_ldisc)(struct uart_port *, struct ktermios *); unsigned int (*get_mctrl)(struct uart_port *); @@ -74,6 +74,7 @@ struct uart_8250_port; struct uart_8250_ops { int (*setup_irq)(struct uart_8250_port *); void (*release_irq)(struct uart_8250_port *); + void (*setup_timer)(struct uart_8250_port *); }; struct uart_8250_em485 { @@ -157,7 +158,7 @@ extern int early_serial8250_setup(struct earlycon_device *device, extern void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk); extern void serial8250_do_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old); + struct ktermios *termios, const struct ktermios *old); extern void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios); extern unsigned int serial8250_do_get_mctrl(struct uart_port *port); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 1eaea9fe44d8..d657f2a42a7b 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -387,7 +387,7 @@ struct uart_ops { void (*shutdown)(struct uart_port *); void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new, - struct ktermios *old); + const struct ktermios *old); void (*set_ldisc)(struct uart_port *, struct ktermios *); void (*pm)(struct uart_port *, unsigned int state, unsigned int oldstate); @@ -422,7 +422,7 @@ struct uart_icount { __u32 buf_overrun; }; -typedef unsigned int __bitwise upf_t; +typedef u64 __bitwise upf_t; typedef unsigned int __bitwise upstat_t; struct uart_port { @@ -433,7 +433,7 @@ struct uart_port { void (*serial_out)(struct uart_port *, int, int); void (*set_termios)(struct uart_port *, struct ktermios *new, - struct ktermios *old); + const struct ktermios *old); void (*set_ldisc)(struct uart_port *, struct ktermios *); unsigned int (*get_mctrl)(struct uart_port *); @@ -513,23 +513,24 @@ struct uart_port { #define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ ) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ ) -#define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19)) +#define UPF_NO_THRE_TEST ((__force upf_t) BIT_ULL(19)) /* Port has hardware-assisted h/w flow control */ -#define UPF_AUTO_CTS ((__force upf_t) (1 << 20)) -#define UPF_AUTO_RTS ((__force upf_t) (1 << 21)) +#define UPF_AUTO_CTS ((__force upf_t) BIT_ULL(20)) +#define UPF_AUTO_RTS ((__force upf_t) BIT_ULL(21)) #define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS)) /* Port has hardware-assisted s/w flow control */ -#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22)) -#define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) -#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) -#define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) -#define UPF_BUG_THRE ((__force upf_t) (1 << 26)) +#define UPF_SOFT_FLOW ((__force upf_t) BIT_ULL(22)) +#define UPF_CONS_FLOW ((__force upf_t) BIT_ULL(23)) +#define UPF_SHARE_IRQ ((__force upf_t) BIT_ULL(24)) +#define UPF_EXAR_EFR ((__force upf_t) BIT_ULL(25)) +#define UPF_BUG_THRE ((__force upf_t) BIT_ULL(26)) /* The exact UART type is known and should not be probed. */ -#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) -#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) -#define UPF_FIXED_PORT ((__force upf_t) (1 << 29)) -#define UPF_DEAD ((__force upf_t) (1 << 30)) -#define UPF_IOREMAP ((__force upf_t) (1 << 31)) +#define UPF_FIXED_TYPE ((__force upf_t) BIT_ULL(27)) +#define UPF_BOOT_AUTOCONF ((__force upf_t) BIT_ULL(28)) +#define UPF_FIXED_PORT ((__force upf_t) BIT_ULL(29)) +#define UPF_DEAD ((__force upf_t) BIT_ULL(30)) +#define UPF_IOREMAP ((__force upf_t) BIT_ULL(31)) +#define UPF_FULL_PROBE ((__force upf_t) BIT_ULL(32)) #define __UPF_CHANGE_MASK 0x17fff #define UPF_CHANGE_MASK ((__force upf_t) __UPF_CHANGE_MASK) @@ -669,7 +670,7 @@ void uart_write_wakeup(struct uart_port *port); void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud); unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old, unsigned int min, + const struct ktermios *old, unsigned int min, unsigned int max); unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud); @@ -950,5 +951,4 @@ static inline int uart_handle_break(struct uart_port *port) !((cflag) & CLOCAL)) int uart_get_rs485_mode(struct uart_port *port); -int uart_rs485_config(struct uart_port *port); #endif /* LINUX_SERIAL_CORE_H */ diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 822599957b35..9e4537f409c2 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -892,6 +892,9 @@ struct sdw_master_ops { * meaningful if multi_link is set. If set to 1, hardware-based * synchronization will be used even if a stream only uses a single * SoundWire segment. + * @dev_num_ida_min: if set, defines the minimum values for the IDA + * used to allocate system-unique device numbers. This value needs to be + * identical across all SoundWire bus in the system. */ struct sdw_bus { struct device *dev; @@ -916,6 +919,7 @@ struct sdw_bus { u32 bank_switch_timeout; bool multi_link; int hw_sync_min_links; + int dev_num_ida_min; }; int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index ec16ae49e6a4..2e9fd91572d4 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -15,32 +15,21 @@ #define SDW_LINK_SIZE 0x10000 /* Intel SHIM Registers Definition */ +/* LCAP */ #define SDW_SHIM_LCAP 0x0 +#define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0) + +/* LCTL */ #define SDW_SHIM_LCTL 0x4 -#define SDW_SHIM_IPPTR 0x8 -#define SDW_SHIM_SYNC 0xC - -#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x)) -#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x)) -#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x)) -#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x)) -#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x)) -#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x)) - -#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y))) -#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y))) -#define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * (x)) -#define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x)) -#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x)) - -#define SDW_SHIM_WAKEEN 0x190 -#define SDW_SHIM_WAKESTS 0x192 #define SDW_SHIM_LCTL_SPA BIT(0) #define SDW_SHIM_LCTL_SPA_MASK GENMASK(3, 0) #define SDW_SHIM_LCTL_CPA BIT(8) #define SDW_SHIM_LCTL_CPA_MASK GENMASK(11, 8) +/* SYNC */ +#define SDW_SHIM_SYNC 0xC + #define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1) #define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1) #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) @@ -49,19 +38,33 @@ #define SDW_SHIM_SYNC_CMDSYNC BIT(16) #define SDW_SHIM_SYNC_SYNCGO BIT(24) +/* Control stream capabililities and channel mask */ +#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x)) +#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x)) +#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x)) +#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x)) +#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x)) + +/* PCM Stream capabilities */ +#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x)) + #define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0) #define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4) #define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8) +/* PCM Stream Channel Map */ +#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y))) + +/* PCM Stream Channel Count */ +#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y))) + #define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0) #define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4) #define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8) #define SDW_SHIM_PCMSYCM_DIR BIT(15) -#define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0) -#define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4) -#define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8) -#define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13) +/* IO control */ +#define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x)) #define SDW_SHIM_IOCTL_MIF BIT(0) #define SDW_SHIM_IOCTL_CO BIT(1) @@ -73,13 +76,23 @@ #define SDW_SHIM_IOCTL_CIBD BIT(8) #define SDW_SHIM_IOCTL_DIBD BIT(9) +/* Wake Enable*/ +#define SDW_SHIM_WAKEEN 0x190 + +#define SDW_SHIM_WAKEEN_ENABLE BIT(0) + +/* Wake Status */ +#define SDW_SHIM_WAKESTS 0x192 + +#define SDW_SHIM_WAKESTS_STATUS BIT(0) + +/* AC Timing control */ +#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x)) + #define SDW_SHIM_CTMCTL_DACTQE BIT(0) #define SDW_SHIM_CTMCTL_DODS BIT(1) #define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3) -#define SDW_SHIM_WAKEEN_ENABLE BIT(0) -#define SDW_SHIM_WAKESTS_STATUS BIT(0) - /* Intel ALH Register definitions */ #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x))) #define SDW_ALH_NUM_STREAMS 64 diff --git a/include/linux/termios_internal.h b/include/linux/termios_internal.h new file mode 100644 index 000000000000..d77f29e5e2b7 --- /dev/null +++ b/include/linux/termios_internal.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_TERMIOS_CONV_H +#define _LINUX_TERMIOS_CONV_H + +#include +#include + +/* intr=^C quit=^\ erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^O werase=^W lnext=^V + eol2=\0 +*/ + +#ifdef VDSUSP +#define INIT_C_CC_VDSUSP_EXTRA [VDSUSP] = 'Y'-0x40, +#else +#define INIT_C_CC_VDSUSP_EXTRA +#endif + +#define INIT_C_CC { \ + [VINTR] = 'C'-0x40, \ + [VQUIT] = '\\'-0x40, \ + [VERASE] = '\177', \ + [VKILL] = 'U'-0x40, \ + [VEOF] = 'D'-0x40, \ + [VSTART] = 'Q'-0x40, \ + [VSTOP] = 'S'-0x40, \ + [VSUSP] = 'Z'-0x40, \ + [VREPRINT] = 'R'-0x40, \ + [VDISCARD] = 'O'-0x40, \ + [VWERASE] = 'W'-0x40, \ + [VLNEXT] = 'V'-0x40, \ + INIT_C_CC_VDSUSP_EXTRA \ + [VMIN] = 1 } + +int user_termio_to_kernel_termios(struct ktermios *, struct termio __user *); +int kernel_termios_to_user_termio(struct termio __user *, struct ktermios *); +#ifdef TCGETS2 +int user_termios_to_kernel_termios(struct ktermios *, struct termios2 __user *); +int kernel_termios_to_user_termios(struct termios2 __user *, struct ktermios *); +int user_termios_to_kernel_termios_1(struct ktermios *, struct termios __user *); +int kernel_termios_to_user_termios_1(struct termios __user *, struct ktermios *); +#else /* TCGETS2 */ +int user_termios_to_kernel_termios(struct ktermios *, struct termios __user *); +int kernel_termios_to_user_termios(struct termios __user *, struct ktermios *); +#endif /* TCGETS2 */ + +#endif /* _LINUX_TERMIOS_CONV_H */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 7b0a5d478ef6..730c3301d710 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -122,8 +122,6 @@ struct tty_operations; /** * struct tty_struct - state associated with a tty while open * - * @magic: magic value set early in @alloc_tty_struct to %TTY_MAGIC, for - * debugging purposes * @kref: reference counting by tty_kref_get() and tty_kref_put(), reaching zero * frees the structure * @dev: class device or %NULL (e.g. ptys, serdev) @@ -193,7 +191,6 @@ struct tty_operations; * &struct tty_port. */ struct tty_struct { - int magic; struct kref kref; struct device *dev; struct tty_driver *driver; @@ -260,9 +257,6 @@ struct tty_file_private { struct list_head list; }; -/* tty magic number */ -#define TTY_MAGIC 0x5401 - /** * DOC: TTY Struct Flags * @@ -434,7 +428,7 @@ int tty_hung_up_p(struct file *filp); void do_SAK(struct tty_struct *tty); void __do_SAK(struct tty_struct *tty); void no_tty(void); -speed_t tty_termios_baud_rate(struct ktermios *termios); +speed_t tty_termios_baud_rate(const struct ktermios *termios); void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud); void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, @@ -458,7 +452,7 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty) unsigned char tty_get_char_size(unsigned int cflag); unsigned char tty_get_frame_size(unsigned int cflag); -void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); +void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old); int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b); int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 4841d8069c07..e00034118c7b 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,7 @@ struct serial_struct; * * Optional. * - * @set_termios: ``void ()(struct tty_struct *tty, struct ktermios *old)`` + * @set_termios: ``void ()(struct tty_struct *tty, const struct ktermios *old)`` * * This routine allows the @tty driver to be notified when device's * termios settings have changed. New settings are in @tty->termios. @@ -365,7 +366,7 @@ struct tty_operations { unsigned int cmd, unsigned long arg); long (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct ktermios * old); + void (*set_termios)(struct tty_struct *tty, const struct ktermios *old); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); void (*stop)(struct tty_struct *tty); @@ -396,7 +397,6 @@ struct tty_operations { /** * struct tty_driver -- driver for TTY devices * - * @magic: set to %TTY_DRIVER_MAGIC in __tty_alloc_driver() * @kref: reference counting. Reaching zero frees all the internals and the * driver. * @cdevs: allocated/registered character /dev devices @@ -432,7 +432,6 @@ struct tty_operations { * @driver_name, @name, @type, @subtype, @init_termios, and @ops. */ struct tty_driver { - int magic; struct kref kref; struct cdev **cdevs; struct module *owner; @@ -489,9 +488,6 @@ static inline void tty_set_operations(struct tty_driver *driver, driver->ops = op; } -/* tty driver magic number */ -#define TTY_DRIVER_MAGIC 0x5402 - /** * DOC: TTY Driver Flags * diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index ede6f2157f32..dcb61ec11424 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -130,7 +130,7 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, * a pointer to wordsize-sensitive structure belongs here, but most of * ldiscs will happily leave it %NULL. * - * @set_termios: [TTY] ``void ()(struct tty_struct *tty, struct ktermios *old)`` + * @set_termios: [TTY] ``void ()(struct tty_struct *tty, const struct ktermios *old)`` * * This function notifies the line discpline that a change has been made * to the termios structure. @@ -227,7 +227,7 @@ struct tty_ldisc_ops { unsigned long arg); int (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct ktermios *old); + void (*set_termios)(struct tty_struct *tty, const struct ktermios *old); __poll_t (*poll)(struct tty_struct *tty, struct file *file, struct poll_table_struct *wait); void (*hangup)(struct tty_struct *tty); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index edf3342507f1..ee38835ed77c 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -62,6 +62,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_REQUIRES_ALIGNED_DMA BIT(13) #define CI_HDRC_IMX_IS_HSIC BIT(14) #define CI_HDRC_PMQOS BIT(15) +#define CI_HDRC_PHY_VBUS_CONTROL BIT(16) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 67f8713d3fa3..78cd566ee238 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -479,7 +479,6 @@ static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) struct pci_dev; struct pci_device_id; extern int usb_hcd_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id, const struct hc_driver *driver); extern void usb_hcd_pci_remove(struct pci_dev *dev); extern void usb_hcd_pci_shutdown(struct pci_dev *dev); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 8ea319f89e1f..f7bfedb740f5 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -276,8 +276,8 @@ struct usb_serial_driver { unsigned int cmd, unsigned long arg); void (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); int (*set_serial)(struct tty_struct *tty, struct serial_struct *ss); - void (*set_termios)(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); + void (*set_termios)(struct tty_struct *tty, struct usb_serial_port *port, + const struct ktermios *old); void (*break_ctl)(struct tty_struct *tty, int break_state); unsigned int (*chars_in_buffer)(struct tty_struct *tty); void (*wait_until_sent)(struct tty_struct *tty, long timeout); diff --git a/include/linux/usb/tcpci.h b/include/linux/usb/tcpci.h index 20c0bedb8ec8..17657451c762 100644 --- a/include/linux/usb/tcpci.h +++ b/include/linux/usb/tcpci.h @@ -167,6 +167,11 @@ /* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */ #define TCPC_TRANSMIT_BUFFER_MAX_LEN 31 +#define tcpc_presenting_rd(reg, cc) \ + (!(TCPC_ROLE_CTRL_DRP & (reg)) && \ + (((reg) & (TCPC_ROLE_CTRL_## cc ##_MASK << TCPC_ROLE_CTRL_## cc ##_SHIFT)) == \ + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_## cc ##_SHIFT))) + struct tcpci; /* @@ -207,4 +212,21 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci); struct tcpm_port; struct tcpm_port *tcpci_get_tcpm_port(struct tcpci *tcpci); + +static inline enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) +{ + switch (cc) { + case 0x1: + return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA; + case 0x2: + return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD; + case 0x3: + if (sink) + return TYPEC_CC_RP_3_0; + fallthrough; + case 0x0: + default: + return TYPEC_CC_OPEN; + } +} #endif /* __LINUX_USB_TCPCI_H */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index b5ab452fca5b..c1f5aebef170 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -30,7 +30,6 @@ struct vc_data *vc_deallocate(unsigned int console); void reset_palette(struct vc_data *vc); void do_blank_screen(int entering_gfx); void do_unblank_screen(int leaving_gfx); -void unblank_screen(void); void poke_blanked_console(void); int con_font_op(struct vc_data *vc, struct console_font_op *op); int con_set_cmap(unsigned char __user *cmap); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index b708d63995f4..725ff91b26e0 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -540,6 +540,10 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat, s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul, unsigned int div); +void v4l2_simplify_fraction(u32 *numerator, u32 *denominator, + unsigned int n_terms, unsigned int threshold); +u32 v4l2_fraction_to_interval(u32 numerator, u32 denominator); + static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf) { /* diff --git a/include/media/v4l2-uvc.h b/include/media/v4l2-uvc.h new file mode 100644 index 000000000000..f83e31661333 --- /dev/null +++ b/include/media/v4l2-uvc.h @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * v4l2 uvc internal API header + * + * Some commonly needed functions for uvc drivers + */ + +#ifndef __LINUX_V4L2_UVC_H +#define __LINUX_V4L2_UVC_H + +/* ------------------------------------------------------------------------ + * GUIDs + */ +#define UVC_GUID_UVC_CAMERA \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} +#define UVC_GUID_UVC_OUTPUT \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} +#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03} +#define UVC_GUID_UVC_PROCESSING \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01} +#define UVC_GUID_UVC_SELECTOR \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02} +#define UVC_GUID_EXT_GPIO_CONTROLLER \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03} + +#define UVC_GUID_FORMAT_MJPEG \ + { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_YUY2 \ + { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_YUY2_ISIGHT \ + { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_NV12 \ + { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_YV12 \ + { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_I420 \ + { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_UYVY \ + { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y800 \ + { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y8 \ + { 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y10 \ + { 'Y', '1', '0', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y12 \ + { 'Y', '1', '2', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y16 \ + { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BY8 \ + { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BA81 \ + { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GBRG \ + { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GRBG \ + { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RGGB \ + { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BG16 \ + { 'B', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GB16 \ + { 'G', 'B', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RG16 \ + { 'R', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GR16 \ + { 'G', 'R', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RGBP \ + { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BGR3 \ + { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} +#define UVC_GUID_FORMAT_M420 \ + { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + +#define UVC_GUID_FORMAT_H264 \ + { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_H265 \ + { 'H', '2', '6', '5', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y8I \ + { 'Y', '8', 'I', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Y12I \ + { 'Y', '1', '2', 'I', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_Z16 \ + { 'Z', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RW10 \ + { 'R', 'W', '1', '0', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_INVZ \ + { 'I', 'N', 'V', 'Z', 0x90, 0x2d, 0x58, 0x4a, \ + 0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b} +#define UVC_GUID_FORMAT_INZI \ + { 'I', 'N', 'Z', 'I', 0x66, 0x1a, 0x42, 0xa2, \ + 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a} +#define UVC_GUID_FORMAT_INVI \ + { 'I', 'N', 'V', 'I', 0xdb, 0x57, 0x49, 0x5e, \ + 0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f} +#define UVC_GUID_FORMAT_CNF4 \ + { 'C', ' ', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + +#define UVC_GUID_FORMAT_D3DFMT_L8 \ + {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \ + {0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + +#define UVC_GUID_FORMAT_HEVC \ + { 'H', 'E', 'V', 'C', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + +/* ------------------------------------------------------------------------ + * Video formats + */ + +struct uvc_format_desc { + char *name; + u8 guid[16]; + u32 fcc; +}; + +static struct uvc_format_desc uvc_fmts[] = { + { + .name = "YUV 4:2:2 (YUYV)", + .guid = UVC_GUID_FORMAT_YUY2, + .fcc = V4L2_PIX_FMT_YUYV, + }, + { + .name = "YUV 4:2:2 (YUYV)", + .guid = UVC_GUID_FORMAT_YUY2_ISIGHT, + .fcc = V4L2_PIX_FMT_YUYV, + }, + { + .name = "YUV 4:2:0 (NV12)", + .guid = UVC_GUID_FORMAT_NV12, + .fcc = V4L2_PIX_FMT_NV12, + }, + { + .name = "MJPEG", + .guid = UVC_GUID_FORMAT_MJPEG, + .fcc = V4L2_PIX_FMT_MJPEG, + }, + { + .name = "YVU 4:2:0 (YV12)", + .guid = UVC_GUID_FORMAT_YV12, + .fcc = V4L2_PIX_FMT_YVU420, + }, + { + .name = "YUV 4:2:0 (I420)", + .guid = UVC_GUID_FORMAT_I420, + .fcc = V4L2_PIX_FMT_YUV420, + }, + { + .name = "YUV 4:2:0 (M420)", + .guid = UVC_GUID_FORMAT_M420, + .fcc = V4L2_PIX_FMT_M420, + }, + { + .name = "YUV 4:2:2 (UYVY)", + .guid = UVC_GUID_FORMAT_UYVY, + .fcc = V4L2_PIX_FMT_UYVY, + }, + { + .name = "Greyscale 8-bit (Y800)", + .guid = UVC_GUID_FORMAT_Y800, + .fcc = V4L2_PIX_FMT_GREY, + }, + { + .name = "Greyscale 8-bit (Y8 )", + .guid = UVC_GUID_FORMAT_Y8, + .fcc = V4L2_PIX_FMT_GREY, + }, + { + .name = "Greyscale 8-bit (D3DFMT_L8)", + .guid = UVC_GUID_FORMAT_D3DFMT_L8, + .fcc = V4L2_PIX_FMT_GREY, + }, + { + .name = "IR 8-bit (L8_IR)", + .guid = UVC_GUID_FORMAT_KSMEDIA_L8_IR, + .fcc = V4L2_PIX_FMT_GREY, + }, + { + .name = "Greyscale 10-bit (Y10 )", + .guid = UVC_GUID_FORMAT_Y10, + .fcc = V4L2_PIX_FMT_Y10, + }, + { + .name = "Greyscale 12-bit (Y12 )", + .guid = UVC_GUID_FORMAT_Y12, + .fcc = V4L2_PIX_FMT_Y12, + }, + { + .name = "Greyscale 16-bit (Y16 )", + .guid = UVC_GUID_FORMAT_Y16, + .fcc = V4L2_PIX_FMT_Y16, + }, + { + .name = "BGGR Bayer (BY8 )", + .guid = UVC_GUID_FORMAT_BY8, + .fcc = V4L2_PIX_FMT_SBGGR8, + }, + { + .name = "BGGR Bayer (BA81)", + .guid = UVC_GUID_FORMAT_BA81, + .fcc = V4L2_PIX_FMT_SBGGR8, + }, + { + .name = "GBRG Bayer (GBRG)", + .guid = UVC_GUID_FORMAT_GBRG, + .fcc = V4L2_PIX_FMT_SGBRG8, + }, + { + .name = "GRBG Bayer (GRBG)", + .guid = UVC_GUID_FORMAT_GRBG, + .fcc = V4L2_PIX_FMT_SGRBG8, + }, + { + .name = "RGGB Bayer (RGGB)", + .guid = UVC_GUID_FORMAT_RGGB, + .fcc = V4L2_PIX_FMT_SRGGB8, + }, + { + .name = "RGB565", + .guid = UVC_GUID_FORMAT_RGBP, + .fcc = V4L2_PIX_FMT_RGB565, + }, + { + .name = "BGR 8:8:8 (BGR3)", + .guid = UVC_GUID_FORMAT_BGR3, + .fcc = V4L2_PIX_FMT_BGR24, + }, + { + .name = "H.264", + .guid = UVC_GUID_FORMAT_H264, + .fcc = V4L2_PIX_FMT_H264, + }, + { + .name = "H.265", + .guid = UVC_GUID_FORMAT_H265, + .fcc = V4L2_PIX_FMT_HEVC, + }, + { + .name = "Greyscale 8 L/R (Y8I)", + .guid = UVC_GUID_FORMAT_Y8I, + .fcc = V4L2_PIX_FMT_Y8I, + }, + { + .name = "Greyscale 12 L/R (Y12I)", + .guid = UVC_GUID_FORMAT_Y12I, + .fcc = V4L2_PIX_FMT_Y12I, + }, + { + .name = "Depth data 16-bit (Z16)", + .guid = UVC_GUID_FORMAT_Z16, + .fcc = V4L2_PIX_FMT_Z16, + }, + { + .name = "Bayer 10-bit (SRGGB10P)", + .guid = UVC_GUID_FORMAT_RW10, + .fcc = V4L2_PIX_FMT_SRGGB10P, + }, + { + .name = "Bayer 16-bit (SBGGR16)", + .guid = UVC_GUID_FORMAT_BG16, + .fcc = V4L2_PIX_FMT_SBGGR16, + }, + { + .name = "Bayer 16-bit (SGBRG16)", + .guid = UVC_GUID_FORMAT_GB16, + .fcc = V4L2_PIX_FMT_SGBRG16, + }, + { + .name = "Bayer 16-bit (SRGGB16)", + .guid = UVC_GUID_FORMAT_RG16, + .fcc = V4L2_PIX_FMT_SRGGB16, + }, + { + .name = "Bayer 16-bit (SGRBG16)", + .guid = UVC_GUID_FORMAT_GR16, + .fcc = V4L2_PIX_FMT_SGRBG16, + }, + { + .name = "Depth data 16-bit (Z16)", + .guid = UVC_GUID_FORMAT_INVZ, + .fcc = V4L2_PIX_FMT_Z16, + }, + { + .name = "Greyscale 10-bit (Y10 )", + .guid = UVC_GUID_FORMAT_INVI, + .fcc = V4L2_PIX_FMT_Y10, + }, + { + .name = "IR:Depth 26-bit (INZI)", + .guid = UVC_GUID_FORMAT_INZI, + .fcc = V4L2_PIX_FMT_INZI, + }, + { + .name = "4-bit Depth Confidence (Packed)", + .guid = UVC_GUID_FORMAT_CNF4, + .fcc = V4L2_PIX_FMT_CNF4, + }, + { + .name = "HEVC", + .guid = UVC_GUID_FORMAT_HEVC, + .fcc = V4L2_PIX_FMT_HEVC, + }, +}; + +static inline struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) +{ + unsigned int len = ARRAY_SIZE(uvc_fmts); + unsigned int i; + + for (i = 0; i < len; ++i) { + if (memcmp(guid, uvc_fmts[i].guid, 16) == 0) + return &uvc_fmts[i]; + } + + return NULL; +} + +#endif /* __LINUX_V4L2_UVC_H */ diff --git a/include/uapi/linux/usbip.h b/include/uapi/linux/usbip.h index fd393d908d8a..e4421ad55b2e 100644 --- a/include/uapi/linux/usbip.h +++ b/include/uapi/linux/usbip.h @@ -24,4 +24,30 @@ enum usbip_device_status { VDEV_ST_USED, VDEV_ST_ERROR }; + +/* USB URB Transfer flags: + * + * USBIP server and client (vchi) pack URBs in TCP packets. The following + * are the transfer type defines used in USBIP protocol. + */ + +#define USBIP_URB_SHORT_NOT_OK 0x0001 +#define USBIP_URB_ISO_ASAP 0x0002 +#define USBIP_URB_NO_TRANSFER_DMA_MAP 0x0004 +#define USBIP_URB_ZERO_PACKET 0x0040 +#define USBIP_URB_NO_INTERRUPT 0x0080 +#define USBIP_URB_FREE_BUFFER 0x0100 +#define USBIP_URB_DIR_IN 0x0200 +#define USBIP_URB_DIR_OUT 0 +#define USBIP_URB_DIR_MASK USBIP_URB_DIR_IN + +#define USBIP_URB_DMA_MAP_SINGLE 0x00010000 +#define USBIP_URB_DMA_MAP_PAGE 0x00020000 +#define USBIP_URB_DMA_MAP_SG 0x00040000 +#define USBIP_URB_MAP_LOCAL 0x00080000 +#define USBIP_URB_SETUP_MAP_SINGLE 0x00100000 +#define USBIP_URB_SETUP_MAP_LOCAL 0x00200000 +#define USBIP_URB_DMA_SG_COMBINED 0x00400000 +#define USBIP_URB_ALIGNED_TEMP_BUFFER 0x00800000 + #endif /* _UAPI_LINUX_USBIP_H */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index deb783bf231d..316021e6fa41 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4377,6 +4377,26 @@ void cgroup_file_notify(struct cgroup_file *cfile) spin_unlock_irqrestore(&cgroup_file_kn_lock, flags); } +/** + * cgroup_file_show - show or hide a hidden cgroup file + * @cfile: target cgroup_file obtained by setting cftype->file_offset + * @show: whether to show or hide + */ +void cgroup_file_show(struct cgroup_file *cfile, bool show) +{ + struct kernfs_node *kn; + + spin_lock_irq(&cgroup_file_kn_lock); + kn = cfile->kn; + kernfs_get(kn); + spin_unlock_irq(&cgroup_file_kn_lock); + + if (kn) + kernfs_show(kn, show); + + kernfs_put(kn); +} + /** * css_next_child - find the next child of a given css * @pos: the current position (%NULL to initiate traversal) diff --git a/kernel/module/internal.h b/kernel/module/internal.h index 69adc32a8289..ba60aaebab34 100644 --- a/kernel/module/internal.h +++ b/kernel/module/internal.h @@ -53,6 +53,7 @@ extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const s32 __start___kcrctab[]; extern const s32 __start___kcrctab_gpl[]; +#include struct load_info { const char *name; /* pointer to module in temporary copy, freed at end of load_module() */ @@ -62,8 +63,7 @@ struct load_info { Elf_Shdr *sechdrs; char *secstrings, *strtab; unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs; - struct _ddebug *debug; - unsigned int num_debug; + struct _ddebug_info dyndbg; bool sig_ok; #ifdef CONFIG_KALLSYMS unsigned long mod_kallsyms_init_off; diff --git a/kernel/module/main.c b/kernel/module/main.c index 03f002a6fc2a..c1b5a2760821 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1609,16 +1609,16 @@ static void free_modinfo(struct module *mod) } } -static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num) +static void dynamic_debug_setup(struct module *mod, struct _ddebug_info *dyndbg) { - if (!debug) + if (!dyndbg->num_descs) return; - ddebug_add_module(debug, num, mod->name); + ddebug_add_module(dyndbg, mod->name); } -static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug) +static void dynamic_debug_remove(struct module *mod, struct _ddebug_info *dyndbg) { - if (debug) + if (dyndbg->num_descs) ddebug_remove_module(mod->name); } @@ -2122,8 +2122,10 @@ static int find_module_sections(struct module *mod, struct load_info *info) if (section_addr(info, "__obsparm")) pr_warn("%s: Ignoring obsolete parameters\n", mod->name); - info->debug = section_objs(info, "__dyndbg", - sizeof(*info->debug), &info->num_debug); + info->dyndbg.descs = section_objs(info, "__dyndbg", + sizeof(*info->dyndbg.descs), &info->dyndbg.num_descs); + info->dyndbg.classes = section_objs(info, "__dyndbg_classes", + sizeof(*info->dyndbg.classes), &info->dyndbg.num_classes); return 0; } @@ -2816,7 +2818,7 @@ static int load_module(struct load_info *info, const char __user *uargs, } init_build_id(mod, info); - dynamic_debug_setup(mod, info->debug, info->num_debug); + dynamic_debug_setup(mod, &info->dyndbg); /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ ftrace_module_init(mod); @@ -2880,7 +2882,7 @@ static int load_module(struct load_info *info, const char __user *uargs, ddebug_cleanup: ftrace_release_mod(mod); - dynamic_debug_remove(mod, info->debug); + dynamic_debug_remove(mod, &info->dyndbg); synchronize_rcu(); kfree(mod->args); free_arch_cleanup: diff --git a/kernel/panic.c b/kernel/panic.c index c6eb8f8db0c0..da323209f583 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -329,9 +329,6 @@ void panic(const char *fmt, ...) if (_crash_kexec_post_notifiers) __crash_kexec(NULL); -#ifdef CONFIG_VT - unblank_screen(); -#endif console_unblank(); /* diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f473f7d8a0a2..a05cd9dc5f8b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2572,6 +2572,16 @@ config TEST_STATIC_KEYS If unsure, say N. +config TEST_DYNAMIC_DEBUG + tristate "Test DYNAMIC_DEBUG" + depends on DYNAMIC_DEBUG + help + This module registers a tracer callback to count enabled + pr_debugs in a 'do_debugging' function, then alters their + enablements, calls the function, and compares counts. + + If unsure, say N. + config TEST_KMOD tristate "kmod stress tester" depends on m diff --git a/lib/Makefile b/lib/Makefile index 7d7c9f67eff6..8f6fc027f605 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o +obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o obj-$(CONFIG_TEST_PRINTF) += test_printf.o obj-$(CONFIG_TEST_SCANF) += test_scanf.o obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c index 8be59f84eaea..bfd53972a4d8 100644 --- a/lib/bust_spinlocks.c +++ b/lib/bust_spinlocks.c @@ -22,9 +22,6 @@ void bust_spinlocks(int yes) if (yes) { ++oops_in_progress; } else { -#ifdef CONFIG_VT - unblank_screen(); -#endif console_unblank(); if (--oops_in_progress == 0) wake_up_klogd(); diff --git a/lib/devres.c b/lib/devres.c index 55eb07e80cbb..6baf43902ead 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -103,21 +103,6 @@ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, } EXPORT_SYMBOL(devm_ioremap_wc); -/** - * devm_ioremap_np - Managed ioremap_np() - * @dev: Generic device to remap IO address for - * @offset: Resource address to map - * @size: Size of map - * - * Managed ioremap_np(). Map is automatically unmapped on driver detach. - */ -void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset, - resource_size_t size) -{ - return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NP); -} -EXPORT_SYMBOL(devm_ioremap_np); - /** * devm_iounmap - Managed iounmap() * @dev: Generic device to unmap for diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index dd7f56af9aed..009f2ead09c1 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -41,9 +41,11 @@ extern struct _ddebug __start___dyndbg[]; extern struct _ddebug __stop___dyndbg[]; +extern struct ddebug_class_map __start___dyndbg_classes[]; +extern struct ddebug_class_map __stop___dyndbg_classes[]; struct ddebug_table { - struct list_head link; + struct list_head link, maps; const char *mod_name; unsigned int num_ddebugs; struct _ddebug *ddebugs; @@ -54,12 +56,13 @@ struct ddebug_query { const char *module; const char *function; const char *format; + const char *class_string; unsigned int first_lineno, last_lineno; }; struct ddebug_iter { struct ddebug_table *table; - unsigned int idx; + int idx; }; struct flag_settings { @@ -134,15 +137,33 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg) fmtlen--; } - v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n", - msg, - query->function ?: "", - query->filename ?: "", - query->module ?: "", - fmtlen, query->format ?: "", - query->first_lineno, query->last_lineno); + v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n", + msg, + query->function ?: "", + query->filename ?: "", + query->module ?: "", + fmtlen, query->format ?: "", + query->first_lineno, query->last_lineno, query->class_string); } +static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt, + const char *class_string, int *class_id) +{ + struct ddebug_class_map *map; + int idx; + + list_for_each_entry(map, &dt->maps, link) { + idx = match_string(map->class_names, map->length, class_string); + if (idx >= 0) { + *class_id = idx + map->base; + return map; + } + } + *class_id = -ENOENT; + return NULL; +} + +#define __outvar /* filled by callee */ /* * Search the tables for _ddebug's which match the given `query' and * apply the `flags' and `mask' to them. Returns number of matching @@ -156,7 +177,9 @@ static int ddebug_change(const struct ddebug_query *query, struct ddebug_table *dt; unsigned int newflags; unsigned int nfound = 0; - struct flagsbuf fbuf; + struct flagsbuf fbuf, nbuf; + struct ddebug_class_map *map = NULL; + int __outvar valid_class; /* search for matching ddebugs */ mutex_lock(&ddebug_lock); @@ -167,9 +190,22 @@ static int ddebug_change(const struct ddebug_query *query, !match_wildcard(query->module, dt->mod_name)) continue; + if (query->class_string) { + map = ddebug_find_valid_class(dt, query->class_string, &valid_class); + if (!map) + continue; + } else { + /* constrain query, do not touch class'd callsites */ + valid_class = _DPRINTK_CLASS_DFLT; + } + for (i = 0; i < dt->num_ddebugs; i++) { struct _ddebug *dp = &dt->ddebugs[i]; + /* match site against query-class */ + if (dp->class_id != valid_class) + continue; + /* match against the source filename */ if (query->filename && !match_wildcard(query->filename, dp->filename) && @@ -211,16 +247,18 @@ static int ddebug_change(const struct ddebug_query *query, continue; #ifdef CONFIG_JUMP_LABEL if (dp->flags & _DPRINTK_FLAGS_PRINT) { - if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT)) + if (!(newflags & _DPRINTK_FLAGS_PRINT)) static_branch_disable(&dp->key.dd_key_true); - } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT) + } else if (newflags & _DPRINTK_FLAGS_PRINT) { static_branch_enable(&dp->key.dd_key_true); + } #endif + v4pr_info("changed %s:%d [%s]%s %s => %s\n", + trim_prefix(dp->filename), dp->lineno, + dt->mod_name, dp->function, + ddebug_describe_flags(dp->flags, &fbuf), + ddebug_describe_flags(newflags, &nbuf)); dp->flags = newflags; - v4pr_info("changed %s:%d [%s]%s =%s\n", - trim_prefix(dp->filename), dp->lineno, - dt->mod_name, dp->function, - ddebug_describe_flags(dp->flags, &fbuf)); } } mutex_unlock(&ddebug_lock); @@ -383,10 +421,6 @@ static int ddebug_parse_query(char *words[], int nwords, return -EINVAL; } - if (modname) - /* support $modname.dyndbg= */ - query->module = modname; - for (i = 0; i < nwords; i += 2) { char *keyword = words[i]; char *arg = words[i+1]; @@ -420,6 +454,8 @@ static int ddebug_parse_query(char *words[], int nwords, } else if (!strcmp(keyword, "line")) { if (parse_linerange(query, arg)) return -EINVAL; + } else if (!strcmp(keyword, "class")) { + rc = check_set(&query->class_string, arg, "class"); } else { pr_err("unknown keyword \"%s\"\n", keyword); return -EINVAL; @@ -427,6 +463,13 @@ static int ddebug_parse_query(char *words[], int nwords, if (rc) return rc; } + if (!query->module && modname) + /* + * support $modname.dyndbg=, when + * not given in the query itself + */ + query->module = modname; + vpr_info_dq(query, "parsed"); return 0; } @@ -553,34 +596,217 @@ static int ddebug_exec_queries(char *query, const char *modname) return nfound; } -/** - * dynamic_debug_exec_queries - select and change dynamic-debug prints - * @query: query-string described in admin-guide/dynamic-debug-howto - * @modname: string containing module name, usually &module.mod_name - * - * This uses the >/proc/dynamic_debug/control reader, allowing module - * authors to modify their dynamic-debug callsites. The modname is - * canonically struct module.mod_name, but can also be null or a - * module-wildcard, for example: "drm*". - */ -int dynamic_debug_exec_queries(const char *query, const char *modname) +/* apply a new bitmap to the sys-knob's current bit-state */ +static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, + unsigned long *new_bits, unsigned long *old_bits) { - int rc; - char *qry; /* writable copy of query */ +#define QUERY_SIZE 128 + char query[QUERY_SIZE]; + const struct ddebug_class_map *map = dcp->map; + int matches = 0; + int bi, ct; - if (!query) { - pr_err("non-null query/command string expected\n"); + v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits); + + for (bi = 0; bi < map->length; bi++) { + if (test_bit(bi, new_bits) == test_bit(bi, old_bits)) + continue; + + snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi], + test_bit(bi, new_bits) ? '+' : '-', dcp->flags); + + ct = ddebug_exec_queries(query, NULL); + matches += ct; + + v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi, + ct, map->class_names[bi], *new_bits); + } + return matches; +} + +/* stub to later conditionally add "$module." prefix where not already done */ +#define KP_NAME(kp) kp->name + +#define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1) + +/* accept comma-separated-list of [+-] classnames */ +static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + unsigned long curr_bits, old_bits; + char *cl_str, *p, *tmp; + int cls_id, totct = 0; + bool wanted; + + cl_str = tmp = kstrdup(instr, GFP_KERNEL); + p = strchr(cl_str, '\n'); + if (p) + *p = '\0'; + + /* start with previously set state-bits, then modify */ + curr_bits = old_bits = *dcp->bits; + vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits); + + for (; cl_str; cl_str = p) { + p = strchr(cl_str, ','); + if (p) + *p++ = '\0'; + + if (*cl_str == '-') { + wanted = false; + cl_str++; + } else { + wanted = true; + if (*cl_str == '+') + cl_str++; + } + cls_id = match_string(map->class_names, map->length, cl_str); + if (cls_id < 0) { + pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp)); + continue; + } + + /* have one or more valid class_ids of one *_NAMES type */ + switch (map->map_type) { + case DD_CLASS_TYPE_DISJOINT_NAMES: + /* the +/- pertains to a single bit */ + if (test_bit(cls_id, &curr_bits) == wanted) { + v3pr_info("no change on %s\n", cl_str); + continue; + } + curr_bits ^= BIT(cls_id); + totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits); + *dcp->bits = curr_bits; + v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, + map->class_names[cls_id]); + break; + case DD_CLASS_TYPE_LEVEL_NAMES: + /* cls_id = N in 0..max. wanted +/- determines N or N-1 */ + old_bits = CLASSMAP_BITMASK(*dcp->lvl); + curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); + + totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits); + *dcp->lvl = (cls_id + (wanted ? 1 : 0)); + v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id, + map->class_names[cls_id], old_bits, curr_bits); + break; + default: + pr_err("illegal map-type value %d\n", map->map_type); + } + } + kfree(tmp); + vpr_info("total matches: %d\n", totct); + return 0; +} + +/** + * param_set_dyndbg_classes - class FOO >control + * @instr: string echo>d to sysfs, input depends on map_type + * @kp: kp->arg has state: bits/lvl, map, map_type + * + * Enable/disable prdbgs by their class, as given in the arguments to + * DECLARE_DYNDBG_CLASSMAP. For LEVEL map-types, enforce relative + * levels by bitpos. + * + * Returns: 0 or <0 if error. + */ +int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + unsigned long inrep, new_bits, old_bits; + int rc, totct = 0; + + switch (map->map_type) { + + case DD_CLASS_TYPE_DISJOINT_NAMES: + case DD_CLASS_TYPE_LEVEL_NAMES: + /* handle [+-]classnames list separately, we are done here */ + return param_set_dyndbg_classnames(instr, kp); + + case DD_CLASS_TYPE_DISJOINT_BITS: + case DD_CLASS_TYPE_LEVEL_NUM: + /* numeric input, accept and fall-thru */ + rc = kstrtoul(instr, 0, &inrep); + if (rc) { + pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp)); + return -EINVAL; + } + break; + default: + pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type); return -EINVAL; } - qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL); - if (!qry) - return -ENOMEM; - rc = ddebug_exec_queries(qry, modname); - kfree(qry); - return rc; + /* only _BITS,_NUM (numeric) map-types get here */ + switch (map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + /* expect bits. mask and warn if too many */ + if (inrep & ~CLASSMAP_BITMASK(map->length)) { + pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", + KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length)); + inrep &= CLASSMAP_BITMASK(map->length); + } + v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp)); + totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits); + *dcp->bits = inrep; + break; + case DD_CLASS_TYPE_LEVEL_NUM: + /* input is bitpos, of highest verbosity to be enabled */ + if (inrep > map->length) { + pr_warn("%s: level:%ld exceeds max:%d, clamping\n", + KP_NAME(kp), inrep, map->length); + inrep = map->length; + } + old_bits = CLASSMAP_BITMASK(*dcp->lvl); + new_bits = CLASSMAP_BITMASK(inrep); + v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp)); + totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits); + *dcp->lvl = inrep; + break; + default: + pr_warn("%s: bad map type: %d\n", KP_NAME(kp), map->map_type); + } + vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct); + return 0; } -EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries); +EXPORT_SYMBOL(param_set_dyndbg_classes); + +/** + * param_get_dyndbg_classes - classes reader + * @buffer: string description of controlled bits -> classes + * @kp: kp->arg has state: bits, map + * + * Reads last written state, underlying prdbg state may have been + * altered by direct >control. Displays 0x for DISJOINT, 0-N for + * LEVEL Returns: #chars written or <0 on error + */ +int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + + switch (map->map_type) { + + case DD_CLASS_TYPE_DISJOINT_NAMES: + case DD_CLASS_TYPE_DISJOINT_BITS: + return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits); + + case DD_CLASS_TYPE_LEVEL_NAMES: + case DD_CLASS_TYPE_LEVEL_NUM: + return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl); + default: + return -1; + } +} +EXPORT_SYMBOL(param_get_dyndbg_classes); + +const struct kernel_param_ops param_ops_dyndbg_classes = { + .set = param_set_dyndbg_classes, + .get = param_get_dyndbg_classes, +}; +EXPORT_SYMBOL(param_ops_dyndbg_classes); #define PREFIX_SIZE 64 @@ -803,13 +1029,12 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter) { if (list_empty(&ddebug_tables)) { iter->table = NULL; - iter->idx = 0; return NULL; } iter->table = list_entry(ddebug_tables.next, struct ddebug_table, link); - iter->idx = 0; - return &iter->table->ddebugs[iter->idx]; + iter->idx = iter->table->num_ddebugs; + return &iter->table->ddebugs[--iter->idx]; } /* @@ -822,15 +1047,16 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter) { if (iter->table == NULL) return NULL; - if (++iter->idx == iter->table->num_ddebugs) { + if (--iter->idx < 0) { /* iterate to next table */ - iter->idx = 0; if (list_is_last(&iter->table->link, &ddebug_tables)) { iter->table = NULL; return NULL; } iter->table = list_entry(iter->table->link.next, struct ddebug_table, link); + iter->idx = iter->table->num_ddebugs; + --iter->idx; } return &iter->table->ddebugs[iter->idx]; } @@ -876,6 +1102,20 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos) return dp; } +#define class_in_range(class_id, map) \ + (class_id >= map->base && class_id < map->base + map->length) + +static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp) +{ + struct ddebug_class_map *map; + + list_for_each_entry(map, &iter->table->maps, link) + if (class_in_range(dp->class_id, map)) + return map->class_names[dp->class_id - map->base]; + + return NULL; +} + /* * Seq_ops show method. Called several times within a read() * call from userspace, with ddebug_lock held. Formats the @@ -887,6 +1127,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p) struct ddebug_iter *iter = m->private; struct _ddebug *dp = p; struct flagsbuf flags; + char const *class; if (p == SEQ_START_TOKEN) { seq_puts(m, @@ -898,8 +1139,17 @@ static int ddebug_proc_show(struct seq_file *m, void *p) trim_prefix(dp->filename), dp->lineno, iter->table->mod_name, dp->function, ddebug_describe_flags(dp->flags, &flags)); - seq_escape(m, dp->format, "\t\r\n\""); - seq_puts(m, "\"\n"); + seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\""); + seq_puts(m, "\""); + + if (dp->class_id != _DPRINTK_CLASS_DFLT) { + class = ddebug_class_name(iter, dp); + if (class) + seq_printf(m, " class:%s", class); + else + seq_printf(m, " class unknown, _id:%d", dp->class_id); + } + seq_puts(m, "\n"); return 0; } @@ -943,18 +1193,50 @@ static const struct proc_ops proc_fops = { .proc_write = ddebug_proc_write }; +static void ddebug_attach_module_classes(struct ddebug_table *dt, + struct ddebug_class_map *classes, + int num_classes) +{ + struct ddebug_class_map *cm; + int i, j, ct = 0; + + for (cm = classes, i = 0; i < num_classes; i++, cm++) { + + if (!strcmp(cm->mod_name, dt->mod_name)) { + + v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i, + cm->mod_name, cm->base, cm->length, cm->map_type); + + for (j = 0; j < cm->length; j++) + v3pr_info(" %d: %d %s\n", j + cm->base, j, + cm->class_names[j]); + + list_add(&cm->link, &dt->maps); + ct++; + } + } + if (ct) + vpr_info("module:%s attached %d classes\n", dt->mod_name, ct); +} + /* * Allocate a new ddebug_table for the given module * and add it to the global list. */ -int ddebug_add_module(struct _ddebug *tab, unsigned int n, - const char *name) +static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base, + const char *modname) { struct ddebug_table *dt; + v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs); + if (!di->num_descs) { + v3pr_info(" skip %s\n", modname); + return 0; + } + dt = kzalloc(sizeof(*dt), GFP_KERNEL); if (dt == NULL) { - pr_err("error adding module: %s\n", name); + pr_err("error adding module: %s\n", modname); return -ENOMEM; } /* @@ -963,18 +1245,29 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n, * member of struct module, which lives at least as long as * this struct ddebug_table. */ - dt->mod_name = name; - dt->num_ddebugs = n; - dt->ddebugs = tab; + dt->mod_name = modname; + dt->ddebugs = di->descs; + dt->num_ddebugs = di->num_descs; + + INIT_LIST_HEAD(&dt->link); + INIT_LIST_HEAD(&dt->maps); + + if (di->classes && di->num_classes) + ddebug_attach_module_classes(dt, di->classes, di->num_classes); mutex_lock(&ddebug_lock); - list_add(&dt->link, &ddebug_tables); + list_add_tail(&dt->link, &ddebug_tables); mutex_unlock(&ddebug_lock); - vpr_info("%3u debug prints in module %s\n", n, dt->mod_name); + vpr_info("%3u debug prints in module %s\n", di->num_descs, modname); return 0; } +int ddebug_add_module(struct _ddebug_info *di, const char *modname) +{ + return __ddebug_add_module(di, 0, modname); +} + /* helper for ddebug_dyndbg_(boot|module)_param_cb */ static int ddebug_dyndbg_param_cb(char *param, char *val, const char *modname, int on_err) @@ -1083,11 +1376,17 @@ static int __init dynamic_debug_init_control(void) static int __init dynamic_debug_init(void) { - struct _ddebug *iter, *iter_start; - const char *modname = NULL; + struct _ddebug *iter, *iter_mod_start; + int ret, i, mod_sites, mod_ct; + const char *modname; char *cmdline; - int ret = 0; - int n = 0, entries = 0, modct = 0; + + struct _ddebug_info di = { + .descs = __start___dyndbg, + .classes = __start___dyndbg_classes, + .num_descs = __stop___dyndbg - __start___dyndbg, + .num_classes = __stop___dyndbg_classes - __start___dyndbg_classes, + }; if (&__start___dyndbg == &__stop___dyndbg) { if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) { @@ -1098,30 +1397,39 @@ static int __init dynamic_debug_init(void) ddebug_init_success = 1; return 0; } - iter = __start___dyndbg; + + iter = iter_mod_start = __start___dyndbg; modname = iter->modname; - iter_start = iter; - for (; iter < __stop___dyndbg; iter++) { - entries++; + i = mod_sites = mod_ct = 0; + + for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) { + if (strcmp(modname, iter->modname)) { - modct++; - ret = ddebug_add_module(iter_start, n, modname); + mod_ct++; + di.num_descs = mod_sites; + di.descs = iter_mod_start; + ret = __ddebug_add_module(&di, i - mod_sites, modname); if (ret) goto out_err; - n = 0; + + mod_sites = 0; modname = iter->modname; - iter_start = iter; + iter_mod_start = iter; } - n++; } - ret = ddebug_add_module(iter_start, n, modname); + di.num_descs = mod_sites; + di.descs = iter_mod_start; + ret = __ddebug_add_module(&di, i - mod_sites, modname); if (ret) goto out_err; ddebug_init_success = 1; vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n", - entries, modct, (int)((modct * sizeof(struct ddebug_table)) >> 10), - (int)((entries * sizeof(struct _ddebug)) >> 10)); + i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10), + (int)((i * sizeof(struct _ddebug)) >> 10)); + + if (di.num_classes) + v2pr_info(" %d builtin ddebug class-maps\n", di.num_classes); /* now that ddebug tables are loaded, process all boot args * again to find and activate queries given in dyndbg params. diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c new file mode 100644 index 000000000000..8dd250ad022b --- /dev/null +++ b/lib/test_dynamic_debug.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Kernel module for testing dynamic_debug + * + * Authors: + * Jim Cromie + */ + +#define pr_fmt(fmt) "test_dd: " fmt + +#include + +/* run tests by reading or writing sysfs node: do_prints */ + +static void do_prints(void); /* device under test */ +static int param_set_do_prints(const char *instr, const struct kernel_param *kp) +{ + do_prints(); + return 0; +} +static int param_get_do_prints(char *buffer, const struct kernel_param *kp) +{ + do_prints(); + return scnprintf(buffer, PAGE_SIZE, "did do_prints\n"); +} +static const struct kernel_param_ops param_ops_do_prints = { + .set = param_set_do_prints, + .get = param_get_do_prints, +}; +module_param_cb(do_prints, ¶m_ops_do_prints, NULL, 0600); + +/* + * Using the CLASSMAP api: + * - classmaps must have corresponding enum + * - enum symbols must match/correlate with class-name strings in the map. + * - base must equal enum's 1st value + * - multiple maps must set their base to share the 0-30 class_id space !! + * (build-bug-on tips welcome) + * Additionally, here: + * - tie together sysname, mapname, bitsname, flagsname + */ +#define DD_SYS_WRAP(_model, _flags) \ + static unsigned long bits_##_model; \ + static struct ddebug_class_param _flags##_model = { \ + .bits = &bits_##_model, \ + .flags = #_flags, \ + .map = &map_##_model, \ + }; \ + module_param_cb(_flags##_##_model, ¶m_ops_dyndbg_classes, &_flags##_model, 0600) + +/* numeric input, independent bits */ +enum cat_disjoint_bits { + D2_CORE = 0, + D2_DRIVER, + D2_KMS, + D2_PRIME, + D2_ATOMIC, + D2_VBL, + D2_STATE, + D2_LEASE, + D2_DP, + D2_DRMRES }; +DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0, + "D2_CORE", + "D2_DRIVER", + "D2_KMS", + "D2_PRIME", + "D2_ATOMIC", + "D2_VBL", + "D2_STATE", + "D2_LEASE", + "D2_DP", + "D2_DRMRES"); +DD_SYS_WRAP(disjoint_bits, p); +DD_SYS_WRAP(disjoint_bits, T); + +/* symbolic input, independent bits */ +enum cat_disjoint_names { LOW = 11, MID, HI }; +DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10, + "LOW", "MID", "HI"); +DD_SYS_WRAP(disjoint_names, p); +DD_SYS_WRAP(disjoint_names, T); + +/* numeric verbosity, V2 > V1 related */ +enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 }; +DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14, + "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7"); +DD_SYS_WRAP(level_num, p); +DD_SYS_WRAP(level_num, T); + +/* symbolic verbosity */ +enum cat_level_names { L0 = 22, L1, L2, L3, L4, L5, L6, L7 }; +DECLARE_DYNDBG_CLASSMAP(map_level_names, DD_CLASS_TYPE_LEVEL_NAMES, 22, + "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7"); +DD_SYS_WRAP(level_names, p); +DD_SYS_WRAP(level_names, T); + +/* stand-in for all pr_debug etc */ +#define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n") + +static void do_cats(void) +{ + pr_debug("doing categories\n"); + + prdbg(LOW); + prdbg(MID); + prdbg(HI); + + prdbg(D2_CORE); + prdbg(D2_DRIVER); + prdbg(D2_KMS); + prdbg(D2_PRIME); + prdbg(D2_ATOMIC); + prdbg(D2_VBL); + prdbg(D2_STATE); + prdbg(D2_LEASE); + prdbg(D2_DP); + prdbg(D2_DRMRES); +} + +static void do_levels(void) +{ + pr_debug("doing levels\n"); + + prdbg(V1); + prdbg(V2); + prdbg(V3); + prdbg(V4); + prdbg(V5); + prdbg(V6); + prdbg(V7); + + prdbg(L1); + prdbg(L2); + prdbg(L3); + prdbg(L4); + prdbg(L5); + prdbg(L6); + prdbg(L7); +} + +static void do_prints(void) +{ + do_cats(); + do_levels(); +} + +static int __init test_dynamic_debug_init(void) +{ + pr_debug("init start\n"); + do_prints(); + pr_debug("init done\n"); + return 0; +} + +static void __exit test_dynamic_debug_exit(void) +{ + pr_debug("exited\n"); +} + +module_init(test_dynamic_debug_init); +module_exit(test_dynamic_debug_exit); + +MODULE_AUTHOR("Jim Cromie "); +MODULE_LICENSE("GPL"); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ebd78fdbd6e8..8009e0e93216 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -35,7 +35,6 @@ #include #include -#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ #define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ #define RFCOMM_TTY_MINOR 0 @@ -855,7 +854,8 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l return -ENOIOCTLCMD; } -static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) +static void rfcomm_tty_set_termios(struct tty_struct *tty, + const struct ktermios *old) { struct ktermios *new = &tty->termios; int old_baud_rate = tty_termios_baud_rate(old);