mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	Char/Misc and other driver subsystem updates for 6.9-rc1
Here is the big set of char/misc and a number of other driver subsystem
 updates for 6.9-rc1.  Included in here are:
   - IIO driver updates, loads of new ones and evolution of existing ones
   - coresight driver updates
   - const cleanups for many driver subsystems
   - speakup driver additions
   - platform remove callback void cleanups
   - mei driver updates
   - mhi driver updates
   - cdx driver updates for MSI interrupt handling
   - nvmem driver updates
   - other smaller driver updates and cleanups, full details in the
     shortlog
 
 All of these have been in linux-next for a long time with no reported
 issue, other than a build warning with some older versions of gcc for a
 speakup driver, fix for that will come in a few days when I catch up
 with my pending patch queues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZfwuLg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynKVACgjvR1cD8NYk9PcGWc9ZaXAZ6zSnwAn260kMoe
 lLFtwszo7m0N6ZULBWBd
 =y3yz
 -----END PGP SIGNATURE-----
Merge tag 'char-misc-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc and other driver subsystem updates from Greg KH:
 "Here is the big set of char/misc and a number of other driver
  subsystem updates for 6.9-rc1. Included in here are:
   - IIO driver updates, loads of new ones and evolution of existing ones
   - coresight driver updates
   - const cleanups for many driver subsystems
   - speakup driver additions
   - platform remove callback void cleanups
   - mei driver updates
   - mhi driver updates
   - cdx driver updates for MSI interrupt handling
   - nvmem driver updates
   - other smaller driver updates and cleanups, full details in the
    shortlog
  All of these have been in linux-next for a long time with no reported
  issue, other than a build warning for the speakup driver"
The build warning hits clang and is a gcc (and C23) extension, and is
fixed up in the merge.
Link: https://lore.kernel.org/all/20240321134831.GA2762840@dev-arch.thelio-3990X/
* tag 'char-misc-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (279 commits)
  binder: remove redundant variable page_addr
  uio_dmem_genirq: UIO_MEM_DMA_COHERENT conversion
  uio_pruss: UIO_MEM_DMA_COHERENT conversion
  cnic,bnx2,bnx2x: use UIO_MEM_DMA_COHERENT
  uio: introduce UIO_MEM_DMA_COHERENT type
  cdx: add MSI support for CDX bus
  pps: use cflags-y instead of EXTRA_CFLAGS
  speakup: Add /dev/synthu device
  speakup: Fix 8bit characters from direct synth
  parport: sunbpp: Convert to platform remove callback returning void
  parport: amiga: Convert to platform remove callback returning void
  char: xillybus: Convert to platform remove callback returning void
  vmw_balloon: change maintainership
  MAINTAINERS: change the maintainer for hpilo driver
  char: xilinx_hwicap: Fix NULL vs IS_ERR() bug
  hpet: remove hpets::hp_clocksource
  platform: goldfish: move the separate 'default' propery for CONFIG_GOLDFISH
  char: xilinx_hwicap: drop casting to void in dev_set_drvdata
  greybus: move is_gb_* functions out of greybus.h
  greybus: Remove usage of the deprecated ida_simple_xx() API
  ...
			
			
This commit is contained in:
		
						commit
						bb41fe35dc
					
				
					 305 changed files with 15181 additions and 4508 deletions
				
			
		
							
								
								
									
										2
									
								
								.mailmap
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.mailmap
									
									
									
									
									
								
							|  | @ -439,6 +439,8 @@ Mukesh Ojha <quic_mojha@quicinc.com> <mojha@codeaurora.org> | ||||||
| Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org> | Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org> | ||||||
| Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org> | Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org> | ||||||
| Mythri P K <mythripk@ti.com> | Mythri P K <mythripk@ti.com> | ||||||
|  | Nadav Amit <nadav.amit@gmail.com> <namit@vmware.com> | ||||||
|  | Nadav Amit <nadav.amit@gmail.com> <namit@cs.technion.ac.il> | ||||||
| Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com> | Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com> | ||||||
| Naoya Horiguchi <naoya.horiguchi@nec.com> <n-horiguchi@ah.jp.nec.com> | Naoya Horiguchi <naoya.horiguchi@nec.com> <n-horiguchi@ah.jp.nec.com> | ||||||
| Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com> | Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com> | ||||||
|  |  | ||||||
|  | @ -170,3 +170,90 @@ Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_t | ||||||
| Description: | Description: | ||||||
| 		(RW) Set/Get the MSR(mux select register) for the DSB subunit | 		(RW) Set/Get the MSR(mux select register) for the DSB subunit | ||||||
| 		TPDM. | 		TPDM. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_mode | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description:	(Write) Set the data collection mode of CMB tpdm. Continuous | ||||||
|  | 		change creates CMB data set elements on every CMBCLK edge. | ||||||
|  | 		Trace-on-change creates CMB data set elements only when a new | ||||||
|  | 		data set element differs in value from the previous element | ||||||
|  | 		in a CMB data set. | ||||||
|  | 
 | ||||||
|  | 		Accepts only one of the 2 values -  0 or 1. | ||||||
|  | 		0 : Continuous CMB collection mode. | ||||||
|  | 		1 : Trace-on-change CMB collection mode. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpr[0:1] | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the value of the trigger pattern for the CMB | ||||||
|  | 		subunit TPDM. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpmr[0:1] | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the mask of the trigger pattern for the CMB | ||||||
|  | 		subunit TPDM. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:1] | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the value of the pattern for the CMB subunit TPDM. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:1] | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the mask of the pattern for the CMB subunit TPDM. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_patt/enable_ts | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(Write) Set the pattern timestamp of CMB tpdm. Read | ||||||
|  | 		the pattern timestamp of CMB tpdm. | ||||||
|  | 
 | ||||||
|  | 		Accepts only one of the 2 values -  0 or 1. | ||||||
|  | 		0 : Disable CMB pattern timestamp. | ||||||
|  | 		1 : Enable CMB pattern timestamp. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_trig_ts | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the trigger timestamp of the CMB for tpdm. | ||||||
|  | 
 | ||||||
|  | 		Accepts only one of the 2 values -  0 or 1. | ||||||
|  | 		0 : Set the CMB trigger type to false | ||||||
|  | 		1 : Set the CMB trigger type to true | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_ts_all | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Read or write the status of timestamp upon all interface. | ||||||
|  | 		Only value 0 and 1  can be written to this node. Set this node to 1 to requeset | ||||||
|  | 		timestamp to all trace packet. | ||||||
|  | 		Accepts only one of the 2 values -  0 or 1. | ||||||
|  | 		0 : Disable the timestamp of all trace packets. | ||||||
|  | 		1 : Enable the timestamp of all trace packets. | ||||||
|  | 
 | ||||||
|  | What:		/sys/bus/coresight/devices/<tpdm-name>/cmb_msr/msr[0:31] | ||||||
|  | Date:		January 2024 | ||||||
|  | KernelVersion	6.9 | ||||||
|  | Contact:	Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com> | ||||||
|  | Description: | ||||||
|  | 		(RW) Set/Get the MSR(mux select register) for the CMB subunit | ||||||
|  | 		TPDM. | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | What:		/sys/bus/iio/devices/iio:deviceX/in_shunt_resistorY | ||||||
|  | KernelVersion:	6.7 | ||||||
|  | Contact:	linux-iio@vger.kernel.org | ||||||
|  | Description: | ||||||
|  | 		The value of the shunt resistor may be known only at runtime | ||||||
|  | 		and set by a client application. This attribute allows to | ||||||
|  | 		set its value in micro-ohms. X is the IIO index of the device. | ||||||
|  | 		Y is the channel number. The value is used to calculate | ||||||
|  | 		current, power and accumulated energy. | ||||||
|  | @ -44,14 +44,21 @@ properties: | ||||||
|     minItems: 1 |     minItems: 1 | ||||||
|     maxItems: 2 |     maxItems: 2 | ||||||
| 
 | 
 | ||||||
|   qcom,dsb-element-size: |   qcom,dsb-element-bits: | ||||||
|     description: |     description: | ||||||
|       Specifies the DSB(Discrete Single Bit) element size supported by |       Specifies the DSB(Discrete Single Bit) element size supported by | ||||||
|       the monitor. The associated aggregator will read this size before it |       the monitor. The associated aggregator will read this size before it | ||||||
|       is enabled. DSB element size currently only supports 32-bit and 64-bit. |       is enabled. DSB element size currently only supports 32-bit and 64-bit. | ||||||
|     $ref: /schemas/types.yaml#/definitions/uint8 |  | ||||||
|     enum: [32, 64] |     enum: [32, 64] | ||||||
| 
 | 
 | ||||||
|  |   qcom,cmb-element-bits: | ||||||
|  |     description: | ||||||
|  |       Specifies the CMB(Continuous Multi-Bit) element size supported by | ||||||
|  |       the monitor. The associated aggregator will read this size before it | ||||||
|  |       is enabled. CMB element size currently only supports 8-bit, 32-bit | ||||||
|  |       and 64-bit. | ||||||
|  |     enum: [8, 32, 64] | ||||||
|  | 
 | ||||||
|   qcom,dsb-msrs-num: |   qcom,dsb-msrs-num: | ||||||
|     description: |     description: | ||||||
|       Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) |       Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) | ||||||
|  | @ -61,6 +68,15 @@ properties: | ||||||
|     minimum: 0 |     minimum: 0 | ||||||
|     maximum: 32 |     maximum: 32 | ||||||
| 
 | 
 | ||||||
|  |   qcom,cmb-msrs-num: | ||||||
|  |     description: | ||||||
|  |       Specifies the number of CMB MSR(mux select register) registers supported | ||||||
|  |       by the monitor. If this property is not configured or set to 0, it means | ||||||
|  |       this TPDM doesn't support CMB MSR. | ||||||
|  |     $ref: /schemas/types.yaml#/definitions/uint32 | ||||||
|  |     minimum: 0 | ||||||
|  |     maximum: 32 | ||||||
|  | 
 | ||||||
|   clocks: |   clocks: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|  | @ -94,7 +110,7 @@ examples: | ||||||
|       compatible = "qcom,coresight-tpdm", "arm,primecell"; |       compatible = "qcom,coresight-tpdm", "arm,primecell"; | ||||||
|       reg = <0x0684c000 0x1000>; |       reg = <0x0684c000 0x1000>; | ||||||
| 
 | 
 | ||||||
|       qcom,dsb-element-size = /bits/ 8 <32>; |       qcom,dsb-element-bits = <32>; | ||||||
|       qcom,dsb-msrs-num = <16>; |       qcom,dsb-msrs-num = <16>; | ||||||
| 
 | 
 | ||||||
|       clocks = <&aoss_qmp>; |       clocks = <&aoss_qmp>; | ||||||
|  | @ -110,4 +126,22 @@ examples: | ||||||
|       }; |       }; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     tpdm@6c29000 { | ||||||
|  |       compatible = "qcom,coresight-tpdm", "arm,primecell"; | ||||||
|  |       reg = <0x06c29000 0x1000>; | ||||||
|  | 
 | ||||||
|  |       qcom,cmb-element-bits = <64>; | ||||||
|  |       qcom,cmb-msrs-num = <32>; | ||||||
|  | 
 | ||||||
|  |       clocks = <&aoss_qmp>; | ||||||
|  |       clock-names = "apb_pclk"; | ||||||
|  | 
 | ||||||
|  |       out-ports { | ||||||
|  |         port { | ||||||
|  |           tpdm_ipcc_out_funnel_center: endpoint { | ||||||
|  |             remote-endpoint = <&funnel_center_in_tpdm_ipcc>; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
| ... | ... | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ properties: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|   label: |   label: | ||||||
|     $ref: /schemas/types.yaml#/definitions/string |  | ||||||
|     description: Unique name to identify which channel this is. |     description: Unique name to identify which channel this is. | ||||||
| 
 | 
 | ||||||
|   bipolar: |   bipolar: | ||||||
|  |  | ||||||
|  | @ -44,6 +44,9 @@ properties: | ||||||
|       Pin that controls the powerdown mode of the device. |       Pin that controls the powerdown mode of the device. | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|  |   io-backends: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|   reset-gpios: |   reset-gpios: | ||||||
|     description: |     description: | ||||||
|       Reset pin for the device. |       Reset pin for the device. | ||||||
|  | @ -68,6 +71,7 @@ examples: | ||||||
|             reg = <0>; |             reg = <0>; | ||||||
|             clocks = <&adc_clk>; |             clocks = <&adc_clk>; | ||||||
|             clock-names = "adc-clk"; |             clock-names = "adc-clk"; | ||||||
|  |             io-backends = <&iio_backend>; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
| ... | ... | ||||||
|  |  | ||||||
|  | @ -39,12 +39,15 @@ properties: | ||||||
|     $ref: /schemas/types.yaml#/definitions/phandle |     $ref: /schemas/types.yaml#/definitions/phandle | ||||||
|     description: |     description: | ||||||
|       A reference to a the actual ADC to which this FPGA ADC interfaces to. |       A reference to a the actual ADC to which this FPGA ADC interfaces to. | ||||||
|  |     deprecated: true | ||||||
|  | 
 | ||||||
|  |   '#io-backend-cells': | ||||||
|  |     const: 0 | ||||||
| 
 | 
 | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - dmas |   - dmas | ||||||
|   - reg |   - reg | ||||||
|   - adi,adc-dev |  | ||||||
| 
 | 
 | ||||||
| additionalProperties: false | additionalProperties: false | ||||||
| 
 | 
 | ||||||
|  | @ -55,7 +58,6 @@ examples: | ||||||
|         reg = <0x44a00000 0x10000>; |         reg = <0x44a00000 0x10000>; | ||||||
|         dmas = <&rx_dma 0>; |         dmas = <&rx_dma 0>; | ||||||
|         dma-names = "rx"; |         dma-names = "rx"; | ||||||
| 
 |         #io-backend-cells = <0>; | ||||||
|         adi,adc-dev = <&spi_adc>; |  | ||||||
|     }; |     }; | ||||||
| ... | ... | ||||||
|  |  | ||||||
							
								
								
									
										120
									
								
								Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,120 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/iio/adc/microchip,pac1934.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Microchip PAC1934 Power Monitors with Accumulator | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Marius Cristea <marius.cristea@microchip.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   This device is part of the Microchip family of Power Monitors with | ||||||
|  |   Accumulator. | ||||||
|  |   The datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here: | ||||||
|  |     https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - microchip,pac1931 | ||||||
|  |       - microchip,pac1932 | ||||||
|  |       - microchip,pac1933 | ||||||
|  |       - microchip,pac1934 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   "#address-cells": | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|  |   "#size-cells": | ||||||
|  |     const: 0 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   slow-io-gpios: | ||||||
|  |     description: | ||||||
|  |       A GPIO used to trigger a change is sampling rate (lowering the chip power | ||||||
|  |       consumption). If configured in SLOW mode, if this pin is forced high, | ||||||
|  |       sampling rate is forced to eight samples/second. When it is forced low, | ||||||
|  |       the sampling rate is 1024 samples/second unless a different sample rate | ||||||
|  |       has been programmed. | ||||||
|  | 
 | ||||||
|  | patternProperties: | ||||||
|  |   "^channel@[1-4]+$": | ||||||
|  |     type: object | ||||||
|  |     $ref: adc.yaml | ||||||
|  |     description: | ||||||
|  |       Represents the external channels which are connected to the ADC. | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       reg: | ||||||
|  |         items: | ||||||
|  |           minimum: 1 | ||||||
|  |           maximum: 4 | ||||||
|  | 
 | ||||||
|  |       shunt-resistor-micro-ohms: | ||||||
|  |         description: | ||||||
|  |           Value in micro Ohms of the shunt resistor connected between | ||||||
|  |           the SENSE+ and SENSE- inputs, across which the current is measured. | ||||||
|  |           Value is needed to compute the scaling of the measured current. | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - reg | ||||||
|  |       - shunt-resistor-micro-ohms | ||||||
|  | 
 | ||||||
|  |     unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - "#address-cells" | ||||||
|  |   - "#size-cells" | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     i2c { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         power-monitor@10 { | ||||||
|  |             compatible = "microchip,pac1934"; | ||||||
|  |             reg = <0x10>; | ||||||
|  | 
 | ||||||
|  |             #address-cells = <1>; | ||||||
|  |             #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |             channel@1 { | ||||||
|  |                 reg = <0x1>; | ||||||
|  |                 shunt-resistor-micro-ohms = <24900000>; | ||||||
|  |                 label = "CPU"; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             channel@2 { | ||||||
|  |                 reg = <0x2>; | ||||||
|  |                 shunt-resistor-micro-ohms = <49900000>; | ||||||
|  |                 label = "GPU"; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             channel@3 { | ||||||
|  |                 reg = <0x3>; | ||||||
|  |                 shunt-resistor-micro-ohms = <75000000>; | ||||||
|  |                 label = "MEM"; | ||||||
|  |                 bipolar; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             channel@4 { | ||||||
|  |                 reg = <0x4>; | ||||||
|  |                 shunt-resistor-micro-ohms = <100000000>; | ||||||
|  |                 label = "NET"; | ||||||
|  |                 bipolar; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | ... | ||||||
|  | @ -31,7 +31,6 @@ properties: | ||||||
|       - description: normal conversion, include EOC (End of Conversion), |       - description: normal conversion, include EOC (End of Conversion), | ||||||
|           ECH (End of Chain), JEOC (End of Injected Conversion) and |           ECH (End of Chain), JEOC (End of Injected Conversion) and | ||||||
|           JECH (End of injected Chain). |           JECH (End of injected Chain). | ||||||
|       - description: Self-testing Interrupts. |  | ||||||
| 
 | 
 | ||||||
|   clocks: |   clocks: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
|  | @ -70,8 +69,7 @@ examples: | ||||||
|             reg = <0x44530000 0x10000>; |             reg = <0x44530000 0x10000>; | ||||||
|             interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, |             interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, | ||||||
|                          <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>, |                          <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>, | ||||||
|                          <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>, |                          <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; | ||||||
|                          <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; |  | ||||||
|             clocks = <&clk IMX93_CLK_ADC1_GATE>; |             clocks = <&clk IMX93_CLK_ADC1_GATE>; | ||||||
|             clock-names = "ipg"; |             clock-names = "ipg"; | ||||||
|             vref-supply = <®_vref_1v8>; |             vref-supply = <®_vref_1v8>; | ||||||
|  |  | ||||||
|  | @ -75,7 +75,6 @@ patternProperties: | ||||||
|           in the PMIC-specific files in include/dt-bindings/iio/. |           in the PMIC-specific files in include/dt-bindings/iio/. | ||||||
| 
 | 
 | ||||||
|       label: |       label: | ||||||
|         $ref: /schemas/types.yaml#/definitions/string |  | ||||||
|         description: | |         description: | | ||||||
|             ADC input of the platform as seen in the schematics. |             ADC input of the platform as seen in the schematics. | ||||||
|             For thermistor inputs connected to generic AMUX or GPIO inputs |             For thermistor inputs connected to generic AMUX or GPIO inputs | ||||||
|  |  | ||||||
|  | @ -25,7 +25,14 @@ description: | | ||||||
| 
 | 
 | ||||||
| properties: | properties: | ||||||
|   compatible: |   compatible: | ||||||
|     const: richtek,rtq6056 |     oneOf: | ||||||
|  |       - enum: | ||||||
|  |           - richtek,rtq6056 | ||||||
|  |           - richtek,rtq6059 | ||||||
|  |       - items: | ||||||
|  |           - enum: | ||||||
|  |               - richtek,rtq6053 | ||||||
|  |           - const: richtek,rtq6056 | ||||||
| 
 | 
 | ||||||
|   reg: |   reg: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
|  |  | ||||||
							
								
								
									
										80
									
								
								Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/iio/adc/ti,ads1298.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Texas Instruments' ads1298 medical ADC chips | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   Datasheet at: https://www.ti.com/product/ADS1298 | ||||||
|  |   Bindings for this chip aren't complete. | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Mike Looijmans <mike.looijmans@topic.nl> | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - ti,ads1298 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   spi-cpha: true | ||||||
|  | 
 | ||||||
|  |   reset-gpios: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   avdd-supply: | ||||||
|  |     description: | ||||||
|  |       Analog power supply, voltage between AVDD and AVSS. When providing a | ||||||
|  |       symmetric +/- 2.5V, the regulator should report 5V. | ||||||
|  | 
 | ||||||
|  |   vref-supply: | ||||||
|  |     description: | ||||||
|  |       Optional reference voltage. If omitted, internal reference is used, | ||||||
|  |       which is 2.4V when analog supply is below 4.4V, 4V otherwise. | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     description: Optional 2.048 MHz external source clock on CLK pin | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     description: Interrupt on DRDY pin, triggers on falling edge | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   label: true | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - avdd-supply | ||||||
|  |   - interrupts | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     spi { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         adc@1 { | ||||||
|  |           reg = <1>; | ||||||
|  |           compatible = "ti,ads1298"; | ||||||
|  |           label = "ads1298-1-ecg"; | ||||||
|  |           avdd-supply = <®_iso_5v_a>; | ||||||
|  |           clocks = <&clk_ads1298>; | ||||||
|  |           interrupt-parent = <&gpio0>; | ||||||
|  |           interrupts = <78 IRQ_TYPE_EDGE_FALLING>; | ||||||
|  |           spi-max-frequency = <20000000>; | ||||||
|  |           spi-cpha; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
|  | @ -39,6 +39,17 @@ properties: | ||||||
|     description: | |     description: | | ||||||
|       Channel node of a voltage io-channel. |       Channel node of a voltage io-channel. | ||||||
| 
 | 
 | ||||||
|  |   '#io-channel-cells': | ||||||
|  |     description: | ||||||
|  |       In addition to consuming the measurement services of a voltage | ||||||
|  |       output channel, the voltage divider can act as a provider of | ||||||
|  |       measurement services to other devices. This is particularly | ||||||
|  |       useful in scenarios wherein an ADC has an analog frontend, | ||||||
|  |       such as a voltage divider, and then consuming its raw value | ||||||
|  |       isn't interesting. In this case, the voltage before the divider | ||||||
|  |       is desired. | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|   output-ohms: |   output-ohms: | ||||||
|     description: |     description: | ||||||
|       Resistance Rout over which the output voltage is measured. See full-ohms. |       Resistance Rout over which the output voltage is measured. See full-ohms. | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ description: | | ||||||
|   HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz |   HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz | ||||||
|     https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf |     https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf | ||||||
| 
 | 
 | ||||||
|  |   LTC6373 is a 3-Bit precision instrumentation amplifier with fully differential outputs | ||||||
|  |     https://www.analog.com/media/en/technical-documentation/data-sheets/ltc6373.pdf | ||||||
| 
 | 
 | ||||||
| properties: | properties: | ||||||
|   compatible: |   compatible: | ||||||
|  | @ -28,16 +30,55 @@ properties: | ||||||
|       - adi,adrf5740 |       - adi,adrf5740 | ||||||
|       - adi,hmc425a |       - adi,hmc425a | ||||||
|       - adi,hmc540s |       - adi,hmc540s | ||||||
|  |       - adi,ltc6373 | ||||||
| 
 | 
 | ||||||
|   vcc-supply: true |   vcc-supply: true | ||||||
| 
 | 
 | ||||||
|   ctrl-gpios: |   ctrl-gpios: | ||||||
|     description: |     description: | ||||||
|       Must contain an array of 6 GPIO specifiers, referring to the GPIO pins |       Must contain an array of GPIO specifiers, referring to the GPIO pins | ||||||
|       connected to the control pins V1-V6. |       connected to the control pins. | ||||||
|     minItems: 6 |         ADRF5740  - 4 GPIO connected to D2-D5 | ||||||
|  |         HMC540S   - 4 GPIO connected to V1-V4 | ||||||
|  |         HMC425A   - 6 GPIO connected to V1-V6 | ||||||
|  |         LTC6373   - 3 GPIO connected to A0-A2 | ||||||
|  |     minItems: 1 | ||||||
|     maxItems: 6 |     maxItems: 6 | ||||||
| 
 | 
 | ||||||
|  | allOf: | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: adi,hmc425a | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         ctrl-gpios: | ||||||
|  |           minItems: 6 | ||||||
|  |           maxItems: 6 | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             anyOf: | ||||||
|  |               - const: adi,adrf5740 | ||||||
|  |               - const: adi,hmc540s | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         ctrl-gpios: | ||||||
|  |           minItems: 4 | ||||||
|  |           maxItems: 4 | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: adi,ltc6373 | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         ctrl-gpios: | ||||||
|  |           minItems: 3 | ||||||
|  |           maxItems: 3 | ||||||
|  | 
 | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - ctrl-gpios |   - ctrl-gpios | ||||||
|  |  | ||||||
|  | @ -0,0 +1,127 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | # Copyright 2024 Analog Devices Inc. | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/iio/frequency/adi,admfm2000.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: ADMFM2000 Dual Microwave Down Converter | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Kim Seer Paller <kimseer.paller@analog.com> | ||||||
|  | 
 | ||||||
|  | description: | ||||||
|  |   Dual microwave down converter module with input RF and LO frequency ranges | ||||||
|  |   from 0.5 to 32 GHz and an output IF frequency range from 0.1 to 8 GHz. | ||||||
|  |   It consists of a LNA, mixer, IF filter, DSA, and IF amplifier for each down | ||||||
|  |   conversion path. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - adi,admfm2000 | ||||||
|  | 
 | ||||||
|  |   '#address-cells': | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|  |   '#size-cells': | ||||||
|  |     const: 0 | ||||||
|  | 
 | ||||||
|  | patternProperties: | ||||||
|  |   "^channel@[0-1]$": | ||||||
|  |     type: object | ||||||
|  |     description: Represents a channel of the device. | ||||||
|  | 
 | ||||||
|  |     additionalProperties: false | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       reg: | ||||||
|  |         description: | ||||||
|  |           The channel number. | ||||||
|  |         minimum: 0 | ||||||
|  |         maximum: 1 | ||||||
|  | 
 | ||||||
|  |       adi,mixer-mode: | ||||||
|  |         description: | ||||||
|  |           Enable mixer mode for the channel. It downconverts RF between 5 GHz | ||||||
|  |           and 32 GHz to IF between 0.5 GHz and 8 GHz. If not present, the channel | ||||||
|  |           is in direct IF mode which bypasses the mixer and downconverts RF | ||||||
|  |           between 2 GHz and 8 GHz to IF between 0.5 GHz and 8 GHz. | ||||||
|  |         type: boolean | ||||||
|  | 
 | ||||||
|  |       switch-gpios: | ||||||
|  |         description: | | ||||||
|  |           GPIOs to select the RF path for the channel. The same state of CTRL-A | ||||||
|  |           and CTRL-B GPIOs is not permitted. | ||||||
|  |           CTRL-A   CTRL-B    CH1 Status        CH2 Status | ||||||
|  |           1        0         Direct IF mode    Mixer mode | ||||||
|  |           0        1         Mixer mode        Direct IF mode | ||||||
|  | 
 | ||||||
|  |         items: | ||||||
|  |           - description: CTRL-A GPIO | ||||||
|  |           - description: CTRL-B GPIO | ||||||
|  | 
 | ||||||
|  |       attenuation-gpios: | ||||||
|  |         description: | | ||||||
|  |           Choice of attenuation: | ||||||
|  |           DSA-V4  DSA-V3  DSA-V2  DSA-V1  DSA-V0 | ||||||
|  |           1       1       1       1       1        0 dB | ||||||
|  |           1       1       1       1       0        -1 dB | ||||||
|  |           1       1       1       0       1        -2 dB | ||||||
|  |           1       1       0       1       1        -4 dB | ||||||
|  |           1       0       1       1       1        -8 dB | ||||||
|  |           0       1       1       1       1        -16 dB | ||||||
|  |           0       0       0       0       0        -31 dB | ||||||
|  | 
 | ||||||
|  |         items: | ||||||
|  |           - description: DSA-V0 GPIO | ||||||
|  |           - description: DSA-V1 GPIO | ||||||
|  |           - description: DSA-V2 GPIO | ||||||
|  |           - description: DSA-V3 GPIO | ||||||
|  |           - description: DSA-V4 GPIO | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - reg | ||||||
|  |       - switch-gpios | ||||||
|  |       - attenuation-gpios | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  |     converter { | ||||||
|  |       compatible = "adi,admfm2000"; | ||||||
|  | 
 | ||||||
|  |       #address-cells = <1>; | ||||||
|  |       #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |       channel@0 { | ||||||
|  |         reg = <0>; | ||||||
|  |         switch-gpios = <&gpio 1 GPIO_ACTIVE_LOW>, | ||||||
|  |                        <&gpio 2 GPIO_ACTIVE_HIGH>; | ||||||
|  | 
 | ||||||
|  |         attenuation-gpios = <&gpio 17 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 22 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 23 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 24 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 25 GPIO_ACTIVE_LOW>; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       channel@1 { | ||||||
|  |         reg = <1>; | ||||||
|  |         adi,mixer-mode; | ||||||
|  |         switch-gpios = <&gpio 3 GPIO_ACTIVE_LOW>, | ||||||
|  |                        <&gpio 4 GPIO_ACTIVE_HIGH>; | ||||||
|  | 
 | ||||||
|  |         attenuation-gpios = <&gpio 0 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 5 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 6 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 16 GPIO_ACTIVE_LOW>, | ||||||
|  |                             <&gpio 26 GPIO_ACTIVE_LOW>; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
|  | @ -22,6 +22,9 @@ properties: | ||||||
|   vdd-supply: true |   vdd-supply: true | ||||||
|   vddio-supply: true |   vddio-supply: true | ||||||
| 
 | 
 | ||||||
|  |   spi-max-frequency: | ||||||
|  |     maximum: 10000000 | ||||||
|  | 
 | ||||||
|   interrupts: |   interrupts: | ||||||
|     minItems: 1 |     minItems: 1 | ||||||
|     maxItems: 2 |     maxItems: 2 | ||||||
|  | @ -33,7 +36,10 @@ required: | ||||||
|   - compatible |   - compatible | ||||||
|   - reg |   - reg | ||||||
| 
 | 
 | ||||||
| additionalProperties: false | allOf: | ||||||
|  |   - $ref: /schemas/spi/spi-peripheral-props.yaml# | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
| 
 | 
 | ||||||
| examples: | examples: | ||||||
|   - | |   - | | ||||||
|  |  | ||||||
|  | @ -27,6 +27,9 @@ properties: | ||||||
|   reg: |   reg: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - reg |   - reg | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ additionalProperties: false | ||||||
| 
 | 
 | ||||||
| examples: | examples: | ||||||
|   - | |   - | | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|     i2c { |     i2c { | ||||||
|         #address-cells = <1>; |         #address-cells = <1>; | ||||||
|         #size-cells = <0>; |         #size-cells = <0>; | ||||||
|  | @ -51,5 +52,7 @@ examples: | ||||||
|             compatible = "ti,hdc3021", "ti,hdc3020"; |             compatible = "ti,hdc3021", "ti,hdc3020"; | ||||||
|             reg = <0x47>; |             reg = <0x47>; | ||||||
|             vdd-supply = <&vcc_3v3>; |             vdd-supply = <&vcc_3v3>; | ||||||
|  |             interrupt-parent = <&gpio3>; | ||||||
|  |             interrupts = <23 IRQ_TYPE_EDGE_RISING>; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -35,7 +35,9 @@ properties: | ||||||
|           - st,lsm6dsv |           - st,lsm6dsv | ||||||
|           - st,lsm6dso16is |           - st,lsm6dso16is | ||||||
|       - items: |       - items: | ||||||
|           - const: st,asm330lhhx |           - enum: | ||||||
|  |               - st,asm330lhhx | ||||||
|  |               - st,asm330lhhxg1 | ||||||
|           - const: st,lsm6dsr |           - const: st,lsm6dsr | ||||||
|       - items: |       - items: | ||||||
|           - const: st,lsm6dstx |           - const: st,lsm6dstx | ||||||
|  |  | ||||||
|  | @ -4,19 +4,22 @@ | ||||||
| $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml# | $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml# | ||||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
| 
 | 
 | ||||||
| title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor | title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 UV Sensor | ||||||
| 
 | 
 | ||||||
| maintainers: | maintainers: | ||||||
|   - Christian Eggers <ceggers@arri.de> |   - Christian Eggers <ceggers@arri.de> | ||||||
| 
 | 
 | ||||||
| description: | | description: | | ||||||
|   XYZ True Color Sensor with I2C Interface |   AMS AS73211 XYZ True Color Sensor with I2C Interface | ||||||
|   https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df |   https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df | ||||||
|  |   AMS AS7331 UVA, UVB and UVC Sensor with I2C Interface | ||||||
|  |   https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf | ||||||
| 
 | 
 | ||||||
| properties: | properties: | ||||||
|   compatible: |   compatible: | ||||||
|     enum: |     enum: | ||||||
|       - ams,as73211 |       - ams,as73211 | ||||||
|  |       - ams,as7331 | ||||||
| 
 | 
 | ||||||
|   reg: |   reg: | ||||||
|     description: |     description: | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ properties: | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - reg |   - reg | ||||||
|  |   - vdd-supply | ||||||
| 
 | 
 | ||||||
| additionalProperties: false | additionalProperties: false | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,60 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/iio/magnetometer/voltafield,af8133j.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Voltafield AF8133J magnetometer sensor | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Ondřej Jirman <megi@xff.cz> | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     const: voltafield,af8133j | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   reset-gpios: | ||||||
|  |     description: | ||||||
|  |       A signal for active low reset input of the sensor. (optional; if not | ||||||
|  |       used, software reset over I2C will be used instead) | ||||||
|  | 
 | ||||||
|  |   avdd-supply: | ||||||
|  |     description: | ||||||
|  |       A regulator that provides AVDD power (Working power, usually 3.3V) to | ||||||
|  |       the sensor. | ||||||
|  | 
 | ||||||
|  |   dvdd-supply: | ||||||
|  |     description: | ||||||
|  |       A regulator that provides DVDD power (Digital IO power, 1.8V - AVDD) | ||||||
|  |       to the sensor. | ||||||
|  | 
 | ||||||
|  |   mount-matrix: | ||||||
|  |     description: An optional 3x3 mounting rotation matrix. | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - avdd-supply | ||||||
|  |   - dvdd-supply | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  |     i2c { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         magnetometer@1c { | ||||||
|  |             compatible = "voltafield,af8133j"; | ||||||
|  |             reg = <0x1c>; | ||||||
|  |             avdd-supply = <®_dldo1>; | ||||||
|  |             dvdd-supply = <®_dldo1>; | ||||||
|  |             reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | @ -99,6 +99,9 @@ required: | ||||||
|   - honeywell,transfer-function |   - honeywell,transfer-function | ||||||
|   - honeywell,pressure-triplet |   - honeywell,pressure-triplet | ||||||
| 
 | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: /schemas/spi/spi-peripheral-props.yaml | ||||||
|  | 
 | ||||||
| additionalProperties: false | additionalProperties: false | ||||||
| 
 | 
 | ||||||
| dependentSchemas: | dependentSchemas: | ||||||
|  |  | ||||||
|  | @ -8,25 +8,28 @@ title: Honeywell mprls0025pa pressure sensor | ||||||
| 
 | 
 | ||||||
| maintainers: | maintainers: | ||||||
|   - Andreas Klinger <ak@it-klinger.de> |   - Andreas Klinger <ak@it-klinger.de> | ||||||
|  |   - Petre Rodan <petre.rodan@subdimension.ro> | ||||||
| 
 | 
 | ||||||
| description: | | description: | | ||||||
|   Honeywell pressure sensor of model mprls0025pa. |   Honeywell pressure sensor of model mprls0025pa. | ||||||
| 
 | 
 | ||||||
|   This sensor has an I2C and SPI interface. Only the I2C interface is |   This sensor has an I2C and SPI interface. | ||||||
|   implemented. |  | ||||||
| 
 | 
 | ||||||
|   There are many models with different pressure ranges available. The vendor |   There are many models with different pressure ranges available. The vendor | ||||||
|   calls them "mpr series". All of them have the identical programming model and |   calls them "mpr series". All of them have the identical programming model and | ||||||
|   differ in the pressure range, unit and transfer function. |   differ in the pressure range, unit and transfer function. | ||||||
| 
 | 
 | ||||||
|   To support different models one need to specify the pressure range as well as |   To support different models one need to specify its pressure triplet as well | ||||||
|   the transfer function. Pressure range needs to be converted from its unit to |   as the transfer function. | ||||||
|   pascal. | 
 | ||||||
|  |   For custom silicon chips not covered by the Honeywell MPR series datasheet, | ||||||
|  |   the pressure values can be specified manually via honeywell,pmin-pascal and | ||||||
|  |   honeywell,pmax-pascal. | ||||||
|  |   The minimal range value stands for the minimum pressure and the maximum value | ||||||
|  |   also for the maximum pressure with linear relation inside the range. | ||||||
| 
 | 
 | ||||||
|   The transfer function defines the ranges of numerical values delivered by the |   The transfer function defines the ranges of numerical values delivered by the | ||||||
|   sensor. The minimal range value stands for the minimum pressure and the |   sensor. | ||||||
|   maximum value also for the maximum pressure with linear relation inside the |  | ||||||
|   range. |  | ||||||
| 
 | 
 | ||||||
|   Specifications about the devices can be found at: |   Specifications about the devices can be found at: | ||||||
|     https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ |     https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/ | ||||||
|  | @ -42,6 +45,10 @@ properties: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|   interrupts: |   interrupts: | ||||||
|  |     description: | ||||||
|  |       Optional interrupt for indicating End-of-conversion. | ||||||
|  |       If not present, the driver loops for a while until the received status | ||||||
|  |       byte indicates correct measurement. | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|   reset-gpios: |   reset-gpios: | ||||||
|  | @ -50,6 +57,27 @@ properties: | ||||||
|       If not present the device is not reset during the probe. |       If not present the device is not reset during the probe. | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|  |   honeywell,transfer-function: | ||||||
|  |     description: | | ||||||
|  |       Transfer function which defines the range of valid values delivered by the | ||||||
|  |       sensor. | ||||||
|  |       1 - A, 10% to 90% of 2^24 (1677722 .. 15099494) | ||||||
|  |       2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874) | ||||||
|  |       3 - C, 20% to 80% of 2^24 (3355443 .. 13421773) | ||||||
|  |     enum: [1, 2, 3] | ||||||
|  |     $ref: /schemas/types.yaml#/definitions/uint32 | ||||||
|  | 
 | ||||||
|  |   honeywell,pressure-triplet: | ||||||
|  |     description: | | ||||||
|  |       Case-sensitive five character string that defines pressure range, unit | ||||||
|  |       and type as part of the device nomenclature. In the unlikely case of a | ||||||
|  |       custom chip, unset and provide pmin-pascal and pmax-pascal instead. | ||||||
|  |     enum: [0001BA, 01.6BA, 02.5BA, 0060MG, 0100MG, 0160MG, 0250MG, 0400MG, | ||||||
|  |            0600MG, 0001BG, 01.6BG, 02.5BG, 0100KA, 0160KA, 0250KA, 0006KG, | ||||||
|  |            0010KG, 0016KG, 0025KG, 0040KG, 0060KG, 0100KG, 0160KG, 0250KG, | ||||||
|  |            0015PA, 0025PA, 0030PA, 0001PG, 0005PG, 0015PG, 0030PG, 0300YG] | ||||||
|  |     $ref: /schemas/types.yaml#/definitions/string | ||||||
|  | 
 | ||||||
|   honeywell,pmin-pascal: |   honeywell,pmin-pascal: | ||||||
|     description: |     description: | ||||||
|       Minimum pressure value the sensor can measure in pascal. |       Minimum pressure value the sensor can measure in pascal. | ||||||
|  | @ -58,14 +86,8 @@ properties: | ||||||
|     description: |     description: | ||||||
|       Maximum pressure value the sensor can measure in pascal. |       Maximum pressure value the sensor can measure in pascal. | ||||||
| 
 | 
 | ||||||
|   honeywell,transfer-function: |   spi-max-frequency: | ||||||
|     description: | |     maximum: 800000 | ||||||
|       Transfer function which defines the range of valid values delivered by the |  | ||||||
|       sensor. |  | ||||||
|       1 - A, 10% to 90% of 2^24 (1677722 .. 15099494) |  | ||||||
|       2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874) |  | ||||||
|       3 - C, 20% to 80% of 2^24 (3355443 .. 13421773) |  | ||||||
|     $ref: /schemas/types.yaml#/definitions/uint32 |  | ||||||
| 
 | 
 | ||||||
|   vdd-supply: |   vdd-supply: | ||||||
|     description: provide VDD power to the sensor. |     description: provide VDD power to the sensor. | ||||||
|  | @ -73,11 +95,26 @@ properties: | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - reg |   - reg | ||||||
|   - honeywell,pmin-pascal |  | ||||||
|   - honeywell,pmax-pascal |  | ||||||
|   - honeywell,transfer-function |   - honeywell,transfer-function | ||||||
|   - vdd-supply |   - vdd-supply | ||||||
| 
 | 
 | ||||||
|  | oneOf: | ||||||
|  |   - required: | ||||||
|  |       - honeywell,pressure-triplet | ||||||
|  |   - required: | ||||||
|  |       - honeywell,pmin-pascal | ||||||
|  |       - honeywell,pmax-pascal | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: /schemas/spi/spi-peripheral-props.yaml | ||||||
|  |   - if: | ||||||
|  |       required: | ||||||
|  |         - honeywell,pressure-triplet | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         honeywell,pmin-pascal: false | ||||||
|  |         honeywell,pmax-pascal: false | ||||||
|  | 
 | ||||||
| additionalProperties: false | additionalProperties: false | ||||||
| 
 | 
 | ||||||
| examples: | examples: | ||||||
|  | @ -93,10 +130,29 @@ examples: | ||||||
|             reg = <0x18>; |             reg = <0x18>; | ||||||
|             reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; |             reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; | ||||||
|             interrupt-parent = <&gpio3>; |             interrupt-parent = <&gpio3>; | ||||||
|             interrupts = <21 IRQ_TYPE_EDGE_FALLING>; |             interrupts = <21 IRQ_TYPE_EDGE_RISING>; | ||||||
|             honeywell,pmin-pascal = <0>; | 
 | ||||||
|             honeywell,pmax-pascal = <172369>; |             honeywell,pressure-triplet = "0025PA"; | ||||||
|             honeywell,transfer-function = <1>; |             honeywell,transfer-function = <1>; | ||||||
|             vdd-supply = <&vcc_3v3>; |             vdd-supply = <&vcc_3v3>; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|  |   - | | ||||||
|  |     spi { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         pressure@0 { | ||||||
|  |             compatible = "honeywell,mprls0025pa"; | ||||||
|  |             reg = <0>; | ||||||
|  |             spi-max-frequency = <800000>; | ||||||
|  |             reset-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; | ||||||
|  |             interrupt-parent = <&gpio0>; | ||||||
|  |             interrupts = <30 IRQ_TYPE_EDGE_RISING>; | ||||||
|  | 
 | ||||||
|  |             honeywell,pressure-triplet = "0015PA"; | ||||||
|  |             honeywell,transfer-function = <1>; | ||||||
|  |             vdd-supply = <&vcc_3v3>; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
|  |  | ||||||
|  | @ -24,9 +24,16 @@ properties: | ||||||
|   reg: |   reg: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| 
 | 
 | ||||||
|  |   vcc-supply: | ||||||
|  |     description: provide VCC power to the sensor. | ||||||
|  | 
 | ||||||
|  |   label: | ||||||
|  |     description: Unique name to identify which device this is. | ||||||
|  | 
 | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|   - reg |   - reg | ||||||
|  |   - vcc-supply | ||||||
| 
 | 
 | ||||||
| additionalProperties: false | additionalProperties: false | ||||||
| 
 | 
 | ||||||
|  | @ -39,5 +46,6 @@ examples: | ||||||
|         tmp117@48 { |         tmp117@48 { | ||||||
|              compatible = "ti,tmp117"; |              compatible = "ti,tmp117"; | ||||||
|              reg = <0x48>; |              reg = <0x48>; | ||||||
|  |              vcc-supply = <&pmic_reg_3v3>; | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -23,6 +23,9 @@ properties: | ||||||
| 
 | 
 | ||||||
|   compatible: |   compatible: | ||||||
|     enum: |     enum: | ||||||
|  |       - qcom,msm8909-bimc | ||||||
|  |       - qcom,msm8909-pcnoc | ||||||
|  |       - qcom,msm8909-snoc | ||||||
|       - qcom,msm8916-bimc |       - qcom,msm8916-bimc | ||||||
|       - qcom,msm8916-pcnoc |       - qcom,msm8916-pcnoc | ||||||
|       - qcom,msm8916-snoc |       - qcom,msm8916-snoc | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect | ||||||
| 
 | 
 | ||||||
| maintainers: | maintainers: | ||||||
|   - Georgi Djakov <georgi.djakov@linaro.org> |   - Georgi Djakov <georgi.djakov@linaro.org> | ||||||
|   - Odelu Kukatla <okukatla@codeaurora.org> |   - Odelu Kukatla <quic_okukatla@quicinc.com> | ||||||
| 
 | 
 | ||||||
| description: | | description: | | ||||||
|    RPMh interconnect providers support system bandwidth requirements through |    RPMh interconnect providers support system bandwidth requirements through | ||||||
|  |  | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/interconnect/qcom,sm7150-rpmh.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm RPMh Network-On-Chip Interconnect on SM7150 | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Danila Tikhonov <danila@jiaxyga.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   RPMh interconnect providers support system bandwidth requirements through | ||||||
|  |   RPMh hardware accelerators known as Bus Clock Manager (BCM). | ||||||
|  | 
 | ||||||
|  |   See also:: include/dt-bindings/interconnect/qcom,sm7150-rpmh.h | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: qcom,rpmh-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - qcom,sm7150-aggre1-noc | ||||||
|  |       - qcom,sm7150-aggre2-noc | ||||||
|  |       - qcom,sm7150-compute-noc | ||||||
|  |       - qcom,sm7150-config-noc | ||||||
|  |       - qcom,sm7150-dc-noc | ||||||
|  |       - qcom,sm7150-gem-noc | ||||||
|  |       - qcom,sm7150-mc-virt | ||||||
|  |       - qcom,sm7150-mmss-noc | ||||||
|  |       - qcom,sm7150-system-noc | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  | # Child node's properties | ||||||
|  | patternProperties: | ||||||
|  |   '^interconnect-[0-9]+$': | ||||||
|  |     type: object | ||||||
|  |     description: | ||||||
|  |       The interconnect providers do not have a separate QoS register space, | ||||||
|  |       but share parent's space. | ||||||
|  | 
 | ||||||
|  |     allOf: | ||||||
|  |       - $ref: qcom,rpmh-common.yaml# | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       compatible: | ||||||
|  |         enum: | ||||||
|  |           - qcom,sm7150-camnoc-virt | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - compatible | ||||||
|  | 
 | ||||||
|  |     unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     mc_virt: interconnect@1380000 { | ||||||
|  |         compatible = "qcom,sm7150-mc-virt"; | ||||||
|  |         reg = <0x01380000 0x40000>; | ||||||
|  |         #interconnect-cells = <2>; | ||||||
|  |         qcom,bcm-voters = <&apps_bcm_voter>; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     system_noc: interconnect@1620000 { | ||||||
|  |         compatible = "qcom,sm7150-system-noc"; | ||||||
|  |         reg = <0x01620000 0x40000>; | ||||||
|  |         #interconnect-cells = <2>; | ||||||
|  |         qcom,bcm-voters = <&apps_bcm_voter>; | ||||||
|  | 
 | ||||||
|  |         camnoc_virt: interconnect-0 { | ||||||
|  |             compatible = "qcom,sm7150-camnoc-virt"; | ||||||
|  |             #interconnect-cells = <2>; | ||||||
|  |             qcom,bcm-voters = <&apps_bcm_voter>; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | @ -36,20 +36,18 @@ properties: | ||||||
| 
 | 
 | ||||||
| allOf: | allOf: | ||||||
|   - if: |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: mac-base | ||||||
|       required: [ compatible ] |       required: [ compatible ] | ||||||
|     then: |     then: | ||||||
|       if: |       properties: | ||||||
|         properties: |         "#nvmem-cell-cells": | ||||||
|           compatible: |           description: The first argument is a MAC address offset. | ||||||
|             contains: |           const: 1 | ||||||
|               const: mac-base |       required: | ||||||
|       then: |         - "#nvmem-cell-cells" | ||||||
|         properties: |  | ||||||
|           "#nvmem-cell-cells": |  | ||||||
|             description: The first argument is a MAC address offset. |  | ||||||
|             const: 1 |  | ||||||
|         required: |  | ||||||
|           - "#nvmem-cell-cells" |  | ||||||
| 
 | 
 | ||||||
| required: | required: | ||||||
|   - reg |   - reg | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								Documentation/devicetree/bindings/nvmem/nvmem-provider.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Documentation/devicetree/bindings/nvmem/nvmem-provider.yaml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/nvmem/nvmem-provider.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/base.yaml# | ||||||
|  | 
 | ||||||
|  | title: NVMEM (Non Volatile Memory) Provider | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | ||||||
|  | 
 | ||||||
|  | select: true | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   '#nvmem-cell-cells': | ||||||
|  |     enum: [0, 1] | ||||||
|  | 
 | ||||||
|  | additionalProperties: true | ||||||
|  | @ -1,46 +0,0 @@ | ||||||
| -------------------------------------------------------------------------- |  | ||||||
| =  Zynq UltraScale+ MPSoC nvmem firmware driver binding = |  | ||||||
| -------------------------------------------------------------------------- |  | ||||||
| The nvmem_firmware node provides access to the hardware related data |  | ||||||
| like soc revision, IDCODE... etc, By using the firmware interface. |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| - compatible: should be "xlnx,zynqmp-nvmem-fw" |  | ||||||
| 
 |  | ||||||
| = Data cells = |  | ||||||
| Are child nodes of silicon id, bindings of which as described in |  | ||||||
| bindings/nvmem/nvmem.txt |  | ||||||
| 
 |  | ||||||
| ------- |  | ||||||
|  Example |  | ||||||
| ------- |  | ||||||
| firmware { |  | ||||||
| 	zynqmp_firmware: zynqmp-firmware { |  | ||||||
| 		compatible = "xlnx,zynqmp-firmware"; |  | ||||||
| 		method = "smc"; |  | ||||||
| 
 |  | ||||||
| 		nvmem_firmware { |  | ||||||
| 			compatible = "xlnx,zynqmp-nvmem-fw"; |  | ||||||
| 			#address-cells = <1>; |  | ||||||
| 			#size-cells = <1>; |  | ||||||
| 
 |  | ||||||
| 			/* Data cells */ |  | ||||||
| 			soc_revision: soc_revision { |  | ||||||
| 				reg = <0x0 0x4>; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| = Data consumers = |  | ||||||
| Are device nodes which consume nvmem data cells. |  | ||||||
| 
 |  | ||||||
| For example: |  | ||||||
| 	pcap { |  | ||||||
| 		... |  | ||||||
| 
 |  | ||||||
| 		nvmem-cells = <&soc_revision>; |  | ||||||
| 		nvmem-cell-names = "soc_revision"; |  | ||||||
| 
 |  | ||||||
| 		... |  | ||||||
| 	}; |  | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/nvmem/xlnx,zynqmp-nvmem.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Zynq UltraScale+ MPSoC Non Volatile Memory interface | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |     The ZynqMP MPSoC provides access to the hardware related data | ||||||
|  |     like SOC revision, IDCODE and specific purpose efuses. | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Kalyani Akula <kalyani.akula@amd.com> | ||||||
|  |   - Praveen Teja Kundanala <praveen.teja.kundanala@amd.com> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: nvmem.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     const: xlnx,zynqmp-nvmem-fw | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     nvmem { | ||||||
|  |         compatible = "xlnx,zynqmp-nvmem-fw"; | ||||||
|  |         nvmem-layout { | ||||||
|  |             compatible = "fixed-layout"; | ||||||
|  |             #address-cells = <1>; | ||||||
|  |             #size-cells = <1>; | ||||||
|  | 
 | ||||||
|  |             soc_revision: soc-revision@0 { | ||||||
|  |                 reg = <0x0 0x4>; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | @ -1573,6 +1573,8 @@ patternProperties: | ||||||
|     description: VoCore Studio |     description: VoCore Studio | ||||||
|   "^voipac,.*": |   "^voipac,.*": | ||||||
|     description: Voipac Technologies s.r.o. |     description: Voipac Technologies s.r.o. | ||||||
|  |   "^voltafield,.*": | ||||||
|  |     description: Voltafield Technology Corp. | ||||||
|   "^vot,.*": |   "^vot,.*": | ||||||
|     description: Vision Optical Technology Co., Ltd. |     description: Vision Optical Technology Co., Ltd. | ||||||
|   "^vscom,.*": |   "^vscom,.*": | ||||||
|  |  | ||||||
							
								
								
									
										407
									
								
								Documentation/iio/adis16475.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								Documentation/iio/adis16475.rst
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,407 @@ | ||||||
|  | .. SPDX-License-Identifier: GPL-2.0 | ||||||
|  | 
 | ||||||
|  | ================ | ||||||
|  | ADIS16475 driver | ||||||
|  | ================ | ||||||
|  | 
 | ||||||
|  | This driver supports Analog Device's IMUs on SPI bus. | ||||||
|  | 
 | ||||||
|  | 1. Supported devices | ||||||
|  | ==================== | ||||||
|  | 
 | ||||||
|  | * `ADIS16465 <https://www.analog.com/ADIS16465>`_ | ||||||
|  | * `ADIS16467 <https://www.analog.com/ADIS16467>`_ | ||||||
|  | * `ADIS16470 <https://www.analog.com/ADIS16470>`_ | ||||||
|  | * `ADIS16475 <https://www.analog.com/ADIS16475>`_ | ||||||
|  | * `ADIS16477 <https://www.analog.com/ADIS16477>`_ | ||||||
|  | * `ADIS16500 <https://www.analog.com/ADIS16500>`_ | ||||||
|  | * `ADIS16505 <https://www.analog.com/ADIS16505>`_ | ||||||
|  | * `ADIS16507 <https://www.analog.com/ADIS16507>`_ | ||||||
|  | 
 | ||||||
|  | Each supported device is a precision, miniature microelectromechanical system | ||||||
|  | (MEMS) inertial measurement unit (IMU) that includes a triaxial gyroscope and a | ||||||
|  | triaxial accelerometer. Each inertial sensor in the IMU device combines with | ||||||
|  | signal conditioning that optimizes dynamic performance. The factory calibration | ||||||
|  | characterizes each sensor for sensitivity, bias, alignment, linear acceleration | ||||||
|  | (gyroscope bias), and point of percussion (accelerometer location). As a result, | ||||||
|  | each sensor has dynamic compensation formulas that provide accurate sensor | ||||||
|  | measurements over a broad set of conditions. | ||||||
|  | 
 | ||||||
|  | 2. Device attributes | ||||||
|  | ==================== | ||||||
|  | 
 | ||||||
|  | Accelerometer, gyroscope measurements are always provided. Furthermore, the | ||||||
|  | driver offers the capability to retrieve the delta angle and the delta velocity | ||||||
|  | measurements computed by the device. | ||||||
|  | 
 | ||||||
|  | The delta angle measurements represent a calculation of angular displacement | ||||||
|  | between each sample update, while the delta velocity measurements represent a | ||||||
|  | calculation of linear velocity change between each sample update. | ||||||
|  | 
 | ||||||
|  | Finally, temperature data are provided which show a coarse measurement of | ||||||
|  | the temperature inside of the IMU device. This data is most useful for | ||||||
|  | monitoring relative changes in the thermal environment. | ||||||
|  | 
 | ||||||
|  | The signal chain of each inertial sensor (accelerometers and gyroscopes) | ||||||
|  | includes the application of unique correction formulas, which are derived from | ||||||
|  | extensive characterization of bias, sensitivity, alignment, response to linear | ||||||
|  | acceleration (gyroscopes), and point of percussion (accelerometer location) | ||||||
|  | over a temperature range of −40°C to +85°C, for each ADIS device. These | ||||||
|  | correction formulas are not accessible, but users do have the opportunity to | ||||||
|  | adjust the bias for each sensor individually through the calibbias attribute. | ||||||
|  | 
 | ||||||
|  | Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``, | ||||||
|  | where X is the IIO index of the device. Under these folders reside a set of | ||||||
|  | device files, depending on the characteristics and features of the hardware | ||||||
|  | device in questions. These files are consistently generalized and documented in | ||||||
|  | the IIO ABI documentation. | ||||||
|  | 
 | ||||||
|  | The following tables show the adis16475 related device files, found in the | ||||||
|  | specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. | ||||||
|  | 
 | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | 3-Axis Accelerometer related device files | Description                                              | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_scale                            | Scale for the accelerometer channels.                    | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_x_calibbias                      | Calibration offset for the X-axis accelerometer channel. | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_calibbias_x                      | x-axis acceleration offset correction                    | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_x_raw                            | Raw X-axis accelerometer channel value.                  | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_calibbias_y                      | y-axis acceleration offset correction                    | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_y_raw                            | Raw Y-axis accelerometer channel value.                  | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_z_calibbias                      | Calibration offset for the Z-axis accelerometer channel. | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_accel_z_raw                            | Raw Z-axis accelerometer channel value.                  | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_deltavelocity_scale                    | Scale for delta velocity channels.                       | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_deltavelocity_x_raw                    | Raw X-axis delta velocity channel value.                 | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_deltavelocity_y_raw                    | Raw Y-axis delta velocity channel value.                 | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | | in_deltavelocity_z_raw                    | Raw Z-axis delta velocity channel value.                 | | ||||||
|  | +-------------------------------------------+----------------------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | 3-Axis Gyroscope related device files | Description                                          | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_scale                      | Scale for the gyroscope channels.                    | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_x_calibbias                | Calibration offset for the X-axis gyroscope channel. | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_calibbias_x                | x-axis gyroscope offset correction                   | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_x_raw                      | Raw X-axis gyroscope channel value.                  | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_calibbias_y                | y-axis gyroscope offset correction                   | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_y_raw                      | Raw Y-axis gyroscope channel value.                  | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_z_calibbias                | Calibration offset for the Z-axis gyroscope channel. | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_anglvel_z_raw                      | Raw Z-axis gyroscope channel value.                  | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_deltaangl_scale                    | Scale for delta angle channels.                      | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_deltaangl_x_raw                    | Raw X-axis delta angle channel value.                | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_deltaangl_y_raw                    | Raw Y-axis delta angle channel value.                | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | | in_deltaangl_z_raw                    | Raw Z-axis delta angle channel value.                | | ||||||
|  | +---------------------------------------+------------------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | +----------------------------------+-------------------------------------------+ | ||||||
|  | | Temperature sensor related files | Description                               | | ||||||
|  | +----------------------------------+-------------------------------------------+ | ||||||
|  | | in_temp0_raw                     | Raw temperature channel value.            | | ||||||
|  | +----------------------------------+-------------------------------------------+ | ||||||
|  | | in_temp0_scale                   | Scale for the temperature sensor channel. | | ||||||
|  | +----------------------------------+-------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | +-------------------------------+---------------------------------------------------------+ | ||||||
|  | | Miscellaneous device files    | Description                                             | | ||||||
|  | +-------------------------------+---------------------------------------------------------+ | ||||||
|  | | name                          | Name of the IIO device.                                 | | ||||||
|  | +-------------------------------+---------------------------------------------------------+ | ||||||
|  | | sampling_frequency            | Currently selected sample rate.                         | | ||||||
|  | +-------------------------------+---------------------------------------------------------+ | ||||||
|  | | filter_low_pass_3db_frequency | Bandwidth for the accelerometer and gyroscope channels. | | ||||||
|  | +-------------------------------+---------------------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | The following table shows the adis16475 related device debug files, found in the | ||||||
|  | specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``. | ||||||
|  | 
 | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | Debugfs device files | Description                                                             | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | serial_number        | The serial number of the chip in hexadecimal format.                    | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | product_id           | Chip specific product id (e.g. 16475, 16500, 16505, etc.).              | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | flash_count          | The number of flash writes performed on the device.                     | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | firmware_revision    | String containing the firmware revision in the following format ##.##.  | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | | firmware_date        | String containing the firmware date in the following format mm-dd-yyyy. | | ||||||
|  | +----------------------+-------------------------------------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | Channels processed values | ||||||
|  | ------------------------- | ||||||
|  | 
 | ||||||
|  | A channel value can be read from its _raw attribute. The value returned is the | ||||||
|  | raw value as reported by the devices. To get the processed value of the channel, | ||||||
|  | apply the following formula: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         processed value = (_raw + _offset) * _scale | ||||||
|  | 
 | ||||||
|  | Where _offset and _scale are device attributes. If no _offset attribute is | ||||||
|  | present, simply assume its value is 0. | ||||||
|  | 
 | ||||||
|  | The adis16475 driver offers data for 5 types of channels, the table below shows | ||||||
|  | the measurement units for the processed value, which are defined by the IIO | ||||||
|  | framework: | ||||||
|  | 
 | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Channel type                        | Measurement unit          | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Acceleration on X, Y, and Z axis    | Meters per Second squared | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Angular velocity on X, Y and Z axis | Radians per second        | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Delta velocity on X. Y, and Z axis  | Meters per Second         | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Delta angle on X, Y, and Z axis     | Radians                   | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | | Temperature                         | Millidegrees Celsius      | | ||||||
|  | +-------------------------------------+---------------------------+ | ||||||
|  | 
 | ||||||
|  | Usage examples | ||||||
|  | -------------- | ||||||
|  | 
 | ||||||
|  | Show device name: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  | 	root:/sys/bus/iio/devices/iio:device0> cat name | ||||||
|  |         adis16505-2 | ||||||
|  | 
 | ||||||
|  | Show accelerometer channels value: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw | ||||||
|  |         -275924 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw | ||||||
|  |         -30142222 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw | ||||||
|  |         261265769 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale | ||||||
|  |         0.000000037 | ||||||
|  | 
 | ||||||
|  | - X-axis acceleration = in_accel_x_raw * in_accel_scale = −0.010209188 m/s^2 | ||||||
|  | - Y-axis acceleration = in_accel_y_raw * in_accel_scale = −1.115262214 m/s^2 | ||||||
|  | - Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.666833453 m/s^2 | ||||||
|  | 
 | ||||||
|  | Show gyroscope channels value: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw | ||||||
|  |         -3324626 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw | ||||||
|  |         1336980 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw | ||||||
|  |         -602983 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale | ||||||
|  |         0.000000006 | ||||||
|  | 
 | ||||||
|  | - X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.019947756 rad/s | ||||||
|  | - Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = 0.00802188 rad/s | ||||||
|  | - Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = −0.003617898 rad/s | ||||||
|  | 
 | ||||||
|  | Set calibration offset for accelerometer channels: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias | ||||||
|  |         0 | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias | ||||||
|  |         5000 | ||||||
|  | 
 | ||||||
|  | Set calibration offset for gyroscope channels: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias | ||||||
|  |         0 | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias | ||||||
|  |         -5000 | ||||||
|  | 
 | ||||||
|  | Set sampling frequency: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  | 	root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency | ||||||
|  |         2000.000000 | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency | ||||||
|  |         1000.000000 | ||||||
|  | 
 | ||||||
|  | Set bandwidth for accelerometer and gyroscope: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency | ||||||
|  |         720 | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 360 > filter_low_pass_3db_frequency | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency | ||||||
|  |         360 | ||||||
|  | 
 | ||||||
|  | Show serial number: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/kernel/debug/iio/iio:device0> cat serial_number | ||||||
|  |         0x04f9 | ||||||
|  | 
 | ||||||
|  | Show product id: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/kernel/debug/iio/iio:device0> cat product_id | ||||||
|  |         16505 | ||||||
|  | 
 | ||||||
|  | Show flash count: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/kernel/debug/iio/iio:device0> cat flash_count | ||||||
|  |         150 | ||||||
|  | 
 | ||||||
|  | Show firmware revision: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision | ||||||
|  |         1.6 | ||||||
|  | 
 | ||||||
|  | Show firmware date: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/kernel/debug/iio/iio:device0> cat firmware_date | ||||||
|  |         06-27-2019 | ||||||
|  | 
 | ||||||
|  | 3. Device buffers | ||||||
|  | ================= | ||||||
|  | 
 | ||||||
|  | This driver supports IIO buffers. | ||||||
|  | 
 | ||||||
|  | All devices support retrieving the raw acceleration, gyroscope and temperature | ||||||
|  | measurements using buffers. | ||||||
|  | 
 | ||||||
|  | The following device families also support retrieving the delta velocity, delta | ||||||
|  | angle and temperature measurements using buffers: | ||||||
|  | 
 | ||||||
|  | - ADIS16477 | ||||||
|  | - ADIS16500 | ||||||
|  | - ADIS16505 | ||||||
|  | - ADIS16507 | ||||||
|  | 
 | ||||||
|  | However, when retrieving acceleration or gyroscope data using buffers, delta | ||||||
|  | readings will not be available and vice versa. | ||||||
|  | 
 | ||||||
|  | Usage examples | ||||||
|  | -------------- | ||||||
|  | 
 | ||||||
|  | Set device trigger in current_trigger, if not already set: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo adis16505-2-dev0 > trigger/current_trigger | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger | ||||||
|  |         adis16505-2-dev0 | ||||||
|  | 
 | ||||||
|  | Select channels for buffer read: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en | ||||||
|  | 
 | ||||||
|  | Set the number of samples to be stored in the buffer: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length | ||||||
|  | 
 | ||||||
|  | Enable buffer readings: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable | ||||||
|  | 
 | ||||||
|  | Obtain buffered data: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0 | ||||||
|  |         ... | ||||||
|  |         00001680  01 1f 00 00 ff ff fe ef  00 00 47 bf 00 03 35 55  |..........G...5U| | ||||||
|  |         00001690  01 1f 00 00 ff ff ff d9  00 00 46 f1 00 03 35 35  |..........F...55| | ||||||
|  |         000016a0  01 1f 00 00 ff ff fe fc  00 00 46 cb 00 03 35 7b  |..........F...5{| | ||||||
|  |         000016b0  01 1f 00 00 ff ff fe 41  00 00 47 0d 00 03 35 8b  |.......A..G...5.| | ||||||
|  |         000016c0  01 1f 00 00 ff ff fe 37  00 00 46 b4 00 03 35 90  |.......7..F...5.| | ||||||
|  |         000016d0  01 1d 00 00 ff ff fe 5a  00 00 45 d7 00 03 36 08  |.......Z..E...6.| | ||||||
|  |         000016e0  01 1b 00 00 ff ff fe fb  00 00 45 e7 00 03 36 60  |..........E...6`| | ||||||
|  |         000016f0  01 1a 00 00 ff ff ff 17  00 00 46 bc 00 03 36 de  |..........F...6.| | ||||||
|  |         00001700  01 1a 00 00 ff ff fe 59  00 00 46 d7 00 03 37 b8  |.......Y..F...7.| | ||||||
|  |         00001710  01 1a 00 00 ff ff fe ae  00 00 46 95 00 03 37 ba  |..........F...7.| | ||||||
|  |         00001720  01 1a 00 00 ff ff fe c5  00 00 46 63 00 03 37 9f  |..........Fc..7.| | ||||||
|  |         00001730  01 1a 00 00 ff ff fe 55  00 00 46 89 00 03 37 c1  |.......U..F...7.| | ||||||
|  |         00001740  01 1a 00 00 ff ff fe 31  00 00 46 aa 00 03 37 f7  |.......1..F...7.| | ||||||
|  |         ... | ||||||
|  | 
 | ||||||
|  | See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered | ||||||
|  | data is structured. | ||||||
|  | 
 | ||||||
|  | 4. IIO Interfacing Tools | ||||||
|  | ======================== | ||||||
|  | 
 | ||||||
|  | Linux Kernel Tools | ||||||
|  | ------------------ | ||||||
|  | 
 | ||||||
|  | Linux Kernel provides some userspace tools that can be used to retrieve data | ||||||
|  | from IIO sysfs: | ||||||
|  | 
 | ||||||
|  | * lsiio: example application that provides a list of IIO devices and triggers | ||||||
|  | * iio_event_monitor: example application that reads events from an IIO device | ||||||
|  |   and prints them | ||||||
|  | * iio_generic_buffer: example application that reads data from buffer | ||||||
|  | * iio_utils: set of APIs, typically used to access sysfs files. | ||||||
|  | 
 | ||||||
|  | LibIIO | ||||||
|  | ------ | ||||||
|  | 
 | ||||||
|  | LibIIO is a C/C++ library that provides generic access to IIO devices. The | ||||||
|  | library abstracts the low-level details of the hardware, and provides a simple | ||||||
|  | yet complete programming interface that can be used for advanced projects. | ||||||
|  | 
 | ||||||
|  | For more information about LibIIO, please see: | ||||||
|  | https://github.com/analogdevicesinc/libiio | ||||||
							
								
								
									
										152
									
								
								Documentation/iio/iio_devbuf.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								Documentation/iio/iio_devbuf.rst
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,152 @@ | ||||||
|  | .. SPDX-License-Identifier: GPL-2.0 | ||||||
|  | 
 | ||||||
|  | ============================= | ||||||
|  | Industrial IIO device buffers | ||||||
|  | ============================= | ||||||
|  | 
 | ||||||
|  | 1. Overview | ||||||
|  | =========== | ||||||
|  | 
 | ||||||
|  | The Industrial I/O core offers a way for continuous data capture based on a | ||||||
|  | trigger source. Multiple data channels can be read at once from | ||||||
|  | ``/dev/iio:deviceX`` character device node, thus reducing the CPU load. | ||||||
|  | 
 | ||||||
|  | Devices with buffer support feature an additional sub-directory in the | ||||||
|  | ``/sys/bus/iio/devices/iio:deviceX/`` directory hierarchy, called bufferY, where | ||||||
|  | Y defaults to 0, for devices with a single buffer. | ||||||
|  | 
 | ||||||
|  | 2. Buffer attributes | ||||||
|  | ==================== | ||||||
|  | 
 | ||||||
|  | An IIO buffer has an associated attributes directory under | ||||||
|  | ``/sys/bus/iio/iio:deviceX/bufferY/``. The attributes are described below. | ||||||
|  | 
 | ||||||
|  | ``length`` | ||||||
|  | ---------- | ||||||
|  | 
 | ||||||
|  | Read / Write attribute which states the total number of data samples (capacity) | ||||||
|  | that can be stored by the buffer. | ||||||
|  | 
 | ||||||
|  | ``enable`` | ||||||
|  | ---------- | ||||||
|  | 
 | ||||||
|  | Read / Write attribute which starts / stops the buffer capture. This file should | ||||||
|  | be written last, after length and selection of scan elements. Writing a non-zero | ||||||
|  | value may result in an error, such as EINVAL, if, for example, an unsupported | ||||||
|  | combination of channels is given. | ||||||
|  | 
 | ||||||
|  | ``watermark`` | ||||||
|  | ------------- | ||||||
|  | 
 | ||||||
|  | Read / Write positive integer attribute specifying the maximum number of scan | ||||||
|  | elements to wait for. | ||||||
|  | 
 | ||||||
|  | Poll will block until the watermark is reached. | ||||||
|  | 
 | ||||||
|  | Blocking read will wait until the minimum between the requested read amount or | ||||||
|  | the low watermark is available. | ||||||
|  | 
 | ||||||
|  | Non-blocking read will retrieve the available samples from the buffer even if | ||||||
|  | there are less samples than the watermark level. This allows the application to | ||||||
|  | block on poll with a timeout and read the available samples after the timeout | ||||||
|  | expires and thus have a maximum delay guarantee. | ||||||
|  | 
 | ||||||
|  | Data available | ||||||
|  | -------------- | ||||||
|  | 
 | ||||||
|  | Read-only attribute indicating the bytes of data available in the buffer. In the | ||||||
|  | case of an output buffer, this indicates the amount of empty space available to | ||||||
|  | write data to. In the case of an input buffer, this indicates the amount of data | ||||||
|  | available for reading. | ||||||
|  | 
 | ||||||
|  | Scan elements | ||||||
|  | ------------- | ||||||
|  | 
 | ||||||
|  | The meta information associated with a channel data placed in a buffer is called | ||||||
|  | a scan element. The scan elements attributes are presented below. | ||||||
|  | 
 | ||||||
|  | **_en** | ||||||
|  | 
 | ||||||
|  | Read / Write attribute used for enabling a channel. If and only if its value | ||||||
|  | is non-zero, then a triggered capture will contain data samples for this | ||||||
|  | channel. | ||||||
|  | 
 | ||||||
|  | **_index** | ||||||
|  | 
 | ||||||
|  | Read-only unsigned integer attribute specifying the position of the channel in | ||||||
|  | the buffer. Note these are not dependent on what is enabled and may not be | ||||||
|  | contiguous. Thus for userspace to establish the full layout these must be used | ||||||
|  | in conjunction with all _en attributes to establish which channels are present, | ||||||
|  | and the relevant _type attributes to establish the data storage format. | ||||||
|  | 
 | ||||||
|  | **_type** | ||||||
|  | 
 | ||||||
|  | Read-only attribute containing the description of the scan element data storage | ||||||
|  | within the buffer and hence the form in which it is read from userspace. Format | ||||||
|  | is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift], where: | ||||||
|  | 
 | ||||||
|  | - **be** or **le** specifies big or little-endian. | ||||||
|  | - **s** or **u** specifies if signed (2's complement) or unsigned. | ||||||
|  | - **bits** is the number of valid data bits. | ||||||
|  | - **storagebits** is the number of bits (after padding) that it occupies in the | ||||||
|  |   buffer. | ||||||
|  | - **repeat** specifies the number of bits/storagebits repetitions. When the | ||||||
|  |   repeat element is 0 or 1, then the repeat value is omitted. | ||||||
|  | - **shift** if specified, is the shift that needs to be applied prior to | ||||||
|  |   masking out unused bits. | ||||||
|  | 
 | ||||||
|  | For example, a driver for a 3-axis accelerometer with 12-bit resolution where | ||||||
|  | data is stored in two 8-bit registers is as follows:: | ||||||
|  | 
 | ||||||
|  |           7   6   5   4   3   2   1   0 | ||||||
|  |         +---+---+---+---+---+---+---+---+ | ||||||
|  |         |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) | ||||||
|  |         +---+---+---+---+---+---+---+---+ | ||||||
|  | 
 | ||||||
|  |           7   6   5   4   3   2   1   0 | ||||||
|  |         +---+---+---+---+---+---+---+---+ | ||||||
|  |         |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) | ||||||
|  |         +---+---+---+---+---+---+---+---+ | ||||||
|  | 
 | ||||||
|  | will have the following scan element type for each axis: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |         $ cat /sys/bus/iio/devices/iio:device0/buffer0/in_accel_y_type | ||||||
|  |         le:s12/16>>4 | ||||||
|  | 
 | ||||||
|  | A userspace application will interpret data samples read from the buffer as | ||||||
|  | two-byte little-endian signed data, that needs a 4 bits right shift before | ||||||
|  | masking out the 12 valid bits of data. | ||||||
|  | 
 | ||||||
|  | It is also worth mentioning that the data in the buffer will be naturally | ||||||
|  | aligned, so the userspace application has to handle the buffers accordingly. | ||||||
|  | 
 | ||||||
|  | Take for example, a driver with four channels with the following description: | ||||||
|  | - channel0: index: 0, type: be:u16/16>>0 | ||||||
|  | - channel1: index: 1, type: be:u32/32>>0 | ||||||
|  | - channel2: index: 2, type: be:u32/32>>0 | ||||||
|  | - channel3: index: 3, type: be:u64/64>>0 | ||||||
|  | 
 | ||||||
|  | If all channels are enabled, the data will be aligned in the buffer as follows:: | ||||||
|  | 
 | ||||||
|  |           0-1   2   3   4-7  8-11  12  13  14  15  16-23   -> buffer byte number | ||||||
|  |         +-----+---+---+-----+-----+---+---+---+---+-----+ | ||||||
|  |         |CHN_0|PAD|PAD|CHN_1|CHN_2|PAD|PAD|PAD|PAD|CHN_3|  -> buffer content | ||||||
|  |         +-----+---+---+-----+-----+---+---+---+---+-----+ | ||||||
|  | 
 | ||||||
|  | If only channel0 and channel3 are enabled, the data will be aligned in the | ||||||
|  | buffer as follows:: | ||||||
|  | 
 | ||||||
|  |           0-1   2   3   4   5   6   7  8-15    -> buffer byte number | ||||||
|  |         +-----+---+---+---+---+---+---+-----+ | ||||||
|  |         |CHN_0|PAD|PAD|PAD|PAD|PAD|PAD|CHN_3|  -> buffer content | ||||||
|  |         +-----+---+---+---+---+---+---+-----+ | ||||||
|  | 
 | ||||||
|  | Typically the buffered data is found in raw format (unscaled with no offset | ||||||
|  | applied), however there are corner cases in which the buffered data may be found | ||||||
|  | in a processed form. Please note that these corner cases are not addressed by | ||||||
|  | this documentation. | ||||||
|  | 
 | ||||||
|  | Please see ``Documentation/ABI/testing/sysfs-bus-iio`` for a complete | ||||||
|  | description of the attributes. | ||||||
|  | @ -8,7 +8,14 @@ Industrial I/O | ||||||
|    :maxdepth: 1 |    :maxdepth: 1 | ||||||
| 
 | 
 | ||||||
|    iio_configfs |    iio_configfs | ||||||
|  |    iio_devbuf | ||||||
| 
 | 
 | ||||||
|    ep93xx_adc | Industrial I/O Kernel Drivers | ||||||
|  | ============================= | ||||||
| 
 | 
 | ||||||
|  | .. toctree:: | ||||||
|  |    :maxdepth: 1 | ||||||
|  | 
 | ||||||
|  |    adis16475 | ||||||
|    bno055 |    bno055 | ||||||
|  |    ep93xx_adc | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								MAINTAINERS
									
									
									
									
									
								
							|  | @ -579,6 +579,12 @@ F:	drivers/iio/accel/adxl372.c | ||||||
| F:	drivers/iio/accel/adxl372_i2c.c | F:	drivers/iio/accel/adxl372_i2c.c | ||||||
| F:	drivers/iio/accel/adxl372_spi.c | F:	drivers/iio/accel/adxl372_spi.c | ||||||
| 
 | 
 | ||||||
|  | AF8133J THREE-AXIS MAGNETOMETER DRIVER | ||||||
|  | M:	Ondřej Jirman <megi@xff.cz> | ||||||
|  | S:	Maintained | ||||||
|  | F:	Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml | ||||||
|  | F:	drivers/iio/magnetometer/af8133j.c | ||||||
|  | 
 | ||||||
| AF9013 MEDIA DRIVER | AF9013 MEDIA DRIVER | ||||||
| L:	linux-media@vger.kernel.org | L:	linux-media@vger.kernel.org | ||||||
| S:	Orphan | S:	Orphan | ||||||
|  | @ -1158,7 +1164,7 @@ L:	linux-iio@vger.kernel.org | ||||||
| S:	Supported | S:	Supported | ||||||
| W:	http://ez.analog.com/community/linux-device-drivers | W:	http://ez.analog.com/community/linux-device-drivers | ||||||
| F:	Documentation/devicetree/bindings/iio/adc/adi,ad7091r* | F:	Documentation/devicetree/bindings/iio/adc/adi,ad7091r* | ||||||
| F:	drivers/iio/adc/drivers/iio/adc/ad7091r* | F:	drivers/iio/adc/ad7091r* | ||||||
| 
 | 
 | ||||||
| ANALOG DEVICES INC AD7192 DRIVER | ANALOG DEVICES INC AD7192 DRIVER | ||||||
| M:	Alexandru Tachici <alexandru.tachici@analog.com> | M:	Alexandru Tachici <alexandru.tachici@analog.com> | ||||||
|  | @ -1281,6 +1287,14 @@ W:	https://ez.analog.com/linux-software-drivers | ||||||
| F:	Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml | F:	Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml | ||||||
| F:	drivers/hwmon/adm1177.c | F:	drivers/hwmon/adm1177.c | ||||||
| 
 | 
 | ||||||
|  | ANALOG DEVICES INC ADMFM2000 DRIVER | ||||||
|  | M:	Kim Seer Paller <kimseer.paller@analog.com> | ||||||
|  | L:	linux-iio@vger.kernel.org | ||||||
|  | S:	Supported | ||||||
|  | W:	https://ez.analog.com/linux-software-drivers | ||||||
|  | F:	Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml | ||||||
|  | F:	drivers/iio/frequency/admfm2000.c | ||||||
|  | 
 | ||||||
| ANALOG DEVICES INC ADMV1013 DRIVER | ANALOG DEVICES INC ADMV1013 DRIVER | ||||||
| M:	Antoniu Miclaus <antoniu.miclaus@analog.com> | M:	Antoniu Miclaus <antoniu.miclaus@analog.com> | ||||||
| L:	linux-iio@vger.kernel.org | L:	linux-iio@vger.kernel.org | ||||||
|  | @ -9509,7 +9523,7 @@ T:	git git://linuxtv.org/media_tree.git | ||||||
| F:	drivers/media/usb/hdpvr/ | F:	drivers/media/usb/hdpvr/ | ||||||
| 
 | 
 | ||||||
| HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER | HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER | ||||||
| M:	Matt Hsiao <matt.hsiao@hpe.com> | M:	Keng-Yu Lin <keng-yu.lin@hpe.com> | ||||||
| S:	Supported | S:	Supported | ||||||
| F:	drivers/misc/hpilo.[ch] | F:	drivers/misc/hpilo.[ch] | ||||||
| 
 | 
 | ||||||
|  | @ -9879,10 +9893,11 @@ F:	drivers/iio/pressure/hsc030pa* | ||||||
| 
 | 
 | ||||||
| HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER | HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER | ||||||
| M:	Andreas Klinger <ak@it-klinger.de> | M:	Andreas Klinger <ak@it-klinger.de> | ||||||
|  | M:	Petre Rodan <petre.rodan@subdimension.ro> | ||||||
| L:	linux-iio@vger.kernel.org | L:	linux-iio@vger.kernel.org | ||||||
| S:	Maintained | S:	Maintained | ||||||
| F:	Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml | F:	Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml | ||||||
| F:	drivers/iio/pressure/mprls0025pa.c | F:	drivers/iio/pressure/mprls0025pa* | ||||||
| 
 | 
 | ||||||
| HP BIOSCFG DRIVER | HP BIOSCFG DRIVER | ||||||
| M:	Jorge Lopez <jorge.lopez2@hp.com> | M:	Jorge Lopez <jorge.lopez2@hp.com> | ||||||
|  | @ -10475,6 +10490,14 @@ L:	linux-media@vger.kernel.org | ||||||
| S:	Maintained | S:	Maintained | ||||||
| F:	drivers/media/rc/iguanair.c | F:	drivers/media/rc/iguanair.c | ||||||
| 
 | 
 | ||||||
|  | IIO BACKEND FRAMEWORK | ||||||
|  | M:	Nuno Sa <nuno.sa@analog.com> | ||||||
|  | R:	Olivier Moysan <olivier.moysan@foss.st.com> | ||||||
|  | L:	linux-iio@vger.kernel.org | ||||||
|  | S:	Maintained | ||||||
|  | F:	drivers/iio/industrialio-backend.c | ||||||
|  | F:	include/linux/iio/backend.h | ||||||
|  | 
 | ||||||
| IIO DIGITAL POTENTIOMETER DAC | IIO DIGITAL POTENTIOMETER DAC | ||||||
| M:	Peter Rosin <peda@axentia.se> | M:	Peter Rosin <peda@axentia.se> | ||||||
| L:	linux-iio@vger.kernel.org | L:	linux-iio@vger.kernel.org | ||||||
|  | @ -10497,6 +10520,7 @@ L:	linux-iio@vger.kernel.org | ||||||
| S:	Maintained | S:	Maintained | ||||||
| F:	drivers/iio/industrialio-gts-helper.c | F:	drivers/iio/industrialio-gts-helper.c | ||||||
| F:	include/linux/iio/iio-gts-helper.h | F:	include/linux/iio/iio-gts-helper.h | ||||||
|  | F:	drivers/iio/test/iio-test-gts.c | ||||||
| 
 | 
 | ||||||
| IIO MULTIPLEXER | IIO MULTIPLEXER | ||||||
| M:	Peter Rosin <peda@axentia.se> | M:	Peter Rosin <peda@axentia.se> | ||||||
|  | @ -14487,6 +14511,13 @@ F:	Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml | ||||||
| F:	drivers/nvmem/microchip-otpc.c | F:	drivers/nvmem/microchip-otpc.c | ||||||
| F:	include/dt-bindings/nvmem/microchip,sama7g5-otpc.h | F:	include/dt-bindings/nvmem/microchip,sama7g5-otpc.h | ||||||
| 
 | 
 | ||||||
|  | MICROCHIP PAC1934 POWER/ENERGY MONITOR DRIVER | ||||||
|  | M:	Marius Cristea <marius.cristea@microchip.com> | ||||||
|  | L:	linux-iio@vger.kernel.org | ||||||
|  | S:	Supported | ||||||
|  | F:	Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml | ||||||
|  | F:	drivers/iio/adc/pac1934.c | ||||||
|  | 
 | ||||||
| MICROCHIP PCI1XXXX GP DRIVER | MICROCHIP PCI1XXXX GP DRIVER | ||||||
| M:	Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com> | M:	Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com> | ||||||
| M:	Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> | M:	Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> | ||||||
|  | @ -23566,8 +23597,8 @@ F:	Documentation/driver-api/vme.rst | ||||||
| F:	drivers/staging/vme_user/ | F:	drivers/staging/vme_user/ | ||||||
| 
 | 
 | ||||||
| VMWARE BALLOON DRIVER | VMWARE BALLOON DRIVER | ||||||
| M:	Nadav Amit <namit@vmware.com> | M:	Jerrin Shaji George <jerrin.shaji-george@broadcom.com> | ||||||
| R:	VMware PV-Drivers Reviewers <pv-drivers@vmware.com> | R:	Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com> | ||||||
| L:	linux-kernel@vger.kernel.org | L:	linux-kernel@vger.kernel.org | ||||||
| S:	Supported | S:	Supported | ||||||
| F:	drivers/misc/vmw_balloon.c | F:	drivers/misc/vmw_balloon.c | ||||||
|  | @ -24344,6 +24375,14 @@ M:	Harsha <harsha.harsha@amd.com> | ||||||
| S:	Maintained | S:	Maintained | ||||||
| F:	drivers/crypto/xilinx/zynqmp-sha.c | F:	drivers/crypto/xilinx/zynqmp-sha.c | ||||||
| 
 | 
 | ||||||
|  | XILINX ZYNQMP NVMEM DRIVER | ||||||
|  | M:	Praveen Teja Kundanala <praveen.teja.kundanala@amd.com> | ||||||
|  | M:	Kalyani Akula <kalyani.akula@amd.com> | ||||||
|  | R:	Michal Simek <michal.simek@amd.com> | ||||||
|  | S:	Maintained | ||||||
|  | F:	Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml | ||||||
|  | F:	drivers/nvmem/zynqmp_nvmem.c | ||||||
|  | 
 | ||||||
| XILLYBUS DRIVER | XILLYBUS DRIVER | ||||||
| M:	Eli Billauer <eli.billauer@gmail.com> | M:	Eli Billauer <eli.billauer@gmail.com> | ||||||
| L:	linux-kernel@vger.kernel.org | L:	linux-kernel@vger.kernel.org | ||||||
|  |  | ||||||
|  | @ -472,10 +472,6 @@ config X86_MPPARSE | ||||||
| 	  For old smp systems that do not have proper acpi support. Newer systems | 	  For old smp systems that do not have proper acpi support. Newer systems | ||||||
| 	  (esp with 64bit cpus) with acpi support, MADT and DSDT will override it | 	  (esp with 64bit cpus) with acpi support, MADT and DSDT will override it | ||||||
| 
 | 
 | ||||||
| config GOLDFISH |  | ||||||
| 	def_bool y |  | ||||||
| 	depends on X86_GOLDFISH |  | ||||||
| 
 |  | ||||||
| config X86_CPU_RESCTRL | config X86_CPU_RESCTRL | ||||||
| 	bool "x86 CPU resource control support" | 	bool "x86 CPU resource control support" | ||||||
| 	depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) | 	depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) | ||||||
|  |  | ||||||
|  | @ -7,9 +7,10 @@ | ||||||
| #include "speakup.h" | #include "speakup.h" | ||||||
| #include "spk_priv.h" | #include "spk_priv.h" | ||||||
| 
 | 
 | ||||||
| static int misc_registered; | static int synth_registered, synthu_registered; | ||||||
| static int dev_opened; | static int dev_opened; | ||||||
| 
 | 
 | ||||||
|  | /* Latin1 version */ | ||||||
| static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, | static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, | ||||||
| 				  size_t nbytes, loff_t *ppos) | 				  size_t nbytes, loff_t *ppos) | ||||||
| { | { | ||||||
|  | @ -34,6 +35,98 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer, | ||||||
| 	return (ssize_t)nbytes; | 	return (ssize_t)nbytes; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* UTF-8 version */ | ||||||
|  | static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer, | ||||||
|  | 				   size_t nbytes, loff_t *ppos) | ||||||
|  | { | ||||||
|  | 	size_t count = nbytes, want; | ||||||
|  | 	const char __user *ptr = buffer; | ||||||
|  | 	size_t bytes; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	unsigned char buf[256]; | ||||||
|  | 	u16 ubuf[256]; | ||||||
|  | 	size_t in, in2, out; | ||||||
|  | 
 | ||||||
|  | 	if (!synth) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	want = 1; | ||||||
|  | 	while (count >= want) { | ||||||
|  | 		/* Copy some UTF-8 piece from userland */ | ||||||
|  | 		bytes = min(count, sizeof(buf)); | ||||||
|  | 		if (copy_from_user(buf, ptr, bytes)) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 		/* Convert to u16 */ | ||||||
|  | 		for (in = 0, out = 0; in < bytes; in++) { | ||||||
|  | 			unsigned char c = buf[in]; | ||||||
|  | 			int nbytes = 8 - fls(c ^ 0xff); | ||||||
|  | 			u32 value; | ||||||
|  | 
 | ||||||
|  | 			switch (nbytes) { | ||||||
|  | 			case 8: /* 0xff */ | ||||||
|  | 			case 7: /* 0xfe */ | ||||||
|  | 			case 1: /* 0x80 */ | ||||||
|  | 				/* Invalid, drop */ | ||||||
|  | 				goto drop; | ||||||
|  | 
 | ||||||
|  | 			case 0: | ||||||
|  | 				/* ASCII, copy */ | ||||||
|  | 				ubuf[out++] = c; | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			default: | ||||||
|  | 				/* 2..6-byte UTF-8 */ | ||||||
|  | 
 | ||||||
|  | 				if (bytes - in < nbytes) { | ||||||
|  | 					/* We don't have it all yet, stop here
 | ||||||
|  | 					 * and wait for the rest | ||||||
|  | 					 */ | ||||||
|  | 					bytes = in; | ||||||
|  | 					want = nbytes; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				/* First byte */ | ||||||
|  | 				value = c & ((1u << (7 - nbytes)) - 1); | ||||||
|  | 
 | ||||||
|  | 				/* Other bytes */ | ||||||
|  | 				for (in2 = 2; in2 <= nbytes; in2++) { | ||||||
|  | 					c = buf[in + 1]; | ||||||
|  | 					if ((c & 0xc0) != 0x80)	{ | ||||||
|  | 						/* Invalid, drop the head */ | ||||||
|  | 						want = 1; | ||||||
|  | 						goto drop; | ||||||
|  | 					} | ||||||
|  | 					value = (value << 6) | (c & 0x3f); | ||||||
|  | 					in++; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (value < 0x10000) | ||||||
|  | 					ubuf[out++] = value; | ||||||
|  | 				want = 1; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | drop: | ||||||
|  | 			/* empty statement */; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		count -= bytes; | ||||||
|  | 		ptr += bytes; | ||||||
|  | 
 | ||||||
|  | 		/* And speak this up */ | ||||||
|  | 		if (out) { | ||||||
|  | 			spin_lock_irqsave(&speakup_info.spinlock, flags); | ||||||
|  | 			for (in = 0; in < out; in++) | ||||||
|  | 				synth_buffer_add(ubuf[in]); | ||||||
|  | 			synth_start(); | ||||||
|  | 			spin_unlock_irqrestore(&speakup_info.spinlock, flags); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return (ssize_t)(nbytes - count); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static ssize_t speakup_file_read(struct file *fp, char __user *buf, | static ssize_t speakup_file_read(struct file *fp, char __user *buf, | ||||||
| 				 size_t nbytes, loff_t *ppos) | 				 size_t nbytes, loff_t *ppos) | ||||||
| { | { | ||||||
|  | @ -62,31 +155,57 @@ static const struct file_operations synth_fops = { | ||||||
| 	.release = speakup_file_release, | 	.release = speakup_file_release, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct file_operations synthu_fops = { | ||||||
|  | 	.read = speakup_file_read, | ||||||
|  | 	.write = speakup_file_writeu, | ||||||
|  | 	.open = speakup_file_open, | ||||||
|  | 	.release = speakup_file_release, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static struct miscdevice synth_device = { | static struct miscdevice synth_device = { | ||||||
| 	.minor = MISC_DYNAMIC_MINOR, | 	.minor = MISC_DYNAMIC_MINOR, | ||||||
| 	.name = "synth", | 	.name = "synth", | ||||||
| 	.fops = &synth_fops, | 	.fops = &synth_fops, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct miscdevice synthu_device = { | ||||||
|  | 	.minor = MISC_DYNAMIC_MINOR, | ||||||
|  | 	.name = "synthu", | ||||||
|  | 	.fops = &synthu_fops, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void speakup_register_devsynth(void) | void speakup_register_devsynth(void) | ||||||
| { | { | ||||||
| 	if (misc_registered != 0) | 	if (!synth_registered) { | ||||||
| 		return; | 		if (misc_register(&synth_device)) { | ||||||
| /* zero it so if register fails, deregister will not ref invalid ptrs */ | 			pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); | ||||||
| 	if (misc_register(&synth_device)) { | 		} else { | ||||||
| 		pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); | 			pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", | ||||||
| 	} else { | 				MISC_MAJOR, synth_device.minor); | ||||||
| 		pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", | 			synth_registered = 1; | ||||||
| 			MISC_MAJOR, synth_device.minor); | 		} | ||||||
| 		misc_registered = 1; | 	} | ||||||
|  | 	if (!synthu_registered) { | ||||||
|  | 		if (misc_register(&synthu_device)) { | ||||||
|  | 			pr_warn("Couldn't initialize miscdevice /dev/synthu.\n"); | ||||||
|  | 		} else { | ||||||
|  | 			pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n", | ||||||
|  | 				MISC_MAJOR, synthu_device.minor); | ||||||
|  | 			synthu_registered = 1; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void speakup_unregister_devsynth(void) | void speakup_unregister_devsynth(void) | ||||||
| { | { | ||||||
| 	if (!misc_registered) | 	if (synth_registered) { | ||||||
| 		return; | 		pr_info("speakup: unregistering synth device /dev/synth\n"); | ||||||
| 	pr_info("speakup: unregistering synth device /dev/synth\n"); | 		misc_deregister(&synth_device); | ||||||
| 	misc_deregister(&synth_device); | 		synth_registered = 0; | ||||||
| 	misc_registered = 0; | 	} | ||||||
|  | 	if (synthu_registered) { | ||||||
|  | 		pr_info("speakup: unregistering synth device /dev/synthu\n"); | ||||||
|  | 		misc_deregister(&synthu_device); | ||||||
|  | 		synthu_registered = 0; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -208,8 +208,10 @@ void spk_do_flush(void) | ||||||
| 	wake_up_process(speakup_task); | 	wake_up_process(speakup_task); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void synth_write(const char *buf, size_t count) | void synth_write(const char *_buf, size_t count) | ||||||
| { | { | ||||||
|  | 	const unsigned char *buf = (const unsigned char *) _buf; | ||||||
|  | 
 | ||||||
| 	while (count--) | 	while (count--) | ||||||
| 		synth_buffer_add(*buf++); | 		synth_buffer_add(*buf++); | ||||||
| 	synth_start(); | 	synth_start(); | ||||||
|  |  | ||||||
|  | @ -925,7 +925,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) | ||||||
| 		int i; | 		int i; | ||||||
| 
 | 
 | ||||||
| 		for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | 		for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | ||||||
| 			unsigned long page_addr; |  | ||||||
| 			bool on_lru; | 			bool on_lru; | ||||||
| 
 | 
 | ||||||
| 			if (!alloc->pages[i].page_ptr) | 			if (!alloc->pages[i].page_ptr) | ||||||
|  | @ -933,7 +932,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) | ||||||
| 
 | 
 | ||||||
| 			on_lru = list_lru_del_obj(&binder_freelist, | 			on_lru = list_lru_del_obj(&binder_freelist, | ||||||
| 						  &alloc->pages[i].lru); | 						  &alloc->pages[i].lru); | ||||||
| 			page_addr = alloc->buffer + i * PAGE_SIZE; |  | ||||||
| 			binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | 			binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||||||
| 				     "%s: %d: page %d %s\n", | 				     "%s: %d: page %d %s\n", | ||||||
| 				     __func__, alloc->pid, i, | 				     __func__, alloc->pid, i, | ||||||
|  |  | ||||||
|  | @ -297,30 +297,30 @@ struct mhi_ring_element { | ||||||
| 	__le32 dword[2]; | 	__le32 dword[2]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define MHI_STATE_LIST				\ | ||||||
|  | 	mhi_state(RESET,	"RESET")	\ | ||||||
|  | 	mhi_state(READY,	"READY")	\ | ||||||
|  | 	mhi_state(M0,		"M0")		\ | ||||||
|  | 	mhi_state(M1,		"M1")		\ | ||||||
|  | 	mhi_state(M2,		"M2")		\ | ||||||
|  | 	mhi_state(M3,		"M3")		\ | ||||||
|  | 	mhi_state(M3_FAST,	"M3_FAST")	\ | ||||||
|  | 	mhi_state(BHI,		"BHI")		\ | ||||||
|  | 	mhi_state_end(SYS_ERR,	"SYS ERROR") | ||||||
|  | 
 | ||||||
|  | #undef mhi_state | ||||||
|  | #undef mhi_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_state(a, b)		case MHI_STATE_##a: return b; | ||||||
|  | #define mhi_state_end(a, b)	case MHI_STATE_##a: return b; | ||||||
|  | 
 | ||||||
| static inline const char *mhi_state_str(enum mhi_state state) | static inline const char *mhi_state_str(enum mhi_state state) | ||||||
| { | { | ||||||
| 	switch (state) { | 	switch (state) { | ||||||
| 	case MHI_STATE_RESET: | 	MHI_STATE_LIST | ||||||
| 		return "RESET"; |  | ||||||
| 	case MHI_STATE_READY: |  | ||||||
| 		return "READY"; |  | ||||||
| 	case MHI_STATE_M0: |  | ||||||
| 		return "M0"; |  | ||||||
| 	case MHI_STATE_M1: |  | ||||||
| 		return "M1"; |  | ||||||
| 	case MHI_STATE_M2: |  | ||||||
| 		return "M2"; |  | ||||||
| 	case MHI_STATE_M3: |  | ||||||
| 		return "M3"; |  | ||||||
| 	case MHI_STATE_M3_FAST: |  | ||||||
| 		return "M3 FAST"; |  | ||||||
| 	case MHI_STATE_BHI: |  | ||||||
| 		return "BHI"; |  | ||||||
| 	case MHI_STATE_SYS_ERR: |  | ||||||
| 		return "SYS ERROR"; |  | ||||||
| 	default: | 	default: | ||||||
| 		return "Unknown state"; | 		return "Unknown state"; | ||||||
| 	} | 	} | ||||||
| }; | } | ||||||
| 
 | 
 | ||||||
| #endif /* _MHI_COMMON_H */ | #endif /* _MHI_COMMON_H */ | ||||||
|  |  | ||||||
|  | @ -1149,8 +1149,9 @@ int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl) | ||||||
| 	mhi_ep_mmio_mask_interrupts(mhi_cntrl); | 	mhi_ep_mmio_mask_interrupts(mhi_cntrl); | ||||||
| 	mhi_ep_mmio_init(mhi_cntrl); | 	mhi_ep_mmio_init(mhi_cntrl); | ||||||
| 
 | 
 | ||||||
| 	mhi_cntrl->mhi_event = kzalloc(mhi_cntrl->event_rings * (sizeof(*mhi_cntrl->mhi_event)), | 	mhi_cntrl->mhi_event = kcalloc(mhi_cntrl->event_rings, | ||||||
| 					GFP_KERNEL); | 				       sizeof(*mhi_cntrl->mhi_event), | ||||||
|  | 				       GFP_KERNEL); | ||||||
| 	if (!mhi_cntrl->mhi_event) | 	if (!mhi_cntrl->mhi_event) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | @ -1496,7 +1497,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, | ||||||
| 	mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", | 	mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", | ||||||
| 							sizeof(struct mhi_ep_ring_item), 0, | 							sizeof(struct mhi_ep_ring_item), 0, | ||||||
| 							0, NULL); | 							0, NULL); | ||||||
| 	if (!mhi_cntrl->ev_ring_el_cache) { | 	if (!mhi_cntrl->ring_item_cache) { | ||||||
| 		ret = -ENOMEM; | 		ret = -ENOMEM; | ||||||
| 		goto err_destroy_tre_buf_cache; | 		goto err_destroy_tre_buf_cache; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -395,7 +395,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) | ||||||
| 	void *buf; | 	void *buf; | ||||||
| 	dma_addr_t dma_addr; | 	dma_addr_t dma_addr; | ||||||
| 	size_t size, fw_sz; | 	size_t size, fw_sz; | ||||||
| 	int i, ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { | 	if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { | ||||||
| 		dev_err(dev, "Device MHI is not in valid state\n"); | 		dev_err(dev, "Device MHI is not in valid state\n"); | ||||||
|  | @ -408,15 +408,6 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		dev_err(dev, "Could not capture serial number via BHI\n"); | 		dev_err(dev, "Could not capture serial number via BHI\n"); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) { |  | ||||||
| 		ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), |  | ||||||
| 				   &mhi_cntrl->oem_pk_hash[i]); |  | ||||||
| 		if (ret) { |  | ||||||
| 			dev_err(dev, "Could not capture OEM PK HASH via BHI\n"); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* wait for ready on pass through or any other execution environment */ | 	/* wait for ready on pass through or any other execution environment */ | ||||||
| 	if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee)) | 	if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee)) | ||||||
| 		goto fw_load_ready_state; | 		goto fw_load_ready_state; | ||||||
|  |  | ||||||
|  | @ -20,50 +20,49 @@ | ||||||
| #include <linux/wait.h> | #include <linux/wait.h> | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
| 
 | 
 | ||||||
|  | #define CREATE_TRACE_POINTS | ||||||
|  | #include "trace.h" | ||||||
|  | 
 | ||||||
| static DEFINE_IDA(mhi_controller_ida); | static DEFINE_IDA(mhi_controller_ida); | ||||||
| 
 | 
 | ||||||
|  | #undef mhi_ee | ||||||
|  | #undef mhi_ee_end | ||||||
|  | 
 | ||||||
|  | #define mhi_ee(a, b)		[MHI_EE_##a] = b, | ||||||
|  | #define mhi_ee_end(a, b)	[MHI_EE_##a] = b, | ||||||
|  | 
 | ||||||
| const char * const mhi_ee_str[MHI_EE_MAX] = { | const char * const mhi_ee_str[MHI_EE_MAX] = { | ||||||
| 	[MHI_EE_PBL] = "PRIMARY BOOTLOADER", | 	MHI_EE_LIST | ||||||
| 	[MHI_EE_SBL] = "SECONDARY BOOTLOADER", |  | ||||||
| 	[MHI_EE_AMSS] = "MISSION MODE", |  | ||||||
| 	[MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE", |  | ||||||
| 	[MHI_EE_WFW] = "WLAN FIRMWARE", |  | ||||||
| 	[MHI_EE_PTHRU] = "PASS THROUGH", |  | ||||||
| 	[MHI_EE_EDL] = "EMERGENCY DOWNLOAD", |  | ||||||
| 	[MHI_EE_FP] = "FLASH PROGRAMMER", |  | ||||||
| 	[MHI_EE_DISABLE_TRANSITION] = "DISABLE", |  | ||||||
| 	[MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #undef dev_st_trans | ||||||
|  | #undef dev_st_trans_end | ||||||
|  | 
 | ||||||
|  | #define dev_st_trans(a, b)	[DEV_ST_TRANSITION_##a] = b, | ||||||
|  | #define dev_st_trans_end(a, b)	[DEV_ST_TRANSITION_##a] = b, | ||||||
|  | 
 | ||||||
| const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { | const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { | ||||||
| 	[DEV_ST_TRANSITION_PBL] = "PBL", | 	DEV_ST_TRANSITION_LIST | ||||||
| 	[DEV_ST_TRANSITION_READY] = "READY", |  | ||||||
| 	[DEV_ST_TRANSITION_SBL] = "SBL", |  | ||||||
| 	[DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", |  | ||||||
| 	[DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER", |  | ||||||
| 	[DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR", |  | ||||||
| 	[DEV_ST_TRANSITION_DISABLE] = "DISABLE", |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #undef ch_state_type | ||||||
|  | #undef ch_state_type_end | ||||||
|  | 
 | ||||||
|  | #define ch_state_type(a, b)	[MHI_CH_STATE_TYPE_##a] = b, | ||||||
|  | #define ch_state_type_end(a, b)	[MHI_CH_STATE_TYPE_##a] = b, | ||||||
|  | 
 | ||||||
| const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { | const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { | ||||||
| 	[MHI_CH_STATE_TYPE_RESET] = "RESET", | 	MHI_CH_STATE_TYPE_LIST | ||||||
| 	[MHI_CH_STATE_TYPE_STOP] = "STOP", |  | ||||||
| 	[MHI_CH_STATE_TYPE_START] = "START", |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #undef mhi_pm_state | ||||||
|  | #undef mhi_pm_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_pm_state(a, b)	[MHI_PM_STATE_##a] = b, | ||||||
|  | #define mhi_pm_state_end(a, b)	[MHI_PM_STATE_##a] = b, | ||||||
|  | 
 | ||||||
| static const char * const mhi_pm_state_str[] = { | static const char * const mhi_pm_state_str[] = { | ||||||
| 	[MHI_PM_STATE_DISABLE] = "DISABLE", | 	MHI_PM_STATE_LIST | ||||||
| 	[MHI_PM_STATE_POR] = "POWER ON RESET", |  | ||||||
| 	[MHI_PM_STATE_M0] = "M0", |  | ||||||
| 	[MHI_PM_STATE_M2] = "M2", |  | ||||||
| 	[MHI_PM_STATE_M3_ENTER] = "M?->M3", |  | ||||||
| 	[MHI_PM_STATE_M3] = "M3", |  | ||||||
| 	[MHI_PM_STATE_M3_EXIT] = "M3->M0", |  | ||||||
| 	[MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", |  | ||||||
| 	[MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", |  | ||||||
| 	[MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", |  | ||||||
| 	[MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", |  | ||||||
| 	[MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const char *to_mhi_pm_state_str(u32 state) | const char *to_mhi_pm_state_str(u32 state) | ||||||
|  | @ -97,11 +96,19 @@ static ssize_t oem_pk_hash_show(struct device *dev, | ||||||
| { | { | ||||||
| 	struct mhi_device *mhi_dev = to_mhi_device(dev); | 	struct mhi_device *mhi_dev = to_mhi_device(dev); | ||||||
| 	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; | 	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; | ||||||
| 	int i, cnt = 0; | 	u32 hash_segment[MHI_MAX_OEM_PK_HASH_SEGMENTS]; | ||||||
|  | 	int i, cnt = 0, ret; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) | 	for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) { | ||||||
| 		cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", | 		ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), &hash_segment[i]); | ||||||
| 				i, mhi_cntrl->oem_pk_hash[i]); | 		if (ret) { | ||||||
|  | 			dev_err(dev, "Could not capture OEM PK HASH\n"); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) | ||||||
|  | 		cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", i, hash_segment[i]); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return cnt; | ||||||
| } | } | ||||||
|  | @ -907,7 +914,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, | ||||||
| 	struct mhi_chan *mhi_chan; | 	struct mhi_chan *mhi_chan; | ||||||
| 	struct mhi_cmd *mhi_cmd; | 	struct mhi_cmd *mhi_cmd; | ||||||
| 	struct mhi_device *mhi_dev; | 	struct mhi_device *mhi_dev; | ||||||
| 	u32 soc_info; |  | ||||||
| 	int ret, i; | 	int ret, i; | ||||||
| 
 | 
 | ||||||
| 	if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || | 	if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || | ||||||
|  | @ -982,17 +988,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, | ||||||
| 		mhi_cntrl->unmap_single = mhi_unmap_single_no_bb; | 		mhi_cntrl->unmap_single = mhi_unmap_single_no_bb; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Read the MHI device info */ |  | ||||||
| 	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, |  | ||||||
| 			   SOC_HW_VERSION_OFFS, &soc_info); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto err_destroy_wq; |  | ||||||
| 
 |  | ||||||
| 	mhi_cntrl->family_number = FIELD_GET(SOC_HW_VERSION_FAM_NUM_BMSK, soc_info); |  | ||||||
| 	mhi_cntrl->device_number = FIELD_GET(SOC_HW_VERSION_DEV_NUM_BMSK, soc_info); |  | ||||||
| 	mhi_cntrl->major_version = FIELD_GET(SOC_HW_VERSION_MAJOR_VER_BMSK, soc_info); |  | ||||||
| 	mhi_cntrl->minor_version = FIELD_GET(SOC_HW_VERSION_MINOR_VER_BMSK, soc_info); |  | ||||||
| 
 |  | ||||||
| 	mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL); | 	mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL); | ||||||
| 	if (mhi_cntrl->index < 0) { | 	if (mhi_cntrl->index < 0) { | ||||||
| 		ret = mhi_cntrl->index; | 		ret = mhi_cntrl->index; | ||||||
|  |  | ||||||
|  | @ -15,12 +15,6 @@ extern struct bus_type mhi_bus_type; | ||||||
| #define MHI_SOC_RESET_REQ_OFFSET			0xb0 | #define MHI_SOC_RESET_REQ_OFFSET			0xb0 | ||||||
| #define MHI_SOC_RESET_REQ				BIT(0) | #define MHI_SOC_RESET_REQ				BIT(0) | ||||||
| 
 | 
 | ||||||
| #define SOC_HW_VERSION_OFFS				0x224 |  | ||||||
| #define SOC_HW_VERSION_FAM_NUM_BMSK			GENMASK(31, 28) |  | ||||||
| #define SOC_HW_VERSION_DEV_NUM_BMSK			GENMASK(27, 16) |  | ||||||
| #define SOC_HW_VERSION_MAJOR_VER_BMSK			GENMASK(15, 8) |  | ||||||
| #define SOC_HW_VERSION_MINOR_VER_BMSK			GENMASK(7, 0) |  | ||||||
| 
 |  | ||||||
| struct mhi_ctxt { | struct mhi_ctxt { | ||||||
| 	struct mhi_event_ctxt *er_ctxt; | 	struct mhi_event_ctxt *er_ctxt; | ||||||
| 	struct mhi_chan_ctxt *chan_ctxt; | 	struct mhi_chan_ctxt *chan_ctxt; | ||||||
|  | @ -42,6 +36,11 @@ enum mhi_ch_state_type { | ||||||
| 	MHI_CH_STATE_TYPE_MAX, | 	MHI_CH_STATE_TYPE_MAX, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define MHI_CH_STATE_TYPE_LIST				\ | ||||||
|  | 	ch_state_type(RESET,		"RESET")	\ | ||||||
|  | 	ch_state_type(STOP,		"STOP")		\ | ||||||
|  | 	ch_state_type_end(START,	"START") | ||||||
|  | 
 | ||||||
| extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; | extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; | ||||||
| #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ | #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ | ||||||
| 				     "INVALID_STATE" : \ | 				     "INVALID_STATE" : \ | ||||||
|  | @ -50,6 +49,18 @@ extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; | ||||||
| #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ | #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ | ||||||
| 				    mode != MHI_DB_BRST_ENABLE) | 				    mode != MHI_DB_BRST_ENABLE) | ||||||
| 
 | 
 | ||||||
|  | #define MHI_EE_LIST						\ | ||||||
|  | 	mhi_ee(PBL,			"PRIMARY BOOTLOADER")	\ | ||||||
|  | 	mhi_ee(SBL,			"SECONDARY BOOTLOADER")	\ | ||||||
|  | 	mhi_ee(AMSS,			"MISSION MODE")		\ | ||||||
|  | 	mhi_ee(RDDM,			"RAMDUMP DOWNLOAD MODE")\ | ||||||
|  | 	mhi_ee(WFW,			"WLAN FIRMWARE")	\ | ||||||
|  | 	mhi_ee(PTHRU,			"PASS THROUGH")		\ | ||||||
|  | 	mhi_ee(EDL,			"EMERGENCY DOWNLOAD")	\ | ||||||
|  | 	mhi_ee(FP,			"FLASH PROGRAMMER")	\ | ||||||
|  | 	mhi_ee(DISABLE_TRANSITION,	"DISABLE")		\ | ||||||
|  | 	mhi_ee_end(NOT_SUPPORTED,	"NOT SUPPORTED") | ||||||
|  | 
 | ||||||
| extern const char * const mhi_ee_str[MHI_EE_MAX]; | extern const char * const mhi_ee_str[MHI_EE_MAX]; | ||||||
| #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ | #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ | ||||||
| 			     "INVALID_EE" : mhi_ee_str[ee]) | 			     "INVALID_EE" : mhi_ee_str[ee]) | ||||||
|  | @ -72,6 +83,15 @@ enum dev_st_transition { | ||||||
| 	DEV_ST_TRANSITION_MAX, | 	DEV_ST_TRANSITION_MAX, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define DEV_ST_TRANSITION_LIST					\ | ||||||
|  | 	dev_st_trans(PBL,		"PBL")			\ | ||||||
|  | 	dev_st_trans(READY,		"READY")		\ | ||||||
|  | 	dev_st_trans(SBL,		"SBL")			\ | ||||||
|  | 	dev_st_trans(MISSION_MODE,	"MISSION MODE")		\ | ||||||
|  | 	dev_st_trans(FP,		"FLASH PROGRAMMER")	\ | ||||||
|  | 	dev_st_trans(SYS_ERR,		"SYS ERROR")		\ | ||||||
|  | 	dev_st_trans_end(DISABLE,	"DISABLE") | ||||||
|  | 
 | ||||||
| extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX]; | extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX]; | ||||||
| #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \ | #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \ | ||||||
| 				"INVALID_STATE" : dev_state_tran_str[state]) | 				"INVALID_STATE" : dev_state_tran_str[state]) | ||||||
|  | @ -88,11 +108,27 @@ enum mhi_pm_state { | ||||||
| 	MHI_PM_STATE_FW_DL_ERR, | 	MHI_PM_STATE_FW_DL_ERR, | ||||||
| 	MHI_PM_STATE_SYS_ERR_DETECT, | 	MHI_PM_STATE_SYS_ERR_DETECT, | ||||||
| 	MHI_PM_STATE_SYS_ERR_PROCESS, | 	MHI_PM_STATE_SYS_ERR_PROCESS, | ||||||
|  | 	MHI_PM_STATE_SYS_ERR_FAIL, | ||||||
| 	MHI_PM_STATE_SHUTDOWN_PROCESS, | 	MHI_PM_STATE_SHUTDOWN_PROCESS, | ||||||
| 	MHI_PM_STATE_LD_ERR_FATAL_DETECT, | 	MHI_PM_STATE_LD_ERR_FATAL_DETECT, | ||||||
| 	MHI_PM_STATE_MAX | 	MHI_PM_STATE_MAX | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define MHI_PM_STATE_LIST							\ | ||||||
|  | 	mhi_pm_state(DISABLE,			"DISABLE")			\ | ||||||
|  | 	mhi_pm_state(POR,			"POWER ON RESET")		\ | ||||||
|  | 	mhi_pm_state(M0,			"M0")				\ | ||||||
|  | 	mhi_pm_state(M2,			"M2")				\ | ||||||
|  | 	mhi_pm_state(M3_ENTER,			"M?->M3")			\ | ||||||
|  | 	mhi_pm_state(M3,			"M3")				\ | ||||||
|  | 	mhi_pm_state(M3_EXIT,			"M3->M0")			\ | ||||||
|  | 	mhi_pm_state(FW_DL_ERR,			"Firmware Download Error")	\ | ||||||
|  | 	mhi_pm_state(SYS_ERR_DETECT,		"SYS ERROR Detect")		\ | ||||||
|  | 	mhi_pm_state(SYS_ERR_PROCESS,		"SYS ERROR Process")		\ | ||||||
|  | 	mhi_pm_state(SYS_ERR_FAIL,		"SYS ERROR Failure")		\ | ||||||
|  | 	mhi_pm_state(SHUTDOWN_PROCESS,		"SHUTDOWN Process")		\ | ||||||
|  | 	mhi_pm_state_end(LD_ERR_FATAL_DETECT,	"Linkdown or Error Fatal Detect") | ||||||
|  | 
 | ||||||
| #define MHI_PM_DISABLE					BIT(0) | #define MHI_PM_DISABLE					BIT(0) | ||||||
| #define MHI_PM_POR					BIT(1) | #define MHI_PM_POR					BIT(1) | ||||||
| #define MHI_PM_M0					BIT(2) | #define MHI_PM_M0					BIT(2) | ||||||
|  | @ -104,14 +140,16 @@ enum mhi_pm_state { | ||||||
| #define MHI_PM_FW_DL_ERR				BIT(7) | #define MHI_PM_FW_DL_ERR				BIT(7) | ||||||
| #define MHI_PM_SYS_ERR_DETECT				BIT(8) | #define MHI_PM_SYS_ERR_DETECT				BIT(8) | ||||||
| #define MHI_PM_SYS_ERR_PROCESS				BIT(9) | #define MHI_PM_SYS_ERR_PROCESS				BIT(9) | ||||||
| #define MHI_PM_SHUTDOWN_PROCESS				BIT(10) | #define MHI_PM_SYS_ERR_FAIL				BIT(10) | ||||||
|  | #define MHI_PM_SHUTDOWN_PROCESS				BIT(11) | ||||||
| /* link not accessible */ | /* link not accessible */ | ||||||
| #define MHI_PM_LD_ERR_FATAL_DETECT			BIT(11) | #define MHI_PM_LD_ERR_FATAL_DETECT			BIT(12) | ||||||
| 
 | 
 | ||||||
| #define MHI_REG_ACCESS_VALID(pm_state)			((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ | #define MHI_REG_ACCESS_VALID(pm_state)			((pm_state & (MHI_PM_POR | MHI_PM_M0 | \ | ||||||
| 						MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ | 						MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \ | ||||||
| 						MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ | 						MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \ | ||||||
| 						MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR))) | 						MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS |  \ | ||||||
|  | 						MHI_PM_FW_DL_ERR))) | ||||||
| #define MHI_PM_IN_ERROR_STATE(pm_state)			(pm_state >= MHI_PM_FW_DL_ERR) | #define MHI_PM_IN_ERROR_STATE(pm_state)			(pm_state >= MHI_PM_FW_DL_ERR) | ||||||
| #define MHI_PM_IN_FATAL_STATE(pm_state)			(pm_state == MHI_PM_LD_ERR_FATAL_DETECT) | #define MHI_PM_IN_FATAL_STATE(pm_state)			(pm_state == MHI_PM_LD_ERR_FATAL_DETECT) | ||||||
| #define MHI_DB_ACCESS_VALID(mhi_cntrl)			(mhi_cntrl->pm_state & mhi_cntrl->db_access) | #define MHI_DB_ACCESS_VALID(mhi_cntrl)			(mhi_cntrl->pm_state & mhi_cntrl->db_access) | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
| #include <linux/skbuff.h> | #include <linux/skbuff.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
|  | #include "trace.h" | ||||||
| 
 | 
 | ||||||
| int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, | int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, | ||||||
| 			      void __iomem *base, u32 offset, u32 *out) | 			      void __iomem *base, u32 offset, u32 *out) | ||||||
|  | @ -493,11 +494,8 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) | ||||||
| 
 | 
 | ||||||
| 	state = mhi_get_mhi_state(mhi_cntrl); | 	state = mhi_get_mhi_state(mhi_cntrl); | ||||||
| 	ee = mhi_get_exec_env(mhi_cntrl); | 	ee = mhi_get_exec_env(mhi_cntrl); | ||||||
| 	dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n", |  | ||||||
| 		TO_MHI_EXEC_STR(mhi_cntrl->ee), |  | ||||||
| 		mhi_state_str(mhi_cntrl->dev_state), |  | ||||||
| 		TO_MHI_EXEC_STR(ee), mhi_state_str(state)); |  | ||||||
| 
 | 
 | ||||||
|  | 	trace_mhi_intvec_states(mhi_cntrl, ee, state); | ||||||
| 	if (state == MHI_STATE_SYS_ERR) { | 	if (state == MHI_STATE_SYS_ERR) { | ||||||
| 		dev_dbg(dev, "System error detected\n"); | 		dev_dbg(dev, "System error detected\n"); | ||||||
| 		pm_state = mhi_tryset_pm_state(mhi_cntrl, | 		pm_state = mhi_tryset_pm_state(mhi_cntrl, | ||||||
|  | @ -838,6 +836,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, | ||||||
| 	while (dev_rp != local_rp) { | 	while (dev_rp != local_rp) { | ||||||
| 		enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | 		enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | ||||||
| 
 | 
 | ||||||
|  | 		trace_mhi_ctrl_event(mhi_cntrl, local_rp); | ||||||
|  | 
 | ||||||
| 		switch (type) { | 		switch (type) { | ||||||
| 		case MHI_PKT_TYPE_BW_REQ_EVENT: | 		case MHI_PKT_TYPE_BW_REQ_EVENT: | ||||||
| 		{ | 		{ | ||||||
|  | @ -1003,6 +1003,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, | ||||||
| 	while (dev_rp != local_rp && event_quota > 0) { | 	while (dev_rp != local_rp && event_quota > 0) { | ||||||
| 		enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | 		enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp); | ||||||
| 
 | 
 | ||||||
|  | 		trace_mhi_data_event(mhi_cntrl, local_rp); | ||||||
|  | 
 | ||||||
| 		chan = MHI_TRE_GET_EV_CHID(local_rp); | 		chan = MHI_TRE_GET_EV_CHID(local_rp); | ||||||
| 
 | 
 | ||||||
| 		WARN_ON(chan >= mhi_cntrl->max_chan); | 		WARN_ON(chan >= mhi_cntrl->max_chan); | ||||||
|  | @ -1243,6 +1245,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, | ||||||
| 	mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len); | 	mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len); | ||||||
| 	mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain); | 	mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain); | ||||||
| 
 | 
 | ||||||
|  | 	trace_mhi_gen_tre(mhi_cntrl, mhi_chan, mhi_tre); | ||||||
| 	/* increment WP */ | 	/* increment WP */ | ||||||
| 	mhi_add_ring_element(mhi_cntrl, tre_ring); | 	mhi_add_ring_element(mhi_cntrl, tre_ring); | ||||||
| 	mhi_add_ring_element(mhi_cntrl, buf_ring); | 	mhi_add_ring_element(mhi_cntrl, buf_ring); | ||||||
|  | @ -1337,9 +1340,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, | ||||||
| 	enum mhi_cmd_type cmd = MHI_CMD_NOP; | 	enum mhi_cmd_type cmd = MHI_CMD_NOP; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan, | 	trace_mhi_channel_command_start(mhi_cntrl, mhi_chan, to_state, TPS("Updating")); | ||||||
| 		TO_CH_STATE_TYPE_STR(to_state)); |  | ||||||
| 
 |  | ||||||
| 	switch (to_state) { | 	switch (to_state) { | ||||||
| 	case MHI_CH_STATE_TYPE_RESET: | 	case MHI_CH_STATE_TYPE_RESET: | ||||||
| 		write_lock_irq(&mhi_chan->lock); | 		write_lock_irq(&mhi_chan->lock); | ||||||
|  | @ -1406,9 +1407,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, | ||||||
| 		write_unlock_irq(&mhi_chan->lock); | 		write_unlock_irq(&mhi_chan->lock); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(dev, "%d: Channel state change to %s successful\n", | 	trace_mhi_channel_command_end(mhi_cntrl, mhi_chan, to_state, TPS("Updated")); | ||||||
| 		mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); |  | ||||||
| 
 |  | ||||||
| exit_channel_update: | exit_channel_update: | ||||||
| 	mhi_cntrl->runtime_put(mhi_cntrl); | 	mhi_cntrl->runtime_put(mhi_cntrl); | ||||||
| 	mhi_device_put(mhi_cntrl->mhi_dev); | 	mhi_device_put(mhi_cntrl->mhi_dev); | ||||||
|  |  | ||||||
|  | @ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = { | ||||||
| 	MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) | 	MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct mhi_controller_config modem_telit_fn980_hw_v1_config = { | static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = { | ||||||
| 	.max_channels = 128, | 	.max_channels = 128, | ||||||
| 	.timeout_ms = 20000, | 	.timeout_ms = 20000, | ||||||
| 	.num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), | 	.num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels), | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/wait.h> | #include <linux/wait.h> | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
|  | #include "trace.h" | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Not all MHI state transitions are synchronous. Transitions like Linkdown, |  * Not all MHI state transitions are synchronous. Transitions like Linkdown, | ||||||
|  | @ -36,7 +37,10 @@ | ||||||
|  *     M0 <--> M0 |  *     M0 <--> M0 | ||||||
|  *     M0 -> FW_DL_ERR |  *     M0 -> FW_DL_ERR | ||||||
|  *     M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 |  *     M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0 | ||||||
|  * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR |  * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS | ||||||
|  |  *     SYS_ERR_PROCESS -> SYS_ERR_FAIL | ||||||
|  |  *     SYS_ERR_FAIL -> SYS_ERR_DETECT | ||||||
|  |  *     SYS_ERR_PROCESS --> POR | ||||||
|  * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT |  * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT | ||||||
|  *     SHUTDOWN_PROCESS -> DISABLE |  *     SHUTDOWN_PROCESS -> DISABLE | ||||||
|  * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT |  * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT | ||||||
|  | @ -93,7 +97,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = { | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		MHI_PM_SYS_ERR_PROCESS, | 		MHI_PM_SYS_ERR_PROCESS, | ||||||
| 		MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS | | 		MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS | | ||||||
|  | 		MHI_PM_LD_ERR_FATAL_DETECT | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		MHI_PM_SYS_ERR_FAIL, | ||||||
|  | 		MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS | | ||||||
| 		MHI_PM_LD_ERR_FATAL_DETECT | 		MHI_PM_LD_ERR_FATAL_DETECT | ||||||
| 	}, | 	}, | ||||||
| 	/* L2 States */ | 	/* L2 States */ | ||||||
|  | @ -123,6 +132,7 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn | ||||||
| 	if (unlikely(!(dev_state_transitions[index].to_states & state))) | 	if (unlikely(!(dev_state_transitions[index].to_states & state))) | ||||||
| 		return cur_state; | 		return cur_state; | ||||||
| 
 | 
 | ||||||
|  | 	trace_mhi_tryset_pm_state(mhi_cntrl, state); | ||||||
| 	mhi_cntrl->pm_state = state; | 	mhi_cntrl->pm_state = state; | ||||||
| 	return mhi_cntrl->pm_state; | 	return mhi_cntrl->pm_state; | ||||||
| } | } | ||||||
|  | @ -629,7 +639,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) | ||||||
| 					!in_reset, timeout); | 					!in_reset, timeout); | ||||||
| 		if (!ret || in_reset) { | 		if (!ret || in_reset) { | ||||||
| 			dev_err(dev, "Device failed to exit MHI Reset state\n"); | 			dev_err(dev, "Device failed to exit MHI Reset state\n"); | ||||||
| 			goto exit_sys_error_transition; | 			write_lock_irq(&mhi_cntrl->pm_lock); | ||||||
|  | 			cur_state = mhi_tryset_pm_state(mhi_cntrl, | ||||||
|  | 							MHI_PM_SYS_ERR_FAIL); | ||||||
|  | 			write_unlock_irq(&mhi_cntrl->pm_lock); | ||||||
|  | 			/* Shutdown may have occurred, otherwise cleanup now */ | ||||||
|  | 			if (cur_state != MHI_PM_SYS_ERR_FAIL) | ||||||
|  | 				goto exit_sys_error_transition; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
|  | @ -758,7 +774,6 @@ void mhi_pm_st_worker(struct work_struct *work) | ||||||
| 	struct mhi_controller *mhi_cntrl = container_of(work, | 	struct mhi_controller *mhi_cntrl = container_of(work, | ||||||
| 							struct mhi_controller, | 							struct mhi_controller, | ||||||
| 							st_worker); | 							st_worker); | ||||||
| 	struct device *dev = &mhi_cntrl->mhi_dev->dev; |  | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irq(&mhi_cntrl->transition_lock); | 	spin_lock_irq(&mhi_cntrl->transition_lock); | ||||||
| 	list_splice_tail_init(&mhi_cntrl->transition_list, &head); | 	list_splice_tail_init(&mhi_cntrl->transition_list, &head); | ||||||
|  | @ -766,8 +781,8 @@ void mhi_pm_st_worker(struct work_struct *work) | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry_safe(itr, tmp, &head, node) { | 	list_for_each_entry_safe(itr, tmp, &head, node) { | ||||||
| 		list_del(&itr->node); | 		list_del(&itr->node); | ||||||
| 		dev_dbg(dev, "Handling state transition: %s\n", | 
 | ||||||
| 			TO_DEV_STATE_TRANS_STR(itr->state)); | 		trace_mhi_pm_st_transition(mhi_cntrl, itr->state); | ||||||
| 
 | 
 | ||||||
| 		switch (itr->state) { | 		switch (itr->state) { | ||||||
| 		case DEV_ST_TRANSITION_PBL: | 		case DEV_ST_TRANSITION_PBL: | ||||||
|  |  | ||||||
							
								
								
									
										282
									
								
								drivers/bus/mhi/host/trace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								drivers/bus/mhi/host/trace.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,282 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0-only */ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #undef TRACE_SYSTEM | ||||||
|  | #define TRACE_SYSTEM mhi_host | ||||||
|  | 
 | ||||||
|  | #if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ) | ||||||
|  | #define _TRACE_EVENT_MHI_HOST_H | ||||||
|  | 
 | ||||||
|  | #include <linux/tracepoint.h> | ||||||
|  | #include <linux/trace_seq.h> | ||||||
|  | #include "../common.h" | ||||||
|  | #include "internal.h" | ||||||
|  | 
 | ||||||
|  | #undef mhi_state | ||||||
|  | #undef mhi_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_state(a, b)		TRACE_DEFINE_ENUM(MHI_STATE_##a); | ||||||
|  | #define mhi_state_end(a, b)	TRACE_DEFINE_ENUM(MHI_STATE_##a); | ||||||
|  | 
 | ||||||
|  | MHI_STATE_LIST | ||||||
|  | 
 | ||||||
|  | #undef mhi_state | ||||||
|  | #undef mhi_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_state(a, b)		{ MHI_STATE_##a, b }, | ||||||
|  | #define mhi_state_end(a, b)	{ MHI_STATE_##a, b } | ||||||
|  | 
 | ||||||
|  | #undef mhi_pm_state | ||||||
|  | #undef mhi_pm_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_pm_state(a, b)		TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); | ||||||
|  | #define mhi_pm_state_end(a, b)		TRACE_DEFINE_ENUM(MHI_PM_STATE_##a); | ||||||
|  | 
 | ||||||
|  | MHI_PM_STATE_LIST | ||||||
|  | 
 | ||||||
|  | #undef mhi_pm_state | ||||||
|  | #undef mhi_pm_state_end | ||||||
|  | 
 | ||||||
|  | #define mhi_pm_state(a, b)		{ MHI_PM_STATE_##a, b }, | ||||||
|  | #define mhi_pm_state_end(a, b)		{ MHI_PM_STATE_##a, b } | ||||||
|  | 
 | ||||||
|  | #undef mhi_ee | ||||||
|  | #undef mhi_ee_end | ||||||
|  | 
 | ||||||
|  | #define mhi_ee(a, b)			TRACE_DEFINE_ENUM(MHI_EE_##a); | ||||||
|  | #define mhi_ee_end(a, b)		TRACE_DEFINE_ENUM(MHI_EE_##a); | ||||||
|  | 
 | ||||||
|  | MHI_EE_LIST | ||||||
|  | 
 | ||||||
|  | #undef mhi_ee | ||||||
|  | #undef mhi_ee_end | ||||||
|  | 
 | ||||||
|  | #define mhi_ee(a, b)			{ MHI_EE_##a, b }, | ||||||
|  | #define mhi_ee_end(a, b)		{ MHI_EE_##a, b } | ||||||
|  | 
 | ||||||
|  | #undef ch_state_type | ||||||
|  | #undef ch_state_type_end | ||||||
|  | 
 | ||||||
|  | #define ch_state_type(a, b)		TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); | ||||||
|  | #define ch_state_type_end(a, b)		TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a); | ||||||
|  | 
 | ||||||
|  | MHI_CH_STATE_TYPE_LIST | ||||||
|  | 
 | ||||||
|  | #undef ch_state_type | ||||||
|  | #undef ch_state_type_end | ||||||
|  | 
 | ||||||
|  | #define ch_state_type(a, b)		{ MHI_CH_STATE_TYPE_##a, b }, | ||||||
|  | #define ch_state_type_end(a, b)		{ MHI_CH_STATE_TYPE_##a, b } | ||||||
|  | 
 | ||||||
|  | #undef dev_st_trans | ||||||
|  | #undef dev_st_trans_end | ||||||
|  | 
 | ||||||
|  | #define dev_st_trans(a, b)		TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); | ||||||
|  | #define dev_st_trans_end(a, b)		TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a); | ||||||
|  | 
 | ||||||
|  | DEV_ST_TRANSITION_LIST | ||||||
|  | 
 | ||||||
|  | #undef dev_st_trans | ||||||
|  | #undef dev_st_trans_end | ||||||
|  | 
 | ||||||
|  | #define dev_st_trans(a, b)		{ DEV_ST_TRANSITION_##a, b }, | ||||||
|  | #define dev_st_trans_end(a, b)		{ DEV_ST_TRANSITION_##a, b } | ||||||
|  | 
 | ||||||
|  | #define TPS(x)	tracepoint_string(x) | ||||||
|  | 
 | ||||||
|  | TRACE_EVENT(mhi_gen_tre, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, | ||||||
|  | 		 struct mhi_ring_element *mhi_tre), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, mhi_chan, mhi_tre), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(int, ch_num) | ||||||
|  | 		__field(void *, wp) | ||||||
|  | 		__field(__le64, tre_ptr) | ||||||
|  | 		__field(__le32, dword0) | ||||||
|  | 		__field(__le32, dword1) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		__entry->ch_num = mhi_chan->chan; | ||||||
|  | 		__entry->wp = mhi_tre; | ||||||
|  | 		__entry->tre_ptr = mhi_tre->ptr; | ||||||
|  | 		__entry->dword0 = mhi_tre->dword[0]; | ||||||
|  | 		__entry->dword1 = mhi_tre->dword[1]; | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n", | ||||||
|  | 		  __get_str(name), __entry->ch_num, __entry->wp, __entry->tre_ptr, | ||||||
|  | 		  __entry->dword0, __entry->dword1) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | TRACE_EVENT(mhi_intvec_states, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, int dev_ee, int dev_state), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, dev_ee, dev_state), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(int, local_ee) | ||||||
|  | 		__field(int, state) | ||||||
|  | 		__field(int, dev_ee) | ||||||
|  | 		__field(int, dev_state) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		__entry->local_ee = mhi_cntrl->ee; | ||||||
|  | 		__entry->state = mhi_cntrl->dev_state; | ||||||
|  | 		__entry->dev_ee = dev_ee; | ||||||
|  | 		__entry->dev_state = dev_state; | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: Local EE: %s State: %s Device EE: %s Dev State: %s\n", | ||||||
|  | 		  __get_str(name), | ||||||
|  | 		  __print_symbolic(__entry->local_ee, MHI_EE_LIST), | ||||||
|  | 		  __print_symbolic(__entry->state, MHI_STATE_LIST), | ||||||
|  | 		  __print_symbolic(__entry->dev_ee, MHI_EE_LIST), | ||||||
|  | 		  __print_symbolic(__entry->dev_state, MHI_STATE_LIST)) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | TRACE_EVENT(mhi_tryset_pm_state, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, int pm_state), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, pm_state), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(int, pm_state) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		if (pm_state) | ||||||
|  | 			pm_state = __fls(pm_state); | ||||||
|  | 		__entry->pm_state = pm_state; | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: PM state: %s\n", __get_str(name), | ||||||
|  | 		  __print_symbolic(__entry->pm_state, MHI_PM_STATE_LIST)) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DECLARE_EVENT_CLASS(mhi_process_event_ring, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, rp), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(__le32, dword0) | ||||||
|  | 		__field(__le32, dword1) | ||||||
|  | 		__field(int, state) | ||||||
|  | 		__field(__le64, ptr) | ||||||
|  | 		__field(void *, rp) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		__entry->rp = rp; | ||||||
|  | 		__entry->ptr = rp->ptr; | ||||||
|  | 		__entry->dword0 = rp->dword[0]; | ||||||
|  | 		__entry->dword1 = rp->dword[1]; | ||||||
|  | 		__entry->state = MHI_TRE_GET_EV_STATE(rp); | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x State: %s\n", | ||||||
|  | 		  __get_str(name), __entry->rp, __entry->ptr, __entry->dword0, | ||||||
|  | 		  __entry->dword1, __print_symbolic(__entry->state, MHI_STATE_LIST)) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DEFINE_EVENT(mhi_process_event_ring, mhi_data_event, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, rp) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DEFINE_EVENT(mhi_process_event_ring, mhi_ctrl_event, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, rp) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DECLARE_EVENT_CLASS(mhi_update_channel_state, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||||||
|  | 		 const char *reason), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, mhi_chan, state, reason), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(int, ch_num) | ||||||
|  | 		__field(int, state) | ||||||
|  | 		__field(const char *, reason) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		__entry->ch_num = mhi_chan->chan; | ||||||
|  | 		__entry->state = state; | ||||||
|  | 		__entry->reason = reason; | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: chan%d: %s state to: %s\n", | ||||||
|  | 		  __get_str(name),  __entry->ch_num, __entry->reason, | ||||||
|  | 		  __print_symbolic(__entry->state, MHI_CH_STATE_TYPE_LIST)) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_start, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||||||
|  | 		 const char *reason), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, mhi_chan, state, reason) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_end, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state, | ||||||
|  | 		 const char *reason), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, mhi_chan, state, reason) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | TRACE_EVENT(mhi_pm_st_transition, | ||||||
|  | 
 | ||||||
|  | 	TP_PROTO(struct mhi_controller *mhi_cntrl, int state), | ||||||
|  | 
 | ||||||
|  | 	TP_ARGS(mhi_cntrl, state), | ||||||
|  | 
 | ||||||
|  | 	TP_STRUCT__entry( | ||||||
|  | 		__string(name, mhi_cntrl->mhi_dev->name) | ||||||
|  | 		__field(int, state) | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_fast_assign( | ||||||
|  | 		__assign_str(name, mhi_cntrl->mhi_dev->name); | ||||||
|  | 		__entry->state = state; | ||||||
|  | 	), | ||||||
|  | 
 | ||||||
|  | 	TP_printk("%s: Handling state transition: %s\n", __get_str(name), | ||||||
|  | 		  __print_symbolic(__entry->state, DEV_ST_TRANSITION_LIST)) | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | #undef TRACE_INCLUDE_PATH | ||||||
|  | #define TRACE_INCLUDE_PATH ../../drivers/bus/mhi/host | ||||||
|  | #undef TRACE_INCLUDE_FILE | ||||||
|  | #define TRACE_INCLUDE_FILE trace | ||||||
|  | 
 | ||||||
|  | #include <trace/define_trace.h> | ||||||
|  | @ -8,3 +8,7 @@ | ||||||
| ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS | ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_CDX_BUS) += cdx.o controller/ | obj-$(CONFIG_CDX_BUS) += cdx.o controller/ | ||||||
|  | 
 | ||||||
|  | ifdef CONFIG_GENERIC_MSI_IRQ | ||||||
|  | obj-$(CONFIG_CDX_BUS) += cdx_msi.o | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
|  | #include <linux/irqdomain.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/of.h> | #include <linux/of.h> | ||||||
| #include <linux/of_device.h> | #include <linux/of_device.h> | ||||||
|  | @ -302,8 +303,19 @@ static int cdx_probe(struct device *dev) | ||||||
| { | { | ||||||
| 	struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); | 	struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); | ||||||
| 	struct cdx_device *cdx_dev = to_cdx_device(dev); | 	struct cdx_device *cdx_dev = to_cdx_device(dev); | ||||||
|  | 	struct cdx_controller *cdx = cdx_dev->cdx; | ||||||
| 	int error; | 	int error; | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Setup MSI device data so that generic MSI alloc/free can | ||||||
|  | 	 * be used by the device driver. | ||||||
|  | 	 */ | ||||||
|  | 	if (cdx->msi_domain) { | ||||||
|  | 		error = msi_setup_device_data(&cdx_dev->dev); | ||||||
|  | 		if (error) | ||||||
|  | 			return error; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	error = cdx_drv->probe(cdx_dev); | 	error = cdx_drv->probe(cdx_dev); | ||||||
| 	if (error) { | 	if (error) { | ||||||
| 		dev_err_probe(dev, error, "%s failed\n", __func__); | 		dev_err_probe(dev, error, "%s failed\n", __func__); | ||||||
|  | @ -787,6 +799,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) | ||||||
| 
 | 
 | ||||||
| 	/* Populate CDX dev params */ | 	/* Populate CDX dev params */ | ||||||
| 	cdx_dev->req_id = dev_params->req_id; | 	cdx_dev->req_id = dev_params->req_id; | ||||||
|  | 	cdx_dev->msi_dev_id = dev_params->msi_dev_id; | ||||||
| 	cdx_dev->vendor = dev_params->vendor; | 	cdx_dev->vendor = dev_params->vendor; | ||||||
| 	cdx_dev->device = dev_params->device; | 	cdx_dev->device = dev_params->device; | ||||||
| 	cdx_dev->subsystem_vendor = dev_params->subsys_vendor; | 	cdx_dev->subsystem_vendor = dev_params->subsys_vendor; | ||||||
|  | @ -804,12 +817,19 @@ int cdx_device_add(struct cdx_dev_params *dev_params) | ||||||
| 	cdx_dev->dev.bus = &cdx_bus_type; | 	cdx_dev->dev.bus = &cdx_bus_type; | ||||||
| 	cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; | 	cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; | ||||||
| 	cdx_dev->dev.release = cdx_device_release; | 	cdx_dev->dev.release = cdx_device_release; | ||||||
|  | 	cdx_dev->msi_write_pending = false; | ||||||
|  | 	mutex_init(&cdx_dev->irqchip_lock); | ||||||
| 
 | 
 | ||||||
| 	/* Set Name */ | 	/* Set Name */ | ||||||
| 	dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", | 	dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", | ||||||
| 		     ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), | 		     ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), | ||||||
| 		     cdx_dev->dev_num); | 		     cdx_dev->dev_num); | ||||||
| 
 | 
 | ||||||
|  | 	if (cdx->msi_domain) { | ||||||
|  | 		cdx_dev->num_msi = dev_params->num_msi; | ||||||
|  | 		dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ret = device_add(&cdx_dev->dev); | 	ret = device_add(&cdx_dev->dev); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		dev_err(&cdx_dev->dev, | 		dev_err(&cdx_dev->dev, | ||||||
|  |  | ||||||
|  | @ -25,6 +25,8 @@ | ||||||
|  * @req_id: Requestor ID associated with CDX device |  * @req_id: Requestor ID associated with CDX device | ||||||
|  * @class: Class of the CDX Device |  * @class: Class of the CDX Device | ||||||
|  * @revision: Revision of the CDX device |  * @revision: Revision of the CDX device | ||||||
|  |  * @msi_dev_id: MSI device ID associated with CDX device | ||||||
|  |  * @num_msi: Number of MSI's supported by the device | ||||||
|  */ |  */ | ||||||
| struct cdx_dev_params { | struct cdx_dev_params { | ||||||
| 	struct cdx_controller *cdx; | 	struct cdx_controller *cdx; | ||||||
|  | @ -40,6 +42,8 @@ struct cdx_dev_params { | ||||||
| 	u32 req_id; | 	u32 req_id; | ||||||
| 	u32 class; | 	u32 class; | ||||||
| 	u8 revision; | 	u8 revision; | ||||||
|  | 	u32 msi_dev_id; | ||||||
|  | 	u32 num_msi; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -79,4 +83,12 @@ int cdx_device_add(struct cdx_dev_params *dev_params); | ||||||
|  */ |  */ | ||||||
| struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); | struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * cdx_msi_domain_init - Init the CDX bus MSI domain. | ||||||
|  |  * @dev: Device of the CDX bus controller | ||||||
|  |  * | ||||||
|  |  * Return: CDX MSI domain, NULL on failure | ||||||
|  |  */ | ||||||
|  | struct irq_domain *cdx_msi_domain_init(struct device *dev); | ||||||
|  | 
 | ||||||
| #endif /* _CDX_H_ */ | #endif /* _CDX_H_ */ | ||||||
|  |  | ||||||
							
								
								
									
										192
									
								
								drivers/cdx/cdx_msi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								drivers/cdx/cdx_msi.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,192 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * AMD CDX bus driver MSI support | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/of.h> | ||||||
|  | #include <linux/of_device.h> | ||||||
|  | #include <linux/of_address.h> | ||||||
|  | #include <linux/of_irq.h> | ||||||
|  | #include <linux/irq.h> | ||||||
|  | #include <linux/irqdomain.h> | ||||||
|  | #include <linux/msi.h> | ||||||
|  | #include <linux/cdx/cdx_bus.h> | ||||||
|  | 
 | ||||||
|  | #include "cdx.h" | ||||||
|  | 
 | ||||||
|  | static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg) | ||||||
|  | { | ||||||
|  | 	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||||||
|  | 	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||||||
|  | 
 | ||||||
|  | 	/* We would not operate on msg here rather we wait for irq_bus_sync_unlock()
 | ||||||
|  | 	 * to be called from preemptible task context. | ||||||
|  | 	 */ | ||||||
|  | 	msi_desc->msg = *msg; | ||||||
|  | 	cdx_dev->msi_write_pending = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdx_msi_write_irq_lock(struct irq_data *irq_data) | ||||||
|  | { | ||||||
|  | 	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||||||
|  | 	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&cdx_dev->irqchip_lock); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdx_msi_write_irq_unlock(struct irq_data *irq_data) | ||||||
|  | { | ||||||
|  | 	struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); | ||||||
|  | 	struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); | ||||||
|  | 	struct cdx_controller *cdx = cdx_dev->cdx; | ||||||
|  | 	struct cdx_device_config dev_config; | ||||||
|  | 
 | ||||||
|  | 	if (!cdx_dev->msi_write_pending) { | ||||||
|  | 		mutex_unlock(&cdx_dev->irqchip_lock); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cdx_dev->msi_write_pending = false; | ||||||
|  | 	mutex_unlock(&cdx_dev->irqchip_lock); | ||||||
|  | 
 | ||||||
|  | 	dev_config.msi.msi_index = msi_desc->msi_index; | ||||||
|  | 	dev_config.msi.data = msi_desc->msg.data; | ||||||
|  | 	dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * dev_configure() is a controller callback which can interact with | ||||||
|  | 	 * Firmware or other entities, and can sleep, so invoke this function | ||||||
|  | 	 * outside of the mutex held region. | ||||||
|  | 	 */ | ||||||
|  | 	dev_config.type = CDX_DEV_MSI_CONF; | ||||||
|  | 	if (cdx->ops->dev_configure) | ||||||
|  | 		cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int cdx_enable_msi(struct cdx_device *cdx_dev) | ||||||
|  | { | ||||||
|  | 	struct cdx_controller *cdx = cdx_dev->cdx; | ||||||
|  | 	struct cdx_device_config dev_config; | ||||||
|  | 
 | ||||||
|  | 	dev_config.type = CDX_DEV_MSI_ENABLE; | ||||||
|  | 	dev_config.msi_enable = true; | ||||||
|  | 	if (cdx->ops->dev_configure) { | ||||||
|  | 		return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, | ||||||
|  | 					       &dev_config); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return -EOPNOTSUPP; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(cdx_enable_msi); | ||||||
|  | 
 | ||||||
|  | void cdx_disable_msi(struct cdx_device *cdx_dev) | ||||||
|  | { | ||||||
|  | 	struct cdx_controller *cdx = cdx_dev->cdx; | ||||||
|  | 	struct cdx_device_config dev_config; | ||||||
|  | 
 | ||||||
|  | 	dev_config.type = CDX_DEV_MSI_ENABLE; | ||||||
|  | 	dev_config.msi_enable = false; | ||||||
|  | 	if (cdx->ops->dev_configure) | ||||||
|  | 		cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(cdx_disable_msi); | ||||||
|  | 
 | ||||||
|  | static struct irq_chip cdx_msi_irq_chip = { | ||||||
|  | 	.name			= "CDX-MSI", | ||||||
|  | 	.irq_mask		= irq_chip_mask_parent, | ||||||
|  | 	.irq_unmask		= irq_chip_unmask_parent, | ||||||
|  | 	.irq_eoi		= irq_chip_eoi_parent, | ||||||
|  | 	.irq_set_affinity	= msi_domain_set_affinity, | ||||||
|  | 	.irq_write_msi_msg	= cdx_msi_write_msg, | ||||||
|  | 	.irq_bus_lock		= cdx_msi_write_irq_lock, | ||||||
|  | 	.irq_bus_sync_unlock	= cdx_msi_write_irq_unlock | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Convert an msi_desc to a unique identifier within the domain. */ | ||||||
|  | static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev, | ||||||
|  | 					     struct msi_desc *desc) | ||||||
|  | { | ||||||
|  | 	return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) | ||||||
|  | { | ||||||
|  | 	arg->desc = desc; | ||||||
|  | 	arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int cdx_msi_prepare(struct irq_domain *msi_domain, | ||||||
|  | 			   struct device *dev, | ||||||
|  | 			   int nvec, msi_alloc_info_t *info) | ||||||
|  | { | ||||||
|  | 	struct cdx_device *cdx_dev = to_cdx_device(dev); | ||||||
|  | 	struct device *parent = cdx_dev->cdx->dev; | ||||||
|  | 	struct msi_domain_info *msi_info; | ||||||
|  | 	u32 dev_id; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	/* Retrieve device ID from requestor ID using parent device */ | ||||||
|  | 	ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask", | ||||||
|  | 			NULL, &dev_id); | ||||||
|  | 	if (ret) { | ||||||
|  | 		dev_err(dev, "of_map_id failed for MSI: %d\n", ret); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | #ifdef GENERIC_MSI_DOMAIN_OPS | ||||||
|  | 	/* Set the device Id to be passed to the GIC-ITS */ | ||||||
|  | 	info->scratchpad[0].ul = dev_id; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	msi_info = msi_get_domain_info(msi_domain->parent); | ||||||
|  | 
 | ||||||
|  | 	return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct msi_domain_ops cdx_msi_ops = { | ||||||
|  | 	.msi_prepare	= cdx_msi_prepare, | ||||||
|  | 	.set_desc	= cdx_msi_set_desc | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct msi_domain_info cdx_msi_domain_info = { | ||||||
|  | 	.ops	= &cdx_msi_ops, | ||||||
|  | 	.chip	= &cdx_msi_irq_chip, | ||||||
|  | 	.flags	= MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | | ||||||
|  | 		  MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct irq_domain *cdx_msi_domain_init(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct device_node *np = dev->of_node; | ||||||
|  | 	struct fwnode_handle *fwnode_handle; | ||||||
|  | 	struct irq_domain *cdx_msi_domain; | ||||||
|  | 	struct device_node *parent_node; | ||||||
|  | 	struct irq_domain *parent; | ||||||
|  | 
 | ||||||
|  | 	fwnode_handle = of_node_to_fwnode(np); | ||||||
|  | 
 | ||||||
|  | 	parent_node = of_parse_phandle(np, "msi-map", 1); | ||||||
|  | 	if (!parent_node) { | ||||||
|  | 		dev_err(dev, "msi-map not present on cdx controller\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS); | ||||||
|  | 	if (!parent || !msi_get_domain_info(parent)) { | ||||||
|  | 		dev_err(dev, "unable to locate ITS domain\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent); | ||||||
|  | 	if (!cdx_msi_domain) { | ||||||
|  | 		dev_err(dev, "unable to create CDX-MSI domain\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dev_dbg(dev, "CDX-MSI domain created\n"); | ||||||
|  | 
 | ||||||
|  | 	return cdx_msi_domain; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER); | ||||||
|  | @ -9,6 +9,7 @@ if CDX_BUS | ||||||
| 
 | 
 | ||||||
| config CDX_CONTROLLER | config CDX_CONTROLLER | ||||||
| 	tristate "CDX bus controller" | 	tristate "CDX bus controller" | ||||||
|  | 	select GENERIC_MSI_IRQ | ||||||
| 	select REMOTEPROC | 	select REMOTEPROC | ||||||
| 	select RPMSG | 	select RPMSG | ||||||
| 	help | 	help | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include <linux/platform_device.h> | #include <linux/platform_device.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/cdx/cdx_bus.h> | #include <linux/cdx/cdx_bus.h> | ||||||
|  | #include <linux/irqdomain.h> | ||||||
| 
 | 
 | ||||||
| #include "cdx_controller.h" | #include "cdx_controller.h" | ||||||
| #include "../cdx.h" | #include "../cdx.h" | ||||||
|  | @ -60,9 +61,19 @@ static int cdx_configure_device(struct cdx_controller *cdx, | ||||||
| 				u8 bus_num, u8 dev_num, | 				u8 bus_num, u8 dev_num, | ||||||
| 				struct cdx_device_config *dev_config) | 				struct cdx_device_config *dev_config) | ||||||
| { | { | ||||||
|  | 	u16 msi_index; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
|  | 	u32 data; | ||||||
|  | 	u64 addr; | ||||||
| 
 | 
 | ||||||
| 	switch (dev_config->type) { | 	switch (dev_config->type) { | ||||||
|  | 	case CDX_DEV_MSI_CONF: | ||||||
|  | 		msi_index = dev_config->msi.msi_index; | ||||||
|  | 		data = dev_config->msi.data; | ||||||
|  | 		addr = dev_config->msi.addr; | ||||||
|  | 
 | ||||||
|  | 		ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data); | ||||||
|  | 		break; | ||||||
| 	case CDX_DEV_RESET_CONF: | 	case CDX_DEV_RESET_CONF: | ||||||
| 		ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); | 		ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); | ||||||
| 		break; | 		break; | ||||||
|  | @ -70,6 +81,9 @@ static int cdx_configure_device(struct cdx_controller *cdx, | ||||||
| 		ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, | 		ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, | ||||||
| 						 dev_config->bus_master_enable); | 						 dev_config->bus_master_enable); | ||||||
| 		break; | 		break; | ||||||
|  | 	case CDX_DEV_MSI_ENABLE: | ||||||
|  | 		ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable); | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		ret = -EINVAL; | 		ret = -EINVAL; | ||||||
| 	} | 	} | ||||||
|  | @ -178,6 +192,14 @@ static int xlnx_cdx_probe(struct platform_device *pdev) | ||||||
| 	cdx->priv = cdx_mcdi; | 	cdx->priv = cdx_mcdi; | ||||||
| 	cdx->ops = &cdx_ops; | 	cdx->ops = &cdx_ops; | ||||||
| 
 | 
 | ||||||
|  | 	/* Create MSI domain */ | ||||||
|  | 	cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); | ||||||
|  | 	if (!cdx->msi_domain) { | ||||||
|  | 		dev_err(&pdev->dev, "cdx_msi_domain_init() failed"); | ||||||
|  | 		ret = -ENODEV; | ||||||
|  | 		goto cdx_msi_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ret = cdx_setup_rpmsg(pdev); | 	ret = cdx_setup_rpmsg(pdev); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		if (ret != -EPROBE_DEFER) | 		if (ret != -EPROBE_DEFER) | ||||||
|  | @ -189,6 +211,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev) | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| cdx_rpmsg_fail: | cdx_rpmsg_fail: | ||||||
|  | 	irq_domain_remove(cdx->msi_domain); | ||||||
|  | cdx_msi_fail: | ||||||
| 	kfree(cdx); | 	kfree(cdx); | ||||||
| cdx_alloc_fail: | cdx_alloc_fail: | ||||||
| 	cdx_mcdi_finish(cdx_mcdi); | 	cdx_mcdi_finish(cdx_mcdi); | ||||||
|  | @ -205,6 +229,7 @@ static int xlnx_cdx_remove(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	cdx_destroy_rpmsg(pdev); | 	cdx_destroy_rpmsg(pdev); | ||||||
| 
 | 
 | ||||||
|  | 	irq_domain_remove(cdx->msi_domain); | ||||||
| 	kfree(cdx); | 	kfree(cdx); | ||||||
| 
 | 
 | ||||||
| 	cdx_mcdi_finish(cdx_mcdi); | 	cdx_mcdi_finish(cdx_mcdi); | ||||||
|  |  | ||||||
|  | @ -455,6 +455,12 @@ | ||||||
| #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST			84 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST			84 | ||||||
| #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN			4 | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN			4 | ||||||
| 
 | 
 | ||||||
|  | /* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2 msgresponse */ | ||||||
|  | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN				92 | ||||||
|  | /* Requester ID used by device for GIC ITS DeviceID */ | ||||||
|  | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST	88 | ||||||
|  | #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_LEN		4 | ||||||
|  | 
 | ||||||
| /***********************************/ | /***********************************/ | ||||||
| /*
 | /*
 | ||||||
|  * MC_CMD_CDX_BUS_DOWN |  * MC_CMD_CDX_BUS_DOWN | ||||||
|  | @ -616,6 +622,64 @@ | ||||||
| #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN	2 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN	2 | ||||||
| #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH	1 | #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH	1 | ||||||
| 
 | 
 | ||||||
|  | /***********************************/ | ||||||
|  | /*
 | ||||||
|  |  * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG | ||||||
|  |  * Populates the MSI message to be used by the hardware to raise the specified | ||||||
|  |  * interrupt vector. Versal-net implementation specific limitations are that | ||||||
|  |  * only 4 CDX devices with MSI interrupt capability are supported and all | ||||||
|  |  * vectors within a device must use the same write address. The command will | ||||||
|  |  * return EINVAL if any of these limitations is violated. | ||||||
|  |  */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG					0x9 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET				0x9 | ||||||
|  | #undef MC_CMD_0x9_PRIVILEGE_CTG | ||||||
|  | 
 | ||||||
|  | #define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN | ||||||
|  | 
 | ||||||
|  | /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN				28 | ||||||
|  | /* Device bus number, in range 0 to BUS_COUNT-1 */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST			0 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN			4 | ||||||
|  | /* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST			4 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN			4 | ||||||
|  | /*
 | ||||||
|  |  * Device-relative MSI vector number. Must be < MSI_COUNT reported for the | ||||||
|  |  * device. | ||||||
|  |  */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST		8 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN		4 | ||||||
|  | /* Reserved (alignment) */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST		12 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN			4 | ||||||
|  | /*
 | ||||||
|  |  * MSI address to be used by the hardware. Typically, on ARM systems this | ||||||
|  |  * address is translated by the IOMMU (if enabled) and it is the responsibility | ||||||
|  |  * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA | ||||||
|  |  * here. | ||||||
|  |  */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST		16 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN		8 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST		16 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN		4 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN		128 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH		32 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST		20 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN		4 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN		160 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH		32 | ||||||
|  | /*
 | ||||||
|  |  * MSI data to be used by the hardware. On versal-net, only the lower 16-bits | ||||||
|  |  * are used, the remaining bits are ignored and should be set to zero. | ||||||
|  |  */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST		24 | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN			4 | ||||||
|  | 
 | ||||||
|  | /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */ | ||||||
|  | #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN				0 | ||||||
|  | 
 | ||||||
| /***********************************/ | /***********************************/ | ||||||
| /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ | /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ | ||||||
| #define MC_CMD_V2_EXTN					0x7f | #define MC_CMD_V2_EXTN					0x7f | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, | ||||||
| 			    u8 bus_num, u8 dev_num, | 			    u8 bus_num, u8 dev_num, | ||||||
| 			    struct cdx_dev_params *dev_params) | 			    struct cdx_dev_params *dev_params) | ||||||
| { | { | ||||||
| 	MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); | 	MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN); | ||||||
| 	MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); | 	MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); | ||||||
| 	struct resource *res = &dev_params->res[0]; | 	struct resource *res = &dev_params->res[0]; | ||||||
| 	size_t outlen; | 	size_t outlen; | ||||||
|  | @ -64,7 +64,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) | 	if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN) | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 
 | 
 | ||||||
| 	dev_params->bus_num = bus_num; | 	dev_params->bus_num = bus_num; | ||||||
|  | @ -73,6 +73,9 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, | ||||||
| 	req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); | 	req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); | ||||||
| 	dev_params->req_id = req_id; | 	dev_params->req_id = req_id; | ||||||
| 
 | 
 | ||||||
|  | 	dev_params->msi_dev_id = MCDI_DWORD(outbuf, | ||||||
|  | 					    CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); | ||||||
|  | 
 | ||||||
| 	dev_params->res_count = 0; | 	dev_params->res_count = 0; | ||||||
| 	if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { | 	if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { | ||||||
| 		res[dev_params->res_count].start = | 		res[dev_params->res_count].start = | ||||||
|  | @ -127,6 +130,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, | ||||||
| 	dev_params->class = MCDI_DWORD(outbuf, | 	dev_params->class = MCDI_DWORD(outbuf, | ||||||
| 				       CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; | 				       CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; | ||||||
| 	dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); | 	dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); | ||||||
|  | 	dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -155,6 +159,24 @@ int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, | ||||||
|  | 		       u32 msi_vector, u64 msi_address, u32 msi_data) | ||||||
|  | { | ||||||
|  | 	MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); | ||||||
|  | 	MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); | ||||||
|  | 	MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); | ||||||
|  | 	MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); | ||||||
|  | 	MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); | ||||||
|  | 
 | ||||||
|  | 	ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf), | ||||||
|  | 			   NULL, 0, NULL); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) | int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) | ||||||
| { | { | ||||||
| 	MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); | 	MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); | ||||||
|  | @ -226,3 +248,10 @@ int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||||||
| 	return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, | 	return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, | ||||||
| 			MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); | 			MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||||||
|  | 			u8 dev_num, bool enable) | ||||||
|  | { | ||||||
|  | 	return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, | ||||||
|  | 			MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -65,6 +65,26 @@ int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num); | ||||||
|  */ |  */ | ||||||
| int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); | int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * cdx_mcdi_write_msi - Write MSI configuration for CDX device | ||||||
|  |  * @cdx: pointer to MCDI interface. | ||||||
|  |  * @bus_num: Bus number. | ||||||
|  |  * @dev_num: Device number. | ||||||
|  |  * @msi_vector: Device-relative MSI vector number. | ||||||
|  |  *	Must be < MSI_COUNT reported for the device. | ||||||
|  |  * @msi_address: MSI address to be used by the hardware. Typically, on ARM | ||||||
|  |  *	systems this address is translated by the IOMMU (if enabled) and | ||||||
|  |  *	it is the responsibility of the entity managing the IOMMU (APU kernel) | ||||||
|  |  *	to supply the correct IOVA here. | ||||||
|  |  * @msi_data: MSI data to be used by the hardware. On versal-net, only the | ||||||
|  |  *	lower 16-bits are used, the remaining bits are ignored and should be | ||||||
|  |  *	set to zero. | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success, <0 on failure | ||||||
|  |  */ | ||||||
|  | int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, | ||||||
|  | 		       u32 msi_vector, u64 msi_address, u32 msi_data); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num |  * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num | ||||||
|  * @cdx: pointer to MCDI interface. |  * @cdx: pointer to MCDI interface. | ||||||
|  | @ -89,4 +109,17 @@ int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, | ||||||
| int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, | int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||||||
| 			       u8 dev_num, bool enable); | 			       u8 dev_num, bool enable); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented | ||||||
|  |  *			 by bus_num:dev_num | ||||||
|  |  * @cdx: pointer to MCDI interface. | ||||||
|  |  * @bus_num: Bus number. | ||||||
|  |  * @dev_num: Device number. | ||||||
|  |  * @enable: Enable msi's if set, disable otherwise. | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success, <0 on failure | ||||||
|  |  */ | ||||||
|  | int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, | ||||||
|  | 			u8 dev_num, bool enable); | ||||||
|  | 
 | ||||||
| #endif /* CDX_MCDI_FUNCTIONS_H */ | #endif /* CDX_MCDI_FUNCTIONS_H */ | ||||||
|  |  | ||||||
|  | @ -87,7 +87,6 @@ struct hpets { | ||||||
| 	struct hpets *hp_next; | 	struct hpets *hp_next; | ||||||
| 	struct hpet __iomem *hp_hpet; | 	struct hpet __iomem *hp_hpet; | ||||||
| 	unsigned long hp_hpet_phys; | 	unsigned long hp_hpet_phys; | ||||||
| 	struct clocksource *hp_clocksource; |  | ||||||
| 	unsigned long long hp_tick_freq; | 	unsigned long long hp_tick_freq; | ||||||
| 	unsigned long hp_delta; | 	unsigned long hp_delta; | ||||||
| 	unsigned int hp_ntimer; | 	unsigned int hp_ntimer; | ||||||
|  |  | ||||||
|  | @ -636,11 +636,11 @@ static int hwicap_setup(struct platform_device *pdev, int id, | ||||||
| 		retval = -ENOMEM; | 		retval = -ENOMEM; | ||||||
| 		goto failed; | 		goto failed; | ||||||
| 	} | 	} | ||||||
| 	dev_set_drvdata(dev, (void *)drvdata); | 	dev_set_drvdata(dev, drvdata); | ||||||
| 
 | 
 | ||||||
| 	drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); | 	drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); | ||||||
| 	if (!drvdata->base_address) { | 	if (IS_ERR(drvdata->base_address)) { | ||||||
| 		retval = -ENODEV; | 		retval = PTR_ERR(drvdata->base_address); | ||||||
| 		goto failed; | 		goto failed; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -64,19 +64,17 @@ static int xilly_drv_probe(struct platform_device *op) | ||||||
| 	return xillybus_endpoint_discovery(endpoint); | 	return xillybus_endpoint_discovery(endpoint); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int xilly_drv_remove(struct platform_device *op) | static void xilly_drv_remove(struct platform_device *op) | ||||||
| { | { | ||||||
| 	struct device *dev = &op->dev; | 	struct device *dev = &op->dev; | ||||||
| 	struct xilly_endpoint *endpoint = dev_get_drvdata(dev); | 	struct xilly_endpoint *endpoint = dev_get_drvdata(dev); | ||||||
| 
 | 
 | ||||||
| 	xillybus_endpoint_remove(endpoint); | 	xillybus_endpoint_remove(endpoint); | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct platform_driver xillybus_platform_driver = { | static struct platform_driver xillybus_platform_driver = { | ||||||
| 	.probe = xilly_drv_probe, | 	.probe = xilly_drv_probe, | ||||||
| 	.remove = xilly_drv_remove, | 	.remove_new = xilly_drv_remove, | ||||||
| 	.driver = { | 	.driver = { | ||||||
| 		.name = xillyname, | 		.name = xillyname, | ||||||
| 		.of_match_table = xillybus_of_match, | 		.of_match_table = xillybus_of_match, | ||||||
|  |  | ||||||
|  | @ -177,7 +177,6 @@ static int das08_ai_insn_read(struct comedi_device *dev, | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	chan = CR_CHAN(insn->chanspec); | 	chan = CR_CHAN(insn->chanspec); | ||||||
| 	range = CR_RANGE(insn->chanspec); |  | ||||||
| 
 | 
 | ||||||
| 	/* clear crap */ | 	/* clear crap */ | ||||||
| 	inb(dev->iobase + DAS08_AI_LSB_REG); | 	inb(dev->iobase + DAS08_AI_LSB_REG); | ||||||
|  |  | ||||||
|  | @ -123,7 +123,7 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| struct bus_type dio_bus_type = { | const struct bus_type dio_bus_type = { | ||||||
| 	.name	= "dio", | 	.name	= "dio", | ||||||
| 	.match	= dio_bus_match, | 	.match	= dio_bus_match, | ||||||
| 	.probe	= dio_device_probe, | 	.probe	= dio_device_probe, | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
|  * Xilinx Zynq MPSoC Firmware layer |  * Xilinx Zynq MPSoC Firmware layer | ||||||
|  * |  * | ||||||
|  *  Copyright (C) 2014-2022 Xilinx, Inc. |  *  Copyright (C) 2014-2022 Xilinx, Inc. | ||||||
|  |  *  Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc. | ||||||
|  * |  * | ||||||
|  *  Michal Simek <michal.simek@amd.com> |  *  Michal Simek <michal.simek@amd.com> | ||||||
|  *  Davorin Mista <davorin.mista@aggios.com> |  *  Davorin Mista <davorin.mista@aggios.com> | ||||||
|  | @ -1384,6 +1385,30 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); | EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * zynqmp_pm_efuse_access - Provides access to efuse memory. | ||||||
|  |  * @address:	Address of the efuse params structure | ||||||
|  |  * @out:		Returned output value | ||||||
|  |  * | ||||||
|  |  * Return:	Returns status, either success or error code. | ||||||
|  |  */ | ||||||
|  | int zynqmp_pm_efuse_access(const u64 address, u32 *out) | ||||||
|  | { | ||||||
|  | 	u32 ret_payload[PAYLOAD_ARG_CNT]; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!out) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	ret = zynqmp_pm_invoke_fn(PM_EFUSE_ACCESS, ret_payload, 2, | ||||||
|  | 				  upper_32_bits(address), | ||||||
|  | 				  lower_32_bits(address)); | ||||||
|  | 	*out = ret_payload[1]; | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash |  * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash | ||||||
|  * @address:	Address of the data/ Address of output buffer where |  * @address:	Address of the data/ Address of output buffer where | ||||||
|  |  | ||||||
|  | @ -327,7 +327,7 @@ static struct attribute *dfl_dev_attrs[] = { | ||||||
| }; | }; | ||||||
| ATTRIBUTE_GROUPS(dfl_dev); | ATTRIBUTE_GROUPS(dfl_dev); | ||||||
| 
 | 
 | ||||||
| static struct bus_type dfl_bus_type = { | static const struct bus_type dfl_bus_type = { | ||||||
| 	.name		= "dfl", | 	.name		= "dfl", | ||||||
| 	.match		= dfl_bus_match, | 	.match		= dfl_bus_match, | ||||||
| 	.probe		= dfl_bus_probe, | 	.probe		= dfl_bus_probe, | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ int fpga_bridge_enable(struct fpga_bridge *bridge) | ||||||
| { | { | ||||||
| 	dev_dbg(&bridge->dev, "enable\n"); | 	dev_dbg(&bridge->dev, "enable\n"); | ||||||
| 
 | 
 | ||||||
| 	if (bridge->br_ops && bridge->br_ops->enable_set) | 	if (bridge->br_ops->enable_set) | ||||||
| 		return bridge->br_ops->enable_set(bridge, 1); | 		return bridge->br_ops->enable_set(bridge, 1); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -48,7 +48,7 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) | ||||||
| { | { | ||||||
| 	dev_dbg(&bridge->dev, "disable\n"); | 	dev_dbg(&bridge->dev, "disable\n"); | ||||||
| 
 | 
 | ||||||
| 	if (bridge->br_ops && bridge->br_ops->enable_set) | 	if (bridge->br_ops->enable_set) | ||||||
| 		return bridge->br_ops->enable_set(bridge, 0); | 		return bridge->br_ops->enable_set(bridge, 0); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -296,7 +296,7 @@ static ssize_t state_show(struct device *dev, | ||||||
| 	struct fpga_bridge *bridge = to_fpga_bridge(dev); | 	struct fpga_bridge *bridge = to_fpga_bridge(dev); | ||||||
| 	int state = 1; | 	int state = 1; | ||||||
| 
 | 
 | ||||||
| 	if (bridge->br_ops && bridge->br_ops->enable_show) { | 	if (bridge->br_ops->enable_show) { | ||||||
| 		state = bridge->br_ops->enable_show(bridge); | 		state = bridge->br_ops->enable_show(bridge); | ||||||
| 		if (state < 0) | 		if (state < 0) | ||||||
| 			return state; | 			return state; | ||||||
|  | @ -401,7 +401,7 @@ void fpga_bridge_unregister(struct fpga_bridge *bridge) | ||||||
| 	 * If the low level driver provides a method for putting bridge into | 	 * If the low level driver provides a method for putting bridge into | ||||||
| 	 * a desired state upon unregister, do it. | 	 * a desired state upon unregister, do it. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove) | 	if (bridge->br_ops->fpga_bridge_remove) | ||||||
| 		bridge->br_ops->fpga_bridge_remove(bridge); | 		bridge->br_ops->fpga_bridge_remove(bridge); | ||||||
| 
 | 
 | ||||||
| 	device_unregister(&bridge->dev); | 	device_unregister(&bridge->dev); | ||||||
|  |  | ||||||
|  | @ -166,7 +166,7 @@ static const struct dev_pm_ops gb_bundle_pm_ops = { | ||||||
| 	SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle) | 	SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle) | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_bundle_type = { | const struct device_type greybus_bundle_type = { | ||||||
| 	.name =		"greybus_bundle", | 	.name =		"greybus_bundle", | ||||||
| 	.release =	gb_bundle_release, | 	.release =	gb_bundle_release, | ||||||
| 	.pm =		&gb_bundle_pm_ops, | 	.pm =		&gb_bundle_pm_ops, | ||||||
|  |  | ||||||
|  | @ -436,7 +436,7 @@ static void gb_control_release(struct device *dev) | ||||||
| 	kfree(control); | 	kfree(control); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_control_type = { | const struct device_type greybus_control_type = { | ||||||
| 	.name =		"greybus_control", | 	.name =		"greybus_control", | ||||||
| 	.release =	gb_control_release, | 	.release =	gb_control_release, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -27,6 +27,36 @@ int greybus_disabled(void) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(greybus_disabled); | EXPORT_SYMBOL_GPL(greybus_disabled); | ||||||
| 
 | 
 | ||||||
|  | static int is_gb_host_device(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_hd_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int is_gb_module(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_module_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int is_gb_interface(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_interface_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int is_gb_control(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_control_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int is_gb_bundle(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_bundle_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int is_gb_svc(const struct device *dev) | ||||||
|  | { | ||||||
|  | 	return dev->type == &greybus_svc_type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static bool greybus_match_one_id(struct gb_bundle *bundle, | static bool greybus_match_one_id(struct gb_bundle *bundle, | ||||||
| 				 const struct greybus_bundle_id *id) | 				 const struct greybus_bundle_id *id) | ||||||
| { | { | ||||||
|  | @ -155,7 +185,7 @@ static void greybus_shutdown(struct device *dev) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct bus_type greybus_bus_type = { | const struct bus_type greybus_bus_type = { | ||||||
| 	.name =		"greybus", | 	.name =		"greybus", | ||||||
| 	.match =	greybus_match_device, | 	.match =	greybus_match_device, | ||||||
| 	.uevent =	greybus_uevent, | 	.uevent =	greybus_uevent, | ||||||
|  |  | ||||||
|  | @ -513,16 +513,16 @@ static int es2_cport_allocate(struct gb_host_device *hd, int cport_id, | ||||||
| 
 | 
 | ||||||
| 	if (cport_id < 0) { | 	if (cport_id < 0) { | ||||||
| 		ida_start = 0; | 		ida_start = 0; | ||||||
| 		ida_end = hd->num_cports; | 		ida_end = hd->num_cports - 1; | ||||||
| 	} else if (cport_id < hd->num_cports) { | 	} else if (cport_id < hd->num_cports) { | ||||||
| 		ida_start = cport_id; | 		ida_start = cport_id; | ||||||
| 		ida_end = cport_id + 1; | 		ida_end = cport_id; | ||||||
| 	} else { | 	} else { | ||||||
| 		dev_err(&hd->dev, "cport %d not available\n", cport_id); | 		dev_err(&hd->dev, "cport %d not available\n", cport_id); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); | 	return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) | static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) | ||||||
|  | @ -535,7 +535,7 @@ static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ida_simple_remove(&hd->cport_id_map, cport_id); | 	ida_free(&hd->cport_id_map, cport_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int cport_enable(struct gb_host_device *hd, u16 cport_id, | static int cport_enable(struct gb_host_device *hd, u16 cport_id, | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id) | ||||||
| 	struct ida *id_map = &hd->cport_id_map; | 	struct ida *id_map = &hd->cport_id_map; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL); | 	ret = ida_alloc_range(id_map, cport_id, cport_id, GFP_KERNEL); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id); | 		dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id); | ||||||
| 		return ret; | 		return ret; | ||||||
|  | @ -64,7 +64,7 @@ void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id) | ||||||
| { | { | ||||||
| 	struct ida *id_map = &hd->cport_id_map; | 	struct ida *id_map = &hd->cport_id_map; | ||||||
| 
 | 
 | ||||||
| 	ida_simple_remove(id_map, cport_id); | 	ida_free(id_map, cport_id); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved); | EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved); | ||||||
| 
 | 
 | ||||||
|  | @ -80,16 +80,16 @@ int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id, | ||||||
| 
 | 
 | ||||||
| 	if (cport_id < 0) { | 	if (cport_id < 0) { | ||||||
| 		ida_start = 0; | 		ida_start = 0; | ||||||
| 		ida_end = hd->num_cports; | 		ida_end = hd->num_cports - 1; | ||||||
| 	} else if (cport_id < hd->num_cports) { | 	} else if (cport_id < hd->num_cports) { | ||||||
| 		ida_start = cport_id; | 		ida_start = cport_id; | ||||||
| 		ida_end = cport_id + 1; | 		ida_end = cport_id; | ||||||
| 	} else { | 	} else { | ||||||
| 		dev_err(&hd->dev, "cport %d not available\n", cport_id); | 		dev_err(&hd->dev, "cport %d not available\n", cport_id); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); | 	return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Locking: Caller guarantees serialisation */ | /* Locking: Caller guarantees serialisation */ | ||||||
|  | @ -100,7 +100,7 @@ void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ida_simple_remove(&hd->cport_id_map, cport_id); | 	ida_free(&hd->cport_id_map, cport_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void gb_hd_release(struct device *dev) | static void gb_hd_release(struct device *dev) | ||||||
|  | @ -111,12 +111,12 @@ static void gb_hd_release(struct device *dev) | ||||||
| 
 | 
 | ||||||
| 	if (hd->svc) | 	if (hd->svc) | ||||||
| 		gb_svc_put(hd->svc); | 		gb_svc_put(hd->svc); | ||||||
| 	ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id); | 	ida_free(&gb_hd_bus_id_map, hd->bus_id); | ||||||
| 	ida_destroy(&hd->cport_id_map); | 	ida_destroy(&hd->cport_id_map); | ||||||
| 	kfree(hd); | 	kfree(hd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_hd_type = { | const struct device_type greybus_hd_type = { | ||||||
| 	.name		= "greybus_host_device", | 	.name		= "greybus_host_device", | ||||||
| 	.release	= gb_hd_release, | 	.release	= gb_hd_release, | ||||||
| }; | }; | ||||||
|  | @ -162,7 +162,7 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver, | ||||||
| 	if (!hd) | 	if (!hd) | ||||||
| 		return ERR_PTR(-ENOMEM); | 		return ERR_PTR(-ENOMEM); | ||||||
| 
 | 
 | ||||||
| 	ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL); | 	ret = ida_alloc_min(&gb_hd_bus_id_map, 1, GFP_KERNEL); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		kfree(hd); | 		kfree(hd); | ||||||
| 		return ERR_PTR(ret); | 		return ERR_PTR(ret); | ||||||
|  |  | ||||||
|  | @ -131,9 +131,8 @@ static int gb_interface_route_create(struct gb_interface *intf) | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/* Allocate an interface device id. */ | 	/* Allocate an interface device id. */ | ||||||
| 	ret = ida_simple_get(&svc->device_id_map, | 	ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN, | ||||||
| 			     GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1, | 			      GB_SVC_DEVICE_ID_MAX, GFP_KERNEL); | ||||||
| 			     GFP_KERNEL); |  | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); | 		dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); | ||||||
| 		return ret; | 		return ret; | ||||||
|  | @ -165,7 +164,7 @@ static int gb_interface_route_create(struct gb_interface *intf) | ||||||
| 	 * XXX anymore. | 	 * XXX anymore. | ||||||
| 	 */ | 	 */ | ||||||
| err_ida_remove: | err_ida_remove: | ||||||
| 	ida_simple_remove(&svc->device_id_map, device_id); | 	ida_free(&svc->device_id_map, device_id); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -178,7 +177,7 @@ static void gb_interface_route_destroy(struct gb_interface *intf) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id); | 	gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id); | ||||||
| 	ida_simple_remove(&svc->device_id_map, intf->device_id); | 	ida_free(&svc->device_id_map, intf->device_id); | ||||||
| 	intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; | 	intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -765,7 +764,7 @@ static const struct dev_pm_ops gb_interface_pm_ops = { | ||||||
| 			   gb_interface_runtime_idle) | 			   gb_interface_runtime_idle) | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_interface_type = { | const struct device_type greybus_interface_type = { | ||||||
| 	.name =		"greybus_interface", | 	.name =		"greybus_interface", | ||||||
| 	.release =	gb_interface_release, | 	.release =	gb_interface_release, | ||||||
| 	.pm =		&gb_interface_pm_ops, | 	.pm =		&gb_interface_pm_ops, | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ static void gb_module_release(struct device *dev) | ||||||
| 	kfree(module); | 	kfree(module); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_module_type = { | const struct device_type greybus_module_type = { | ||||||
| 	.name		= "greybus_module", | 	.name		= "greybus_module", | ||||||
| 	.release	= gb_module_release, | 	.release	= gb_module_release, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1305,7 +1305,7 @@ static void gb_svc_release(struct device *dev) | ||||||
| 	kfree(svc); | 	kfree(svc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct device_type greybus_svc_type = { | const struct device_type greybus_svc_type = { | ||||||
| 	.name		= "greybus_svc", | 	.name		= "greybus_svc", | ||||||
| 	.release	= gb_svc_release, | 	.release	= gb_svc_release, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -2,6 +2,26 @@ | ||||||
| #
 | #
 | ||||||
| # Makefile for CoreSight drivers.
 | # Makefile for CoreSight drivers.
 | ||||||
| #
 | #
 | ||||||
|  | 
 | ||||||
|  | # Current W=1 warnings
 | ||||||
|  | subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter | ||||||
|  | subdir-ccflags-y += -Wmissing-declarations | ||||||
|  | subdir-ccflags-y += -Wmissing-format-attribute | ||||||
|  | subdir-ccflags-y += -Wmissing-prototypes | ||||||
|  | subdir-ccflags-y += -Wold-style-definition | ||||||
|  | subdir-ccflags-y += -Wmissing-include-dirs | ||||||
|  | subdir-ccflags-y += -Wno-sign-compare | ||||||
|  | condflags := \
 | ||||||
|  | 	$(call cc-option, -Wrestrict)				\
 | ||||||
|  | 	$(call cc-option, -Wunused-but-set-variable)		\
 | ||||||
|  | 	$(call cc-option, -Wunused-const-variable)		\
 | ||||||
|  | 	$(call cc-option, -Wpacked-not-aligned)			\
 | ||||||
|  | 	$(call cc-option, -Wformat-overflow)			\
 | ||||||
|  | 	$(call cc-option, -Wformat-truncation)			\
 | ||||||
|  | 	$(call cc-option, -Wstringop-overflow)			\
 | ||||||
|  | 	$(call cc-option, -Wstringop-truncation) | ||||||
|  | subdir-ccflags-y += $(condflags) | ||||||
|  | 
 | ||||||
| obj-$(CONFIG_CORESIGHT) += coresight.o | obj-$(CONFIG_CORESIGHT) += coresight.o | ||||||
| coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
 | coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
 | ||||||
| 		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
 | 		coresight-sysfs.o coresight-syscfg.o coresight-config.o \
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| /* ETMv4 includes and features */ | /* ETMv4 includes and features */ | ||||||
| #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) | #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) | ||||||
| #include "coresight-etm4x-cfg.h" | #include "coresight-etm4x-cfg.h" | ||||||
|  | #include "coresight-cfg-preload.h" | ||||||
| 
 | 
 | ||||||
| /* preload configurations and features */ | /* preload configurations and features */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <linux/device.h> | #include <linux/device.h> | ||||||
| #include <linux/io.h> | #include <linux/io.h> | ||||||
| #include <linux/idr.h> |  | ||||||
| #include <linux/err.h> | #include <linux/err.h> | ||||||
| #include <linux/export.h> | #include <linux/export.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
|  | @ -25,15 +24,12 @@ | ||||||
| #include "coresight-priv.h" | #include "coresight-priv.h" | ||||||
| #include "coresight-syscfg.h" | #include "coresight-syscfg.h" | ||||||
| 
 | 
 | ||||||
| static DEFINE_MUTEX(coresight_mutex); |  | ||||||
| static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * Use IDR to map the hash of the source's device name |  * Mutex used to lock all sysfs enable and disable actions and loading and | ||||||
|  * to the pointer of path for the source. The idr is for |  * unloading devices by the Coresight core. | ||||||
|  * the sources which aren't associated with CPU. |  | ||||||
|  */ |  */ | ||||||
| static DEFINE_IDR(path_idr); | DEFINE_MUTEX(coresight_mutex); | ||||||
|  | static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct coresight_node - elements of a path, from source to sink |  * struct coresight_node - elements of a path, from source to sink | ||||||
|  | @ -45,12 +41,6 @@ struct coresight_node { | ||||||
| 	struct list_head link; | 	struct list_head link; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * When operating Coresight drivers from the sysFS interface, only a single |  | ||||||
|  * path can exist from a tracer (associated to a CPU) to a sink. |  | ||||||
|  */ |  | ||||||
| static DEFINE_PER_CPU(struct list_head *, tracer_path); |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * When losing synchronisation a new barrier packet needs to be inserted at the |  * When losing synchronisation a new barrier packet needs to be inserted at the | ||||||
|  * beginning of the data collected in a buffer.  That way the decoder knows that |  * beginning of the data collected in a buffer.  That way the decoder knows that | ||||||
|  | @ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt); | ||||||
| 
 | 
 | ||||||
| static const struct cti_assoc_op *cti_assoc_ops; | static const struct cti_assoc_op *cti_assoc_ops; | ||||||
| 
 | 
 | ||||||
| ssize_t coresight_simple_show_pair(struct device *_dev, |  | ||||||
| 			      struct device_attribute *attr, char *buf) |  | ||||||
| { |  | ||||||
| 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); |  | ||||||
| 	struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); |  | ||||||
| 	u64 val; |  | ||||||
| 
 |  | ||||||
| 	pm_runtime_get_sync(_dev->parent); |  | ||||||
| 	val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); |  | ||||||
| 	pm_runtime_put_sync(_dev->parent); |  | ||||||
| 	return sysfs_emit(buf, "0x%llx\n", val); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(coresight_simple_show_pair); |  | ||||||
| 
 |  | ||||||
| ssize_t coresight_simple_show32(struct device *_dev, |  | ||||||
| 			      struct device_attribute *attr, char *buf) |  | ||||||
| { |  | ||||||
| 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); |  | ||||||
| 	struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); |  | ||||||
| 	u64 val; |  | ||||||
| 
 |  | ||||||
| 	pm_runtime_get_sync(_dev->parent); |  | ||||||
| 	val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); |  | ||||||
| 	pm_runtime_put_sync(_dev->parent); |  | ||||||
| 	return sysfs_emit(buf, "0x%llx\n", val); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(coresight_simple_show32); |  | ||||||
| 
 |  | ||||||
| void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) | void coresight_set_cti_ops(const struct cti_assoc_op *cti_op) | ||||||
| { | { | ||||||
| 	cti_assoc_ops = cti_op; | 	cti_assoc_ops = cti_op; | ||||||
|  | @ -279,42 +241,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper); | ||||||
| static int coresight_enable_sink(struct coresight_device *csdev, | static int coresight_enable_sink(struct coresight_device *csdev, | ||||||
| 				 enum cs_mode mode, void *data) | 				 enum cs_mode mode, void *data) | ||||||
| { | { | ||||||
| 	int ret; | 	return sink_ops(csdev)->enable(csdev, mode, data); | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * We need to make sure the "new" session is compatible with the |  | ||||||
| 	 * existing "mode" of operation. |  | ||||||
| 	 */ |  | ||||||
| 	if (!sink_ops(csdev)->enable) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	ret = sink_ops(csdev)->enable(csdev, mode, data); |  | ||||||
| 	if (ret) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	csdev->enable = true; |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void coresight_disable_sink(struct coresight_device *csdev) | static void coresight_disable_sink(struct coresight_device *csdev) | ||||||
| { | { | ||||||
| 	int ret; | 	sink_ops(csdev)->disable(csdev); | ||||||
| 
 |  | ||||||
| 	if (!sink_ops(csdev)->disable) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ret = sink_ops(csdev)->disable(csdev); |  | ||||||
| 	if (ret) |  | ||||||
| 		return; |  | ||||||
| 	csdev->enable = false; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int coresight_enable_link(struct coresight_device *csdev, | static int coresight_enable_link(struct coresight_device *csdev, | ||||||
| 				 struct coresight_device *parent, | 				 struct coresight_device *parent, | ||||||
| 				 struct coresight_device *child) | 				 struct coresight_device *child) | ||||||
| { | { | ||||||
| 	int ret = 0; |  | ||||||
| 	int link_subtype; | 	int link_subtype; | ||||||
| 	struct coresight_connection *inconn, *outconn; | 	struct coresight_connection *inconn, *outconn; | ||||||
| 
 | 
 | ||||||
|  | @ -330,21 +268,13 @@ static int coresight_enable_link(struct coresight_device *csdev, | ||||||
| 	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) | 	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) | ||||||
| 		return PTR_ERR(outconn); | 		return PTR_ERR(outconn); | ||||||
| 
 | 
 | ||||||
| 	if (link_ops(csdev)->enable) { | 	return link_ops(csdev)->enable(csdev, inconn, outconn); | ||||||
| 		ret = link_ops(csdev)->enable(csdev, inconn, outconn); |  | ||||||
| 		if (!ret) |  | ||||||
| 			csdev->enable = true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void coresight_disable_link(struct coresight_device *csdev, | static void coresight_disable_link(struct coresight_device *csdev, | ||||||
| 				   struct coresight_device *parent, | 				   struct coresight_device *parent, | ||||||
| 				   struct coresight_device *child) | 				   struct coresight_device *child) | ||||||
| { | { | ||||||
| 	int i; |  | ||||||
| 	int link_subtype; |  | ||||||
| 	struct coresight_connection *inconn, *outconn; | 	struct coresight_connection *inconn, *outconn; | ||||||
| 
 | 
 | ||||||
| 	if (!parent || !child) | 	if (!parent || !child) | ||||||
|  | @ -352,50 +282,10 @@ static void coresight_disable_link(struct coresight_device *csdev, | ||||||
| 
 | 
 | ||||||
| 	inconn = coresight_find_out_connection(parent, csdev); | 	inconn = coresight_find_out_connection(parent, csdev); | ||||||
| 	outconn = coresight_find_out_connection(csdev, child); | 	outconn = coresight_find_out_connection(csdev, child); | ||||||
| 	link_subtype = csdev->subtype.link_subtype; |  | ||||||
| 
 | 
 | ||||||
| 	if (link_ops(csdev)->disable) { | 	link_ops(csdev)->disable(csdev, inconn, outconn); | ||||||
| 		link_ops(csdev)->disable(csdev, inconn, outconn); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { |  | ||||||
| 		for (i = 0; i < csdev->pdata->nr_inconns; i++) |  | ||||||
| 			if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) != |  | ||||||
| 			    0) |  | ||||||
| 				return; |  | ||||||
| 	} else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { |  | ||||||
| 		for (i = 0; i < csdev->pdata->nr_outconns; i++) |  | ||||||
| 			if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) != |  | ||||||
| 			    0) |  | ||||||
| 				return; |  | ||||||
| 	} else { |  | ||||||
| 		if (atomic_read(&csdev->refcnt) != 0) |  | ||||||
| 			return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	csdev->enable = false; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, |  | ||||||
| 			    void *data) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	if (!csdev->enable) { |  | ||||||
| 		if (source_ops(csdev)->enable) { |  | ||||||
| 			ret = source_ops(csdev)->enable(csdev, data, mode); |  | ||||||
| 			if (ret) |  | ||||||
| 				return ret; |  | ||||||
| 		} |  | ||||||
| 		csdev->enable = true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	atomic_inc(&csdev->refcnt); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(coresight_enable_source); |  | ||||||
| 
 |  | ||||||
| static bool coresight_is_helper(struct coresight_device *csdev) | static bool coresight_is_helper(struct coresight_device *csdev) | ||||||
| { | { | ||||||
| 	return csdev->type == CORESIGHT_DEV_TYPE_HELPER; | 	return csdev->type == CORESIGHT_DEV_TYPE_HELPER; | ||||||
|  | @ -404,29 +294,12 @@ static bool coresight_is_helper(struct coresight_device *csdev) | ||||||
| static int coresight_enable_helper(struct coresight_device *csdev, | static int coresight_enable_helper(struct coresight_device *csdev, | ||||||
| 				   enum cs_mode mode, void *data) | 				   enum cs_mode mode, void *data) | ||||||
| { | { | ||||||
| 	int ret; | 	return helper_ops(csdev)->enable(csdev, mode, data); | ||||||
| 
 |  | ||||||
| 	if (!helper_ops(csdev)->enable) |  | ||||||
| 		return 0; |  | ||||||
| 	ret = helper_ops(csdev)->enable(csdev, mode, data); |  | ||||||
| 	if (ret) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	csdev->enable = true; |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void coresight_disable_helper(struct coresight_device *csdev) | static void coresight_disable_helper(struct coresight_device *csdev) | ||||||
| { | { | ||||||
| 	int ret; | 	helper_ops(csdev)->disable(csdev, NULL); | ||||||
| 
 |  | ||||||
| 	if (!helper_ops(csdev)->disable) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ret = helper_ops(csdev)->disable(csdev, NULL); |  | ||||||
| 	if (ret) |  | ||||||
| 		return; |  | ||||||
| 	csdev->enable = false; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void coresight_disable_helpers(struct coresight_device *csdev) | static void coresight_disable_helpers(struct coresight_device *csdev) | ||||||
|  | @ -441,25 +314,20 @@ static void coresight_disable_helpers(struct coresight_device *csdev) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /*
 | ||||||
|  *  coresight_disable_source - Drop the reference count by 1 and disable |  * Helper function to call source_ops(csdev)->disable and also disable the | ||||||
|  *  the device if there are no users left. |  * helpers. | ||||||
|  * |  * | ||||||
|  *  @csdev: The coresight device to disable |  * There is an imbalance between coresight_enable_path() and | ||||||
|  *  @data: Opaque data to pass on to the disable function of the source device. |  * coresight_disable_path(). Enabling also enables the source's helpers as part | ||||||
|  *         For example in perf mode this is a pointer to the struct perf_event. |  * of the path, but disabling always skips the first item in the path (which is | ||||||
|  * |  * the source), so sources and their helpers don't get disabled as part of that | ||||||
|  *  Returns true if the device has been disabled. |  * function and we need the extra step here. | ||||||
|  */ |  */ | ||||||
| bool coresight_disable_source(struct coresight_device *csdev, void *data) | void coresight_disable_source(struct coresight_device *csdev, void *data) | ||||||
| { | { | ||||||
| 	if (atomic_dec_return(&csdev->refcnt) == 0) { | 	source_ops(csdev)->disable(csdev, data); | ||||||
| 		if (source_ops(csdev)->disable) | 	coresight_disable_helpers(csdev); | ||||||
| 			source_ops(csdev)->disable(csdev, data); |  | ||||||
| 		coresight_disable_helpers(csdev); |  | ||||||
| 		csdev->enable = false; |  | ||||||
| 	} |  | ||||||
| 	return !csdev->enable; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(coresight_disable_source); | EXPORT_SYMBOL_GPL(coresight_disable_source); | ||||||
| 
 | 
 | ||||||
|  | @ -484,7 +352,7 @@ static void coresight_disable_path_from(struct list_head *path, | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * ETF devices are tricky... They can be a link or a sink, | 		 * ETF devices are tricky... They can be a link or a sink, | ||||||
| 		 * depending on how they are configured.  If an ETF has been | 		 * depending on how they are configured.  If an ETF has been | ||||||
| 		 * "activated" it will be configured as a sink, otherwise | 		 * selected as a sink it will be configured as a sink, otherwise | ||||||
| 		 * go ahead with the link configuration. | 		 * go ahead with the link configuration. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (type == CORESIGHT_DEV_TYPE_LINKSINK) | 		if (type == CORESIGHT_DEV_TYPE_LINKSINK) | ||||||
|  | @ -562,7 +430,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * ETF devices are tricky... They can be a link or a sink, | 		 * ETF devices are tricky... They can be a link or a sink, | ||||||
| 		 * depending on how they are configured.  If an ETF has been | 		 * depending on how they are configured.  If an ETF has been | ||||||
| 		 * "activated" it will be configured as a sink, otherwise | 		 * selected as a sink it will be configured as a sink, otherwise | ||||||
| 		 * go ahead with the link configuration. | 		 * go ahead with the link configuration. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (type == CORESIGHT_DEV_TYPE_LINKSINK) | 		if (type == CORESIGHT_DEV_TYPE_LINKSINK) | ||||||
|  | @ -619,48 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path) | ||||||
| 	return csdev; | 	return csdev; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct coresight_device * |  | ||||||
| coresight_find_enabled_sink(struct coresight_device *csdev) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
| 	struct coresight_device *sink = NULL; |  | ||||||
| 
 |  | ||||||
| 	if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || |  | ||||||
| 	     csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && |  | ||||||
| 	     csdev->activated) |  | ||||||
| 		return csdev; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Recursively explore each port found on this element. |  | ||||||
| 	 */ |  | ||||||
| 	for (i = 0; i < csdev->pdata->nr_outconns; i++) { |  | ||||||
| 		struct coresight_device *child_dev; |  | ||||||
| 
 |  | ||||||
| 		child_dev = csdev->pdata->out_conns[i]->dest_dev; |  | ||||||
| 		if (child_dev) |  | ||||||
| 			sink = coresight_find_enabled_sink(child_dev); |  | ||||||
| 		if (sink) |  | ||||||
| 			return sink; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * coresight_get_enabled_sink - returns the first enabled sink using |  | ||||||
|  * connection based search starting from the source reference |  | ||||||
|  * |  | ||||||
|  * @source: Coresight source device reference |  | ||||||
|  */ |  | ||||||
| struct coresight_device * |  | ||||||
| coresight_get_enabled_sink(struct coresight_device *source) |  | ||||||
| { |  | ||||||
| 	if (!source) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	return coresight_find_enabled_sink(source); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int coresight_sink_by_id(struct device *dev, const void *data) | static int coresight_sink_by_id(struct device *dev, const void *data) | ||||||
| { | { | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | @ -794,11 +620,10 @@ static void coresight_drop_device(struct coresight_device *csdev) | ||||||
|  * @sink:	The final sink we want in this path. |  * @sink:	The final sink we want in this path. | ||||||
|  * @path:	The list to add devices to. |  * @path:	The list to add devices to. | ||||||
|  * |  * | ||||||
|  * The tree of Coresight device is traversed until an activated sink is |  * The tree of Coresight device is traversed until @sink is found. | ||||||
|  * found.  From there the sink is added to the list along with all the |  * From there the sink is added to the list along with all the devices that led | ||||||
|  * devices that led to that point - the end result is a list from source |  * to that point - the end result is a list from source to sink. In that list | ||||||
|  * to sink. In that list the source is the first device and the sink the |  * the source is the first device and the sink the last one. | ||||||
|  * last one. |  | ||||||
|  */ |  */ | ||||||
| static int _coresight_build_path(struct coresight_device *csdev, | static int _coresight_build_path(struct coresight_device *csdev, | ||||||
| 				 struct coresight_device *sink, | 				 struct coresight_device *sink, | ||||||
|  | @ -808,7 +633,7 @@ static int _coresight_build_path(struct coresight_device *csdev, | ||||||
| 	bool found = false; | 	bool found = false; | ||||||
| 	struct coresight_node *node; | 	struct coresight_node *node; | ||||||
| 
 | 
 | ||||||
| 	/* An activated sink has been found.  Enqueue the element */ | 	/* The sink has been found.  Enqueue the element */ | ||||||
| 	if (csdev == sink) | 	if (csdev == sink) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
|  | @ -1072,269 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** coresight_validate_source - make sure a source has the right credentials
 |  | ||||||
|  *  @csdev:	the device structure for a source. |  | ||||||
|  *  @function:	the function this was called from. |  | ||||||
|  * |  | ||||||
|  * Assumes the coresight_mutex is held. |  | ||||||
|  */ |  | ||||||
| static int coresight_validate_source(struct coresight_device *csdev, |  | ||||||
| 				     const char *function) |  | ||||||
| { |  | ||||||
| 	u32 type, subtype; |  | ||||||
| 
 |  | ||||||
| 	type = csdev->type; |  | ||||||
| 	subtype = csdev->subtype.source_subtype; |  | ||||||
| 
 |  | ||||||
| 	if (type != CORESIGHT_DEV_TYPE_SOURCE) { |  | ||||||
| 		dev_err(&csdev->dev, "wrong device type in %s\n", function); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && |  | ||||||
| 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && |  | ||||||
| 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && |  | ||||||
| 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { |  | ||||||
| 		dev_err(&csdev->dev, "wrong device subtype in %s\n", function); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int coresight_enable(struct coresight_device *csdev) |  | ||||||
| { |  | ||||||
| 	int cpu, ret = 0; |  | ||||||
| 	struct coresight_device *sink; |  | ||||||
| 	struct list_head *path; |  | ||||||
| 	enum coresight_dev_subtype_source subtype; |  | ||||||
| 	u32 hash; |  | ||||||
| 
 |  | ||||||
| 	subtype = csdev->subtype.source_subtype; |  | ||||||
| 
 |  | ||||||
| 	mutex_lock(&coresight_mutex); |  | ||||||
| 
 |  | ||||||
| 	ret = coresight_validate_source(csdev, __func__); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	if (csdev->enable) { |  | ||||||
| 		/*
 |  | ||||||
| 		 * There could be multiple applications driving the software |  | ||||||
| 		 * source. So keep the refcount for each such user when the |  | ||||||
| 		 * source is already enabled. |  | ||||||
| 		 */ |  | ||||||
| 		if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) |  | ||||||
| 			atomic_inc(&csdev->refcnt); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	sink = coresight_get_enabled_sink(csdev); |  | ||||||
| 	if (!sink) { |  | ||||||
| 		ret = -EINVAL; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	path = coresight_build_path(csdev, sink); |  | ||||||
| 	if (IS_ERR(path)) { |  | ||||||
| 		pr_err("building path(s) failed\n"); |  | ||||||
| 		ret = PTR_ERR(path); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto err_path; |  | ||||||
| 
 |  | ||||||
| 	ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto err_source; |  | ||||||
| 
 |  | ||||||
| 	switch (subtype) { |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: |  | ||||||
| 		/*
 |  | ||||||
| 		 * When working from sysFS it is important to keep track |  | ||||||
| 		 * of the paths that were created so that they can be |  | ||||||
| 		 * undone in 'coresight_disable()'.  Since there can only |  | ||||||
| 		 * be a single session per tracer (when working from sysFS) |  | ||||||
| 		 * a per-cpu variable will do just fine. |  | ||||||
| 		 */ |  | ||||||
| 		cpu = source_ops(csdev)->cpu_id(csdev); |  | ||||||
| 		per_cpu(tracer_path, cpu) = path; |  | ||||||
| 		break; |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: |  | ||||||
| 		/*
 |  | ||||||
| 		 * Use the hash of source's device name as ID |  | ||||||
| 		 * and map the ID to the pointer of the path. |  | ||||||
| 		 */ |  | ||||||
| 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); |  | ||||||
| 		ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto err_source; |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		/* We can't be here */ |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	mutex_unlock(&coresight_mutex); |  | ||||||
| 	return ret; |  | ||||||
| 
 |  | ||||||
| err_source: |  | ||||||
| 	coresight_disable_path(path); |  | ||||||
| 
 |  | ||||||
| err_path: |  | ||||||
| 	coresight_release_path(path); |  | ||||||
| 	goto out; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(coresight_enable); |  | ||||||
| 
 |  | ||||||
| void coresight_disable(struct coresight_device *csdev) |  | ||||||
| { |  | ||||||
| 	int cpu, ret; |  | ||||||
| 	struct list_head *path = NULL; |  | ||||||
| 	u32 hash; |  | ||||||
| 
 |  | ||||||
| 	mutex_lock(&coresight_mutex); |  | ||||||
| 
 |  | ||||||
| 	ret = coresight_validate_source(csdev, __func__); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	if (!csdev->enable || !coresight_disable_source(csdev, NULL)) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	switch (csdev->subtype.source_subtype) { |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: |  | ||||||
| 		cpu = source_ops(csdev)->cpu_id(csdev); |  | ||||||
| 		path = per_cpu(tracer_path, cpu); |  | ||||||
| 		per_cpu(tracer_path, cpu) = NULL; |  | ||||||
| 		break; |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: |  | ||||||
| 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: |  | ||||||
| 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); |  | ||||||
| 		/* Find the path by the hash. */ |  | ||||||
| 		path = idr_find(&path_idr, hash); |  | ||||||
| 		if (path == NULL) { |  | ||||||
| 			pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 		idr_remove(&path_idr, hash); |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		/* We can't be here */ |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	coresight_disable_path(path); |  | ||||||
| 	coresight_release_path(path); |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	mutex_unlock(&coresight_mutex); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(coresight_disable); |  | ||||||
| 
 |  | ||||||
| static ssize_t enable_sink_show(struct device *dev, |  | ||||||
| 				struct device_attribute *attr, char *buf) |  | ||||||
| { |  | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); |  | ||||||
| 
 |  | ||||||
| 	return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t enable_sink_store(struct device *dev, |  | ||||||
| 				 struct device_attribute *attr, |  | ||||||
| 				 const char *buf, size_t size) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 	unsigned long val; |  | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); |  | ||||||
| 
 |  | ||||||
| 	ret = kstrtoul(buf, 10, &val); |  | ||||||
| 	if (ret) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	if (val) |  | ||||||
| 		csdev->activated = true; |  | ||||||
| 	else |  | ||||||
| 		csdev->activated = false; |  | ||||||
| 
 |  | ||||||
| 	return size; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| static DEVICE_ATTR_RW(enable_sink); |  | ||||||
| 
 |  | ||||||
| static ssize_t enable_source_show(struct device *dev, |  | ||||||
| 				  struct device_attribute *attr, char *buf) |  | ||||||
| { |  | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); |  | ||||||
| 
 |  | ||||||
| 	return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t enable_source_store(struct device *dev, |  | ||||||
| 				   struct device_attribute *attr, |  | ||||||
| 				   const char *buf, size_t size) |  | ||||||
| { |  | ||||||
| 	int ret = 0; |  | ||||||
| 	unsigned long val; |  | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); |  | ||||||
| 
 |  | ||||||
| 	ret = kstrtoul(buf, 10, &val); |  | ||||||
| 	if (ret) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	if (val) { |  | ||||||
| 		ret = coresight_enable(csdev); |  | ||||||
| 		if (ret) |  | ||||||
| 			return ret; |  | ||||||
| 	} else { |  | ||||||
| 		coresight_disable(csdev); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return size; |  | ||||||
| } |  | ||||||
| static DEVICE_ATTR_RW(enable_source); |  | ||||||
| 
 |  | ||||||
| static struct attribute *coresight_sink_attrs[] = { |  | ||||||
| 	&dev_attr_enable_sink.attr, |  | ||||||
| 	NULL, |  | ||||||
| }; |  | ||||||
| ATTRIBUTE_GROUPS(coresight_sink); |  | ||||||
| 
 |  | ||||||
| static struct attribute *coresight_source_attrs[] = { |  | ||||||
| 	&dev_attr_enable_source.attr, |  | ||||||
| 	NULL, |  | ||||||
| }; |  | ||||||
| ATTRIBUTE_GROUPS(coresight_source); |  | ||||||
| 
 |  | ||||||
| static struct device_type coresight_dev_type[] = { |  | ||||||
| 	{ |  | ||||||
| 		.name = "sink", |  | ||||||
| 		.groups = coresight_sink_groups, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		.name = "link", |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		.name = "linksink", |  | ||||||
| 		.groups = coresight_sink_groups, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		.name = "source", |  | ||||||
| 		.groups = coresight_source_groups, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		.name = "helper", |  | ||||||
| 	} |  | ||||||
| }; |  | ||||||
| /* Ensure the enum matches the names and groups */ |  | ||||||
| static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); |  | ||||||
| 
 |  | ||||||
| static void coresight_device_release(struct device *dev) | static void coresight_device_release(struct device *dev) | ||||||
| { | { | ||||||
| 	struct coresight_device *csdev = to_coresight_device(dev); | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | @ -1799,7 +1361,7 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(coresight_alloc_device_name); | EXPORT_SYMBOL_GPL(coresight_alloc_device_name); | ||||||
| 
 | 
 | ||||||
| struct bus_type coresight_bustype = { | const struct bus_type coresight_bustype = { | ||||||
| 	.name	= "coresight", | 	.name	= "coresight", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = { | ||||||
| 	CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ | 	CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */ | ||||||
| 	CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ | 	CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */ | ||||||
| 	CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ | 	CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */ | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, cti_ids); | MODULE_DEVICE_TABLE(amba, cti_ids); | ||||||
|  |  | ||||||
|  | @ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb"); | ||||||
|  * @pid:	Process ID of the process being monitored by the session |  * @pid:	Process ID of the process being monitored by the session | ||||||
|  *		that is using this component. |  *		that is using this component. | ||||||
|  * @buf:	area of memory where ETB buffer content gets sent. |  * @buf:	area of memory where ETB buffer content gets sent. | ||||||
|  * @mode:	this ETB is being used. |  | ||||||
|  * @buffer_depth: size of @buf. |  * @buffer_depth: size of @buf. | ||||||
|  * @trigger_cntr: amount of words to store after a trigger. |  * @trigger_cntr: amount of words to store after a trigger. | ||||||
|  */ |  */ | ||||||
|  | @ -89,7 +88,6 @@ struct etb_drvdata { | ||||||
| 	local_t			reading; | 	local_t			reading; | ||||||
| 	pid_t			pid; | 	pid_t			pid; | ||||||
| 	u8			*buf; | 	u8			*buf; | ||||||
| 	u32			mode; |  | ||||||
| 	u32			buffer_depth; | 	u32			buffer_depth; | ||||||
| 	u32			trigger_cntr; | 	u32			trigger_cntr; | ||||||
| }; | }; | ||||||
|  | @ -150,20 +148,20 @@ static int etb_enable_sysfs(struct coresight_device *csdev) | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Don't messup with perf sessions. */ | 	/* Don't messup with perf sessions. */ | ||||||
| 	if (drvdata->mode == CS_MODE_PERF) { | 	if (coresight_get_mode(csdev) == CS_MODE_PERF) { | ||||||
| 		ret = -EBUSY; | 		ret = -EBUSY; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (drvdata->mode == CS_MODE_DISABLED) { | 	if (coresight_get_mode(csdev) == CS_MODE_DISABLED) { | ||||||
| 		ret = etb_enable_hw(drvdata); | 		ret = etb_enable_hw(drvdata); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			goto out; | 			goto out; | ||||||
| 
 | 
 | ||||||
| 		drvdata->mode = CS_MODE_SYSFS; | 		coresight_set_mode(csdev, CS_MODE_SYSFS); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	atomic_inc(&csdev->refcnt); | 	csdev->refcnt++; | ||||||
| out: | out: | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 	return ret; | 	return ret; | ||||||
|  | @ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* No need to continue if the component is already in used by sysFS. */ | 	/* No need to continue if the component is already in used by sysFS. */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { | ||||||
| 		ret = -EBUSY; | 		ret = -EBUSY; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  | @ -199,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) | ||||||
| 	 * use for this session. | 	 * use for this session. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->pid == pid) { | 	if (drvdata->pid == pid) { | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -216,8 +214,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		/* Associate with monitored process. */ | 		/* Associate with monitored process. */ | ||||||
| 		drvdata->pid = pid; | 		drvdata->pid = pid; | ||||||
| 		drvdata->mode = CS_MODE_PERF; | 		coresight_set_mode(drvdata->csdev, CS_MODE_PERF); | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
|  | @ -356,17 +354,18 @@ static int etb_disable(struct coresight_device *csdev) | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	if (atomic_dec_return(&csdev->refcnt)) { | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt) { | ||||||
| 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Complain if we (somehow) got out of sync */ | 	/* Complain if we (somehow) got out of sync */ | ||||||
| 	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 	WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); | ||||||
| 	etb_disable_hw(drvdata); | 	etb_disable_hw(drvdata); | ||||||
| 	/* Dissociate from monitored process. */ | 	/* Dissociate from monitored process. */ | ||||||
| 	drvdata->pid = -1; | 	drvdata->pid = -1; | ||||||
| 	drvdata->mode = CS_MODE_DISABLED; | 	coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(&csdev->dev, "ETB disabled\n"); | 	dev_dbg(&csdev->dev, "ETB disabled\n"); | ||||||
|  | @ -447,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Don't do anything if another tracer is using this sink */ | 	/* Don't do anything if another tracer is using this sink */ | ||||||
| 	if (atomic_read(&csdev->refcnt) != 1) | 	if (csdev->refcnt != 1) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	__etb_disable_hw(drvdata); | 	__etb_disable_hw(drvdata); | ||||||
|  | @ -589,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata) | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { | ||||||
| 		__etb_disable_hw(drvdata); | 		__etb_disable_hw(drvdata); | ||||||
| 		etb_dump_hw(drvdata); | 		etb_dump_hw(drvdata); | ||||||
| 		__etb_enable_hw(drvdata); | 		__etb_enable_hw(drvdata); | ||||||
|  | @ -837,7 +836,7 @@ static const struct amba_id etb_ids[] = { | ||||||
| 		.id	= 0x000bb907, | 		.id	= 0x000bb907, | ||||||
| 		.mask	= 0x000fffff, | 		.mask	= 0x000fffff, | ||||||
| 	}, | 	}, | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, etb_ids); | MODULE_DEVICE_TABLE(amba, etb_ids); | ||||||
|  |  | ||||||
|  | @ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	/* stop tracer */ | 	/* stop tracer */ | ||||||
| 	source_ops(csdev)->disable(csdev, event); | 	coresight_disable_source(csdev, event); | ||||||
| 
 | 
 | ||||||
| 	/* tell the core */ | 	/* tell the core */ | ||||||
| 	event->hw.state = PERF_HES_STOPPED; | 	event->hw.state = PERF_HES_STOPPED; | ||||||
|  |  | ||||||
|  | @ -215,7 +215,6 @@ struct etm_config { | ||||||
|  * @port_size:	port size as reported by ETMCR bit 4-6 and 21. |  * @port_size:	port size as reported by ETMCR bit 4-6 and 21. | ||||||
|  * @arch:	ETM/PTM version number. |  * @arch:	ETM/PTM version number. | ||||||
|  * @use_cpu14:	true if management registers need to be accessed via CP14. |  * @use_cpu14:	true if management registers need to be accessed via CP14. | ||||||
|  * @mode:	this tracer's mode, i.e sysFS, Perf or disabled. |  | ||||||
|  * @sticky_enable: true if ETM base configuration has been done. |  * @sticky_enable: true if ETM base configuration has been done. | ||||||
|  * @boot_enable:true if we should start tracing at boot time. |  * @boot_enable:true if we should start tracing at boot time. | ||||||
|  * @os_unlock:	true if access to management registers is allowed. |  * @os_unlock:	true if access to management registers is allowed. | ||||||
|  | @ -238,7 +237,6 @@ struct etm_drvdata { | ||||||
| 	int				port_size; | 	int				port_size; | ||||||
| 	u8				arch; | 	u8				arch; | ||||||
| 	bool				use_cp14; | 	bool				use_cp14; | ||||||
| 	local_t				mode; |  | ||||||
| 	bool				sticky_enable; | 	bool				sticky_enable; | ||||||
| 	bool				boot_enable; | 	bool				boot_enable; | ||||||
| 	bool				os_unlock; | 	bool				os_unlock; | ||||||
|  |  | ||||||
|  | @ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) | ||||||
|  * |  * | ||||||
|  * Basically the same as @coresight_timeout except for the register access |  * Basically the same as @coresight_timeout except for the register access | ||||||
|  * method where we have to account for CP14 configurations. |  * method where we have to account for CP14 configurations. | ||||||
| 
 |  * | ||||||
|  * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if |  * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if | ||||||
|  * TIMEOUT_US has elapsed, which ever happens first. |  * TIMEOUT_US has elapsed, which ever happens first. | ||||||
|  */ |  */ | ||||||
|  | @ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, | ||||||
| 		      enum cs_mode mode) | 		      enum cs_mode mode) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 	u32 val; |  | ||||||
| 	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
| 
 | 
 | ||||||
| 	val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | 	if (!coresight_take_mode(csdev, mode)) { | ||||||
| 
 | 		/* Someone is already using the tracer */ | ||||||
| 	/* Someone is already using the tracer */ |  | ||||||
| 	if (val) |  | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	switch (mode) { | 	switch (mode) { | ||||||
| 	case CS_MODE_SYSFS: | 	case CS_MODE_SYSFS: | ||||||
|  | @ -578,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event, | ||||||
| 
 | 
 | ||||||
| 	/* The tracer didn't start */ | 	/* The tracer didn't start */ | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		local_set(&drvdata->mode, CS_MODE_DISABLED); | 		coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -672,14 +670,13 @@ static void etm_disable(struct coresight_device *csdev, | ||||||
| 			struct perf_event *event) | 			struct perf_event *event) | ||||||
| { | { | ||||||
| 	enum cs_mode mode; | 	enum cs_mode mode; | ||||||
| 	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * For as long as the tracer isn't disabled another entity can't | 	 * For as long as the tracer isn't disabled another entity can't | ||||||
| 	 * change its status.  As such we can read the status here without | 	 * change its status.  As such we can read the status here without | ||||||
| 	 * fearing it will change under us. | 	 * fearing it will change under us. | ||||||
| 	 */ | 	 */ | ||||||
| 	mode = local_read(&drvdata->mode); | 	mode = coresight_get_mode(csdev); | ||||||
| 
 | 
 | ||||||
| 	switch (mode) { | 	switch (mode) { | ||||||
| 	case CS_MODE_DISABLED: | 	case CS_MODE_DISABLED: | ||||||
|  | @ -696,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (mode) | 	if (mode) | ||||||
| 		local_set(&drvdata->mode, CS_MODE_DISABLED); | 		coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct coresight_ops_source etm_source_ops = { | static const struct coresight_ops_source etm_source_ops = { | ||||||
|  | @ -715,7 +712,7 @@ static int etm_online_cpu(unsigned int cpu) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | 	if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | ||||||
| 		coresight_enable(etmdrvdata[cpu]->csdev); | 		coresight_enable_sysfs(etmdrvdata[cpu]->csdev); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -730,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu) | ||||||
| 		etmdrvdata[cpu]->os_unlock = true; | 		etmdrvdata[cpu]->os_unlock = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (local_read(&etmdrvdata[cpu]->mode)) | 	if (coresight_get_mode(etmdrvdata[cpu]->csdev)) | ||||||
| 		etm_enable_hw(etmdrvdata[cpu]); | 		etm_enable_hw(etmdrvdata[cpu]); | ||||||
| 	spin_unlock(&etmdrvdata[cpu]->spinlock); | 	spin_unlock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -742,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&etmdrvdata[cpu]->spinlock); | 	spin_lock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	if (local_read(&etmdrvdata[cpu]->mode)) | 	if (coresight_get_mode(etmdrvdata[cpu]->csdev)) | ||||||
| 		etm_disable_hw(etmdrvdata[cpu]); | 		etm_disable_hw(etmdrvdata[cpu]); | ||||||
| 	spin_unlock(&etmdrvdata[cpu]->spinlock); | 	spin_unlock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -925,7 +922,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) | ||||||
| 	dev_info(&drvdata->csdev->dev, | 	dev_info(&drvdata->csdev->dev, | ||||||
| 		 "%s initialized\n", (char *)coresight_get_uci_data(id)); | 		 "%s initialized\n", (char *)coresight_get_uci_data(id)); | ||||||
| 	if (boot_enable) { | 	if (boot_enable) { | ||||||
| 		coresight_enable(drvdata->csdev); | 		coresight_enable_sysfs(drvdata->csdev); | ||||||
| 		drvdata->boot_enable = true; | 		drvdata->boot_enable = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1003,7 +1000,7 @@ static const struct amba_id etm_ids[] = { | ||||||
| 	CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), | 	CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), | ||||||
| 	/* PTM 1.1 Qualcomm */ | 	/* PTM 1.1 Qualcomm */ | ||||||
| 	CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), | 	CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, etm_ids); | MODULE_DEVICE_TABLE(amba, etm_ids); | ||||||
|  |  | ||||||
|  | @ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev, | ||||||
| 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
| 	struct etm_config *config = &drvdata->config; | 	struct etm_config *config = &drvdata->config; | ||||||
| 
 | 
 | ||||||
| 	if (!local_read(&drvdata->mode)) { | 	if (!coresight_get_mode(drvdata->csdev)) { | ||||||
| 		spin_lock(&drvdata->spinlock); | 		spin_lock(&drvdata->spinlock); | ||||||
| 		for (i = 0; i < drvdata->nr_cntr; i++) | 		for (i = 0; i < drvdata->nr_cntr; i++) | ||||||
| 			ret += sprintf(buf, "counter %d: %x\n", | 			ret += sprintf(buf, "counter %d: %x\n", | ||||||
|  | @ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev, | ||||||
| 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
| 	struct etm_config *config = &drvdata->config; | 	struct etm_config *config = &drvdata->config; | ||||||
| 
 | 
 | ||||||
| 	if (!local_read(&drvdata->mode)) { | 	if (!coresight_get_mode(drvdata->csdev)) { | ||||||
| 		val = config->seq_curr_state; | 		val = config->seq_curr_state; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -840,14 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, | ||||||
| 		       enum cs_mode mode) | 		       enum cs_mode mode) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 	u32 val; |  | ||||||
| 	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |  | ||||||
| 
 | 
 | ||||||
| 	val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | 	if (!coresight_take_mode(csdev, mode)) { | ||||||
| 
 | 		/* Someone is already using the tracer */ | ||||||
| 	/* Someone is already using the tracer */ |  | ||||||
| 	if (val) |  | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	switch (mode) { | 	switch (mode) { | ||||||
| 	case CS_MODE_SYSFS: | 	case CS_MODE_SYSFS: | ||||||
|  | @ -862,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, | ||||||
| 
 | 
 | ||||||
| 	/* The tracer didn't start */ | 	/* The tracer didn't start */ | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		local_set(&drvdata->mode, CS_MODE_DISABLED); | 		coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -1004,14 +1001,13 @@ static void etm4_disable(struct coresight_device *csdev, | ||||||
| 			 struct perf_event *event) | 			 struct perf_event *event) | ||||||
| { | { | ||||||
| 	enum cs_mode mode; | 	enum cs_mode mode; | ||||||
| 	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * For as long as the tracer isn't disabled another entity can't | 	 * For as long as the tracer isn't disabled another entity can't | ||||||
| 	 * change its status.  As such we can read the status here without | 	 * change its status.  As such we can read the status here without | ||||||
| 	 * fearing it will change under us. | 	 * fearing it will change under us. | ||||||
| 	 */ | 	 */ | ||||||
| 	mode = local_read(&drvdata->mode); | 	mode = coresight_get_mode(csdev); | ||||||
| 
 | 
 | ||||||
| 	switch (mode) { | 	switch (mode) { | ||||||
| 	case CS_MODE_DISABLED: | 	case CS_MODE_DISABLED: | ||||||
|  | @ -1025,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (mode) | 	if (mode) | ||||||
| 		local_set(&drvdata->mode, CS_MODE_DISABLED); | 		coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct coresight_ops_source etm4_source_ops = { | static const struct coresight_ops_source etm4_source_ops = { | ||||||
|  | @ -1200,6 +1196,7 @@ static void etm4_init_arch_data(void *info) | ||||||
| 	struct etm4_init_arg *init_arg = info; | 	struct etm4_init_arg *init_arg = info; | ||||||
| 	struct etmv4_drvdata *drvdata; | 	struct etmv4_drvdata *drvdata; | ||||||
| 	struct csdev_access *csa; | 	struct csdev_access *csa; | ||||||
|  | 	struct device *dev = init_arg->dev; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	drvdata = dev_get_drvdata(init_arg->dev); | 	drvdata = dev_get_drvdata(init_arg->dev); | ||||||
|  | @ -1213,6 +1210,10 @@ static void etm4_init_arch_data(void *info) | ||||||
| 	if (!etm4_init_csdev_access(drvdata, csa)) | 	if (!etm4_init_csdev_access(drvdata, csa)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (!csa->io_mem || | ||||||
|  | 	    fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) | ||||||
|  | 		drvdata->skip_power_up = true; | ||||||
|  | 
 | ||||||
| 	/* Detect the support for OS Lock before we actually use it */ | 	/* Detect the support for OS Lock before we actually use it */ | ||||||
| 	etm_detect_os_lock(drvdata, csa); | 	etm_detect_os_lock(drvdata, csa); | ||||||
| 
 | 
 | ||||||
|  | @ -1650,7 +1651,7 @@ static int etm4_online_cpu(unsigned int cpu) | ||||||
| 		return etm4_probe_cpu(cpu); | 		return etm4_probe_cpu(cpu); | ||||||
| 
 | 
 | ||||||
| 	if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | 	if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) | ||||||
| 		coresight_enable(etmdrvdata[cpu]->csdev); | 		coresight_enable_sysfs(etmdrvdata[cpu]->csdev); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1663,7 +1664,7 @@ static int etm4_starting_cpu(unsigned int cpu) | ||||||
| 	if (!etmdrvdata[cpu]->os_unlock) | 	if (!etmdrvdata[cpu]->os_unlock) | ||||||
| 		etm4_os_unlock(etmdrvdata[cpu]); | 		etm4_os_unlock(etmdrvdata[cpu]); | ||||||
| 
 | 
 | ||||||
| 	if (local_read(&etmdrvdata[cpu]->mode)) | 	if (coresight_get_mode(etmdrvdata[cpu]->csdev)) | ||||||
| 		etm4_enable_hw(etmdrvdata[cpu]); | 		etm4_enable_hw(etmdrvdata[cpu]); | ||||||
| 	spin_unlock(&etmdrvdata[cpu]->spinlock); | 	spin_unlock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -1675,7 +1676,7 @@ static int etm4_dying_cpu(unsigned int cpu) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&etmdrvdata[cpu]->spinlock); | 	spin_lock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	if (local_read(&etmdrvdata[cpu]->mode)) | 	if (coresight_get_mode(etmdrvdata[cpu]->csdev)) | ||||||
| 		etm4_disable_hw(etmdrvdata[cpu]); | 		etm4_disable_hw(etmdrvdata[cpu]); | ||||||
| 	spin_unlock(&etmdrvdata[cpu]->spinlock); | 	spin_unlock(&etmdrvdata[cpu]->spinlock); | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -1833,7 +1834,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata) | ||||||
| 	 * Save and restore the ETM Trace registers only if | 	 * Save and restore the ETM Trace registers only if | ||||||
| 	 * the ETM is active. | 	 * the ETM is active. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (local_read(&drvdata->mode) && drvdata->save_state) | 	if (coresight_get_mode(drvdata->csdev) && drvdata->save_state) | ||||||
| 		ret = __etm4_cpu_save(drvdata); | 		ret = __etm4_cpu_save(drvdata); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -2040,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) | ||||||
| 	if (!drvdata->arch) | 	if (!drvdata->arch) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	/* TRCPDCR is not accessible with system instructions. */ |  | ||||||
| 	if (!desc.access.io_mem || |  | ||||||
| 	    fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) |  | ||||||
| 		drvdata->skip_power_up = true; |  | ||||||
| 
 |  | ||||||
| 	major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); | 	major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); | ||||||
| 	minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); | 	minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); | ||||||
| 
 | 
 | ||||||
|  | @ -2098,7 +2094,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) | ||||||
| 		 drvdata->cpu, type_name, major, minor); | 		 drvdata->cpu, type_name, major, minor); | ||||||
| 
 | 
 | ||||||
| 	if (boot_enable) { | 	if (boot_enable) { | ||||||
| 		coresight_enable(drvdata->csdev); | 		coresight_enable_sysfs(drvdata->csdev); | ||||||
| 		drvdata->boot_enable = true; | 		drvdata->boot_enable = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2390,7 +2386,7 @@ static const struct of_device_id etm4_sysreg_match[] = { | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ACPI | #ifdef CONFIG_ACPI | ||||||
| static const struct acpi_device_id etm4x_acpi_ids[] = { | static const struct acpi_device_id etm4x_acpi_ids[] = { | ||||||
| 	{"ARMHC500", 0}, /* ARM CoreSight ETM4x */ | 	{"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */ | ||||||
| 	{} | 	{} | ||||||
| }; | }; | ||||||
| MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); | MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); | ||||||
|  |  | ||||||
|  | @ -1016,7 +1016,6 @@ struct etmv4_drvdata { | ||||||
| 	void __iomem			*base; | 	void __iomem			*base; | ||||||
| 	struct coresight_device		*csdev; | 	struct coresight_device		*csdev; | ||||||
| 	spinlock_t			spinlock; | 	spinlock_t			spinlock; | ||||||
| 	local_t				mode; |  | ||||||
| 	int				cpu; | 	int				cpu; | ||||||
| 	u8				arch; | 	u8				arch; | ||||||
| 	u8				nr_pe; | 	u8				nr_pe; | ||||||
|  |  | ||||||
|  | @ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ACPI | #ifdef CONFIG_ACPI | ||||||
| static const struct acpi_device_id static_funnel_ids[] = { | static const struct acpi_device_id static_funnel_ids[] = { | ||||||
| 	{"ARMHC9FE", 0}, | 	{"ARMHC9FE", 0, 0, 0}, | ||||||
| 	{}, | 	{}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = { | ||||||
| 		.id     = 0x000bb9eb, | 		.id     = 0x000bb9eb, | ||||||
| 		.mask   = 0x000fffff, | 		.mask   = 0x000fffff, | ||||||
| 	}, | 	}, | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); | MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); | ||||||
|  |  | ||||||
|  | @ -12,6 +12,9 @@ | ||||||
| #include <linux/coresight.h> | #include <linux/coresight.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
|  | extern struct mutex coresight_mutex; | ||||||
|  | extern struct device_type coresight_dev_type[]; | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Coresight management registers (0xf00-0xfcc) |  * Coresight management registers (0xf00-0xfcc) | ||||||
|  * 0xfa0 - 0xfa4: Management	registers in PFTv1.0 |  * 0xfa0 - 0xfa4: Management	registers in PFTv1.0 | ||||||
|  | @ -130,8 +133,6 @@ void coresight_disable_path(struct list_head *path); | ||||||
| int coresight_enable_path(struct list_head *path, enum cs_mode mode, | int coresight_enable_path(struct list_head *path, enum cs_mode mode, | ||||||
| 			  void *sink_data); | 			  void *sink_data); | ||||||
| struct coresight_device *coresight_get_sink(struct list_head *path); | struct coresight_device *coresight_get_sink(struct list_head *path); | ||||||
| struct coresight_device * |  | ||||||
| coresight_get_enabled_sink(struct coresight_device *source); |  | ||||||
| struct coresight_device *coresight_get_sink_by_id(u32 id); | struct coresight_device *coresight_get_sink_by_id(u32 id); | ||||||
| struct coresight_device * | struct coresight_device * | ||||||
| coresight_find_default_sink(struct coresight_device *csdev); | coresight_find_default_sink(struct coresight_device *csdev); | ||||||
|  | @ -231,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev, | ||||||
| 
 | 
 | ||||||
| void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); | void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); | ||||||
| struct coresight_device *coresight_get_percpu_sink(int cpu); | struct coresight_device *coresight_get_percpu_sink(int cpu); | ||||||
| int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, | void coresight_disable_source(struct coresight_device *csdev, void *data); | ||||||
| 			    void *data); |  | ||||||
| bool coresight_disable_source(struct coresight_device *csdev, void *data); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ACPI | #ifdef CONFIG_ACPI | ||||||
| static const struct acpi_device_id static_replicator_acpi_ids[] = { | static const struct acpi_device_id static_replicator_acpi_ids[] = { | ||||||
| 	{"ARMHC985", 0}, /* ARM CoreSight Static Replicator */ | 	{"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */ | ||||||
| 	{} | 	{} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); | ||||||
|  * @spinlock:		only one at a time pls. |  * @spinlock:		only one at a time pls. | ||||||
|  * @chs:		the channels accociated to this STM. |  * @chs:		the channels accociated to this STM. | ||||||
|  * @stm:		structure associated to the generic STM interface. |  * @stm:		structure associated to the generic STM interface. | ||||||
|  * @mode:		this tracer's mode (enum cs_mode), i.e sysFS, or disabled. |  | ||||||
|  * @traceid:		value of the current ID for this component. |  * @traceid:		value of the current ID for this component. | ||||||
|  * @write_bytes:	Maximus bytes this STM can write at a time. |  * @write_bytes:	Maximus bytes this STM can write at a time. | ||||||
|  * @stmsper:		settings for register STMSPER. |  * @stmsper:		settings for register STMSPER. | ||||||
|  | @ -136,7 +135,6 @@ struct stm_drvdata { | ||||||
| 	spinlock_t		spinlock; | 	spinlock_t		spinlock; | ||||||
| 	struct channel_space	chs; | 	struct channel_space	chs; | ||||||
| 	struct stm_data		stm; | 	struct stm_data		stm; | ||||||
| 	local_t			mode; |  | ||||||
| 	u8			traceid; | 	u8			traceid; | ||||||
| 	u32			write_bytes; | 	u32			write_bytes; | ||||||
| 	u32			stmsper; | 	u32			stmsper; | ||||||
|  | @ -195,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata) | ||||||
| static int stm_enable(struct coresight_device *csdev, struct perf_event *event, | static int stm_enable(struct coresight_device *csdev, struct perf_event *event, | ||||||
| 		      enum cs_mode mode) | 		      enum cs_mode mode) | ||||||
| { | { | ||||||
| 	u32 val; |  | ||||||
| 	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
| 
 | 
 | ||||||
| 	if (mode != CS_MODE_SYSFS) | 	if (mode != CS_MODE_SYSFS) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); | 	if (!coresight_take_mode(csdev, mode)) { | ||||||
| 
 | 		/* Someone is already using the tracer */ | ||||||
| 	/* Someone is already using the tracer */ |  | ||||||
| 	if (val) |  | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	pm_runtime_get_sync(csdev->dev.parent); | 	pm_runtime_get_sync(csdev->dev.parent); | ||||||
| 
 | 
 | ||||||
|  | @ -266,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev, | ||||||
| 	 * change its status.  As such we can read the status here without | 	 * change its status.  As such we can read the status here without | ||||||
| 	 * fearing it will change under us. | 	 * fearing it will change under us. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (local_read(&drvdata->mode) == CS_MODE_SYSFS) { | 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
| 		spin_lock(&drvdata->spinlock); | 		spin_lock(&drvdata->spinlock); | ||||||
| 		stm_disable_hw(drvdata); | 		stm_disable_hw(drvdata); | ||||||
| 		spin_unlock(&drvdata->spinlock); | 		spin_unlock(&drvdata->spinlock); | ||||||
|  | @ -276,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev, | ||||||
| 
 | 
 | ||||||
| 		pm_runtime_put(csdev->dev.parent); | 		pm_runtime_put(csdev->dev.parent); | ||||||
| 
 | 
 | ||||||
| 		local_set(&drvdata->mode, CS_MODE_DISABLED); | 		coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 		dev_dbg(&csdev->dev, "STM tracing disabled\n"); | 		dev_dbg(&csdev->dev, "STM tracing disabled\n"); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -334,7 +330,7 @@ static int stm_generic_link(struct stm_data *stm_data, | ||||||
| 	if (!drvdata || !drvdata->csdev) | 	if (!drvdata || !drvdata->csdev) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	return coresight_enable(drvdata->csdev); | 	return coresight_enable_sysfs(drvdata->csdev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void stm_generic_unlink(struct stm_data *stm_data, | static void stm_generic_unlink(struct stm_data *stm_data, | ||||||
|  | @ -345,7 +341,7 @@ static void stm_generic_unlink(struct stm_data *stm_data, | ||||||
| 	if (!drvdata || !drvdata->csdev) | 	if (!drvdata || !drvdata->csdev) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	coresight_disable(drvdata->csdev); | 	coresight_disable_sysfs(drvdata->csdev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static phys_addr_t | static phys_addr_t | ||||||
|  | @ -373,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, | ||||||
| { | { | ||||||
| 	struct stm_drvdata *drvdata = container_of(stm_data, | 	struct stm_drvdata *drvdata = container_of(stm_data, | ||||||
| 						   struct stm_drvdata, stm); | 						   struct stm_drvdata, stm); | ||||||
| 	if (!(drvdata && local_read(&drvdata->mode))) | 	if (!(drvdata && coresight_get_mode(drvdata->csdev))) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	if (channel >= drvdata->numsp) | 	if (channel >= drvdata->numsp) | ||||||
|  | @ -408,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, | ||||||
| 						   struct stm_drvdata, stm); | 						   struct stm_drvdata, stm); | ||||||
| 	unsigned int stm_flags; | 	unsigned int stm_flags; | ||||||
| 
 | 
 | ||||||
| 	if (!(drvdata && local_read(&drvdata->mode))) | 	if (!(drvdata && coresight_get_mode(drvdata->csdev))) | ||||||
| 		return -EACCES; | 		return -EACCES; | ||||||
| 
 | 
 | ||||||
| 	if (channel >= drvdata->numsp) | 	if (channel >= drvdata->numsp) | ||||||
|  | @ -515,7 +511,7 @@ static ssize_t port_select_show(struct device *dev, | ||||||
| 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
| 	unsigned long val; | 	unsigned long val; | ||||||
| 
 | 
 | ||||||
| 	if (!local_read(&drvdata->mode)) { | 	if (!coresight_get_mode(drvdata->csdev)) { | ||||||
| 		val = drvdata->stmspscr; | 		val = drvdata->stmspscr; | ||||||
| 	} else { | 	} else { | ||||||
| 		spin_lock(&drvdata->spinlock); | 		spin_lock(&drvdata->spinlock); | ||||||
|  | @ -541,7 +537,7 @@ static ssize_t port_select_store(struct device *dev, | ||||||
| 	spin_lock(&drvdata->spinlock); | 	spin_lock(&drvdata->spinlock); | ||||||
| 	drvdata->stmspscr = val; | 	drvdata->stmspscr = val; | ||||||
| 
 | 
 | ||||||
| 	if (local_read(&drvdata->mode)) { | 	if (coresight_get_mode(drvdata->csdev)) { | ||||||
| 		CS_UNLOCK(drvdata->base); | 		CS_UNLOCK(drvdata->base); | ||||||
| 		/* Process as per ARM's TRM recommendation */ | 		/* Process as per ARM's TRM recommendation */ | ||||||
| 		stmsper = readl_relaxed(drvdata->base + STMSPER); | 		stmsper = readl_relaxed(drvdata->base + STMSPER); | ||||||
|  | @ -562,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev, | ||||||
| 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
| 	unsigned long val; | 	unsigned long val; | ||||||
| 
 | 
 | ||||||
| 	if (!local_read(&drvdata->mode)) { | 	if (!coresight_get_mode(drvdata->csdev)) { | ||||||
| 		val = drvdata->stmsper; | 		val = drvdata->stmsper; | ||||||
| 	} else { | 	} else { | ||||||
| 		spin_lock(&drvdata->spinlock); | 		spin_lock(&drvdata->spinlock); | ||||||
|  | @ -588,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev, | ||||||
| 	spin_lock(&drvdata->spinlock); | 	spin_lock(&drvdata->spinlock); | ||||||
| 	drvdata->stmsper = val; | 	drvdata->stmsper = val; | ||||||
| 
 | 
 | ||||||
| 	if (local_read(&drvdata->mode)) { | 	if (coresight_get_mode(drvdata->csdev)) { | ||||||
| 		CS_UNLOCK(drvdata->base); | 		CS_UNLOCK(drvdata->base); | ||||||
| 		writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); | 		writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER); | ||||||
| 		CS_LOCK(drvdata->base); | 		CS_LOCK(drvdata->base); | ||||||
|  | @ -950,7 +946,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = { | ||||||
| static const struct amba_id stm_ids[] = { | static const struct amba_id stm_ids[] = { | ||||||
| 	CS_AMBA_ID_DATA(0x000bb962, "STM32"), | 	CS_AMBA_ID_DATA(0x000bb962, "STM32"), | ||||||
| 	CS_AMBA_ID_DATA(0x000bb963, "STM500"), | 	CS_AMBA_ID_DATA(0x000bb963, "STM500"), | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, stm_ids); | MODULE_DEVICE_TABLE(amba, stm_ids); | ||||||
|  |  | ||||||
|  | @ -5,10 +5,401 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <linux/device.h> | #include <linux/device.h> | ||||||
|  | #include <linux/idr.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| 
 | 
 | ||||||
| #include "coresight-priv.h" | #include "coresight-priv.h" | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Use IDR to map the hash of the source's device name | ||||||
|  |  * to the pointer of path for the source. The idr is for | ||||||
|  |  * the sources which aren't associated with CPU. | ||||||
|  |  */ | ||||||
|  | static DEFINE_IDR(path_idr); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * When operating Coresight drivers from the sysFS interface, only a single | ||||||
|  |  * path can exist from a tracer (associated to a CPU) to a sink. | ||||||
|  |  */ | ||||||
|  | static DEFINE_PER_CPU(struct list_head *, tracer_path); | ||||||
|  | 
 | ||||||
|  | ssize_t coresight_simple_show_pair(struct device *_dev, | ||||||
|  | 			      struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||||||
|  | 	struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr); | ||||||
|  | 	u64 val; | ||||||
|  | 
 | ||||||
|  | 	pm_runtime_get_sync(_dev->parent); | ||||||
|  | 	val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off); | ||||||
|  | 	pm_runtime_put_sync(_dev->parent); | ||||||
|  | 	return sysfs_emit(buf, "0x%llx\n", val); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(coresight_simple_show_pair); | ||||||
|  | 
 | ||||||
|  | ssize_t coresight_simple_show32(struct device *_dev, | ||||||
|  | 			      struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev); | ||||||
|  | 	struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr); | ||||||
|  | 	u64 val; | ||||||
|  | 
 | ||||||
|  | 	pm_runtime_get_sync(_dev->parent); | ||||||
|  | 	val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off); | ||||||
|  | 	pm_runtime_put_sync(_dev->parent); | ||||||
|  | 	return sysfs_emit(buf, "0x%llx\n", val); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(coresight_simple_show32); | ||||||
|  | 
 | ||||||
|  | static int coresight_enable_source_sysfs(struct coresight_device *csdev, | ||||||
|  | 					 enum cs_mode mode, void *data) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Comparison with CS_MODE_SYSFS works without taking any device | ||||||
|  | 	 * specific spinlock because the truthyness of that comparison can only | ||||||
|  | 	 * change with coresight_mutex held, which we already have here. | ||||||
|  | 	 */ | ||||||
|  | 	lockdep_assert_held(&coresight_mutex); | ||||||
|  | 	if (coresight_get_mode(csdev) != CS_MODE_SYSFS) { | ||||||
|  | 		ret = source_ops(csdev)->enable(csdev, data, mode); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	csdev->refcnt++; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  *  coresight_disable_source_sysfs - Drop the reference count by 1 and disable | ||||||
|  |  *  the device if there are no users left. | ||||||
|  |  * | ||||||
|  |  *  @csdev: The coresight device to disable | ||||||
|  |  *  @data: Opaque data to pass on to the disable function of the source device. | ||||||
|  |  *         For example in perf mode this is a pointer to the struct perf_event. | ||||||
|  |  * | ||||||
|  |  *  Returns true if the device has been disabled. | ||||||
|  |  */ | ||||||
|  | static bool coresight_disable_source_sysfs(struct coresight_device *csdev, | ||||||
|  | 					   void *data) | ||||||
|  | { | ||||||
|  | 	lockdep_assert_held(&coresight_mutex); | ||||||
|  | 	if (coresight_get_mode(csdev) != CS_MODE_SYSFS) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt == 0) { | ||||||
|  | 		coresight_disable_source(csdev, data); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * coresight_find_activated_sysfs_sink - returns the first sink activated via | ||||||
|  |  * sysfs using connection based search starting from the source reference. | ||||||
|  |  * | ||||||
|  |  * @csdev: Coresight source device reference | ||||||
|  |  */ | ||||||
|  | static struct coresight_device * | ||||||
|  | coresight_find_activated_sysfs_sink(struct coresight_device *csdev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	struct coresight_device *sink = NULL; | ||||||
|  | 
 | ||||||
|  | 	if ((csdev->type == CORESIGHT_DEV_TYPE_SINK || | ||||||
|  | 	     csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && | ||||||
|  | 	     csdev->sysfs_sink_activated) | ||||||
|  | 		return csdev; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Recursively explore each port found on this element. | ||||||
|  | 	 */ | ||||||
|  | 	for (i = 0; i < csdev->pdata->nr_outconns; i++) { | ||||||
|  | 		struct coresight_device *child_dev; | ||||||
|  | 
 | ||||||
|  | 		child_dev = csdev->pdata->out_conns[i]->dest_dev; | ||||||
|  | 		if (child_dev) | ||||||
|  | 			sink = coresight_find_activated_sysfs_sink(child_dev); | ||||||
|  | 		if (sink) | ||||||
|  | 			return sink; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** coresight_validate_source - make sure a source has the right credentials to
 | ||||||
|  |  *  be used via sysfs. | ||||||
|  |  *  @csdev:	the device structure for a source. | ||||||
|  |  *  @function:	the function this was called from. | ||||||
|  |  * | ||||||
|  |  * Assumes the coresight_mutex is held. | ||||||
|  |  */ | ||||||
|  | static int coresight_validate_source_sysfs(struct coresight_device *csdev, | ||||||
|  | 				     const char *function) | ||||||
|  | { | ||||||
|  | 	u32 type, subtype; | ||||||
|  | 
 | ||||||
|  | 	type = csdev->type; | ||||||
|  | 	subtype = csdev->subtype.source_subtype; | ||||||
|  | 
 | ||||||
|  | 	if (type != CORESIGHT_DEV_TYPE_SOURCE) { | ||||||
|  | 		dev_err(&csdev->dev, "wrong device type in %s\n", function); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC && | ||||||
|  | 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE && | ||||||
|  | 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM && | ||||||
|  | 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) { | ||||||
|  | 		dev_err(&csdev->dev, "wrong device subtype in %s\n", function); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int coresight_enable_sysfs(struct coresight_device *csdev) | ||||||
|  | { | ||||||
|  | 	int cpu, ret = 0; | ||||||
|  | 	struct coresight_device *sink; | ||||||
|  | 	struct list_head *path; | ||||||
|  | 	enum coresight_dev_subtype_source subtype; | ||||||
|  | 	u32 hash; | ||||||
|  | 
 | ||||||
|  | 	subtype = csdev->subtype.source_subtype; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&coresight_mutex); | ||||||
|  | 
 | ||||||
|  | 	ret = coresight_validate_source_sysfs(csdev, __func__); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * mode == SYSFS implies that it's already enabled. Don't look at the | ||||||
|  | 	 * refcount to determine this because we don't claim the source until | ||||||
|  | 	 * coresight_enable_source() so can still race with Perf mode which | ||||||
|  | 	 * doesn't hold coresight_mutex. | ||||||
|  | 	 */ | ||||||
|  | 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
|  | 		/*
 | ||||||
|  | 		 * There could be multiple applications driving the software | ||||||
|  | 		 * source. So keep the refcount for each such user when the | ||||||
|  | 		 * source is already enabled. | ||||||
|  | 		 */ | ||||||
|  | 		if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) | ||||||
|  | 			csdev->refcnt++; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	sink = coresight_find_activated_sysfs_sink(csdev); | ||||||
|  | 	if (!sink) { | ||||||
|  | 		ret = -EINVAL; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	path = coresight_build_path(csdev, sink); | ||||||
|  | 	if (IS_ERR(path)) { | ||||||
|  | 		pr_err("building path(s) failed\n"); | ||||||
|  | 		ret = PTR_ERR(path); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto err_path; | ||||||
|  | 
 | ||||||
|  | 	ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto err_source; | ||||||
|  | 
 | ||||||
|  | 	switch (subtype) { | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||||||
|  | 		/*
 | ||||||
|  | 		 * When working from sysFS it is important to keep track | ||||||
|  | 		 * of the paths that were created so that they can be | ||||||
|  | 		 * undone in 'coresight_disable()'.  Since there can only | ||||||
|  | 		 * be a single session per tracer (when working from sysFS) | ||||||
|  | 		 * a per-cpu variable will do just fine. | ||||||
|  | 		 */ | ||||||
|  | 		cpu = source_ops(csdev)->cpu_id(csdev); | ||||||
|  | 		per_cpu(tracer_path, cpu) = path; | ||||||
|  | 		break; | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||||||
|  | 		/*
 | ||||||
|  | 		 * Use the hash of source's device name as ID | ||||||
|  | 		 * and map the ID to the pointer of the path. | ||||||
|  | 		 */ | ||||||
|  | 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||||||
|  | 		ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto err_source; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		/* We can't be here */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	mutex_unlock(&coresight_mutex); | ||||||
|  | 	return ret; | ||||||
|  | 
 | ||||||
|  | err_source: | ||||||
|  | 	coresight_disable_path(path); | ||||||
|  | 
 | ||||||
|  | err_path: | ||||||
|  | 	coresight_release_path(path); | ||||||
|  | 	goto out; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(coresight_enable_sysfs); | ||||||
|  | 
 | ||||||
|  | void coresight_disable_sysfs(struct coresight_device *csdev) | ||||||
|  | { | ||||||
|  | 	int cpu, ret; | ||||||
|  | 	struct list_head *path = NULL; | ||||||
|  | 	u32 hash; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&coresight_mutex); | ||||||
|  | 
 | ||||||
|  | 	ret = coresight_validate_source_sysfs(csdev, __func__); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	if (!coresight_disable_source_sysfs(csdev, NULL)) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	switch (csdev->subtype.source_subtype) { | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: | ||||||
|  | 		cpu = source_ops(csdev)->cpu_id(csdev); | ||||||
|  | 		path = per_cpu(tracer_path, cpu); | ||||||
|  | 		per_cpu(tracer_path, cpu) = NULL; | ||||||
|  | 		break; | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE: | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM: | ||||||
|  | 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS: | ||||||
|  | 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev))); | ||||||
|  | 		/* Find the path by the hash. */ | ||||||
|  | 		path = idr_find(&path_idr, hash); | ||||||
|  | 		if (path == NULL) { | ||||||
|  | 			pr_err("Path is not found for %s\n", dev_name(&csdev->dev)); | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 		idr_remove(&path_idr, hash); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		/* We can't be here */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	coresight_disable_path(path); | ||||||
|  | 	coresight_release_path(path); | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	mutex_unlock(&coresight_mutex); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(coresight_disable_sysfs); | ||||||
|  | 
 | ||||||
|  | static ssize_t enable_sink_show(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | 
 | ||||||
|  | 	return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t enable_sink_store(struct device *dev, | ||||||
|  | 				 struct device_attribute *attr, | ||||||
|  | 				 const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 	unsigned long val; | ||||||
|  | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | 
 | ||||||
|  | 	ret = kstrtoul(buf, 10, &val); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	csdev->sysfs_sink_activated = !!val; | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RW(enable_sink); | ||||||
|  | 
 | ||||||
|  | static ssize_t enable_source_show(struct device *dev, | ||||||
|  | 				  struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | 
 | ||||||
|  | 	guard(mutex)(&coresight_mutex); | ||||||
|  | 	return scnprintf(buf, PAGE_SIZE, "%u\n", | ||||||
|  | 			 coresight_get_mode(csdev) == CS_MODE_SYSFS); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t enable_source_store(struct device *dev, | ||||||
|  | 				   struct device_attribute *attr, | ||||||
|  | 				   const char *buf, size_t size) | ||||||
|  | { | ||||||
|  | 	int ret = 0; | ||||||
|  | 	unsigned long val; | ||||||
|  | 	struct coresight_device *csdev = to_coresight_device(dev); | ||||||
|  | 
 | ||||||
|  | 	ret = kstrtoul(buf, 10, &val); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	if (val) { | ||||||
|  | 		ret = coresight_enable_sysfs(csdev); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 	} else { | ||||||
|  | 		coresight_disable_sysfs(csdev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RW(enable_source); | ||||||
|  | 
 | ||||||
|  | static struct attribute *coresight_sink_attrs[] = { | ||||||
|  | 	&dev_attr_enable_sink.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | ATTRIBUTE_GROUPS(coresight_sink); | ||||||
|  | 
 | ||||||
|  | static struct attribute *coresight_source_attrs[] = { | ||||||
|  | 	&dev_attr_enable_source.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | ATTRIBUTE_GROUPS(coresight_source); | ||||||
|  | 
 | ||||||
|  | struct device_type coresight_dev_type[] = { | ||||||
|  | 	[CORESIGHT_DEV_TYPE_SINK] = { | ||||||
|  | 		.name = "sink", | ||||||
|  | 		.groups = coresight_sink_groups, | ||||||
|  | 	}, | ||||||
|  | 	[CORESIGHT_DEV_TYPE_LINK] = { | ||||||
|  | 		.name = "link", | ||||||
|  | 	}, | ||||||
|  | 	[CORESIGHT_DEV_TYPE_LINKSINK] = { | ||||||
|  | 		.name = "linksink", | ||||||
|  | 		.groups = coresight_sink_groups, | ||||||
|  | 	}, | ||||||
|  | 	[CORESIGHT_DEV_TYPE_SOURCE] = { | ||||||
|  | 		.name = "source", | ||||||
|  | 		.groups = coresight_source_groups, | ||||||
|  | 	}, | ||||||
|  | 	[CORESIGHT_DEV_TYPE_HELPER] = { | ||||||
|  | 		.name = "helper", | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | /* Ensure the enum matches the names and groups */ | ||||||
|  | static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Connections group - links attribute. |  * Connections group - links attribute. | ||||||
|  * Count of created links between coresight components in the group. |  * Count of created links between coresight components in the group. | ||||||
|  |  | ||||||
|  | @ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev) | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	if (drvdata->mode == CS_MODE_DISABLED) | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) | 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) | ||||||
|  | @ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = { | ||||||
| 	CS_AMBA_ID(0x000bb9e9), | 	CS_AMBA_ID(0x000bb9e9), | ||||||
| 	/* Coresight SoC 600 TMC-ETF */ | 	/* Coresight SoC 600 TMC-ETF */ | ||||||
| 	CS_AMBA_ID(0x000bb9ea), | 	CS_AMBA_ID(0x000bb9ea), | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, tmc_ids); | MODULE_DEVICE_TABLE(amba, tmc_ids); | ||||||
|  |  | ||||||
|  | @ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata) | ||||||
| 	 * When operating in sysFS mode the content of the buffer needs to be | 	 * When operating in sysFS mode the content of the buffer needs to be | ||||||
| 	 * read before the TMC is disabled. | 	 * read before the TMC is disabled. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) | ||||||
| 		tmc_etb_dump_hw(drvdata); | 		tmc_etb_dump_hw(drvdata); | ||||||
| 	tmc_disable_hw(drvdata); | 	tmc_disable_hw(drvdata); | ||||||
| 
 | 
 | ||||||
|  | @ -205,8 +205,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) | ||||||
| 	 * sink is already enabled no memory is needed and the HW need not be | 	 * sink is already enabled no memory is needed and the HW need not be | ||||||
| 	 * touched. | 	 * touched. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -228,8 +228,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) | ||||||
| 
 | 
 | ||||||
| 	ret = tmc_etb_enable_hw(drvdata); | 	ret = tmc_etb_enable_hw(drvdata); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		drvdata->mode = CS_MODE_SYSFS; | 		coresight_set_mode(csdev, CS_MODE_SYSFS); | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 	} else { | 	} else { | ||||||
| 		/* Free up the buffer if we failed to enable */ | 		/* Free up the buffer if we failed to enable */ | ||||||
| 		used = false; | 		used = false; | ||||||
|  | @ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 		 * No need to continue if the ETB/ETF is already operated | 		 * No need to continue if the ETB/ETF is already operated | ||||||
| 		 * from sysFS. | 		 * from sysFS. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (drvdata->mode == CS_MODE_SYSFS) { | 		if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
| 			ret = -EBUSY; | 			ret = -EBUSY; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
|  | @ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 		 * use for this session. | 		 * use for this session. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (drvdata->pid == pid) { | 		if (drvdata->pid == pid) { | ||||||
| 			atomic_inc(&csdev->refcnt); | 			csdev->refcnt++; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -292,8 +292,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 		if (!ret) { | 		if (!ret) { | ||||||
| 			/* Associate with monitored process. */ | 			/* Associate with monitored process. */ | ||||||
| 			drvdata->pid = pid; | 			drvdata->pid = pid; | ||||||
| 			drvdata->mode = CS_MODE_PERF; | 			coresight_set_mode(csdev, CS_MODE_PERF); | ||||||
| 			atomic_inc(&csdev->refcnt); | 			csdev->refcnt++; | ||||||
| 		} | 		} | ||||||
| 	} while (0); | 	} while (0); | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
|  | @ -338,17 +338,18 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (atomic_dec_return(&csdev->refcnt)) { | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt) { | ||||||
| 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Complain if we (somehow) got out of sync */ | 	/* Complain if we (somehow) got out of sync */ | ||||||
| 	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 	WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); | ||||||
| 	tmc_etb_disable_hw(drvdata); | 	tmc_etb_disable_hw(drvdata); | ||||||
| 	/* Dissociate from monitored process. */ | 	/* Dissociate from monitored process. */ | ||||||
| 	drvdata->pid = -1; | 	drvdata->pid = -1; | ||||||
| 	drvdata->mode = CS_MODE_DISABLED; | 	coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 
 | 
 | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
|  | @ -371,15 +372,15 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (atomic_read(&csdev->refcnt) == 0) { | 	if (csdev->refcnt == 0) { | ||||||
| 		ret = tmc_etf_enable_hw(drvdata); | 		ret = tmc_etf_enable_hw(drvdata); | ||||||
| 		if (!ret) { | 		if (!ret) { | ||||||
| 			drvdata->mode = CS_MODE_SYSFS; | 			coresight_set_mode(csdev, CS_MODE_SYSFS); | ||||||
| 			first_enable = true; | 			first_enable = true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	if (first_enable) | 	if (first_enable) | ||||||
|  | @ -401,9 +402,10 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (atomic_dec_return(&csdev->refcnt) == 0) { | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt == 0) { | ||||||
| 		tmc_etf_disable_hw(drvdata); | 		tmc_etf_disable_hw(drvdata); | ||||||
| 		drvdata->mode = CS_MODE_DISABLED; | 		coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 		last_disable = true; | 		last_disable = true; | ||||||
| 	} | 	} | ||||||
| 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | 	spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
|  | @ -483,13 +485,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	/* This shouldn't happen */ | 	/* This shouldn't happen */ | ||||||
| 	if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF)) | 	if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Don't do anything if another tracer is using this sink */ | 	/* Don't do anything if another tracer is using this sink */ | ||||||
| 	if (atomic_read(&csdev->refcnt) != 1) | 	if (csdev->refcnt != 1) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	CS_UNLOCK(drvdata->base); | 	CS_UNLOCK(drvdata->base); | ||||||
|  | @ -629,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Don't interfere if operated from Perf */ | 	/* Don't interfere if operated from Perf */ | ||||||
| 	if (drvdata->mode == CS_MODE_PERF) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) { | ||||||
| 		ret = -EINVAL; | 		ret = -EINVAL; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  | @ -641,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Disable the TMC if need be */ | 	/* Disable the TMC if need be */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { | ||||||
| 		/* There is no point in reading a TMC in HW FIFO mode */ | 		/* There is no point in reading a TMC in HW FIFO mode */ | ||||||
| 		mode = readl_relaxed(drvdata->base + TMC_MODE); | 		mode = readl_relaxed(drvdata->base + TMC_MODE); | ||||||
| 		if (mode != TMC_MODE_CIRCULAR_BUFFER) { | 		if (mode != TMC_MODE_CIRCULAR_BUFFER) { | ||||||
|  | @ -673,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata) | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Re-enable the TMC if need be */ | 	/* Re-enable the TMC if need be */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { | ||||||
| 		/* There is no point in reading a TMC in HW FIFO mode */ | 		/* There is no point in reading a TMC in HW FIFO mode */ | ||||||
| 		mode = readl_relaxed(drvdata->base + TMC_MODE); | 		mode = readl_relaxed(drvdata->base + TMC_MODE); | ||||||
| 		if (mode != TMC_MODE_CIRCULAR_BUFFER) { | 		if (mode != TMC_MODE_CIRCULAR_BUFFER) { | ||||||
|  |  | ||||||
|  | @ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata) | ||||||
| 	 * When operating in sysFS mode the content of the buffer needs to be | 	 * When operating in sysFS mode the content of the buffer needs to be | ||||||
| 	 * read before the TMC is disabled. | 	 * read before the TMC is disabled. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) | ||||||
| 		tmc_etr_sync_sysfs_buf(drvdata); | 		tmc_etr_sync_sysfs_buf(drvdata); | ||||||
| 
 | 
 | ||||||
| 	tmc_disable_hw(drvdata); | 	tmc_disable_hw(drvdata); | ||||||
|  | @ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) | ||||||
| 		spin_lock_irqsave(&drvdata->spinlock, flags); | 		spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (drvdata->reading || drvdata->mode == CS_MODE_PERF) { | 	if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) { | ||||||
| 		ret = -EBUSY; | 		ret = -EBUSY; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  | @ -1230,15 +1230,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) | ||||||
| 	 * sink is already enabled no memory is needed and the HW need not be | 	 * sink is already enabled no memory is needed and the HW need not be | ||||||
| 	 * touched, even if the buffer size has changed. | 	 * touched, even if the buffer size has changed. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = tmc_etr_enable_hw(drvdata, sysfs_buf); | 	ret = tmc_etr_enable_hw(drvdata, sysfs_buf); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		drvdata->mode = CS_MODE_SYSFS; | 		coresight_set_mode(csdev, CS_MODE_SYSFS); | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
|  | @ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* Don't do anything if another tracer is using this sink */ | 	/* Don't do anything if another tracer is using this sink */ | ||||||
| 	if (atomic_read(&csdev->refcnt) != 1) { | 	if (csdev->refcnt != 1) { | ||||||
| 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  | @ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 	 /* Don't use this sink if it is already claimed by sysFS */ | 	 /* Don't use this sink if it is already claimed by sysFS */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { | ||||||
| 		rc = -EBUSY; | 		rc = -EBUSY; | ||||||
| 		goto unlock_out; | 		goto unlock_out; | ||||||
| 	} | 	} | ||||||
|  | @ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 	 * use for this session. | 	 * use for this session. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (drvdata->pid == pid) { | 	if (drvdata->pid == pid) { | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 		goto unlock_out; | 		goto unlock_out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1684,9 +1684,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) | ||||||
| 	if (!rc) { | 	if (!rc) { | ||||||
| 		/* Associate with monitored process. */ | 		/* Associate with monitored process. */ | ||||||
| 		drvdata->pid = pid; | 		drvdata->pid = pid; | ||||||
| 		drvdata->mode = CS_MODE_PERF; | 		coresight_set_mode(csdev, CS_MODE_PERF); | ||||||
| 		drvdata->perf_buf = etr_perf->etr_buf; | 		drvdata->perf_buf = etr_perf->etr_buf; | ||||||
| 		atomic_inc(&csdev->refcnt); | 		csdev->refcnt++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| unlock_out: | unlock_out: | ||||||
|  | @ -1719,17 +1719,18 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (atomic_dec_return(&csdev->refcnt)) { | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt) { | ||||||
| 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | 		spin_unlock_irqrestore(&drvdata->spinlock, flags); | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Complain if we (somehow) got out of sync */ | 	/* Complain if we (somehow) got out of sync */ | ||||||
| 	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED); | 	WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED); | ||||||
| 	tmc_etr_disable_hw(drvdata); | 	tmc_etr_disable_hw(drvdata); | ||||||
| 	/* Dissociate from monitored process. */ | 	/* Dissociate from monitored process. */ | ||||||
| 	drvdata->pid = -1; | 	drvdata->pid = -1; | ||||||
| 	drvdata->mode = CS_MODE_DISABLED; | 	coresight_set_mode(csdev, CS_MODE_DISABLED); | ||||||
| 	/* Reset perf specific data */ | 	/* Reset perf specific data */ | ||||||
| 	drvdata->perf_buf = NULL; | 	drvdata->perf_buf = NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -1777,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Disable the TMC if we are trying to read from a running session. */ | 	/* Disable the TMC if we are trying to read from a running session. */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) | ||||||
| 		__tmc_etr_disable_hw(drvdata); | 		__tmc_etr_disable_hw(drvdata); | ||||||
| 
 | 
 | ||||||
| 	drvdata->reading = true; | 	drvdata->reading = true; | ||||||
|  | @ -1799,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) | ||||||
| 	spin_lock_irqsave(&drvdata->spinlock, flags); | 	spin_lock_irqsave(&drvdata->spinlock, flags); | ||||||
| 
 | 
 | ||||||
| 	/* RE-enable the TMC if need be */ | 	/* RE-enable the TMC if need be */ | ||||||
| 	if (drvdata->mode == CS_MODE_SYSFS) { | 	if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * The trace run will continue with the same allocated trace | 		 * The trace run will continue with the same allocated trace | ||||||
| 		 * buffer. Since the tracer is still enabled drvdata::buf can't | 		 * buffer. Since the tracer is still enabled drvdata::buf can't | ||||||
|  |  | ||||||
|  | @ -178,7 +178,6 @@ struct etr_buf { | ||||||
|  * @size:	trace buffer size for this TMC (common for all modes). |  * @size:	trace buffer size for this TMC (common for all modes). | ||||||
|  * @max_burst_size: The maximum burst size that can be initiated by |  * @max_burst_size: The maximum burst size that can be initiated by | ||||||
|  *		TMC-ETR on AXI bus. |  *		TMC-ETR on AXI bus. | ||||||
|  * @mode:	how this TMC is being used. |  | ||||||
|  * @config_type: TMC variant, must be of type @tmc_config_type. |  * @config_type: TMC variant, must be of type @tmc_config_type. | ||||||
|  * @memwidth:	width of the memory interface databus, in bytes. |  * @memwidth:	width of the memory interface databus, in bytes. | ||||||
|  * @trigger_cntr: amount of words to store after a trigger. |  * @trigger_cntr: amount of words to store after a trigger. | ||||||
|  | @ -203,7 +202,6 @@ struct tmc_drvdata { | ||||||
| 	u32			len; | 	u32			len; | ||||||
| 	u32			size; | 	u32			size; | ||||||
| 	u32			max_burst_size; | 	u32			max_burst_size; | ||||||
| 	u32			mode; |  | ||||||
| 	enum tmc_config_type	config_type; | 	enum tmc_config_type	config_type; | ||||||
| 	enum tmc_mem_intf_width	memwidth; | 	enum tmc_mem_intf_width	memwidth; | ||||||
| 	u32			trigger_cntr; | 	u32			trigger_cntr; | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include "coresight-priv.h" | #include "coresight-priv.h" | ||||||
| #include "coresight-tpda.h" | #include "coresight-tpda.h" | ||||||
| #include "coresight-trace-id.h" | #include "coresight-trace-id.h" | ||||||
|  | #include "coresight-tpdm.h" | ||||||
| 
 | 
 | ||||||
| DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); | DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda"); | ||||||
| 
 | 
 | ||||||
|  | @ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev) | ||||||
| 			CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); | 			CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | static void tpda_clear_element_size(struct coresight_device *csdev) | ||||||
|  * Read the DSB element size from the TPDM device |  | ||||||
|  * Returns |  | ||||||
|  *    The dsb element size read from the devicetree if available. |  | ||||||
|  *    0 - Otherwise, with a warning once. |  | ||||||
|  */ |  | ||||||
| static int tpdm_read_dsb_element_size(struct coresight_device *csdev) |  | ||||||
| { | { | ||||||
| 	int rc = 0; | 	struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
| 	u8 size = 0; | 
 | ||||||
|  | 	drvdata->dsb_esize = 0; | ||||||
|  | 	drvdata->cmb_esize = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val) | ||||||
|  | { | ||||||
|  | 	/* Clear all relevant fields */ | ||||||
|  | 	*val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE); | ||||||
|  | 
 | ||||||
|  | 	if (drvdata->dsb_esize == 64) | ||||||
|  | 		*val |= TPDA_Pn_CR_DSBSIZE; | ||||||
|  | 	else if (drvdata->dsb_esize == 32) | ||||||
|  | 		*val &= ~TPDA_Pn_CR_DSBSIZE; | ||||||
|  | 
 | ||||||
|  | 	if (drvdata->cmb_esize == 64) | ||||||
|  | 		*val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2); | ||||||
|  | 	else if (drvdata->cmb_esize == 32) | ||||||
|  | 		*val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1); | ||||||
|  | 	else if (drvdata->cmb_esize == 8) | ||||||
|  | 		*val &= ~TPDA_Pn_CR_CMBSIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Read the element size from the TPDM device. One TPDM must have at least one of the | ||||||
|  |  * element size property. | ||||||
|  |  * Returns | ||||||
|  |  *    0 - The element size property is read | ||||||
|  |  *    Others - Cannot read the property of the element size | ||||||
|  |  */ | ||||||
|  | static int tpdm_read_element_size(struct tpda_drvdata *drvdata, | ||||||
|  | 				  struct coresight_device *csdev) | ||||||
|  | { | ||||||
|  | 	int rc = -EINVAL; | ||||||
|  | 	struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent); | ||||||
|  | 
 | ||||||
|  | 	if (tpdm_has_dsb_dataset(tpdm_data)) { | ||||||
|  | 		rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), | ||||||
|  | 				"qcom,dsb-element-bits", &drvdata->dsb_esize); | ||||||
|  | 	} | ||||||
|  | 	if (tpdm_has_cmb_dataset(tpdm_data)) { | ||||||
|  | 		rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent), | ||||||
|  | 				"qcom,cmb-element-bits", &drvdata->cmb_esize); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent), |  | ||||||
| 			"qcom,dsb-element-size", &size); |  | ||||||
| 	if (rc) | 	if (rc) | ||||||
| 		dev_warn_once(&csdev->dev, | 		dev_warn_once(&csdev->dev, | ||||||
| 			"Failed to read TPDM DSB Element size: %d\n", rc); | 			"Failed to read TPDM Element size: %d\n", rc); | ||||||
| 
 | 
 | ||||||
| 	return size; | 	return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev) | ||||||
|  * Parameter "inport" is used to pass in the input port number |  * Parameter "inport" is used to pass in the input port number | ||||||
|  * of TPDA, and it is set to -1 in the recursize call. |  * of TPDA, and it is set to -1 in the recursize call. | ||||||
|  */ |  */ | ||||||
| static int tpda_get_element_size(struct coresight_device *csdev, | static int tpda_get_element_size(struct tpda_drvdata *drvdata, | ||||||
|  | 				 struct coresight_device *csdev, | ||||||
| 				 int inport) | 				 int inport) | ||||||
| { | { | ||||||
| 	int dsb_size = -ENOENT; | 	int rc = 0; | ||||||
| 	int i, size; | 	int i; | ||||||
| 	struct coresight_device *in; | 	struct coresight_device *in; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < csdev->pdata->nr_inconns; i++) { | 	for (i = 0; i < csdev->pdata->nr_inconns; i++) { | ||||||
|  | @ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev, | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		/* Ignore the paths that do not match port */ | 		/* Ignore the paths that do not match port */ | ||||||
| 		if (inport > 0 && | 		if (inport >= 0 && | ||||||
| 		    csdev->pdata->in_conns[i]->dest_port != inport) | 		    csdev->pdata->in_conns[i]->dest_port != inport) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (coresight_device_is_tpdm(in)) { | 		if (coresight_device_is_tpdm(in)) { | ||||||
| 			size = tpdm_read_dsb_element_size(in); | 			if (drvdata->dsb_esize || drvdata->cmb_esize) | ||||||
|  | 				return -EEXIST; | ||||||
|  | 			rc = tpdm_read_element_size(drvdata, in); | ||||||
|  | 			if (rc) | ||||||
|  | 				return rc; | ||||||
| 		} else { | 		} else { | ||||||
| 			/* Recurse down the path */ | 			/* Recurse down the path */ | ||||||
| 			size = tpda_get_element_size(in, -1); | 			rc = tpda_get_element_size(drvdata, in, -1); | ||||||
| 		} | 			if (rc) | ||||||
| 
 | 				return rc; | ||||||
| 		if (size < 0) |  | ||||||
| 			return size; |  | ||||||
| 
 |  | ||||||
| 		if (dsb_size < 0) { |  | ||||||
| 			/* Found a size, save it. */ |  | ||||||
| 			dsb_size = size; |  | ||||||
| 		} else { |  | ||||||
| 			/* Found duplicate TPDMs */ |  | ||||||
| 			return -EEXIST; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return dsb_size; | 
 | ||||||
|  | 	return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Settings pre enabling port control register */ | /* Settings pre enabling port control register */ | ||||||
|  | @ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata) | ||||||
| static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) | static int tpda_enable_port(struct tpda_drvdata *drvdata, int port) | ||||||
| { | { | ||||||
| 	u32 val; | 	u32 val; | ||||||
| 	int size; | 	int rc; | ||||||
| 
 | 
 | ||||||
| 	val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); | 	val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port)); | ||||||
| 	/*
 | 	tpda_clear_element_size(drvdata->csdev); | ||||||
| 	 * Configure aggregator port n DSB data set element size | 	rc = tpda_get_element_size(drvdata, drvdata->csdev, port); | ||||||
| 	 * Set the bit to 0 if the size is 32 | 	if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) { | ||||||
| 	 * Set the bit to 1 if the size is 64 | 		tpda_set_element_size(drvdata, &val); | ||||||
| 	 */ | 		/* Enable the port */ | ||||||
| 	size = tpda_get_element_size(drvdata->csdev, port); | 		val |= TPDA_Pn_CR_ENA; | ||||||
| 	switch (size) { | 		writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); | ||||||
| 	case 32: | 	} else if (rc == -EEXIST) | ||||||
| 		val &= ~TPDA_Pn_CR_DSBSIZE; |  | ||||||
| 		break; |  | ||||||
| 	case 64: |  | ||||||
| 		val |= TPDA_Pn_CR_DSBSIZE; |  | ||||||
| 		break; |  | ||||||
| 	case 0: |  | ||||||
| 		return -EEXIST; |  | ||||||
| 	case -EEXIST: |  | ||||||
| 		dev_warn_once(&drvdata->csdev->dev, | 		dev_warn_once(&drvdata->csdev->dev, | ||||||
| 			"Detected multiple TPDMs on port %d", -EEXIST); | 			      "Detected multiple TPDMs on port %d", port); | ||||||
| 		return -EEXIST; | 	else | ||||||
| 	default: | 		dev_warn_once(&drvdata->csdev->dev, | ||||||
| 		return -EINVAL; | 			      "Didn't find TPDM element size"); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Enable the port */ | 	return rc; | ||||||
| 	val |= TPDA_Pn_CR_ENA; |  | ||||||
| 	writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port)); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int __tpda_enable(struct tpda_drvdata *drvdata, int port) | static int __tpda_enable(struct tpda_drvdata *drvdata, int port) | ||||||
|  | @ -148,7 +168,12 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) | ||||||
| 
 | 
 | ||||||
| 	CS_UNLOCK(drvdata->base); | 	CS_UNLOCK(drvdata->base); | ||||||
| 
 | 
 | ||||||
| 	if (!drvdata->csdev->enable) | 	/*
 | ||||||
|  | 	 * Only do pre-port enable for first port that calls enable when the | ||||||
|  | 	 * device's main refcount is still 0 | ||||||
|  | 	 */ | ||||||
|  | 	lockdep_assert_held(&drvdata->spinlock); | ||||||
|  | 	if (!drvdata->csdev->refcnt) | ||||||
| 		tpda_enable_pre_port(drvdata); | 		tpda_enable_pre_port(drvdata); | ||||||
| 
 | 
 | ||||||
| 	ret = tpda_enable_port(drvdata, port); | 	ret = tpda_enable_port(drvdata, port); | ||||||
|  | @ -169,6 +194,7 @@ static int tpda_enable(struct coresight_device *csdev, | ||||||
| 		ret = __tpda_enable(drvdata, in->dest_port); | 		ret = __tpda_enable(drvdata, in->dest_port); | ||||||
| 		if (!ret) { | 		if (!ret) { | ||||||
| 			atomic_inc(&in->dest_refcnt); | 			atomic_inc(&in->dest_refcnt); | ||||||
|  | 			csdev->refcnt++; | ||||||
| 			dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); | 			dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -197,9 +223,10 @@ static void tpda_disable(struct coresight_device *csdev, | ||||||
| 	struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | 	struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&drvdata->spinlock); | 	spin_lock(&drvdata->spinlock); | ||||||
| 	if (atomic_dec_return(&in->dest_refcnt) == 0) | 	if (atomic_dec_return(&in->dest_refcnt) == 0) { | ||||||
| 		__tpda_disable(drvdata, in->dest_port); | 		__tpda_disable(drvdata, in->dest_port); | ||||||
| 
 | 		csdev->refcnt--; | ||||||
|  | 	} | ||||||
| 	spin_unlock(&drvdata->spinlock); | 	spin_unlock(&drvdata->spinlock); | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); | 	dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); | ||||||
|  | @ -300,7 +327,7 @@ static struct amba_id tpda_ids[] = { | ||||||
| 		.id     = 0x000f0f00, | 		.id     = 0x000f0f00, | ||||||
| 		.mask   = 0x000fff00, | 		.mask   = 0x000fff00, | ||||||
| 	}, | 	}, | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct amba_driver tpda_driver = { | static struct amba_driver tpda_driver = { | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ | ||||||
| #define TPDA_Pn_CR(n)		(0x004 + (n * 4)) | #define TPDA_Pn_CR(n)		(0x004 + (n * 4)) | ||||||
| /* Aggregator port enable bit */ | /* Aggregator port enable bit */ | ||||||
| #define TPDA_Pn_CR_ENA		BIT(0) | #define TPDA_Pn_CR_ENA		BIT(0) | ||||||
|  | /* Aggregator port CMB data set element size bit */ | ||||||
|  | #define TPDA_Pn_CR_CMBSIZE		GENMASK(7, 6) | ||||||
| /* Aggregator port DSB data set element size bit */ | /* Aggregator port DSB data set element size bit */ | ||||||
| #define TPDA_Pn_CR_DSBSIZE		BIT(8) | #define TPDA_Pn_CR_DSBSIZE		BIT(8) | ||||||
| 
 | 
 | ||||||
|  | @ -25,6 +27,8 @@ | ||||||
|  * @csdev:      component vitals needed by the framework. |  * @csdev:      component vitals needed by the framework. | ||||||
|  * @spinlock:   lock for the drvdata value. |  * @spinlock:   lock for the drvdata value. | ||||||
|  * @enable:     enable status of the component. |  * @enable:     enable status of the component. | ||||||
|  |  * @dsb_esize   Record the DSB element size. | ||||||
|  |  * @cmb_esize   Record the CMB element size. | ||||||
|  */ |  */ | ||||||
| struct tpda_drvdata { | struct tpda_drvdata { | ||||||
| 	void __iomem		*base; | 	void __iomem		*base; | ||||||
|  | @ -32,6 +36,8 @@ struct tpda_drvdata { | ||||||
| 	struct coresight_device	*csdev; | 	struct coresight_device	*csdev; | ||||||
| 	spinlock_t		spinlock; | 	spinlock_t		spinlock; | ||||||
| 	u8			atid; | 	u8			atid; | ||||||
|  | 	u32			dsb_esize; | ||||||
|  | 	u32			cmb_esize; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */ | #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */ | ||||||
|  |  | ||||||
|  | @ -66,6 +66,31 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev, | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		return sysfs_emit(buf, "0x%x\n", | 		return sysfs_emit(buf, "0x%x\n", | ||||||
| 				drvdata->dsb->msr[tpdm_attr->idx]); | 				drvdata->dsb->msr[tpdm_attr->idx]); | ||||||
|  | 	case CMB_TRIG_PATT: | ||||||
|  | 		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		return sysfs_emit(buf, "0x%x\n", | ||||||
|  | 			drvdata->cmb->trig_patt[tpdm_attr->idx]); | ||||||
|  | 	case CMB_TRIG_PATT_MASK: | ||||||
|  | 		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		return sysfs_emit(buf, "0x%x\n", | ||||||
|  | 			drvdata->cmb->trig_patt_mask[tpdm_attr->idx]); | ||||||
|  | 	case CMB_PATT: | ||||||
|  | 		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		return sysfs_emit(buf, "0x%x\n", | ||||||
|  | 			drvdata->cmb->patt_val[tpdm_attr->idx]); | ||||||
|  | 	case CMB_PATT_MASK: | ||||||
|  | 		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		return sysfs_emit(buf, "0x%x\n", | ||||||
|  | 			drvdata->cmb->patt_mask[tpdm_attr->idx]); | ||||||
|  | 	case CMB_MSR: | ||||||
|  | 		if (tpdm_attr->idx >= drvdata->cmb_msr_num) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		return sysfs_emit(buf, "0x%x\n", | ||||||
|  | 				drvdata->cmb->msr[tpdm_attr->idx]); | ||||||
| 	} | 	} | ||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| } | } | ||||||
|  | @ -77,60 +102,84 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev, | ||||||
| 					 size_t size) | 					 size_t size) | ||||||
| { | { | ||||||
| 	unsigned long val; | 	unsigned long val; | ||||||
| 	ssize_t ret = size; | 	ssize_t ret = -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
| 	struct tpdm_dataset_attribute *tpdm_attr = | 	struct tpdm_dataset_attribute *tpdm_attr = | ||||||
| 		container_of(attr, struct tpdm_dataset_attribute, attr); | 		container_of(attr, struct tpdm_dataset_attribute, attr); | ||||||
| 
 | 
 | ||||||
| 	if (kstrtoul(buf, 0, &val)) | 	if (kstrtoul(buf, 0, &val)) | ||||||
| 		return -EINVAL; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&drvdata->spinlock); | 	guard(spinlock)(&drvdata->spinlock); | ||||||
| 	switch (tpdm_attr->mem) { | 	switch (tpdm_attr->mem) { | ||||||
| 	case DSB_TRIG_PATT: | 	case DSB_TRIG_PATT: | ||||||
| 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { | ||||||
| 			drvdata->dsb->trig_patt[tpdm_attr->idx] = val; | 			drvdata->dsb->trig_patt[tpdm_attr->idx] = val; | ||||||
| 		else | 			ret = size; | ||||||
| 			ret = -EINVAL; | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case DSB_TRIG_PATT_MASK: | 	case DSB_TRIG_PATT_MASK: | ||||||
| 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { | ||||||
| 			drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val; | 			drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val; | ||||||
| 		else | 			ret = size; | ||||||
| 			ret = -EINVAL; | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case DSB_PATT: | 	case DSB_PATT: | ||||||
| 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { | ||||||
| 			drvdata->dsb->patt_val[tpdm_attr->idx] = val; | 			drvdata->dsb->patt_val[tpdm_attr->idx] = val; | ||||||
| 		else | 			ret = size; | ||||||
| 			ret = -EINVAL; | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case DSB_PATT_MASK: | 	case DSB_PATT_MASK: | ||||||
| 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) | 		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) { | ||||||
| 			drvdata->dsb->patt_mask[tpdm_attr->idx] = val; | 			drvdata->dsb->patt_mask[tpdm_attr->idx] = val; | ||||||
| 		else | 			ret = size; | ||||||
| 			ret = -EINVAL; | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case DSB_MSR: | 	case DSB_MSR: | ||||||
| 		if (tpdm_attr->idx < drvdata->dsb_msr_num) | 		if (tpdm_attr->idx < drvdata->dsb_msr_num) { | ||||||
| 			drvdata->dsb->msr[tpdm_attr->idx] = val; | 			drvdata->dsb->msr[tpdm_attr->idx] = val; | ||||||
| 		else | 			ret = size; | ||||||
| 			ret = -EINVAL; | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CMB_TRIG_PATT: | ||||||
|  | 		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||||||
|  | 			drvdata->cmb->trig_patt[tpdm_attr->idx] = val; | ||||||
|  | 			ret = size; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CMB_TRIG_PATT_MASK: | ||||||
|  | 		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||||||
|  | 			drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val; | ||||||
|  | 			ret = size; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CMB_PATT: | ||||||
|  | 		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||||||
|  | 			drvdata->cmb->patt_val[tpdm_attr->idx] = val; | ||||||
|  | 			ret = size; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CMB_PATT_MASK: | ||||||
|  | 		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) { | ||||||
|  | 			drvdata->cmb->patt_mask[tpdm_attr->idx] = val; | ||||||
|  | 			ret = size; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CMB_MSR: | ||||||
|  | 		if (tpdm_attr->idx < drvdata->cmb_msr_num) { | ||||||
|  | 			drvdata->cmb->msr[tpdm_attr->idx] = val; | ||||||
|  | 			ret = size; | ||||||
|  | 		} | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		ret = -EINVAL; | 		break; | ||||||
| 	} | 	} | ||||||
| 	spin_unlock(&drvdata->spinlock); |  | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) |  | ||||||
| { |  | ||||||
| 	return (drvdata->datasets & TPDM_PIDR0_DS_DSB); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static umode_t tpdm_dsb_is_visible(struct kobject *kobj, | static umode_t tpdm_dsb_is_visible(struct kobject *kobj, | ||||||
| 				   struct attribute *attr, int n) | 				   struct attribute *attr, int n) | ||||||
| { | { | ||||||
|  | @ -143,6 +192,18 @@ static umode_t tpdm_dsb_is_visible(struct kobject *kobj, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static umode_t tpdm_cmb_is_visible(struct kobject *kobj, | ||||||
|  | 				   struct attribute *attr, int n) | ||||||
|  | { | ||||||
|  | 	struct device *dev = kobj_to_dev(kobj); | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 
 | ||||||
|  | 	if (drvdata && tpdm_has_cmb_dataset(drvdata)) | ||||||
|  | 		return attr->mode; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, | static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, | ||||||
| 				       struct attribute *attr, int n) | 				       struct attribute *attr, int n) | ||||||
| { | { | ||||||
|  | @ -159,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj, | ||||||
|  | 				       struct attribute *attr, int n) | ||||||
|  | { | ||||||
|  | 	struct device *dev = kobj_to_dev(kobj); | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 
 | ||||||
|  | 	struct device_attribute *dev_attr = | ||||||
|  | 		container_of(attr, struct device_attribute, attr); | ||||||
|  | 	struct tpdm_dataset_attribute *tpdm_attr = | ||||||
|  | 		container_of(dev_attr, struct tpdm_dataset_attribute, attr); | ||||||
|  | 
 | ||||||
|  | 	if (tpdm_attr->idx < drvdata->cmb_msr_num) | ||||||
|  | 		return attr->mode; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) | static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) | ||||||
| { | { | ||||||
| 	if (tpdm_has_dsb_dataset(drvdata)) { | 	if (tpdm_has_dsb_dataset(drvdata)) { | ||||||
|  | @ -167,6 +245,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata) | ||||||
| 		drvdata->dsb->trig_ts = true; | 		drvdata->dsb->trig_ts = true; | ||||||
| 		drvdata->dsb->trig_type = false; | 		drvdata->dsb->trig_type = false; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (drvdata->cmb) | ||||||
|  | 		memset(drvdata->cmb, 0, sizeof(struct cmb_dataset)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val) | static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val) | ||||||
|  | @ -233,25 +314,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) | ||||||
| { | { | ||||||
| 	u32 val, i; | 	u32 val, i; | ||||||
| 
 | 
 | ||||||
|  | 	if (!tpdm_has_dsb_dataset(drvdata)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) | 	for (i = 0; i < TPDM_DSB_MAX_EDCR; i++) | ||||||
| 		writel_relaxed(drvdata->dsb->edge_ctrl[i], | 		writel_relaxed(drvdata->dsb->edge_ctrl[i], | ||||||
| 			   drvdata->base + TPDM_DSB_EDCR(i)); | 			       drvdata->base + TPDM_DSB_EDCR(i)); | ||||||
| 	for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) | 	for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++) | ||||||
| 		writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], | 		writel_relaxed(drvdata->dsb->edge_ctrl_mask[i], | ||||||
| 			   drvdata->base + TPDM_DSB_EDCMR(i)); | 			       drvdata->base + TPDM_DSB_EDCMR(i)); | ||||||
| 	for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { | 	for (i = 0; i < TPDM_DSB_MAX_PATT; i++) { | ||||||
| 		writel_relaxed(drvdata->dsb->patt_val[i], | 		writel_relaxed(drvdata->dsb->patt_val[i], | ||||||
| 			   drvdata->base + TPDM_DSB_TPR(i)); | 			       drvdata->base + TPDM_DSB_TPR(i)); | ||||||
| 		writel_relaxed(drvdata->dsb->patt_mask[i], | 		writel_relaxed(drvdata->dsb->patt_mask[i], | ||||||
| 			   drvdata->base + TPDM_DSB_TPMR(i)); | 			       drvdata->base + TPDM_DSB_TPMR(i)); | ||||||
| 		writel_relaxed(drvdata->dsb->trig_patt[i], | 		writel_relaxed(drvdata->dsb->trig_patt[i], | ||||||
| 			   drvdata->base + TPDM_DSB_XPR(i)); | 			       drvdata->base + TPDM_DSB_XPR(i)); | ||||||
| 		writel_relaxed(drvdata->dsb->trig_patt_mask[i], | 		writel_relaxed(drvdata->dsb->trig_patt_mask[i], | ||||||
| 			   drvdata->base + TPDM_DSB_XPMR(i)); | 			       drvdata->base + TPDM_DSB_XPMR(i)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	set_dsb_tier(drvdata); | 	set_dsb_tier(drvdata); | ||||||
| 
 |  | ||||||
| 	set_dsb_msr(drvdata); | 	set_dsb_msr(drvdata); | ||||||
| 
 | 
 | ||||||
| 	val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | 	val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | ||||||
|  | @ -267,6 +350,76 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata) | ||||||
| 	writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | 	writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void set_cmb_tier(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	u32 val; | ||||||
|  | 
 | ||||||
|  | 	val = readl_relaxed(drvdata->base + TPDM_CMB_TIER); | ||||||
|  | 
 | ||||||
|  | 	/* Clear all relevant fields */ | ||||||
|  | 	val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL | | ||||||
|  | 		 TPDM_CMB_TIER_XTRIG_TSENAB); | ||||||
|  | 
 | ||||||
|  | 	/* Set pattern timestamp type and enablement */ | ||||||
|  | 	if (drvdata->cmb->patt_ts) | ||||||
|  | 		val |= TPDM_CMB_TIER_PATT_TSENAB; | ||||||
|  | 
 | ||||||
|  | 	/* Set trigger timestamp */ | ||||||
|  | 	if (drvdata->cmb->trig_ts) | ||||||
|  | 		val |= TPDM_CMB_TIER_XTRIG_TSENAB; | ||||||
|  | 
 | ||||||
|  | 	/* Set all timestamp enablement*/ | ||||||
|  | 	if (drvdata->cmb->ts_all) | ||||||
|  | 		val |= TPDM_CMB_TIER_TS_ALL; | ||||||
|  | 
 | ||||||
|  | 	writel_relaxed(val, drvdata->base + TPDM_CMB_TIER); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void set_cmb_msr(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < drvdata->cmb_msr_num; i++) | ||||||
|  | 		writel_relaxed(drvdata->cmb->msr[i], | ||||||
|  | 			   drvdata->base + TPDM_CMB_MSR(i)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	u32 val, i; | ||||||
|  | 
 | ||||||
|  | 	if (!tpdm_has_cmb_dataset(drvdata)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	/* Configure pattern registers */ | ||||||
|  | 	for (i = 0; i < TPDM_CMB_MAX_PATT; i++) { | ||||||
|  | 		writel_relaxed(drvdata->cmb->patt_val[i], | ||||||
|  | 			drvdata->base + TPDM_CMB_TPR(i)); | ||||||
|  | 		writel_relaxed(drvdata->cmb->patt_mask[i], | ||||||
|  | 			drvdata->base + TPDM_CMB_TPMR(i)); | ||||||
|  | 		writel_relaxed(drvdata->cmb->trig_patt[i], | ||||||
|  | 			drvdata->base + TPDM_CMB_XPR(i)); | ||||||
|  | 		writel_relaxed(drvdata->cmb->trig_patt_mask[i], | ||||||
|  | 			drvdata->base + TPDM_CMB_XPMR(i)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	set_cmb_tier(drvdata); | ||||||
|  | 	set_cmb_msr(drvdata); | ||||||
|  | 
 | ||||||
|  | 	val = readl_relaxed(drvdata->base + TPDM_CMB_CR); | ||||||
|  | 	/*
 | ||||||
|  | 	 * Set to 0 for continuous CMB collection mode, | ||||||
|  | 	 * 1 for trace-on-change CMB collection mode. | ||||||
|  | 	 */ | ||||||
|  | 	if (drvdata->cmb->trace_mode) | ||||||
|  | 		val |= TPDM_CMB_CR_MODE; | ||||||
|  | 	else | ||||||
|  | 		val &= ~TPDM_CMB_CR_MODE; | ||||||
|  | 	/* Set the enable bit of CMB control register to 1 */ | ||||||
|  | 	val |= TPDM_CMB_CR_ENA; | ||||||
|  | 	writel_relaxed(val, drvdata->base + TPDM_CMB_CR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * TPDM enable operations |  * TPDM enable operations | ||||||
|  * The TPDM or Monitor serves as data collection component for various |  * The TPDM or Monitor serves as data collection component for various | ||||||
|  | @ -279,8 +432,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata) | ||||||
| { | { | ||||||
| 	CS_UNLOCK(drvdata->base); | 	CS_UNLOCK(drvdata->base); | ||||||
| 
 | 
 | ||||||
| 	if (tpdm_has_dsb_dataset(drvdata)) | 	tpdm_enable_dsb(drvdata); | ||||||
| 		tpdm_enable_dsb(drvdata); | 	tpdm_enable_cmb(drvdata); | ||||||
| 
 | 
 | ||||||
| 	CS_LOCK(drvdata->base); | 	CS_LOCK(drvdata->base); | ||||||
| } | } | ||||||
|  | @ -308,19 +461,35 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata) | ||||||
| { | { | ||||||
| 	u32 val; | 	u32 val; | ||||||
| 
 | 
 | ||||||
|  | 	if (!tpdm_has_dsb_dataset(drvdata)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	/* Set the enable bit of DSB control register to 0 */ | 	/* Set the enable bit of DSB control register to 0 */ | ||||||
| 	val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | 	val = readl_relaxed(drvdata->base + TPDM_DSB_CR); | ||||||
| 	val &= ~TPDM_DSB_CR_ENA; | 	val &= ~TPDM_DSB_CR_ENA; | ||||||
| 	writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | 	writel_relaxed(val, drvdata->base + TPDM_DSB_CR); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	u32 val; | ||||||
|  | 
 | ||||||
|  | 	if (!tpdm_has_cmb_dataset(drvdata)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	val = readl_relaxed(drvdata->base + TPDM_CMB_CR); | ||||||
|  | 	/* Set the enable bit of CMB control register to 0 */ | ||||||
|  | 	val &= ~TPDM_CMB_CR_ENA; | ||||||
|  | 	writel_relaxed(val, drvdata->base + TPDM_CMB_CR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* TPDM disable operations */ | /* TPDM disable operations */ | ||||||
| static void __tpdm_disable(struct tpdm_drvdata *drvdata) | static void __tpdm_disable(struct tpdm_drvdata *drvdata) | ||||||
| { | { | ||||||
| 	CS_UNLOCK(drvdata->base); | 	CS_UNLOCK(drvdata->base); | ||||||
| 
 | 
 | ||||||
| 	if (tpdm_has_dsb_dataset(drvdata)) | 	tpdm_disable_dsb(drvdata); | ||||||
| 		tpdm_disable_dsb(drvdata); | 	tpdm_disable_cmb(drvdata); | ||||||
| 
 | 
 | ||||||
| 	CS_LOCK(drvdata->base); | 	CS_LOCK(drvdata->base); | ||||||
| } | } | ||||||
|  | @ -366,6 +535,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata) | ||||||
| 		if (!drvdata->dsb) | 		if (!drvdata->dsb) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) { | ||||||
|  | 		drvdata->cmb = devm_kzalloc(drvdata->dev, | ||||||
|  | 						sizeof(*drvdata->cmb), GFP_KERNEL); | ||||||
|  | 		if (!drvdata->cmb) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 	} | ||||||
| 	tpdm_reset_datasets(drvdata); | 	tpdm_reset_datasets(drvdata); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -577,9 +752,18 @@ static ssize_t enable_ts_show(struct device *dev, | ||||||
| 			      char *buf) | 			      char *buf) | ||||||
| { | { | ||||||
| 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 	struct tpdm_dataset_attribute *tpdm_attr = | ||||||
|  | 		container_of(attr, struct tpdm_dataset_attribute, attr); | ||||||
|  | 	ssize_t size = -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	return sysfs_emit(buf, "%u\n", | 	if (tpdm_attr->mem == DSB_PATT) | ||||||
| 			 (unsigned int)drvdata->dsb->patt_ts); | 		size = sysfs_emit(buf, "%u\n", | ||||||
|  | 				  (unsigned int)drvdata->dsb->patt_ts); | ||||||
|  | 	else if (tpdm_attr->mem == CMB_PATT) | ||||||
|  | 		size = sysfs_emit(buf, "%u\n", | ||||||
|  | 				  (unsigned int)drvdata->cmb->patt_ts); | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -591,17 +775,23 @@ static ssize_t enable_ts_store(struct device *dev, | ||||||
| 			       size_t size) | 			       size_t size) | ||||||
| { | { | ||||||
| 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 	struct tpdm_dataset_attribute *tpdm_attr = | ||||||
|  | 		container_of(attr, struct tpdm_dataset_attribute, attr); | ||||||
| 	unsigned long val; | 	unsigned long val; | ||||||
| 
 | 
 | ||||||
| 	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | 	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&drvdata->spinlock); | 	guard(spinlock)(&drvdata->spinlock); | ||||||
| 	drvdata->dsb->patt_ts = !!val; | 	if (tpdm_attr->mem == DSB_PATT) | ||||||
| 	spin_unlock(&drvdata->spinlock); | 		drvdata->dsb->patt_ts = !!val; | ||||||
|  | 	else if (tpdm_attr->mem == CMB_PATT) | ||||||
|  | 		drvdata->cmb->patt_ts = !!val; | ||||||
|  | 	else | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
| 	return size; | 	return size; | ||||||
| } | } | ||||||
| static DEVICE_ATTR_RW(enable_ts); |  | ||||||
| 
 | 
 | ||||||
| static ssize_t set_type_show(struct device *dev, | static ssize_t set_type_show(struct device *dev, | ||||||
| 			     struct device_attribute *attr, | 			     struct device_attribute *attr, | ||||||
|  | @ -704,6 +894,96 @@ static ssize_t dsb_trig_ts_store(struct device *dev, | ||||||
| } | } | ||||||
| static DEVICE_ATTR_RW(dsb_trig_ts); | static DEVICE_ATTR_RW(dsb_trig_ts); | ||||||
| 
 | 
 | ||||||
|  | static ssize_t cmb_mode_show(struct device *dev, | ||||||
|  | 			     struct device_attribute *attr, | ||||||
|  | 			     char *buf) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t cmb_mode_store(struct device *dev, | ||||||
|  | 			      struct device_attribute *attr, | ||||||
|  | 			      const char *buf, | ||||||
|  | 			      size_t size) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 	unsigned long trace_mode; | ||||||
|  | 
 | ||||||
|  | 	if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	spin_lock(&drvdata->spinlock); | ||||||
|  | 	drvdata->cmb->trace_mode = trace_mode; | ||||||
|  | 	spin_unlock(&drvdata->spinlock); | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RW(cmb_mode); | ||||||
|  | 
 | ||||||
|  | static ssize_t cmb_ts_all_show(struct device *dev, | ||||||
|  | 			       struct device_attribute *attr, | ||||||
|  | 			       char *buf) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%u\n", | ||||||
|  | 			  (unsigned int)drvdata->cmb->ts_all); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t cmb_ts_all_store(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, | ||||||
|  | 				const char *buf, | ||||||
|  | 				size_t size) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 	unsigned long val; | ||||||
|  | 
 | ||||||
|  | 	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	guard(spinlock)(&drvdata->spinlock); | ||||||
|  | 	if (val) | ||||||
|  | 		drvdata->cmb->ts_all = true; | ||||||
|  | 	else | ||||||
|  | 		drvdata->cmb->ts_all = false; | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RW(cmb_ts_all); | ||||||
|  | 
 | ||||||
|  | static ssize_t cmb_trig_ts_show(struct device *dev, | ||||||
|  | 				struct device_attribute *attr, | ||||||
|  | 				char *buf) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 
 | ||||||
|  | 	return sysfs_emit(buf, "%u\n", | ||||||
|  | 			  (unsigned int)drvdata->cmb->trig_ts); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t cmb_trig_ts_store(struct device *dev, | ||||||
|  | 				 struct device_attribute *attr, | ||||||
|  | 				 const char *buf, | ||||||
|  | 				 size_t size) | ||||||
|  | { | ||||||
|  | 	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); | ||||||
|  | 	unsigned long val; | ||||||
|  | 
 | ||||||
|  | 	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	guard(spinlock)(&drvdata->spinlock); | ||||||
|  | 	if (val) | ||||||
|  | 		drvdata->cmb->trig_ts = true; | ||||||
|  | 	else | ||||||
|  | 		drvdata->cmb->trig_ts = false; | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RW(cmb_trig_ts); | ||||||
|  | 
 | ||||||
| static struct attribute *tpdm_dsb_edge_attrs[] = { | static struct attribute *tpdm_dsb_edge_attrs[] = { | ||||||
| 	&dev_attr_ctrl_idx.attr, | 	&dev_attr_ctrl_idx.attr, | ||||||
| 	&dev_attr_ctrl_val.attr, | 	&dev_attr_ctrl_val.attr, | ||||||
|  | @ -772,7 +1052,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = { | ||||||
| 	DSB_PATT_MASK_ATTR(5), | 	DSB_PATT_MASK_ATTR(5), | ||||||
| 	DSB_PATT_MASK_ATTR(6), | 	DSB_PATT_MASK_ATTR(6), | ||||||
| 	DSB_PATT_MASK_ATTR(7), | 	DSB_PATT_MASK_ATTR(7), | ||||||
| 	&dev_attr_enable_ts.attr, | 	DSB_PATT_ENABLE_TS, | ||||||
| 	&dev_attr_set_type.attr, | 	&dev_attr_set_type.attr, | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
|  | @ -813,6 +1093,59 @@ static struct attribute *tpdm_dsb_msr_attrs[] = { | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct attribute *tpdm_cmb_trig_patt_attrs[] = { | ||||||
|  | 	CMB_TRIG_PATT_ATTR(0), | ||||||
|  | 	CMB_TRIG_PATT_ATTR(1), | ||||||
|  | 	CMB_TRIG_PATT_MASK_ATTR(0), | ||||||
|  | 	CMB_TRIG_PATT_MASK_ATTR(1), | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct attribute *tpdm_cmb_patt_attrs[] = { | ||||||
|  | 	CMB_PATT_ATTR(0), | ||||||
|  | 	CMB_PATT_ATTR(1), | ||||||
|  | 	CMB_PATT_MASK_ATTR(0), | ||||||
|  | 	CMB_PATT_MASK_ATTR(1), | ||||||
|  | 	CMB_PATT_ENABLE_TS, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct attribute *tpdm_cmb_msr_attrs[] = { | ||||||
|  | 	CMB_MSR_ATTR(0), | ||||||
|  | 	CMB_MSR_ATTR(1), | ||||||
|  | 	CMB_MSR_ATTR(2), | ||||||
|  | 	CMB_MSR_ATTR(3), | ||||||
|  | 	CMB_MSR_ATTR(4), | ||||||
|  | 	CMB_MSR_ATTR(5), | ||||||
|  | 	CMB_MSR_ATTR(6), | ||||||
|  | 	CMB_MSR_ATTR(7), | ||||||
|  | 	CMB_MSR_ATTR(8), | ||||||
|  | 	CMB_MSR_ATTR(9), | ||||||
|  | 	CMB_MSR_ATTR(10), | ||||||
|  | 	CMB_MSR_ATTR(11), | ||||||
|  | 	CMB_MSR_ATTR(12), | ||||||
|  | 	CMB_MSR_ATTR(13), | ||||||
|  | 	CMB_MSR_ATTR(14), | ||||||
|  | 	CMB_MSR_ATTR(15), | ||||||
|  | 	CMB_MSR_ATTR(16), | ||||||
|  | 	CMB_MSR_ATTR(17), | ||||||
|  | 	CMB_MSR_ATTR(18), | ||||||
|  | 	CMB_MSR_ATTR(19), | ||||||
|  | 	CMB_MSR_ATTR(20), | ||||||
|  | 	CMB_MSR_ATTR(21), | ||||||
|  | 	CMB_MSR_ATTR(22), | ||||||
|  | 	CMB_MSR_ATTR(23), | ||||||
|  | 	CMB_MSR_ATTR(24), | ||||||
|  | 	CMB_MSR_ATTR(25), | ||||||
|  | 	CMB_MSR_ATTR(26), | ||||||
|  | 	CMB_MSR_ATTR(27), | ||||||
|  | 	CMB_MSR_ATTR(28), | ||||||
|  | 	CMB_MSR_ATTR(29), | ||||||
|  | 	CMB_MSR_ATTR(30), | ||||||
|  | 	CMB_MSR_ATTR(31), | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static struct attribute *tpdm_dsb_attrs[] = { | static struct attribute *tpdm_dsb_attrs[] = { | ||||||
| 	&dev_attr_dsb_mode.attr, | 	&dev_attr_dsb_mode.attr, | ||||||
| 	&dev_attr_dsb_trig_ts.attr, | 	&dev_attr_dsb_trig_ts.attr, | ||||||
|  | @ -820,6 +1153,13 @@ static struct attribute *tpdm_dsb_attrs[] = { | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct attribute *tpdm_cmb_attrs[] = { | ||||||
|  | 	&dev_attr_cmb_mode.attr, | ||||||
|  | 	&dev_attr_cmb_ts_all.attr, | ||||||
|  | 	&dev_attr_cmb_trig_ts.attr, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static struct attribute_group tpdm_dsb_attr_grp = { | static struct attribute_group tpdm_dsb_attr_grp = { | ||||||
| 	.attrs = tpdm_dsb_attrs, | 	.attrs = tpdm_dsb_attrs, | ||||||
| 	.is_visible = tpdm_dsb_is_visible, | 	.is_visible = tpdm_dsb_is_visible, | ||||||
|  | @ -849,6 +1189,29 @@ static struct attribute_group tpdm_dsb_msr_grp = { | ||||||
| 	.name = "dsb_msr", | 	.name = "dsb_msr", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct attribute_group tpdm_cmb_attr_grp = { | ||||||
|  | 	.attrs = tpdm_cmb_attrs, | ||||||
|  | 	.is_visible = tpdm_cmb_is_visible, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct attribute_group tpdm_cmb_trig_patt_grp = { | ||||||
|  | 	.attrs = tpdm_cmb_trig_patt_attrs, | ||||||
|  | 	.is_visible = tpdm_cmb_is_visible, | ||||||
|  | 	.name = "cmb_trig_patt", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct attribute_group tpdm_cmb_patt_grp = { | ||||||
|  | 	.attrs = tpdm_cmb_patt_attrs, | ||||||
|  | 	.is_visible = tpdm_cmb_is_visible, | ||||||
|  | 	.name = "cmb_patt", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct attribute_group tpdm_cmb_msr_grp = { | ||||||
|  | 	.attrs = tpdm_cmb_msr_attrs, | ||||||
|  | 	.is_visible = tpdm_cmb_msr_is_visible, | ||||||
|  | 	.name = "cmb_msr", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct attribute_group *tpdm_attr_grps[] = { | static const struct attribute_group *tpdm_attr_grps[] = { | ||||||
| 	&tpdm_attr_grp, | 	&tpdm_attr_grp, | ||||||
| 	&tpdm_dsb_attr_grp, | 	&tpdm_dsb_attr_grp, | ||||||
|  | @ -856,6 +1219,10 @@ static const struct attribute_group *tpdm_attr_grps[] = { | ||||||
| 	&tpdm_dsb_trig_patt_grp, | 	&tpdm_dsb_trig_patt_grp, | ||||||
| 	&tpdm_dsb_patt_grp, | 	&tpdm_dsb_patt_grp, | ||||||
| 	&tpdm_dsb_msr_grp, | 	&tpdm_dsb_msr_grp, | ||||||
|  | 	&tpdm_cmb_attr_grp, | ||||||
|  | 	&tpdm_cmb_trig_patt_grp, | ||||||
|  | 	&tpdm_cmb_patt_grp, | ||||||
|  | 	&tpdm_cmb_msr_grp, | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -894,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) | ||||||
| 		of_property_read_u32(drvdata->dev->of_node, | 		of_property_read_u32(drvdata->dev->of_node, | ||||||
| 			   "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); | 			   "qcom,dsb-msrs-num", &drvdata->dsb_msr_num); | ||||||
| 
 | 
 | ||||||
|  | 	if (drvdata && tpdm_has_cmb_dataset(drvdata)) | ||||||
|  | 		of_property_read_u32(drvdata->dev->of_node, | ||||||
|  | 			   "qcom,cmb-msrs-num", &drvdata->cmb_msr_num); | ||||||
|  | 
 | ||||||
| 	/* Set up coresight component description */ | 	/* Set up coresight component description */ | ||||||
| 	desc.name = coresight_alloc_device_name(&tpdm_devs, dev); | 	desc.name = coresight_alloc_device_name(&tpdm_devs, dev); | ||||||
| 	if (!desc.name) | 	if (!desc.name) | ||||||
|  | @ -933,7 +1304,7 @@ static struct amba_id tpdm_ids[] = { | ||||||
| 		.id = 0x000f0e00, | 		.id = 0x000f0e00, | ||||||
| 		.mask = 0x000fff00, | 		.mask = 0x000fff00, | ||||||
| 	}, | 	}, | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct amba_driver tpdm_driver = { | static struct amba_driver tpdm_driver = { | ||||||
|  |  | ||||||
|  | @ -9,6 +9,38 @@ | ||||||
| /* The max number of the datasets that TPDM supports */ | /* The max number of the datasets that TPDM supports */ | ||||||
| #define TPDM_DATASETS       7 | #define TPDM_DATASETS       7 | ||||||
| 
 | 
 | ||||||
|  | /* CMB Subunit Registers */ | ||||||
|  | #define TPDM_CMB_CR		(0xA00) | ||||||
|  | /* CMB subunit timestamp insertion enable register */ | ||||||
|  | #define TPDM_CMB_TIER		(0xA04) | ||||||
|  | /* CMB subunit timestamp pattern registers */ | ||||||
|  | #define TPDM_CMB_TPR(n)		(0xA08 + (n * 4)) | ||||||
|  | /* CMB subunit timestamp pattern mask registers */ | ||||||
|  | #define TPDM_CMB_TPMR(n)	(0xA10 + (n * 4)) | ||||||
|  | /* CMB subunit trigger pattern registers */ | ||||||
|  | #define TPDM_CMB_XPR(n)		(0xA18 + (n * 4)) | ||||||
|  | /* CMB subunit trigger pattern mask registers */ | ||||||
|  | #define TPDM_CMB_XPMR(n)	(0xA20 + (n * 4)) | ||||||
|  | /* CMB MSR register */ | ||||||
|  | #define TPDM_CMB_MSR(n)		(0xA80 + (n * 4)) | ||||||
|  | 
 | ||||||
|  | /* Enable bit for CMB subunit */ | ||||||
|  | #define TPDM_CMB_CR_ENA		BIT(0) | ||||||
|  | /* Trace collection mode for CMB subunit */ | ||||||
|  | #define TPDM_CMB_CR_MODE	BIT(1) | ||||||
|  | /* Timestamp control for pattern match */ | ||||||
|  | #define TPDM_CMB_TIER_PATT_TSENAB	BIT(0) | ||||||
|  | /* CMB CTI timestamp request */ | ||||||
|  | #define TPDM_CMB_TIER_XTRIG_TSENAB	BIT(1) | ||||||
|  | /* For timestamp fo all trace */ | ||||||
|  | #define TPDM_CMB_TIER_TS_ALL		BIT(2) | ||||||
|  | 
 | ||||||
|  | /* Patten register number */ | ||||||
|  | #define TPDM_CMB_MAX_PATT		2 | ||||||
|  | 
 | ||||||
|  | /* MAX number of DSB MSR */ | ||||||
|  | #define TPDM_CMB_MAX_MSR 32 | ||||||
|  | 
 | ||||||
| /* DSB Subunit Registers */ | /* DSB Subunit Registers */ | ||||||
| #define TPDM_DSB_CR		(0x780) | #define TPDM_DSB_CR		(0x780) | ||||||
| #define TPDM_DSB_TIER		(0x784) | #define TPDM_DSB_TIER		(0x784) | ||||||
|  | @ -79,10 +111,12 @@ | ||||||
|  * |  * | ||||||
|  * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0 |  * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0 | ||||||
|  * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0 |  * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0 | ||||||
|  |  * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #define TPDM_PIDR0_DS_IMPDEF	BIT(0) | #define TPDM_PIDR0_DS_IMPDEF	BIT(0) | ||||||
| #define TPDM_PIDR0_DS_DSB	BIT(1) | #define TPDM_PIDR0_DS_DSB	BIT(1) | ||||||
|  | #define TPDM_PIDR0_DS_CMB	BIT(2) | ||||||
| 
 | 
 | ||||||
| #define TPDM_DSB_MAX_LINES	256 | #define TPDM_DSB_MAX_LINES	256 | ||||||
| /* MAX number of EDCR registers */ | /* MAX number of EDCR registers */ | ||||||
|  | @ -113,6 +147,16 @@ | ||||||
| 	   }								\ | 	   }								\ | ||||||
| 	})[0].attr.attr) | 	})[0].attr.attr) | ||||||
| 
 | 
 | ||||||
|  | #define tpdm_patt_enable_ts(name, mem)				\ | ||||||
|  | 	(&((struct tpdm_dataset_attribute[]) {			\ | ||||||
|  | 	   {							\ | ||||||
|  | 		__ATTR(name, 0644, enable_ts_show,		\ | ||||||
|  | 		enable_ts_store),		\ | ||||||
|  | 		mem,						\ | ||||||
|  | 		0,						\ | ||||||
|  | 	   }							\ | ||||||
|  | 	})[0].attr.attr) | ||||||
|  | 
 | ||||||
| #define DSB_EDGE_CTRL_ATTR(nr)					\ | #define DSB_EDGE_CTRL_ATTR(nr)					\ | ||||||
| 		tpdm_simple_dataset_ro(edcr##nr,		\ | 		tpdm_simple_dataset_ro(edcr##nr,		\ | ||||||
| 		DSB_EDGE_CTRL, nr) | 		DSB_EDGE_CTRL, nr) | ||||||
|  | @ -137,10 +181,38 @@ | ||||||
| 		tpdm_simple_dataset_rw(tpmr##nr,		\ | 		tpdm_simple_dataset_rw(tpmr##nr,		\ | ||||||
| 		DSB_PATT_MASK, nr) | 		DSB_PATT_MASK, nr) | ||||||
| 
 | 
 | ||||||
|  | #define DSB_PATT_ENABLE_TS					\ | ||||||
|  | 		tpdm_patt_enable_ts(enable_ts,			\ | ||||||
|  | 		DSB_PATT) | ||||||
|  | 
 | ||||||
| #define DSB_MSR_ATTR(nr)					\ | #define DSB_MSR_ATTR(nr)					\ | ||||||
| 		tpdm_simple_dataset_rw(msr##nr,			\ | 		tpdm_simple_dataset_rw(msr##nr,			\ | ||||||
| 		DSB_MSR, nr) | 		DSB_MSR, nr) | ||||||
| 
 | 
 | ||||||
|  | #define CMB_TRIG_PATT_ATTR(nr)					\ | ||||||
|  | 		tpdm_simple_dataset_rw(xpr##nr,			\ | ||||||
|  | 		CMB_TRIG_PATT, nr) | ||||||
|  | 
 | ||||||
|  | #define CMB_TRIG_PATT_MASK_ATTR(nr)				\ | ||||||
|  | 		tpdm_simple_dataset_rw(xpmr##nr,		\ | ||||||
|  | 		CMB_TRIG_PATT_MASK, nr) | ||||||
|  | 
 | ||||||
|  | #define CMB_PATT_ATTR(nr)					\ | ||||||
|  | 		tpdm_simple_dataset_rw(tpr##nr,			\ | ||||||
|  | 		CMB_PATT, nr) | ||||||
|  | 
 | ||||||
|  | #define CMB_PATT_MASK_ATTR(nr)					\ | ||||||
|  | 		tpdm_simple_dataset_rw(tpmr##nr,		\ | ||||||
|  | 		CMB_PATT_MASK, nr) | ||||||
|  | 
 | ||||||
|  | #define CMB_PATT_ENABLE_TS					\ | ||||||
|  | 		tpdm_patt_enable_ts(enable_ts,			\ | ||||||
|  | 		CMB_PATT) | ||||||
|  | 
 | ||||||
|  | #define CMB_MSR_ATTR(nr)					\ | ||||||
|  | 		tpdm_simple_dataset_rw(msr##nr,			\ | ||||||
|  | 		CMB_MSR, nr) | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct dsb_dataset - specifics associated to dsb dataset |  * struct dsb_dataset - specifics associated to dsb dataset | ||||||
|  * @mode:             DSB programming mode |  * @mode:             DSB programming mode | ||||||
|  | @ -173,6 +245,30 @@ struct dsb_dataset { | ||||||
| 	bool			trig_type; | 	bool			trig_type; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct cmb_dataset | ||||||
|  |  * @trace_mode:       Dataset collection mode | ||||||
|  |  * @patt_val:         Save value for pattern | ||||||
|  |  * @patt_mask:        Save value for pattern mask | ||||||
|  |  * @trig_patt:        Save value for trigger pattern | ||||||
|  |  * @trig_patt_mask:   Save value for trigger pattern mask | ||||||
|  |  * @msr               Save value for MSR | ||||||
|  |  * @patt_ts:          Indicates if pattern match for timestamp is enabled. | ||||||
|  |  * @trig_ts:          Indicates if CTI trigger for timestamp is enabled. | ||||||
|  |  * @ts_all:           Indicates if timestamp is enabled for all packets. | ||||||
|  |  */ | ||||||
|  | struct cmb_dataset { | ||||||
|  | 	u32			trace_mode; | ||||||
|  | 	u32			patt_val[TPDM_CMB_MAX_PATT]; | ||||||
|  | 	u32			patt_mask[TPDM_CMB_MAX_PATT]; | ||||||
|  | 	u32			trig_patt[TPDM_CMB_MAX_PATT]; | ||||||
|  | 	u32			trig_patt_mask[TPDM_CMB_MAX_PATT]; | ||||||
|  | 	u32			msr[TPDM_CMB_MAX_MSR]; | ||||||
|  | 	bool			patt_ts; | ||||||
|  | 	bool			trig_ts; | ||||||
|  | 	bool			ts_all; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct tpdm_drvdata - specifics associated to an TPDM component |  * struct tpdm_drvdata - specifics associated to an TPDM component | ||||||
|  * @base:       memory mapped base address for this component. |  * @base:       memory mapped base address for this component. | ||||||
|  | @ -182,7 +278,9 @@ struct dsb_dataset { | ||||||
|  * @enable:     enable status of the component. |  * @enable:     enable status of the component. | ||||||
|  * @datasets:   The datasets types present of the TPDM. |  * @datasets:   The datasets types present of the TPDM. | ||||||
|  * @dsb         Specifics associated to TPDM DSB. |  * @dsb         Specifics associated to TPDM DSB. | ||||||
|  |  * @cmb         Specifics associated to TPDM CMB. | ||||||
|  * @dsb_msr_num Number of MSR supported by DSB TPDM |  * @dsb_msr_num Number of MSR supported by DSB TPDM | ||||||
|  |  * @cmb_msr_num Number of MSR supported by CMB TPDM | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| struct tpdm_drvdata { | struct tpdm_drvdata { | ||||||
|  | @ -193,7 +291,9 @@ struct tpdm_drvdata { | ||||||
| 	bool			enable; | 	bool			enable; | ||||||
| 	unsigned long		datasets; | 	unsigned long		datasets; | ||||||
| 	struct dsb_dataset	*dsb; | 	struct dsb_dataset	*dsb; | ||||||
|  | 	struct cmb_dataset	*cmb; | ||||||
| 	u32			dsb_msr_num; | 	u32			dsb_msr_num; | ||||||
|  | 	u32			cmb_msr_num; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Enumerate members of various datasets */ | /* Enumerate members of various datasets */ | ||||||
|  | @ -205,6 +305,11 @@ enum dataset_mem { | ||||||
| 	DSB_PATT, | 	DSB_PATT, | ||||||
| 	DSB_PATT_MASK, | 	DSB_PATT_MASK, | ||||||
| 	DSB_MSR, | 	DSB_MSR, | ||||||
|  | 	CMB_TRIG_PATT, | ||||||
|  | 	CMB_TRIG_PATT_MASK, | ||||||
|  | 	CMB_PATT, | ||||||
|  | 	CMB_PATT_MASK, | ||||||
|  | 	CMB_MSR | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -220,4 +325,13 @@ struct tpdm_dataset_attribute { | ||||||
| 	u32 idx; | 	u32 idx; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	return (drvdata->datasets & TPDM_PIDR0_DS_DSB); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata) | ||||||
|  | { | ||||||
|  | 	return (drvdata->datasets & TPDM_PIDR0_DS_CMB); | ||||||
|  | } | ||||||
| #endif  /* _CORESIGHT_CORESIGHT_TPDM_H */ | #endif  /* _CORESIGHT_CORESIGHT_TPDM_H */ | ||||||
|  |  | ||||||
|  | @ -58,6 +58,7 @@ struct tpiu_drvdata { | ||||||
| 	void __iomem		*base; | 	void __iomem		*base; | ||||||
| 	struct clk		*atclk; | 	struct clk		*atclk; | ||||||
| 	struct coresight_device	*csdev; | 	struct coresight_device	*csdev; | ||||||
|  | 	spinlock_t		spinlock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void tpiu_enable_hw(struct csdev_access *csa) | static void tpiu_enable_hw(struct csdev_access *csa) | ||||||
|  | @ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa) | ||||||
| static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, | static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, | ||||||
| 		       void *__unused) | 		       void *__unused) | ||||||
| { | { | ||||||
|  | 	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
|  | 
 | ||||||
|  | 	guard(spinlock)(&drvdata->spinlock); | ||||||
| 	tpiu_enable_hw(&csdev->access); | 	tpiu_enable_hw(&csdev->access); | ||||||
| 	atomic_inc(&csdev->refcnt); | 	csdev->refcnt++; | ||||||
| 	dev_dbg(&csdev->dev, "TPIU enabled\n"); | 	dev_dbg(&csdev->dev, "TPIU enabled\n"); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa) | ||||||
| 
 | 
 | ||||||
| static int tpiu_disable(struct coresight_device *csdev) | static int tpiu_disable(struct coresight_device *csdev) | ||||||
| { | { | ||||||
| 	if (atomic_dec_return(&csdev->refcnt)) | 	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); | ||||||
|  | 
 | ||||||
|  | 	guard(spinlock)(&drvdata->spinlock); | ||||||
|  | 	csdev->refcnt--; | ||||||
|  | 	if (csdev->refcnt) | ||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 
 | 
 | ||||||
| 	tpiu_disable_hw(&csdev->access); | 	tpiu_disable_hw(&csdev->access); | ||||||
|  | @ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) | ||||||
| 	if (!drvdata) | 	if (!drvdata) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 	spin_lock_init(&drvdata->spinlock); | ||||||
|  | 
 | ||||||
| 	drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ | 	drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ | ||||||
| 	if (!IS_ERR(drvdata->atclk)) { | 	if (!IS_ERR(drvdata->atclk)) { | ||||||
| 		ret = clk_prepare_enable(drvdata->atclk); | 		ret = clk_prepare_enable(drvdata->atclk); | ||||||
|  | @ -218,7 +228,7 @@ static const struct amba_id tpiu_ids[] = { | ||||||
| 		.id	= 0x000bb9e7, | 		.id	= 0x000bb9e7, | ||||||
| 		.mask	= 0x000fffff, | 		.mask	= 0x000fffff, | ||||||
| 	}, | 	}, | ||||||
| 	{ 0, 0}, | 	{ 0, 0, NULL }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MODULE_DEVICE_TABLE(amba, tpiu_ids); | MODULE_DEVICE_TABLE(amba, tpiu_ids); | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds