Char/Misc driver patches for 5.12-rc1
Here is the large set of char/misc/whatever driver subsystem updates for 5.12-rc1. Over time it seems like this tree is collecting more and more tiny driver subsystems in one place, making it easier for those maintainers, which is why this is getting larger. Included in here are: - coresight driver updates - habannalabs driver updates - virtual acrn driver addition (proper acks from the x86 maintainers) - broadcom misc driver addition - speakup driver updates - soundwire driver updates - fpga driver updates - amba driver updates - mei driver updates - vfio driver updates - greybus driver updates - nvmeem driver updates - phy driver updates - mhi driver updates - interconnect driver udpates - fsl-mc bus driver updates - random driver fix - some small misc driver updates (rtsx, pvpanic, etc.) All of these have been in linux-next for a while, with the only reported issue being a merge conflict in include/linux/mod_devicetable.h that you will hit in your tree due to the dfl_device_id addition from the fpga subsystem in here. The resolution should be simple. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYDZf9w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yk3xgCcCEN+pCJTum+uAzSNH3YKs/onaDgAnRSVwOUw tNW6n1JhXLYl9f5JdhvS =MOHs -----END PGP SIGNATURE----- Merge tag 'char-misc-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc driver updates from Greg KH: "Here is the large set of char/misc/whatever driver subsystem updates for 5.12-rc1. Over time it seems like this tree is collecting more and more tiny driver subsystems in one place, making it easier for those maintainers, which is why this is getting larger. Included in here are: - coresight driver updates - habannalabs driver updates - virtual acrn driver addition (proper acks from the x86 maintainers) - broadcom misc driver addition - speakup driver updates - soundwire driver updates - fpga driver updates - amba driver updates - mei driver updates - vfio driver updates - greybus driver updates - nvmeem driver updates - phy driver updates - mhi driver updates - interconnect driver udpates - fsl-mc bus driver updates - random driver fix - some small misc driver updates (rtsx, pvpanic, etc.) All of these have been in linux-next for a while, with the only reported issue being a merge conflict due to the dfl_device_id addition from the fpga subsystem in here" * tag 'char-misc-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (311 commits) spmi: spmi-pmic-arb: Fix hw_irq overflow Documentation: coresight: Add PID tracing description coresight: etm-perf: Support PID tracing for kernel at EL2 coresight: etm-perf: Clarify comment on perf options ACRN: update MAINTAINERS: mailing list is subscribers-only regmap: sdw-mbq: use MODULE_LICENSE("GPL") regmap: sdw: use no_pm routines for SoundWire 1.2 MBQ regmap: sdw: use _no_pm functions in regmap_read/write soundwire: intel: fix possible crash when no device is detected MAINTAINERS: replace my with email with replacements mhi: Fix double dma free uapi: map_to_7segment: Update example in documentation uio: uio_pci_generic: don't fail probe if pdev->irq equals to IRQ_NOTCONNECTED drivers/misc/vmw_vmci: restrict too big queue size in qp_host_alloc_queue firewire: replace tricky statement by two simple ones vme: make remove callback return void firmware: google: make coreboot driver's remove callback return void firmware: xilinx: Use explicit values for all enum values sample/acrn: Introduce a sample of HSM ioctl interface usage virt: acrn: Introduce an interface for Service VM to control vCPU ...
This commit is contained in:
commit
e229b429bb
8
CREDITS
8
CREDITS
|
@ -1244,10 +1244,10 @@ S: 80050-430 - Curitiba - Paraná
|
|||
S: Brazil
|
||||
|
||||
N: Oded Gabbay
|
||||
E: oded.gabbay@gmail.com
|
||||
D: HabanaLabs and AMD KFD maintainer
|
||||
S: 12 Shraga Raphaeli
|
||||
S: Petah-Tikva, 4906418
|
||||
E: ogabbay@kernel.org
|
||||
D: HabanaLabs maintainer
|
||||
S: 29 Duchifat St.
|
||||
S: Ra'anana 4372029
|
||||
S: Israel
|
||||
|
||||
N: Kumar Gala
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
What: /sys/bus/fsl-mc/rescan
|
||||
Date: January 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
Description: Writing a non-zero value to this attribute will
|
||||
force a rescan of fsl-mc bus in the system and
|
||||
synchronize the objects under fsl-mc bus and the
|
||||
Management Complex firmware.
|
||||
Users: Userspace drivers and management tools
|
||||
|
||||
What: /sys/bus/fsl-mc/autorescan
|
||||
Date: January 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
Description: Writing a zero value to this attribute will
|
||||
disable the DPRC IRQs on which automatic rescan
|
||||
of the fsl-mc bus is performed. A non-zero value
|
||||
will enable the DPRC IRQs.
|
||||
Users: Userspace drivers and management tools
|
|
@ -273,7 +273,7 @@ Description: In `/sys/accessibility/speakup` is a directory corresponding to
|
|||
Below is a description of values and parameters for soft
|
||||
synthesizer, which is currently the most commonly used.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/caps_start
|
||||
What: /sys/accessibility/speakup/<synth-name>/caps_start
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: This is the string that is sent to the synthesizer to cause it
|
||||
|
@ -281,7 +281,7 @@ Description: This is the string that is sent to the synthesizer to cause it
|
|||
and most others, this causes the pitch of the voice to rise
|
||||
above the currently set pitch.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/caps_stop
|
||||
What: /sys/accessibility/speakup/<synth-name>/caps_stop
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: This is the string sent to the synthesizer to cause it to stop
|
||||
|
@ -290,12 +290,12 @@ Description: This is the string sent to the synthesizer to cause it to stop
|
|||
down to the
|
||||
currently set pitch.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/delay_time
|
||||
What: /sys/accessibility/speakup/<synth-name>/delay_time
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: TODO:
|
||||
|
||||
What: /sys/accessibility/speakup/soft/direct
|
||||
What: /sys/accessibility/speakup/<synth-name>/direct
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Controls if punctuation is spoken by speakup, or by the
|
||||
|
@ -306,36 +306,43 @@ Description: Controls if punctuation is spoken by speakup, or by the
|
|||
than". Zero lets speakup speak the punctuation. One lets the
|
||||
synthesizer itself speak punctuation.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/freq
|
||||
What: /sys/accessibility/speakup/<synth-name>/freq
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the frequency of the speech synthesizer. Range is
|
||||
0-9.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/full_time
|
||||
What: /sys/accessibility/speakup/<synth-name>/flush_time
|
||||
KernelVersion: 5.12
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the timeout to wait for the synthesizer flush to
|
||||
complete. This can be used when the cable gets faulty and flush
|
||||
notifications are getting lost.
|
||||
|
||||
What: /sys/accessibility/speakup/<synth-name>/full_time
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: TODO:
|
||||
|
||||
What: /sys/accessibility/speakup/soft/jiffy_delta
|
||||
What: /sys/accessibility/speakup/<synth-name>/jiffy_delta
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: This controls how many jiffys the kernel gives to the
|
||||
synthesizer. Setting this too high can make a system unstable,
|
||||
or even crash it.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/pitch
|
||||
What: /sys/accessibility/speakup/<synth-name>/pitch
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the pitch of the synthesizer. The range is 0-9.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/inflection
|
||||
What: /sys/accessibility/speakup/<synth-name>/inflection
|
||||
KernelVersion: 5.8
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the inflection of the synthesizer, i.e. the pitch
|
||||
range. The range is 0-9.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/punct
|
||||
What: /sys/accessibility/speakup/<synth-name>/punct
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the amount of punctuation spoken by the
|
||||
|
@ -343,13 +350,13 @@ Description: Gets or sets the amount of punctuation spoken by the
|
|||
TODO: How is this related to speakup's punc_level, or
|
||||
reading_punc.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/rate
|
||||
What: /sys/accessibility/speakup/<synth-name>/rate
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the rate of the synthesizer. Range is from zero
|
||||
slowest, to nine fastest.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/tone
|
||||
What: /sys/accessibility/speakup/<synth-name>/tone
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the tone of the speech synthesizer. The range for
|
||||
|
@ -357,12 +364,12 @@ Description: Gets or sets the tone of the speech synthesizer. The range for
|
|||
difference if using espeak and the espeakup connector.
|
||||
TODO: does espeakup support different tonalities?
|
||||
|
||||
What: /sys/accessibility/speakup/soft/trigger_time
|
||||
What: /sys/accessibility/speakup/<synth-name>/trigger_time
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: TODO:
|
||||
|
||||
What: /sys/accessibility/speakup/soft/voice
|
||||
What: /sys/accessibility/speakup/<synth-name>/voice
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the voice used by the synthesizer if the
|
||||
|
@ -371,7 +378,7 @@ Description: Gets or sets the voice used by the synthesizer if the
|
|||
voices, this parameter will not set the voice when the espeakup
|
||||
connector is used between speakup and espeak.
|
||||
|
||||
What: /sys/accessibility/speakup/soft/vol
|
||||
What: /sys/accessibility/speakup/<synth-name>/vol
|
||||
KernelVersion: 2.6
|
||||
Contact: speakup@linux-speakup.org
|
||||
Description: Gets or sets the volume of the speech synthesizer. Range is 0-9,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/addr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the device address to be used for read or write through
|
||||
PCI bar, or the device VA of a host mapped memory to be read or
|
||||
written directly from the host. The latter option is allowed
|
||||
|
@ -11,7 +11,7 @@ Description: Sets the device address to be used for read or write through
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/clk_gate
|
||||
Date: May 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allow the root user to disable/enable in runtime the clock
|
||||
gating mechanism in Gaudi. Due to how Gaudi is built, the
|
||||
clock gating needs to be disabled in order to access the
|
||||
|
@ -34,28 +34,28 @@ Description: Allow the root user to disable/enable in runtime the clock
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/command_buffers
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays a list with information about the currently allocated
|
||||
command buffers
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays a list with information about the currently active
|
||||
command submissions
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission_jobs
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays a list with detailed information about each JOB (CB) of
|
||||
each active command submission
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/data32
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the root user to read or write directly through the
|
||||
device's PCI bar. Writing to this file generates a write
|
||||
transaction while reading from the file generates a read
|
||||
|
@ -70,7 +70,7 @@ Description: Allows the root user to read or write directly through the
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/data64
|
||||
Date: Jan 2020
|
||||
KernelVersion: 5.6
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the root user to read or write 64 bit data directly
|
||||
through the device's PCI bar. Writing to this file generates a
|
||||
write transaction while reading from the file generates a read
|
||||
|
@ -85,7 +85,7 @@ Description: Allows the root user to read or write 64 bit data directly
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/device
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Enables the root user to set the device to specific state.
|
||||
Valid values are "disable", "enable", "suspend", "resume".
|
||||
User can read this property to see the valid values
|
||||
|
@ -93,28 +93,28 @@ Description: Enables the root user to set the device to specific state.
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/engines
|
||||
Date: Jul 2019
|
||||
KernelVersion: 5.3
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the status registers values of the device engines and
|
||||
their derived idle status
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_addr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets I2C device address for I2C transaction that is generated
|
||||
by the device's CPU
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_bus
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets I2C bus address for I2C transaction that is generated by
|
||||
the device's CPU
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_data
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Triggers an I2C transaction that is generated by the device's
|
||||
CPU. Writing to this file generates a write transaction while
|
||||
reading from the file generates a read transcation
|
||||
|
@ -122,32 +122,32 @@ Description: Triggers an I2C transaction that is generated by the device's
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_reg
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets I2C register id for I2C transaction that is generated by
|
||||
the device's CPU
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/led0
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the state of the first S/W led on the device
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/led1
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the state of the second S/W led on the device
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/led2
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the state of the third S/W led on the device
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/mmu
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the hop values and physical address for a given ASID
|
||||
and virtual address. The user should write the ASID and VA into
|
||||
the file and then read the file to get the result.
|
||||
|
@ -157,14 +157,14 @@ Description: Displays the hop values and physical address for a given ASID
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/set_power_state
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the PCI power state. Valid values are "1" for D0 and "2"
|
||||
for D3Hot
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/userptr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays a list with information about the currently user
|
||||
pointers (user virtual addresses) that are pinned and mapped
|
||||
to DMA addresses
|
||||
|
@ -172,13 +172,21 @@ Description: Displays a list with information about the currently user
|
|||
What: /sys/kernel/debug/habanalabs/hl<n>/vm
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays a list with information about all the active virtual
|
||||
address mappings per ASID
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/stop_on_err
|
||||
Date: Mar 2020
|
||||
KernelVersion: 5.6
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the stop-on_error option for the device engines. Value of
|
||||
"0" is for disable, otherwise enable.
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/dump_security_violations
|
||||
Date: Jan 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Dumps all security violations to dmesg. This will also ack
|
||||
all security violations meanings those violations will not be
|
||||
dumped next time user calls this API
|
||||
|
|
|
@ -371,6 +371,14 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
|
|||
Description: (Read) Print the content of the Device ID Register
|
||||
(0xFC8). The value is taken directly from the HW.
|
||||
|
||||
What: /sys/bus/coresight/devices/etm<N>/mgmt/trcdevarch
|
||||
Date: January 2021
|
||||
KernelVersion: 5.12
|
||||
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
|
||||
Description: (Read) Print the content of the Device Architecture Register
|
||||
(offset 0xFBC). The value is taken directly read
|
||||
from the HW.
|
||||
|
||||
What: /sys/bus/coresight/devices/etm<N>/mgmt/trcdevtype
|
||||
Date: April 2015
|
||||
KernelVersion: 4.01
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
What: /sys/bus/dfl/devices/dfl_dev.X/infX_cal_fail
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. It indicates if the calibration failed on this
|
||||
memory interface. "1" for calibration failure, "0" for OK.
|
||||
Format: %u
|
||||
|
||||
What: /sys/bus/dfl/devices/dfl_dev.X/infX_init_done
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. It indicates if the initialization completed on
|
||||
this memory interface. "1" for initialization complete, "0"
|
||||
for not yet.
|
||||
Format: %u
|
||||
|
||||
What: /sys/bus/dfl/devices/dfl_dev.X/infX_clear
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Write-only. Writing "1" to this file will zero out all memory
|
||||
data in this memory interface. Writing of other values is
|
||||
invalid.
|
||||
Format: %u
|
|
@ -0,0 +1,47 @@
|
|||
What: /sys/bus/dfl/devices/dfl_dev.X/fec_mode
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. Returns the FEC mode of the 25G links of the
|
||||
ethernet retimers configured by Nios firmware. "rs" for Reed
|
||||
Solomon FEC, "kr" for Fire Code FEC, "no" for NO FEC.
|
||||
"not supported" if the FEC mode setting is not supported, this
|
||||
happens when the Nios firmware version major < 3, or no link is
|
||||
configured to 25G.
|
||||
Format: string
|
||||
|
||||
What: /sys/bus/dfl/devices/dfl_dev.X/retimer_A_mode
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. Returns the enumeration value of the working mode of
|
||||
the retimer A configured by the Nios firmware. The value is
|
||||
read out from shared registers filled by the Nios firmware. Now
|
||||
the values could be:
|
||||
|
||||
- "0": Reset
|
||||
- "1": 4x10G
|
||||
- "2": 4x25G
|
||||
- "3": 2x25G
|
||||
- "4": 2x25G+2x10G
|
||||
- "5": 1x25G
|
||||
|
||||
If the Nios firmware is updated in future to support more
|
||||
retimer modes, more enumeration value is expected.
|
||||
Format: 0x%x
|
||||
|
||||
What: /sys/bus/dfl/devices/dfl_dev.X/retimer_B_mode
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. Returns the enumeration value of the working mode of
|
||||
the retimer B configured by the Nios firmware. The value format
|
||||
is the same as retimer_A_mode.
|
||||
|
||||
What: /sys/bus/dfl/devices/dfl_dev.X/nios_fw_version
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.12
|
||||
Contact: Xu Yilun <yilun.xu@intel.com>
|
||||
Description: Read-only. Returns the version of the Nios firmware in the
|
||||
FPGA. Its format is "major.minor.patch".
|
||||
Format: %x.%x.%x
|
|
@ -0,0 +1,24 @@
|
|||
What: /sys/devices/pci0000:00/*/QEMU0001:00/capability
|
||||
Date: Jan 2021
|
||||
Contact: zhenwei pi <pizhenwei@bytedance.com>
|
||||
Description:
|
||||
Read-only attribute. Capabilities of pvpanic device which
|
||||
are supported by QEMU.
|
||||
|
||||
Format: %x.
|
||||
|
||||
Detailed bit definition refers to section <Bit Definition>
|
||||
from pvpanic device specification:
|
||||
https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/specs/pvpanic.txt
|
||||
|
||||
What: /sys/devices/pci0000:00/*/QEMU0001:00/events
|
||||
Date: Jan 2021
|
||||
Contact: zhenwei pi <pizhenwei@bytedance.com>
|
||||
Description:
|
||||
RW attribute. Set/get which features in-use. This attribute
|
||||
is used to enable/disable feature(s) of pvpanic device.
|
||||
Notice that this value should be a subset of capability.
|
||||
|
||||
Format: %x.
|
||||
|
||||
Also refer to pvpanic device specification.
|
|
@ -1,7 +1,7 @@
|
|||
What: /sys/class/habanalabs/hl<n>/armcp_kernel_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the Linux kernel running on the device's CPU.
|
||||
Will be DEPRECATED in Linux kernel version 5.10, and be
|
||||
replaced with cpucp_kernel_ver
|
||||
|
@ -9,7 +9,7 @@ Description: Version of the Linux kernel running on the device's CPU.
|
|||
What: /sys/class/habanalabs/hl<n>/armcp_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the application running on the device's CPU
|
||||
Will be DEPRECATED in Linux kernel version 5.10, and be
|
||||
replaced with cpucp_ver
|
||||
|
@ -17,7 +17,7 @@ Description: Version of the application running on the device's CPU
|
|||
What: /sys/class/habanalabs/hl<n>/clk_max_freq_mhz
|
||||
Date: Jun 2019
|
||||
KernelVersion: not yet upstreamed
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum clock frequency, in MHz.
|
||||
The device clock might be set to lower value than the maximum.
|
||||
The user should read the clk_cur_freq_mhz to see the actual
|
||||
|
@ -27,52 +27,52 @@ Description: Allows the user to set the maximum clock frequency, in MHz.
|
|||
What: /sys/class/habanalabs/hl<n>/clk_cur_freq_mhz
|
||||
Date: Jun 2019
|
||||
KernelVersion: not yet upstreamed
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the current frequency, in MHz, of the device clock.
|
||||
This property is valid only for the Gaudi ASIC family
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/cpld_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the Device's CPLD F/W
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/cpucp_kernel_ver
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the Linux kernel running on the device's CPU
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/cpucp_ver
|
||||
Date: Oct 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the application running on the device's CPU
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/device_type
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the code name of the device according to its type.
|
||||
The supported values are: "GOYA"
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/eeprom
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: A binary file attribute that contains the contents of the
|
||||
on-board EEPROM
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/fuse_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the device's version from the eFuse
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/hard_reset
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Interface to trigger a hard-reset operation for the device.
|
||||
Hard-reset will reset ALL internal components of the device
|
||||
except for the PCI interface and the internal PLLs
|
||||
|
@ -80,14 +80,14 @@ Description: Interface to trigger a hard-reset operation for the device.
|
|||
What: /sys/class/habanalabs/hl<n>/hard_reset_cnt
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays how many times the device have undergone a hard-reset
|
||||
operation since the driver was loaded
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/high_pll
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum clock frequency for MME, TPC
|
||||
and IC when the power management profile is set to "automatic".
|
||||
This property is valid only for the Goya ASIC family
|
||||
|
@ -95,7 +95,7 @@ Description: Allows the user to set the maximum clock frequency for MME, TPC
|
|||
What: /sys/class/habanalabs/hl<n>/ic_clk
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum clock frequency, in Hz, of
|
||||
the Interconnect fabric. Writes to this parameter affect the
|
||||
device only when the power management profile is set to "manual"
|
||||
|
@ -107,27 +107,27 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
|
|||
What: /sys/class/habanalabs/hl<n>/ic_clk_curr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the current clock frequency, in Hz, of the Interconnect
|
||||
fabric. This property is valid only for the Goya ASIC family
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/infineon_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the Device's power supply F/W code
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/max_power
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum power consumption of the
|
||||
device in milliwatts.
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/mme_clk
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum clock frequency, in Hz, of
|
||||
the MME compute engine. Writes to this parameter affect the
|
||||
device only when the power management profile is set to "manual"
|
||||
|
@ -139,21 +139,21 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
|
|||
What: /sys/class/habanalabs/hl<n>/mme_clk_curr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the current clock frequency, in Hz, of the MME compute
|
||||
engine. This property is valid only for the Goya ASIC family
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/pci_addr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the PCI address of the device. This is needed so the
|
||||
user would be able to open a device based on its PCI address
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/pm_mng_profile
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Power management profile. Values are "auto", "manual". In "auto"
|
||||
mode, the driver will set the maximum clock frequency to a high
|
||||
value when a user-space process opens the device's file (unless
|
||||
|
@ -167,13 +167,13 @@ Description: Power management profile. Values are "auto", "manual". In "auto"
|
|||
What: /sys/class/habanalabs/hl<n>/preboot_btl_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the device's preboot F/W code
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/soft_reset
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Interface to trigger a soft-reset operation for the device.
|
||||
Soft-reset will reset only the compute and DMA engines of the
|
||||
device
|
||||
|
@ -181,26 +181,26 @@ Description: Interface to trigger a soft-reset operation for the device.
|
|||
What: /sys/class/habanalabs/hl<n>/soft_reset_cnt
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays how many times the device have undergone a soft-reset
|
||||
operation since the driver was loaded
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/status
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Status of the card: "Operational", "Malfunction", "In reset".
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/thermal_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the Device's thermal daemon
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/tpc_clk
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Allows the user to set the maximum clock frequency, in Hz, of
|
||||
the TPC compute engines. Writes to this parameter affect the
|
||||
device only when the power management profile is set to "manual"
|
||||
|
@ -212,12 +212,12 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
|
|||
What: /sys/class/habanalabs/hl<n>/tpc_clk_curr
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Displays the current clock frequency, in Hz, of the TPC compute
|
||||
engines. This property is valid only for the Goya ASIC family
|
||||
|
||||
What: /sys/class/habanalabs/hl<n>/uboot_ver
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
Contact: oded.gabbay@gmail.com
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Version of the u-boot running on the device's CPU
|
|
@ -1033,7 +1033,9 @@ speakup + keypad 3, you would hear:
|
|||
The speakup key is depressed, so the name of the key state is speakup.
|
||||
This part of the message comes from the states collection.
|
||||
|
||||
14.2. Loading Your Own Messages
|
||||
14.2. Changing language
|
||||
|
||||
14.2.1. Loading Your Own Messages
|
||||
|
||||
The files under the i18n subdirectory all follow the same format.
|
||||
They consist of lines, with one message per line.
|
||||
|
@ -1066,8 +1068,50 @@ echo '1 azul' > /speakup/i18n/colors
|
|||
The next time that Speakup says message 1 from the colors group, it will
|
||||
say "azul", rather than "blue."
|
||||
|
||||
14.2.2. Choose a language
|
||||
|
||||
In the future, translations into various languages will be made available,
|
||||
and most users will just load the files necessary for their language.
|
||||
and most users will just load the files necessary for their language. So far,
|
||||
only French language is available beyond native Canadian English language.
|
||||
|
||||
French is only available after you are logged in.
|
||||
|
||||
Canadian English is the default language. To toggle another language,
|
||||
download the source of Speakup and untar it in your home directory. The
|
||||
following command should let you do this:
|
||||
|
||||
tar xvjf speakup-<version>.tar.bz2
|
||||
|
||||
where <version> is the version number of the application.
|
||||
|
||||
Next, change to the newly created directory, then into the tools/ directory, and
|
||||
run the script speakup_setlocale. You are asked the language that you want to
|
||||
use. Type the number associated to your language (e.g. fr for French) then press
|
||||
Enter. Needed files are copied in the i18n directory.
|
||||
|
||||
Note: the speakupconf must be installed on your system so that settings are saved.
|
||||
Otherwise, you will have an error: your language will be loaded but you will
|
||||
have to run the script again every time Speakup restarts.
|
||||
See section 16.1. for information about speakupconf.
|
||||
|
||||
You will have to repeat these steps for any change of locale, i.e. if you wish
|
||||
change the speakup's language or charset (iso-8859-15 ou UTF-8).
|
||||
|
||||
If you wish store the settings, note that at your next login, you will need to
|
||||
do:
|
||||
|
||||
speakup load
|
||||
|
||||
Alternatively, you can add the above line to your file
|
||||
~/.bashrc or ~/.bash_profile.
|
||||
|
||||
If your system administrator ran himself the script, all the users will be able
|
||||
to change from English to the language choosed by root and do directly
|
||||
speakupconf load (or add this to the ~/.bashrc or
|
||||
~/.bash_profile file). If there are several languages to handle, the
|
||||
administrator (or every user) will have to run the first steps until speakupconf
|
||||
save, choosing the appropriate language, in every user's home directory. Every
|
||||
user will then be able to do speakupconf load, Speakup will load his own settings.
|
||||
|
||||
14.3. No Support for Non-Western-European Languages
|
||||
|
||||
|
|
|
@ -34,9 +34,12 @@ its hardware characteristcs.
|
|||
Program Flow Trace Macrocell:
|
||||
"arm,coresight-etm3x", "arm,primecell";
|
||||
|
||||
- Embedded Trace Macrocell (version 4.x):
|
||||
- Embedded Trace Macrocell (version 4.x), with memory mapped access.
|
||||
"arm,coresight-etm4x", "arm,primecell";
|
||||
|
||||
- Embedded Trace Macrocell (version 4.x), with system register access only.
|
||||
"arm,coresight-etm4x-sysreg";
|
||||
|
||||
- Coresight programmable Replicator :
|
||||
"arm,coresight-dynamic-replicator", "arm,primecell";
|
||||
|
||||
|
|
|
@ -22,23 +22,7 @@ Required properties:
|
|||
MIPI TX Configuration Module
|
||||
============================
|
||||
|
||||
The MIPI TX configuration module controls the MIPI D-PHY.
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,<chip>-mipi-tx"
|
||||
- the supported chips are mt2701, 7623, mt8173 and mt8183.
|
||||
- reg: Physical base address and length of the controller's registers
|
||||
- clocks: PLL reference clock
|
||||
- clock-output-names: name of the output clock line to the DSI encoder
|
||||
- #clock-cells: must be <0>;
|
||||
- #phy-cells: must be <0>.
|
||||
|
||||
Optional properties:
|
||||
- drive-strength-microamp: adjust driving current, should be 3000 ~ 6000. And
|
||||
the step is 200.
|
||||
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
|
||||
unspecified default values shall be used.
|
||||
- nvmem-cell-names: Should be "calibration-data"
|
||||
See phy/mediatek,dsi-phy.yaml
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -53,23 +53,7 @@ Required properties:
|
|||
|
||||
HDMI PHY
|
||||
========
|
||||
|
||||
The HDMI PHY serializes the HDMI encoder's three channel 10-bit parallel
|
||||
output and drives the HDMI pads.
|
||||
|
||||
Required properties:
|
||||
- compatible: "mediatek,<chip>-hdmi-phy"
|
||||
- the supported chips are mt2701, mt7623 and mt8173
|
||||
- reg: Physical base address and length of the module's registers
|
||||
- clocks: PLL reference clock
|
||||
- clock-names: must contain "pll_ref"
|
||||
- clock-output-names: must be "hdmitx_dig_cts" on mt8173
|
||||
- #phy-cells: must be <0>
|
||||
- #clock-cells: must be <0>
|
||||
|
||||
Optional properties:
|
||||
- mediatek,ibias: TX DRV bias current for <1.65Gbps, defaults to 0xa
|
||||
- mediatek,ibias_up: TX DRV bias current for >1.65Gbps, defaults to 0x1c
|
||||
See phy/mediatek,hdmi-phy.yaml
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interconnect/qcom,qcs404.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm QCS404 Network-On-Chip interconnect
|
||||
|
||||
maintainers:
|
||||
- Georgi Djakov <georgi.djakov@linaro.org>
|
||||
|
||||
description: |
|
||||
The Qualcomm QCS404 interconnect providers support adjusting the
|
||||
bandwidth requirements between the various NoC fabrics.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,qcs404-bimc
|
||||
- qcom,qcs404-pcnoc
|
||||
- qcom,qcs404-snoc
|
||||
|
||||
'#interconnect-cells':
|
||||
const: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: bus_a
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Bus A Clock
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#interconnect-cells'
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
|
||||
bimc: interconnect@400000 {
|
||||
reg = <0x00400000 0x80000>;
|
||||
compatible = "qcom,qcs404-bimc";
|
||||
#interconnect-cells = <1>;
|
||||
clock-names = "bus", "bus_a";
|
||||
clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
|
||||
<&rpmcc RPM_SMD_BIMC_A_CLK>;
|
||||
};
|
||||
|
||||
pnoc: interconnect@500000 {
|
||||
reg = <0x00500000 0x15080>;
|
||||
compatible = "qcom,qcs404-pcnoc";
|
||||
#interconnect-cells = <1>;
|
||||
clock-names = "bus", "bus_a";
|
||||
clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
|
||||
<&rpmcc RPM_SMD_PNOC_A_CLK>;
|
||||
};
|
||||
|
||||
snoc: interconnect@580000 {
|
||||
reg = <0x00580000 0x23080>;
|
||||
compatible = "qcom,qcs404-snoc";
|
||||
#interconnect-cells = <1>;
|
||||
clock-names = "bus", "bus_a";
|
||||
clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
|
||||
<&rpmcc RPM_SMD_SNOC_A_CLK>;
|
||||
};
|
|
@ -1,27 +1,35 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
|
||||
$id: http://devicetree.org/schemas/interconnect/qcom,rpm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm MSM8916 Network-On-Chip interconnect
|
||||
title: Qualcomm RPM Network-On-Chip Interconnect
|
||||
|
||||
maintainers:
|
||||
- Georgi Djakov <georgi.djakov@linaro.org>
|
||||
|
||||
description: |
|
||||
The Qualcomm MSM8916 interconnect providers support adjusting the
|
||||
bandwidth requirements between the various NoC fabrics.
|
||||
RPM interconnect providers support system bandwidth requirements through
|
||||
RPM processor. The provider is able to communicate with the RPM through
|
||||
the RPM shared memory device.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,msm8916-bimc
|
||||
- qcom,msm8916-pcnoc
|
||||
- qcom,msm8916-snoc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
- qcom,msm8939-bimc
|
||||
- qcom,msm8939-pcnoc
|
||||
- qcom,msm8939-snoc
|
||||
- qcom,msm8939-snoc-mm
|
||||
- qcom,qcs404-bimc
|
||||
- qcom,qcs404-pcnoc
|
||||
- qcom,qcs404-snoc
|
||||
|
||||
'#interconnect-cells':
|
||||
const: 1
|
|
@ -45,6 +45,10 @@ properties:
|
|||
- qcom,sdm845-mem-noc
|
||||
- qcom,sdm845-mmss-noc
|
||||
- qcom,sdm845-system-noc
|
||||
- qcom,sdx55-ipa-virt
|
||||
- qcom,sdx55-mc-virt
|
||||
- qcom,sdx55-mem-noc
|
||||
- qcom,sdx55-system-noc
|
||||
- qcom,sm8150-aggre1-noc
|
||||
- qcom,sm8150-aggre2-noc
|
||||
- qcom,sm8150-camnoc-noc
|
||||
|
|
|
@ -4,6 +4,7 @@ Required properties:
|
|||
- compatible : shall be one of:
|
||||
"atmel,at93c46d"
|
||||
"eeprom-93xx46"
|
||||
"microchip,93lc46b"
|
||||
- data-size : number of data bits per word (either 8 or 16)
|
||||
|
||||
Optional properties:
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/nvmem/rmem.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Reserved Memory Based nvmem Device
|
||||
|
||||
maintainers:
|
||||
- Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
||||
|
||||
allOf:
|
||||
- $ref: "nvmem.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- raspberrypi,bootloader-config
|
||||
- const: nvmem-rmem
|
||||
|
||||
no-map:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Avoid creating a virtual mapping of the region as part of the OS'
|
||||
standard mapping of system memory.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- no-map
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
reserved-memory {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
blconfig: nvram@10000000 {
|
||||
compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x10000000 0x1000>;
|
||||
no-map;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,86 +0,0 @@
|
|||
Broadcom STB USB PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of
|
||||
"brcm,brcmstb-usb-phy"
|
||||
"brcm,bcm7216-usb-phy"
|
||||
"brcm,bcm7211-usb-phy"
|
||||
|
||||
- reg and reg-names properties requirements are specific to the
|
||||
compatible string.
|
||||
"brcm,brcmstb-usb-phy":
|
||||
- reg: 1 or 2 offset and length pairs. One for the base CTRL registers
|
||||
and an optional pair for systems with USB 3.x support
|
||||
- reg-names: not specified
|
||||
"brcm,bcm7216-usb-phy":
|
||||
- reg: 3 offset and length pairs for CTRL, XHCI_EC and XHCI_GBL
|
||||
registers
|
||||
- reg-names: "ctrl", "xhci_ec", "xhci_gbl"
|
||||
"brcm,bcm7211-usb-phy":
|
||||
- reg: 5 offset and length pairs for CTRL, XHCI_EC, XHCI_GBL,
|
||||
USB_PHY and USB_MDIO registers and an optional pair
|
||||
for the BDC registers
|
||||
- reg-names: "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
|
||||
|
||||
- #phy-cells: Shall be 1 as it expects one argument for setting
|
||||
the type of the PHY. Possible values are:
|
||||
- PHY_TYPE_USB2 for USB1.1/2.0 PHY
|
||||
- PHY_TYPE_USB3 for USB3.x PHY
|
||||
|
||||
Optional Properties:
|
||||
- clocks : clock phandles.
|
||||
- clock-names: String, clock name.
|
||||
- interrupts: wakeup interrupt
|
||||
- interrupt-names: "wakeup"
|
||||
- brcm,ipp: Boolean, Invert Port Power.
|
||||
Possible values are: 0 (Don't invert), 1 (Invert)
|
||||
- brcm,ioc: Boolean, Invert Over Current detection.
|
||||
Possible values are: 0 (Don't invert), 1 (Invert)
|
||||
- dr_mode: String, PHY Device mode.
|
||||
Possible values are: "host", "peripheral ", "drd" or "typec-pd"
|
||||
If this property is not defined, the phy will default to "host" mode.
|
||||
- brcm,syscon-piarbctl: phandle to syscon for handling config registers
|
||||
NOTE: one or both of the following two properties must be set
|
||||
- brcm,has-xhci: Boolean indicating the phy has an XHCI phy.
|
||||
- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
usbphy_0: usb-phy@f0470200 {
|
||||
reg = <0xf0470200 0xb8>,
|
||||
<0xf0471940 0x6c0>;
|
||||
compatible = "brcm,brcmstb-usb-phy";
|
||||
#phy-cells = <1>;
|
||||
dr_mode = "host"
|
||||
brcm,ioc = <1>;
|
||||
brcm,ipp = <1>;
|
||||
brcm,has-xhci;
|
||||
brcm,has-eohci;
|
||||
clocks = <&usb20>, <&usb30>;
|
||||
clock-names = "sw_usb", "sw_usb3";
|
||||
};
|
||||
|
||||
usb-phy@29f0200 {
|
||||
reg = <0x29f0200 0x200>,
|
||||
<0x29c0880 0x30>,
|
||||
<0x29cc100 0x534>,
|
||||
<0x2808000 0x24>,
|
||||
<0x2980080 0x8>;
|
||||
reg-names = "ctrl",
|
||||
"xhci_ec",
|
||||
"xhci_gbl",
|
||||
"usb_phy",
|
||||
"usb_mdio";
|
||||
brcm,ioc = <0x0>;
|
||||
brcm,ipp = <0x0>;
|
||||
compatible = "brcm,bcm7211-usb-phy";
|
||||
interrupts = <0x30>;
|
||||
interrupt-parent = <&vpu_intr1_nosec_intc>;
|
||||
interrupt-names = "wake";
|
||||
#phy-cells = <0x1>;
|
||||
brcm,has-xhci;
|
||||
syscon-piarbctl = <&syscon_piarbctl>;
|
||||
clocks = <&scmi_clk 256>;
|
||||
clock-names = "sw_usb";
|
||||
};
|
|
@ -0,0 +1,196 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/brcm,brcmstb-usb-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom STB USB PHY
|
||||
|
||||
description: Broadcom's PHY that handles EHCI/OHCI and/or XHCI
|
||||
|
||||
maintainers:
|
||||
- Al Cooper <alcooperx@gmail.com>
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm4908-usb-phy
|
||||
- brcm,bcm7211-usb-phy
|
||||
- brcm,bcm7216-usb-phy
|
||||
- brcm,brcmstb-usb-phy
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: the base CTRL register
|
||||
- description: XHCI EC register
|
||||
- description: XHCI GBL register
|
||||
- description: USB PHY register
|
||||
- description: USB MDIO register
|
||||
- description: BDC register
|
||||
|
||||
reg-names:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: ctrl
|
||||
- const: xhci_ec
|
||||
- const: xhci_gbl
|
||||
- const: usb_phy
|
||||
- const: usb_mdio
|
||||
- const: bdc_ec
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: sw_usb
|
||||
- const: sw_usb3
|
||||
|
||||
interrupts:
|
||||
description: wakeup interrupt
|
||||
|
||||
interrupt-names:
|
||||
const: wake
|
||||
|
||||
brcm,ipp:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Invert Port Power
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
brcm,ioc:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Invert Over Current detection
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
dr_mode:
|
||||
description: PHY Device mode. If this property is not defined, the PHY will
|
||||
default to "host" mode.
|
||||
enum:
|
||||
- host
|
||||
- peripheral
|
||||
- drd
|
||||
- typec-pd
|
||||
|
||||
brcm,syscon-piarbctl:
|
||||
description: phandle to syscon for handling config registers
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
brcm,has-xhci:
|
||||
description: Indicates the PHY has an XHCI PHY.
|
||||
type: boolean
|
||||
|
||||
brcm,has-eohci:
|
||||
description: Indicates the PHY has an EHCI/OHCI PHY.
|
||||
type: boolean
|
||||
|
||||
"#phy-cells":
|
||||
description: |
|
||||
Cell allows setting the type of the PHY. Possible values are:
|
||||
- PHY_TYPE_USB2 for USB1.1/2.0 PHY
|
||||
- PHY_TYPE_USB3 for USB3.x PHY
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
anyOf:
|
||||
- required:
|
||||
- brcm,has-xhci
|
||||
- required:
|
||||
- brcm,has-eohci
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- const: brcm,bcm4908-usb-phy
|
||||
- const: brcm,brcmstb-usb-phy
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: brcm,bcm7211-usb-phy
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
reg-names:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: brcm,bcm7216-usb-phy
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
reg-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
usb-phy@f0470200 {
|
||||
compatible = "brcm,brcmstb-usb-phy";
|
||||
reg = <0xf0470200 0xb8>,
|
||||
<0xf0471940 0x6c0>;
|
||||
#phy-cells = <1>;
|
||||
dr_mode = "host";
|
||||
brcm,ioc = <1>;
|
||||
brcm,ipp = <1>;
|
||||
brcm,has-xhci;
|
||||
brcm,has-eohci;
|
||||
clocks = <&usb20>, <&usb30>;
|
||||
clock-names = "sw_usb", "sw_usb3";
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
usb-phy@29f0200 {
|
||||
compatible = "brcm,bcm7211-usb-phy";
|
||||
reg = <0x29f0200 0x200>,
|
||||
<0x29c0880 0x30>,
|
||||
<0x29cc100 0x534>,
|
||||
<0x2808000 0x24>,
|
||||
<0x2980080 0x8>;
|
||||
reg-names = "ctrl",
|
||||
"xhci_ec",
|
||||
"xhci_gbl",
|
||||
"usb_phy",
|
||||
"usb_mdio";
|
||||
brcm,ioc = <0x0>;
|
||||
brcm,ipp = <0x0>;
|
||||
interrupts = <0x30>;
|
||||
interrupt-parent = <&vpu_intr1_nosec_intc>;
|
||||
interrupt-names = "wake";
|
||||
#phy-cells = <0x1>;
|
||||
brcm,has-xhci;
|
||||
brcm,syscon-piarbctl = <&syscon_piarbctl>;
|
||||
clocks = <&scmi_clk 256>;
|
||||
clock-names = "sw_usb";
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mediatek,dsi-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek MIPI Display Serial Interface (DSI) PHY binding
|
||||
|
||||
maintainers:
|
||||
- Chun-Kuang Hu <chunkuang.hu@kernel.org>
|
||||
- Philipp Zabel <p.zabel@pengutronix.de>
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
description: The MIPI DSI PHY supports up to 4-lane output.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^dsi-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-mipi-tx
|
||||
- mediatek,mt7623-mipi-tx
|
||||
- mediatek,mt8173-mipi-tx
|
||||
- mediatek,mt8183-mipi-tx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PLL reference clock
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
nvmem-cells:
|
||||
maxItems: 1
|
||||
description: A phandle to the calibration data provided by a nvmem device,
|
||||
if unspecified, default values shall be used.
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: calibration-data
|
||||
|
||||
drive-strength-microamp:
|
||||
description: adjust driving current
|
||||
multipleOf: 200
|
||||
minimum: 2000
|
||||
maximum: 6000
|
||||
default: 4600
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-output-names
|
||||
- "#phy-cells"
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
dsi-phy@10215000 {
|
||||
compatible = "mediatek,mt8173-mipi-tx";
|
||||
reg = <0x10215000 0x1000>;
|
||||
clocks = <&clk26m>;
|
||||
clock-output-names = "mipi_tx0_pll";
|
||||
drive-strength-microamp = <4000>;
|
||||
nvmem-cells= <&mipi_tx_calibration>;
|
||||
nvmem-cell-names = "calibration-data";
|
||||
#clock-cells = <0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,92 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mediatek,hdmi-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek High Definition Multimedia Interface (HDMI) PHY binding
|
||||
|
||||
maintainers:
|
||||
- Chun-Kuang Hu <chunkuang.hu@kernel.org>
|
||||
- Philipp Zabel <p.zabel@pengutronix.de>
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
description: |
|
||||
The HDMI PHY serializes the HDMI encoder's three channel 10-bit parallel
|
||||
output and drives the HDMI pads.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^hdmi-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-hdmi-phy
|
||||
- mediatek,mt7623-hdmi-phy
|
||||
- mediatek,mt8173-hdmi-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PLL reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pll_ref
|
||||
|
||||
clock-output-names:
|
||||
items:
|
||||
- const: hdmitx_dig_cts
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
mediatek,ibias:
|
||||
description:
|
||||
TX DRV bias current for < 1.65Gbps
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 63
|
||||
default: 0xa
|
||||
|
||||
mediatek,ibias_up:
|
||||
description:
|
||||
TX DRV bias current for >= 1.65Gbps
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 63
|
||||
default: 0x1c
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- clock-output-names
|
||||
- "#phy-cells"
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
hdmi_phy: hdmi-phy@10209100 {
|
||||
compatible = "mediatek,mt8173-hdmi-phy";
|
||||
reg = <0x10209100 0x24>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>;
|
||||
clock-names = "pll_ref";
|
||||
clock-output-names = "hdmitx_dig_cts";
|
||||
mediatek,ibias = <0xa>;
|
||||
mediatek,ibias_up = <0x1c>;
|
||||
#clock-cells = <0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,260 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mediatek,tphy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek T-PHY Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
description: |
|
||||
The T-PHY controller supports physical layer functionality for a number of
|
||||
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
|
||||
|
||||
Layout differences of banks between T-PHY V1 (mt8173/mt2701) and
|
||||
T-PHY V2 (mt2712) when works on USB mode:
|
||||
-----------------------------------
|
||||
Version 1:
|
||||
port offset bank
|
||||
shared 0x0000 SPLLC
|
||||
0x0100 FMREG
|
||||
u2 port0 0x0800 U2PHY_COM
|
||||
u3 port0 0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 U2PHY_COM
|
||||
u3 port1 0x1100 U3PHYD
|
||||
0x1200 U3PHYD_BANK2
|
||||
0x1300 U3PHYA
|
||||
0x1400 U3PHYA_DA
|
||||
u2 port2 0x1800 U2PHY_COM
|
||||
...
|
||||
|
||||
Version 2:
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u3 port0 0x0700 SPLLC
|
||||
0x0800 CHIP
|
||||
0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u3 port1 0x1700 SPLLC
|
||||
0x1800 CHIP
|
||||
0x1900 U3PHYD
|
||||
0x1a00 U3PHYD_BANK2
|
||||
0x1b00 U3PHYA
|
||||
0x1c00 U3PHYA_DA
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
|
||||
SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back
|
||||
into each port; a new bank MISC for u2 ports and CHIP for u3 ports are
|
||||
added on V2.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^t-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2701-tphy
|
||||
- mediatek,mt7623-tphy
|
||||
- mediatek,mt7622-tphy
|
||||
- mediatek,mt8516-tphy
|
||||
- const: mediatek,generic-tphy-v1
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
- const: mediatek,generic-tphy-v2
|
||||
- const: mediatek,mt2701-u3phy
|
||||
deprecated: true
|
||||
- const: mediatek,mt2712-u3phy
|
||||
deprecated: true
|
||||
- const: mediatek,mt8173-u3phy
|
||||
|
||||
reg:
|
||||
description:
|
||||
Register shared by multiple ports, exclude port's private register.
|
||||
It is needed for T-PHY V1, such as mt2701 and mt8173, but not for
|
||||
T-PHY V2, such as mt2712.
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
"#size-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
# Used with non-empty value if optional 'reg' is not provided.
|
||||
# The format of the value is an arbitrary number of triplets of
|
||||
# (child-bus-address, parent-bus-address, length).
|
||||
ranges: true
|
||||
|
||||
mediatek,src-ref-clk-mhz:
|
||||
description:
|
||||
Frequency of reference clock for slew rate calibrate
|
||||
default: 26
|
||||
|
||||
mediatek,src-coef:
|
||||
description:
|
||||
Coefficient for slew rate calibrate, depends on SoC process
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 28
|
||||
|
||||
# Required child node:
|
||||
patternProperties:
|
||||
"^usb-phy@[0-9a-f]+$":
|
||||
type: object
|
||||
description:
|
||||
A sub-node is required for each port the controller provides.
|
||||
Address range information including the usual 'reg' property
|
||||
is used inside these nodes to describe the controller's topology.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Reference clock, (HS is 48Mhz, SS/P is 24~27Mhz)
|
||||
- description: Reference clock of analog phy
|
||||
description:
|
||||
Uses both clocks if the clock of analog and digital phys are
|
||||
separated, otherwise uses "ref" clock only if needed.
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: ref
|
||||
- const: da_ref
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
description: |
|
||||
The cells contain the following arguments.
|
||||
|
||||
- description: The PHY type
|
||||
enum:
|
||||
- PHY_TYPE_USB2
|
||||
- PHY_TYPE_USB3
|
||||
- PHY_TYPE_PCIE
|
||||
- PHY_TYPE_SATA
|
||||
|
||||
# The following optional vendor properties are only for debug or HQA test
|
||||
mediatek,eye-src:
|
||||
description:
|
||||
The value of slew rate calibrate (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,eye-vrt:
|
||||
description:
|
||||
The selection of VRT reference voltage (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,eye-term:
|
||||
description:
|
||||
The selection of HS_TX TERM reference voltage (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,intr:
|
||||
description:
|
||||
The selection of internal resistor (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 31
|
||||
|
||||
mediatek,discth:
|
||||
description:
|
||||
The selection of disconnect threshold (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 15
|
||||
|
||||
mediatek,bc12:
|
||||
description:
|
||||
Specify the flag to enable BC1.2 if support it
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- ranges
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
usb@11271000 {
|
||||
compatible = "mediatek,mt8173-mtu3", "mediatek,mtu3";
|
||||
reg = <0x11271000 0x3000>, <0x11280700 0x0100>;
|
||||
reg-names = "mac", "ippc";
|
||||
phys = <&u2port0 PHY_TYPE_USB2>,
|
||||
<&u3port0 PHY_TYPE_USB3>,
|
||||
<&u2port1 PHY_TYPE_USB2>;
|
||||
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&topckgen CLK_TOP_USB30_SEL>;
|
||||
clock-names = "sys_ck";
|
||||
};
|
||||
|
||||
t-phy@11290000 {
|
||||
compatible = "mediatek,mt8173-u3phy";
|
||||
reg = <0x11290000 0x800>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
u2port0: usb-phy@11290800 {
|
||||
reg = <0x11290800 0x100>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>, <&clk48m>;
|
||||
clock-names = "ref", "da_ref";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u3port0: usb-phy@11290900 {
|
||||
reg = <0x11290900 0x700>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u2port1: usb-phy@11291000 {
|
||||
reg = <0x11291000 0x100>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,64 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mediatek,ufs-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Universal Flash Storage (UFS) M-PHY binding
|
||||
|
||||
maintainers:
|
||||
- Stanley Chu <stanley.chu@mediatek.com>
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
description: |
|
||||
UFS M-PHY nodes are defined to describe on-chip UFS M-PHY hardware macro.
|
||||
Each UFS M-PHY node should have its own node.
|
||||
To bind UFS M-PHY with UFS host controller, the controller node should
|
||||
contain a phandle reference to UFS M-PHY node.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^ufs-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: mediatek,mt8183-ufsphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Unipro core control clock.
|
||||
- description: M-PHY core control clock.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: unipro
|
||||
- const: mp
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mt8183-clk.h>
|
||||
ufsphy: ufs-phy@11fa0000 {
|
||||
compatible = "mediatek,mt8183-ufsphy";
|
||||
reg = <0x11fa0000 0xc000>;
|
||||
clocks = <&infracfg CLK_INFRA_UNIPRO_SCK>,
|
||||
<&infracfg CLK_INFRA_UFS_MP_SAP_BCLK>;
|
||||
clock-names = "unipro", "mp";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,199 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mediatek,xsphy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek XS-PHY Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
|
||||
description: |
|
||||
The XS-PHY controller supports physical layer functionality for USB3.1
|
||||
GEN2 controller on MediaTek SoCs.
|
||||
|
||||
Banks layout of xsphy
|
||||
----------------------------------
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
u31 common 0x3000 DIG_GLB
|
||||
0x3100 PHYA_GLB
|
||||
u31 port0 0x3400 DIG_LN_TOP
|
||||
0x3500 DIG_LN_TX0
|
||||
0x3600 DIG_LN_RX0
|
||||
0x3700 DIG_LN_DAIF
|
||||
0x3800 PHYA_LN
|
||||
u31 port1 0x3a00 DIG_LN_TOP
|
||||
0x3b00 DIG_LN_TX0
|
||||
0x3c00 DIG_LN_RX0
|
||||
0x3d00 DIG_LN_DAIF
|
||||
0x3e00 PHYA_LN
|
||||
...
|
||||
DIG_GLB & PHYA_GLB are shared by U31 ports.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^xs-phy@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- mediatek,mt3611-xsphy
|
||||
- mediatek,mt3612-xsphy
|
||||
- const: mediatek,xsphy
|
||||
|
||||
reg:
|
||||
description:
|
||||
Register shared by multiple U3 ports, exclude port's private register,
|
||||
if only U2 ports provided, shouldn't use the property.
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
"#size-cells":
|
||||
enum: [1, 2]
|
||||
|
||||
ranges: true
|
||||
|
||||
mediatek,src-ref-clk-mhz:
|
||||
description:
|
||||
Frequency of reference clock for slew rate calibrate
|
||||
default: 26
|
||||
|
||||
mediatek,src-coef:
|
||||
description:
|
||||
Coefficient for slew rate calibrate, depends on SoC process
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 17
|
||||
|
||||
# Required child node:
|
||||
patternProperties:
|
||||
"^usb-phy@[0-9a-f]+$":
|
||||
type: object
|
||||
description:
|
||||
A sub-node is required for each port the controller provides.
|
||||
Address range information including the usual 'reg' property
|
||||
is used inside these nodes to describe the controller's topology.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Reference clock, (HS is 48Mhz, SS/P is 24~27Mhz)
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
description: |
|
||||
The cells contain the following arguments.
|
||||
|
||||
- description: The PHY type
|
||||
enum:
|
||||
- PHY_TYPE_USB2
|
||||
- PHY_TYPE_USB3
|
||||
|
||||
# The following optional vendor properties are only for debug or HQA test
|
||||
mediatek,eye-src:
|
||||
description:
|
||||
The value of slew rate calibrate (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,eye-vrt:
|
||||
description:
|
||||
The selection of VRT reference voltage (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,eye-term:
|
||||
description:
|
||||
The selection of HS_TX TERM reference voltage (U2 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 7
|
||||
|
||||
mediatek,efuse-intr:
|
||||
description:
|
||||
The selection of Internal Resistor (U2/U3 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 63
|
||||
|
||||
mediatek,efuse-tx-imp:
|
||||
description:
|
||||
The selection of TX Impedance (U3 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 31
|
||||
|
||||
mediatek,efuse-rx-imp:
|
||||
description:
|
||||
The selection of RX Impedance (U3 phy)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 31
|
||||
|
||||
required:
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- ranges
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
u3phy: xs-phy@11c40000 {
|
||||
compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy";
|
||||
reg = <0x11c43000 0x0200>;
|
||||
mediatek,src-ref-clk-mhz = <26>;
|
||||
mediatek,src-coef = <17>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
u2port0: usb-phy@11c40000 {
|
||||
reg = <0x11c40000 0x0400>;
|
||||
clocks = <&clk48m>;
|
||||
clock-names = "ref";
|
||||
mediatek,eye-src = <4>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u3port0: usb-phy@11c43000 {
|
||||
reg = <0x11c43400 0x0500>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
mediatek,efuse-intr = <28>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,162 +0,0 @@
|
|||
MediaTek T-PHY binding
|
||||
--------------------------
|
||||
|
||||
T-phy controller supports physical layer functionality for a number of
|
||||
controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA.
|
||||
|
||||
Required properties (controller (parent) node):
|
||||
- compatible : should be one of
|
||||
"mediatek,generic-tphy-v1"
|
||||
"mediatek,generic-tphy-v2"
|
||||
"mediatek,mt2701-u3phy" (deprecated)
|
||||
"mediatek,mt2712-u3phy" (deprecated)
|
||||
"mediatek,mt8173-u3phy";
|
||||
make use of "mediatek,generic-tphy-v1" on mt2701 instead and
|
||||
"mediatek,generic-tphy-v2" on mt2712 instead.
|
||||
|
||||
- #address-cells: the number of cells used to represent physical
|
||||
base addresses.
|
||||
- #size-cells: the number of cells used to represent the size of an address.
|
||||
- ranges: the address mapping relationship to the parent, defined with
|
||||
- empty value: if optional 'reg' is used.
|
||||
- non-empty value: if optional 'reg' is not used. should set
|
||||
the child's base address to 0, the physical address
|
||||
within parent's address space, and the length of
|
||||
the address map.
|
||||
|
||||
Required nodes : a sub-node is required for each port the controller
|
||||
provides. Address range information including the usual
|
||||
'reg' property is used inside these nodes to describe
|
||||
the controller's topology.
|
||||
|
||||
Optional properties (controller (parent) node):
|
||||
- reg : offset and length of register shared by multiple ports,
|
||||
exclude port's private register. It is needed on mt2701
|
||||
and mt8173, but not on mt2712.
|
||||
- mediatek,src-ref-clk-mhz : frequency of reference clock for slew rate
|
||||
calibrate
|
||||
- mediatek,src-coef : coefficient for slew rate calibrate, depends on
|
||||
SoC process
|
||||
|
||||
Required properties (port (child) node):
|
||||
- reg : address and length of the register set for the port.
|
||||
- #phy-cells : should be 1 (See second example)
|
||||
cell after port phandle is phy type from:
|
||||
- PHY_TYPE_USB2
|
||||
- PHY_TYPE_USB3
|
||||
- PHY_TYPE_PCIE
|
||||
- PHY_TYPE_SATA
|
||||
|
||||
Optional properties (PHY_TYPE_USB2 port (child) node):
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : may contain
|
||||
"ref": 48M reference clock for HighSpeed (digital) phy; and 26M
|
||||
reference clock for SuperSpeed (digital) phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
"da_ref": the reference clock of analog phy, used if the clocks
|
||||
of analog and digital phys are separated, otherwise uses
|
||||
"ref" clock only if needed.
|
||||
|
||||
- mediatek,eye-src : u32, the value of slew rate calibrate
|
||||
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
|
||||
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
|
||||
- mediatek,bc12 : bool, enable BC12 of u2phy if support it
|
||||
- mediatek,discth : u32, the selection of disconnect threshold
|
||||
- mediatek,intr : u32, the selection of internal R (resistance)
|
||||
|
||||
Example:
|
||||
|
||||
u3phy: usb-phy@11290000 {
|
||||
compatible = "mediatek,mt8173-u3phy";
|
||||
reg = <0 0x11290000 0 0x800>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
u2port0: usb-phy@11290800 {
|
||||
reg = <0 0x11290800 0 0x100>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u3port0: usb-phy@11290900 {
|
||||
reg = <0 0x11290800 0 0x700>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u2port1: usb-phy@11291000 {
|
||||
reg = <0 0x11291000 0 0x100>;
|
||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
Specifying phy control of devices
|
||||
---------------------------------
|
||||
|
||||
Device nodes should specify the configuration required in their "phys"
|
||||
property, containing a phandle to the phy port node and a device type;
|
||||
phy-names for each port are optional.
|
||||
|
||||
Example:
|
||||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
|
||||
usb30: usb@11270000 {
|
||||
...
|
||||
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
|
||||
phy-names = "usb2-0", "usb3-0";
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
Layout differences of banks between mt8173/mt2701 and mt2712
|
||||
-------------------------------------------------------------
|
||||
mt8173 and mt2701:
|
||||
port offset bank
|
||||
shared 0x0000 SPLLC
|
||||
0x0100 FMREG
|
||||
u2 port0 0x0800 U2PHY_COM
|
||||
u3 port0 0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 U2PHY_COM
|
||||
u3 port1 0x1100 U3PHYD
|
||||
0x1200 U3PHYD_BANK2
|
||||
0x1300 U3PHYA
|
||||
0x1400 U3PHYA_DA
|
||||
u2 port2 0x1800 U2PHY_COM
|
||||
...
|
||||
|
||||
mt2712:
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u3 port0 0x0700 SPLLC
|
||||
0x0800 CHIP
|
||||
0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u3 port1 0x1700 SPLLC
|
||||
0x1800 CHIP
|
||||
0x1900 U3PHYD
|
||||
0x1a00 U3PHYD_BANK2
|
||||
0x1b00 U3PHYA
|
||||
0x1c00 U3PHYA_DA
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
|
||||
SPLLC shared by u3 ports and FMREG shared by u2 ports on
|
||||
mt8173/mt2701 are put back into each port; a new bank MISC for
|
||||
u2 ports and CHIP for u3 ports are added on mt2712.
|
|
@ -1,38 +0,0 @@
|
|||
MediaTek Universal Flash Storage (UFS) M-PHY binding
|
||||
--------------------------------------------------------
|
||||
|
||||
UFS M-PHY nodes are defined to describe on-chip UFS M-PHY hardware macro.
|
||||
Each UFS M-PHY node should have its own node.
|
||||
|
||||
To bind UFS M-PHY with UFS host controller, the controller node should
|
||||
contain a phandle reference to UFS M-PHY node.
|
||||
|
||||
Required properties for UFS M-PHY nodes:
|
||||
- compatible : Compatible list, contains the following controller:
|
||||
"mediatek,mt8183-ufsphy" for ufs phy
|
||||
persent on MT81xx chipsets.
|
||||
- reg : Address and length of the UFS M-PHY register set.
|
||||
- #phy-cells : This property shall be set to 0.
|
||||
- clocks : List of phandle and clock specifier pairs.
|
||||
- clock-names : List of clock input name strings sorted in the same
|
||||
order as the clocks property. Following clocks are
|
||||
mandatory.
|
||||
"unipro": Unipro core control clock.
|
||||
"mp": M-PHY core control clock.
|
||||
|
||||
Example:
|
||||
|
||||
ufsphy: phy@11fa0000 {
|
||||
compatible = "mediatek,mt8183-ufsphy";
|
||||
reg = <0 0x11fa0000 0 0xc000>;
|
||||
#phy-cells = <0>;
|
||||
|
||||
clocks = <&infracfg_ao INFRACFG_AO_UNIPRO_SCK_CG>,
|
||||
<&infracfg_ao INFRACFG_AO_UFS_MP_SAP_BCLK_CG>;
|
||||
clock-names = "unipro", "mp";
|
||||
};
|
||||
|
||||
ufshci@11270000 {
|
||||
...
|
||||
phys = <&ufsphy>;
|
||||
};
|
|
@ -1,109 +0,0 @@
|
|||
MediaTek XS-PHY binding
|
||||
--------------------------
|
||||
|
||||
The XS-PHY controller supports physical layer functionality for USB3.1
|
||||
GEN2 controller on MediaTek SoCs.
|
||||
|
||||
Required properties (controller (parent) node):
|
||||
- compatible : should be "mediatek,<soc-model>-xsphy", "mediatek,xsphy",
|
||||
soc-model is the name of SoC, such as mt3611 etc;
|
||||
when using "mediatek,xsphy" compatible string, you need SoC specific
|
||||
ones in addition, one of:
|
||||
- "mediatek,mt3611-xsphy"
|
||||
|
||||
- #address-cells, #size-cells : should use the same values as the root node
|
||||
- ranges: must be present
|
||||
|
||||
Optional properties (controller (parent) node):
|
||||
- reg : offset and length of register shared by multiple U3 ports,
|
||||
exclude port's private register, if only U2 ports provided,
|
||||
shouldn't use the property.
|
||||
- mediatek,src-ref-clk-mhz : u32, frequency of reference clock for slew rate
|
||||
calibrate
|
||||
- mediatek,src-coef : u32, coefficient for slew rate calibrate, depends on
|
||||
SoC process
|
||||
|
||||
Required nodes : a sub-node is required for each port the controller
|
||||
provides. Address range information including the usual
|
||||
'reg' property is used inside these nodes to describe
|
||||
the controller's topology.
|
||||
|
||||
Required properties (port (child) node):
|
||||
- reg : address and length of the register set for the port.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
||||
reference clock for SuperSpeedPlus analog phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
- #phy-cells : should be 1
|
||||
cell after port phandle is phy type from:
|
||||
- PHY_TYPE_USB2
|
||||
- PHY_TYPE_USB3
|
||||
|
||||
The following optional properties are only for debug or HQA test
|
||||
Optional properties (PHY_TYPE_USB2 port (child) node):
|
||||
- mediatek,eye-src : u32, the value of slew rate calibrate
|
||||
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
|
||||
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
|
||||
- mediatek,efuse-intr : u32, the selection of Internal Resistor
|
||||
|
||||
Optional properties (PHY_TYPE_USB3 port (child) node):
|
||||
- mediatek,efuse-intr : u32, the selection of Internal Resistor
|
||||
- mediatek,efuse-tx-imp : u32, the selection of TX Impedance
|
||||
- mediatek,efuse-rx-imp : u32, the selection of RX Impedance
|
||||
|
||||
Banks layout of xsphy
|
||||
-------------------------------------------------------------
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
u31 common 0x3000 DIG_GLB
|
||||
0x3100 PHYA_GLB
|
||||
u31 port0 0x3400 DIG_LN_TOP
|
||||
0x3500 DIG_LN_TX0
|
||||
0x3600 DIG_LN_RX0
|
||||
0x3700 DIG_LN_DAIF
|
||||
0x3800 PHYA_LN
|
||||
u31 port1 0x3a00 DIG_LN_TOP
|
||||
0x3b00 DIG_LN_TX0
|
||||
0x3c00 DIG_LN_RX0
|
||||
0x3d00 DIG_LN_DAIF
|
||||
0x3e00 PHYA_LN
|
||||
...
|
||||
|
||||
DIG_GLB & PHYA_GLB are shared by U31 ports.
|
||||
|
||||
Example:
|
||||
|
||||
u3phy: usb-phy@11c40000 {
|
||||
compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy";
|
||||
reg = <0 0x11c43000 0 0x0200>;
|
||||
mediatek,src-ref-clk-mhz = <26>;
|
||||
mediatek,src-coef = <17>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
u2port0: usb-phy@11c40000 {
|
||||
reg = <0 0x11c40000 0 0x0400>;
|
||||
clocks = <&clk48m>;
|
||||
clock-names = "ref";
|
||||
mediatek,eye-src = <4>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
u3port0: usb-phy@11c43000 {
|
||||
reg = <0 0x11c43400 0 0x0500>;
|
||||
clocks = <&clk26m>;
|
||||
clock-names = "ref";
|
||||
mediatek,efuse-intr = <28>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
|
@ -45,6 +45,12 @@ properties:
|
|||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
vdda1v1-supply:
|
||||
description: regulator providing 1V1 power supply to the PLL block
|
||||
|
||||
vdda1v8-supply:
|
||||
description: regulator providing 1V8 power supply to the PLL block
|
||||
|
||||
#Required child nodes:
|
||||
|
||||
patternProperties:
|
||||
|
@ -61,12 +67,6 @@ patternProperties:
|
|||
phy-supply:
|
||||
description: regulator providing 3V3 power supply to the PHY.
|
||||
|
||||
vdda1v1-supply:
|
||||
description: regulator providing 1V1 power supply to the PLL block
|
||||
|
||||
vdda1v8-supply:
|
||||
description: regulator providing 1V8 power supply to the PLL block
|
||||
|
||||
"#phy-cells":
|
||||
enum: [ 0x0, 0x1 ]
|
||||
|
||||
|
@ -90,8 +90,6 @@ patternProperties:
|
|||
required:
|
||||
- reg
|
||||
- phy-supply
|
||||
- vdda1v1-supply
|
||||
- vdda1v8-supply
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
@ -102,6 +100,8 @@ required:
|
|||
- clocks
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- vdda1v1-supply
|
||||
- vdda1v8-supply
|
||||
- usb-phy@0
|
||||
- usb-phy@1
|
||||
|
||||
|
@ -116,22 +116,20 @@ examples:
|
|||
reg = <0x5a006000 0x1000>;
|
||||
clocks = <&rcc USBPHY_K>;
|
||||
resets = <&rcc USBPHY_R>;
|
||||
vdda1v1-supply = <®11>;
|
||||
vdda1v8-supply = <®18>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usbphyc_port0: usb-phy@0 {
|
||||
reg = <0>;
|
||||
phy-supply = <&vdd_usb>;
|
||||
vdda1v1-supply = <®11>;
|
||||
vdda1v8-supply = <®18>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
usbphyc_port1: usb-phy@1 {
|
||||
reg = <1>;
|
||||
phy-supply = <&vdd_usb>;
|
||||
vdda1v1-supply = <®11>;
|
||||
vdda1v8-supply = <®18>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -25,19 +25,32 @@ properties:
|
|||
- qcom,msm8998-qmp-pcie-phy
|
||||
- qcom,msm8998-qmp-ufs-phy
|
||||
- qcom,msm8998-qmp-usb3-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-usb3-phy
|
||||
- qcom,sdm845-qhp-pcie-phy
|
||||
- qcom,sdm845-qmp-pcie-phy
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sdm845-qmp-usb3-uni-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
- qcom,sm8150-qmp-usb3-uni-phy
|
||||
- qcom,sm8250-qmp-ufs-phy
|
||||
- qcom,sm8250-qmp-gen3x1-pcie-phy
|
||||
- qcom,sm8250-qmp-gen3x2-pcie-phy
|
||||
- qcom,sm8250-qmp-modem-pcie-phy
|
||||
- qcom,sm8250-qmp-usb3-phy
|
||||
- qcom,sm8250-qmp-usb3-uni-phy
|
||||
- qcom,sm8350-qmp-ufs-phy
|
||||
- qcom,sm8350-qmp-usb3-phy
|
||||
- qcom,sm8350-qmp-usb3-uni-phy
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Address and length of PHY's common serdes block.
|
||||
- description: Address and length of PHY's DP_COM control block.
|
||||
|
||||
"#clock-cells":
|
||||
enum: [ 1, 2 ]
|
||||
|
@ -131,6 +144,32 @@ allOf:
|
|||
items:
|
||||
- const: phy
|
||||
- const: common
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Phy aux clock.
|
||||
- description: Phy config clock.
|
||||
- description: 19.2 MHz ref clk.
|
||||
clock-names:
|
||||
items:
|
||||
- const: aux
|
||||
- const: cfg_ahb
|
||||
- const: ref
|
||||
resets:
|
||||
items:
|
||||
- description: reset of phy block.
|
||||
- description: phy common block reset.
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: common
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -285,6 +324,64 @@ allOf:
|
|||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
- qcom,sm8150-qmp-usb3-uni-phy
|
||||
- qcom,sm8250-qmp-usb3-uni-phy
|
||||
- qcom,sm8350-qmp-usb3-uni-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Phy aux clock.
|
||||
- description: 19.2 MHz ref clk source.
|
||||
- description: 19.2 MHz ref clk.
|
||||
- description: Phy common block aux clock.
|
||||
clock-names:
|
||||
items:
|
||||
- const: aux
|
||||
- const: ref_clk_src
|
||||
- const: ref
|
||||
- const: com_aux
|
||||
resets:
|
||||
items:
|
||||
- description: reset of phy block.
|
||||
- description: phy common block reset.
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: common
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sm8250-qmp-usb3-phy
|
||||
- qcom,sm8350-qmp-usb3-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Phy aux clock.
|
||||
- description: 19.2 MHz ref clk.
|
||||
- description: Phy common block aux clock.
|
||||
clock-names:
|
||||
items:
|
||||
- const: aux
|
||||
- const: ref_clk_src
|
||||
- const: com_aux
|
||||
resets:
|
||||
items:
|
||||
- description: reset of phy block.
|
||||
- description: phy common block reset.
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: common
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -21,6 +21,8 @@ properties:
|
|||
- qcom,ipq8074-qusb2-phy
|
||||
- qcom,msm8996-qusb2-phy
|
||||
- qcom,msm8998-qusb2-phy
|
||||
- qcom,sdm660-qusb2-phy
|
||||
- qcom,ipq6018-qusb2-phy
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,sc7180-qusb2-phy
|
||||
|
|
|
@ -16,6 +16,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- qcom,usb-hs-28nm-femtophy
|
||||
- qcom,usb-hs-28nm-mdm9607
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -17,6 +17,8 @@ properties:
|
|||
enum:
|
||||
- qcom,usb-snps-hs-7nm-phy
|
||||
- qcom,sm8150-usb-hs-phy
|
||||
- qcom,sm8250-usb-hs-phy
|
||||
- qcom,sm8350-usb-hs-phy
|
||||
- qcom,usb-snps-femto-v2-phy
|
||||
|
||||
reg:
|
||||
|
|
|
@ -16,11 +16,11 @@ Optional properties:
|
|||
- drive-impedance-ohm: Specifies the drive impedance in Ohm.
|
||||
Possible values are 33, 40, 50, 66 and 100.
|
||||
If not set, the default value of 50 will be applied.
|
||||
- enable-strobe-pulldown: Enable internal pull-down for the strobe line.
|
||||
If not set, pull-down is not used.
|
||||
- output-tapdelay-select: Specifies the phyctrl_otapdlysec register.
|
||||
If not set, the register defaults to 0x4.
|
||||
Maximum value 0xf.
|
||||
- rockchip,enable-strobe-pulldown: Enable internal pull-down for the strobe
|
||||
line. If not set, pull-down is not used.
|
||||
- rockchip,output-tapdelay-select: Specifies the phyctrl_otapdlysec register.
|
||||
If not set, the register defaults to 0x4.
|
||||
Maximum value 0xf.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ patternProperties:
|
|||
WIZ node should have '1' subnode for the SERDES. It could be either
|
||||
Sierra SERDES or Torrent SERDES. Sierra SERDES should follow the
|
||||
bindings specified in
|
||||
Documentation/devicetree/bindings/phy/phy-cadence-sierra.txt
|
||||
Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml
|
||||
Torrent SERDES should follow the bindings specified in
|
||||
Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
|
||||
|
||||
|
|
|
@ -94,7 +94,6 @@ available subsections can be seen below.
|
|||
pps
|
||||
ptp
|
||||
phy/index
|
||||
pti_intel_mid
|
||||
pwm
|
||||
pldmfw/index
|
||||
rfkill
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=============
|
||||
Intel MID PTI
|
||||
=============
|
||||
|
||||
The Intel MID PTI project is HW implemented in Intel Atom
|
||||
system-on-a-chip designs based on the Parallel Trace
|
||||
Interface for MIPI P1149.7 cJTAG standard. The kernel solution
|
||||
for this platform involves the following files::
|
||||
|
||||
./include/linux/pti.h
|
||||
./drivers/.../n_tracesink.h
|
||||
./drivers/.../n_tracerouter.c
|
||||
./drivers/.../n_tracesink.c
|
||||
./drivers/.../pti.c
|
||||
|
||||
pti.c is the driver that enables various debugging features
|
||||
popular on platforms from certain mobile manufacturers.
|
||||
n_tracerouter.c and n_tracesink.c allow extra system information to
|
||||
be collected and routed to the pti driver, such as trace
|
||||
debugging data from a modem. Although n_tracerouter
|
||||
and n_tracesink are a part of the complete PTI solution,
|
||||
these two line disciplines can work separately from
|
||||
pti.c and route any data stream from one /dev/tty node
|
||||
to another /dev/tty node via kernel-space. This provides
|
||||
a stable, reliable connection that will not break unless
|
||||
the user-space application shuts down (plus avoids
|
||||
kernel->user->kernel context switch overheads of routing
|
||||
data).
|
||||
|
||||
An example debugging usage for this driver system:
|
||||
|
||||
* Hook /dev/ttyPTI0 to syslogd. Opening this port will also start
|
||||
a console device to further capture debugging messages to PTI.
|
||||
* Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW.
|
||||
This is where n_tracerouter and n_tracesink are used.
|
||||
* Hook /dev/pti to a user-level debugging application for writing
|
||||
to PTI HW.
|
||||
* `Use mipi_` Kernel Driver API in other device drivers for
|
||||
debugging to PTI by first requesting a PTI write address via
|
||||
mipi_request_masterchannel(1).
|
||||
|
||||
Below is example pseudo-code on how a 'privileged' application
|
||||
can hook up n_tracerouter and n_tracesink to any tty on
|
||||
a system. 'Privileged' means the application has enough
|
||||
privileges to successfully manipulate the ldisc drivers
|
||||
but is not just blindly executing as 'root'. Keep in mind
|
||||
the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
|
||||
and n_tracesink line discpline drivers but is a generic
|
||||
operation for a program to use a line discpline driver
|
||||
on a tty port other than the default n_tty:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/////////// To hook up n_tracerouter and n_tracesink /////////
|
||||
|
||||
// Note that n_tracerouter depends on n_tracesink.
|
||||
#include <errno.h>
|
||||
#define ONE_TTY "/dev/ttyOne"
|
||||
#define TWO_TTY "/dev/ttyTwo"
|
||||
|
||||
// needed global to hand onto ldisc connection
|
||||
static int g_fd_source = -1;
|
||||
static int g_fd_sink = -1;
|
||||
|
||||
// these two vars used to grab LDISC values from loaded ldisc drivers
|
||||
// in OS. Look at /proc/tty/ldiscs to get the right numbers from
|
||||
// the ldiscs loaded in the system.
|
||||
int source_ldisc_num, sink_ldisc_num = -1;
|
||||
int retval;
|
||||
|
||||
g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W
|
||||
g_fd_sink = open(TWO_TTY, O_RDWR); // must be R/W
|
||||
|
||||
if (g_fd_source <= 0) || (g_fd_sink <= 0) {
|
||||
// doubt you'll want to use these exact error lines of code
|
||||
printf("Error on open(). errno: %d\n",errno);
|
||||
return errno;
|
||||
}
|
||||
|
||||
retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num);
|
||||
if (retval < 0) {
|
||||
printf("Error on ioctl(). errno: %d\n", errno);
|
||||
return errno;
|
||||
}
|
||||
|
||||
retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num);
|
||||
if (retval < 0) {
|
||||
printf("Error on ioctl(). errno: %d\n", errno);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/////////// To disconnect n_tracerouter and n_tracesink ////////
|
||||
|
||||
// First make sure data through the ldiscs has stopped.
|
||||
|
||||
// Second, disconnect ldiscs. This provides a
|
||||
// little cleaner shutdown on tty stack.
|
||||
sink_ldisc_num = 0;
|
||||
source_ldisc_num = 0;
|
||||
ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num);
|
||||
ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num);
|
||||
|
||||
// Three, program closes connection, and cleanup:
|
||||
close(g_fd_uart);
|
||||
close(g_fd_gadget);
|
||||
g_fd_uart = g_fd_gadget = NULL;
|
|
@ -501,6 +501,34 @@ Developer only needs to provide a sub feature driver with matched feature id.
|
|||
FME Partial Reconfiguration Sub Feature driver (see drivers/fpga/dfl-fme-pr.c)
|
||||
could be a reference.
|
||||
|
||||
Location of DFLs on a PCI Device
|
||||
================================
|
||||
The original method for finding a DFL on a PCI device assumed the start of the
|
||||
first DFL to offset 0 of bar 0. If the first node of the DFL is an FME,
|
||||
then further DFLs in the port(s) are specified in FME header registers.
|
||||
Alternatively, a PCIe vendor specific capability structure can be used to
|
||||
specify the location of all the DFLs on the device, providing flexibility
|
||||
for the type of starting node in the DFL. Intel has reserved the
|
||||
VSEC ID of 0x43 for this purpose. The vendor specific
|
||||
data begins with a 4 byte vendor specific register for the number of DFLs followed 4 byte
|
||||
Offset/BIR vendor specific registers for each DFL. Bits 2:0 of Offset/BIR register
|
||||
indicates the BAR, and bits 31:3 form the 8 byte aligned offset where bits 2:0 are
|
||||
zero.
|
||||
::
|
||||
|
||||
+----------------------------+
|
||||
|31 Number of DFLS 0|
|
||||
+----------------------------+
|
||||
|31 Offset 3|2 BIR 0|
|
||||
+----------------------------+
|
||||
. . .
|
||||
+----------------------------+
|
||||
|31 Offset 3|2 BIR 0|
|
||||
+----------------------------+
|
||||
|
||||
Being able to specify more than one DFL per BAR has been considered, but it
|
||||
was determined the use case did not provide value. Specifying a single DFL
|
||||
per BAR simplifies the implementation and allows for extra error checking.
|
||||
|
||||
Open discussion
|
||||
===============
|
||||
|
|
|
@ -512,6 +512,38 @@ The --itrace option controls the type and frequency of synthesized events
|
|||
Note that only 64-bit programs are currently supported - further work is
|
||||
required to support instruction decode of 32-bit Arm programs.
|
||||
|
||||
2.2) Tracing PID
|
||||
|
||||
The kernel can be built to write the PID value into the PE ContextID registers.
|
||||
For a kernel running at EL1, the PID is stored in CONTEXTIDR_EL1. A PE may
|
||||
implement Arm Virtualization Host Extensions (VHE), which the kernel can
|
||||
run at EL2 as a virtualisation host; in this case, the PID value is stored in
|
||||
CONTEXTIDR_EL2.
|
||||
|
||||
perf provides PMU formats that program the ETM to insert these values into the
|
||||
trace data; the PMU formats are defined as below:
|
||||
|
||||
"contextid1": Available on both EL1 kernel and EL2 kernel. When the
|
||||
kernel is running at EL1, "contextid1" enables the PID
|
||||
tracing; when the kernel is running at EL2, this enables
|
||||
tracing the PID of guest applications.
|
||||
|
||||
"contextid2": Only usable when the kernel is running at EL2. When
|
||||
selected, enables PID tracing on EL2 kernel.
|
||||
|
||||
"contextid": Will be an alias for the option that enables PID
|
||||
tracing. I.e,
|
||||
contextid == contextid1, on EL1 kernel.
|
||||
contextid == contextid2, on EL2 kernel.
|
||||
|
||||
perf will always enable PID tracing at the relevant EL, this is accomplished by
|
||||
automatically enable the "contextid" config - but for EL2 it is possible to make
|
||||
specific adjustments using configs "contextid1" and "contextid2", E.g. if a user
|
||||
wants to trace PIDs for both host and guest, the two configs "contextid1" and
|
||||
"contextid2" can be set at the same time:
|
||||
|
||||
perf record -e cs_etm/contextid1,contextid2/u -- vm
|
||||
|
||||
|
||||
Generating coverage files for Feedback Directed Optimization: AutoFDO
|
||||
---------------------------------------------------------------------
|
||||
|
|
|
@ -179,6 +179,7 @@ Code Seq# Include File Comments
|
|||
'R' 00-1F linux/random.h conflict!
|
||||
'R' 01 linux/rfkill.h conflict!
|
||||
'R' C0-DF net/bluetooth/rfcomm.h
|
||||
'R' E0 uapi/linux/fsl_mc.h
|
||||
'S' all linux/cdrom.h conflict!
|
||||
'S' 80-81 scsi/scsi_ioctl.h conflict!
|
||||
'S' 82-FF scsi/scsi.h conflict!
|
||||
|
@ -318,6 +319,7 @@ Code Seq# Include File Comments
|
|||
0xA0 all linux/sdp/sdp.h Industrial Device Project
|
||||
<mailto:kenji@bitgate.com>
|
||||
0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver
|
||||
0xA2 all uapi/linux/acrn.h ACRN hypervisor
|
||||
0xA3 80-8F Port ACL in development:
|
||||
<mailto:tlewis@mindspring.com>
|
||||
0xA3 90-9F linux/dtlk.h
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
ACRN CPUID bits
|
||||
===============
|
||||
|
||||
A guest VM running on an ACRN hypervisor can check some of its features using
|
||||
CPUID.
|
||||
|
||||
ACRN cpuid functions are:
|
||||
|
||||
function: 0x40000000
|
||||
|
||||
returns::
|
||||
|
||||
eax = 0x40000010
|
||||
ebx = 0x4e524341
|
||||
ecx = 0x4e524341
|
||||
edx = 0x4e524341
|
||||
|
||||
Note that this value in ebx, ecx and edx corresponds to the string
|
||||
"ACRNACRNACRN". The value in eax corresponds to the maximum cpuid function
|
||||
present in this leaf, and will be updated if more functions are added in the
|
||||
future.
|
||||
|
||||
function: define ACRN_CPUID_FEATURES (0x40000001)
|
||||
|
||||
returns::
|
||||
|
||||
ebx, ecx, edx
|
||||
eax = an OR'ed group of (1 << flag)
|
||||
|
||||
where ``flag`` is defined as below:
|
||||
|
||||
================================= =========== ================================
|
||||
flag value meaning
|
||||
================================= =========== ================================
|
||||
ACRN_FEATURE_PRIVILEGED_VM 0 guest VM is a privileged VM
|
||||
================================= =========== ================================
|
||||
|
||||
function: 0x40000010
|
||||
|
||||
returns::
|
||||
|
||||
ebx, ecx, edx
|
||||
eax = (Virtual) TSC frequency in kHz.
|
|
@ -0,0 +1,12 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
ACRN Hypervisor
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
introduction
|
||||
io-request
|
||||
cpuid
|
|
@ -0,0 +1,43 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ACRN Hypervisor Introduction
|
||||
============================
|
||||
|
||||
The ACRN Hypervisor is a Type 1 hypervisor, running directly on bare-metal
|
||||
hardware. It has a privileged management VM, called Service VM, to manage User
|
||||
VMs and do I/O emulation.
|
||||
|
||||
ACRN userspace is an application running in the Service VM that emulates
|
||||
devices for a User VM based on command line configurations. ACRN Hypervisor
|
||||
Service Module (HSM) is a kernel module in the Service VM which provides
|
||||
hypervisor services to the ACRN userspace.
|
||||
|
||||
Below figure shows the architecture.
|
||||
|
||||
::
|
||||
|
||||
Service VM User VM
|
||||
+----------------------------+ | +------------------+
|
||||
| +--------------+ | | | |
|
||||
| |ACRN userspace| | | | |
|
||||
| +--------------+ | | | |
|
||||
|-----------------ioctl------| | | | ...
|
||||
|kernel space +----------+ | | | |
|
||||
| | HSM | | | | Drivers |
|
||||
| +----------+ | | | |
|
||||
+--------------------|-------+ | +------------------+
|
||||
+---------------------hypercall----------------------------------------+
|
||||
| ACRN Hypervisor |
|
||||
+----------------------------------------------------------------------+
|
||||
| Hardware |
|
||||
+----------------------------------------------------------------------+
|
||||
|
||||
ACRN userspace allocates memory for the User VM, configures and initializes the
|
||||
devices used by the User VM, loads the virtual bootloader, initializes the
|
||||
virtual CPU state and handles I/O request accesses from the User VM. It uses
|
||||
ioctls to communicate with the HSM. HSM implements hypervisor services by
|
||||
interacting with the ACRN Hypervisor via hypercalls. HSM exports a char device
|
||||
interface (/dev/acrn_hsm) to userspace.
|
||||
|
||||
The ACRN hypervisor is open for contribution from anyone. The source repo is
|
||||
available at https://github.com/projectacrn/acrn-hypervisor.
|
|
@ -0,0 +1,97 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
I/O request handling
|
||||
====================
|
||||
|
||||
An I/O request of a User VM, which is constructed by the hypervisor, is
|
||||
distributed by the ACRN Hypervisor Service Module to an I/O client
|
||||
corresponding to the address range of the I/O request. Details of I/O request
|
||||
handling are described in the following sections.
|
||||
|
||||
1. I/O request
|
||||
--------------
|
||||
|
||||
For each User VM, there is a shared 4-KByte memory region used for I/O requests
|
||||
communication between the hypervisor and Service VM. An I/O request is a
|
||||
256-byte structure buffer, which is 'struct acrn_io_request', that is filled by
|
||||
an I/O handler of the hypervisor when a trapped I/O access happens in a User
|
||||
VM. ACRN userspace in the Service VM first allocates a 4-KByte page and passes
|
||||
the GPA (Guest Physical Address) of the buffer to the hypervisor. The buffer is
|
||||
used as an array of 16 I/O request slots with each I/O request slot being 256
|
||||
bytes. This array is indexed by vCPU ID.
|
||||
|
||||
2. I/O clients
|
||||
--------------
|
||||
|
||||
An I/O client is responsible for handling User VM I/O requests whose accessed
|
||||
GPA falls in a certain range. Multiple I/O clients can be associated with each
|
||||
User VM. There is a special client associated with each User VM, called the
|
||||
default client, that handles all I/O requests that do not fit into the range of
|
||||
any other clients. The ACRN userspace acts as the default client for each User
|
||||
VM.
|
||||
|
||||
Below illustration shows the relationship between I/O requests shared buffer,
|
||||
I/O requests and I/O clients.
|
||||
|
||||
::
|
||||
|
||||
+------------------------------------------------------+
|
||||
| Service VM |
|
||||
|+--------------------------------------------------+ |
|
||||
|| +----------------------------------------+ | |
|
||||
|| | shared page ACRN userspace | | |
|
||||
|| | +-----------------+ +------------+ | | |
|
||||
|| +----+->| acrn_io_request |<-+ default | | | |
|
||||
|| | | | +-----------------+ | I/O client | | | |
|
||||
|| | | | | ... | +------------+ | | |
|
||||
|| | | | +-----------------+ | | |
|
||||
|| | +-|--------------------------------------+ | |
|
||||
||---|----|-----------------------------------------| |
|
||||
|| | | kernel | |
|
||||
|| | | +----------------------+ | |
|
||||
|| | | | +-------------+ HSM | | |
|
||||
|| | +--------------+ | | | |
|
||||
|| | | | I/O clients | | | |
|
||||
|| | | | | | | |
|
||||
|| | | +-------------+ | | |
|
||||
|| | +----------------------+ | |
|
||||
|+---|----------------------------------------------+ |
|
||||
+----|-------------------------------------------------+
|
||||
|
|
||||
+----|-------------------------------------------------+
|
||||
| +-+-----------+ |
|
||||
| | I/O handler | ACRN Hypervisor |
|
||||
| +-------------+ |
|
||||
+------------------------------------------------------+
|
||||
|
||||
3. I/O request state transition
|
||||
-------------------------------
|
||||
|
||||
The state transitions of an ACRN I/O request are as follows.
|
||||
|
||||
::
|
||||
|
||||
FREE -> PENDING -> PROCESSING -> COMPLETE -> FREE -> ...
|
||||
|
||||
- FREE: this I/O request slot is empty
|
||||
- PENDING: a valid I/O request is pending in this slot
|
||||
- PROCESSING: the I/O request is being processed
|
||||
- COMPLETE: the I/O request has been processed
|
||||
|
||||
An I/O request in COMPLETE or FREE state is owned by the hypervisor. HSM and
|
||||
ACRN userspace are in charge of processing the others.
|
||||
|
||||
4. Processing flow of I/O requests
|
||||
----------------------------------
|
||||
|
||||
a. The I/O handler of the hypervisor will fill an I/O request with PENDING
|
||||
state when a trapped I/O access happens in a User VM.
|
||||
b. The hypervisor makes an upcall, which is a notification interrupt, to
|
||||
the Service VM.
|
||||
c. The upcall handler schedules a worker to dispatch I/O requests.
|
||||
d. The worker looks for the PENDING I/O requests, assigns them to different
|
||||
registered clients based on the address of the I/O accesses, updates
|
||||
their state to PROCESSING, and notifies the corresponding client to handle.
|
||||
e. The notified client handles the assigned I/O requests.
|
||||
f. The HSM updates I/O requests states to COMPLETE and notifies the hypervisor
|
||||
of the completion via hypercalls.
|
|
@ -12,6 +12,7 @@ Linux Virtualization Support
|
|||
paravirt_ops
|
||||
guest-halt-polling
|
||||
ne_overview
|
||||
acrn/index
|
||||
|
||||
.. only:: html and subproject
|
||||
|
||||
|
|
26
MAINTAINERS
26
MAINTAINERS
|
@ -436,6 +436,15 @@ S: Orphan
|
|||
F: drivers/platform/x86/wmi.c
|
||||
F: include/uapi/linux/wmi.h
|
||||
|
||||
ACRN HYPERVISOR SERVICE MODULE
|
||||
M: Shuo Liu <shuo.a.liu@intel.com>
|
||||
L: acrn-dev@lists.projectacrn.org (subscribers-only)
|
||||
S: Supported
|
||||
W: https://projectacrn.org
|
||||
F: Documentation/virt/acrn/
|
||||
F: drivers/virt/acrn/
|
||||
F: include/uapi/linux/acrn.h
|
||||
|
||||
AD1889 ALSA SOUND DRIVER
|
||||
L: linux-parisc@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -1017,7 +1026,7 @@ F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt
|
|||
F: drivers/mux/adgs1408.c
|
||||
|
||||
ANALOG DEVICES INC ADIN DRIVER
|
||||
M: Alexandru Ardelean <alexaundru.ardelean@analog.com>
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
|
@ -1025,7 +1034,7 @@ F: Documentation/devicetree/bindings/net/adi,adin.yaml
|
|||
F: drivers/net/phy/adin.c
|
||||
|
||||
ANALOG DEVICES INC ADIS DRIVER LIBRARY
|
||||
M: Alexandru Ardelean <alexandru.ardelean@analog.com>
|
||||
M: Nuno Sa <nuno.sa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/imu/adis.c
|
||||
|
@ -3731,6 +3740,13 @@ L: netdev@vger.kernel.org
|
|||
S: Supported
|
||||
F: drivers/net/ethernet/broadcom/tg3.*
|
||||
|
||||
BROADCOM VK DRIVER
|
||||
M: Scott Branden <scott.branden@broadcom.com>
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
S: Supported
|
||||
F: drivers/misc/bcm-vk/
|
||||
F: include/uapi/linux/misc/bcm_vk.h
|
||||
|
||||
BROCADE BFA FC SCSI DRIVER
|
||||
M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
|
||||
M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
|
||||
|
@ -6950,9 +6966,10 @@ M: Wu Hao <hao.wu@intel.com>
|
|||
R: Tom Rix <trix@redhat.com>
|
||||
L: linux-fpga@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-dfl
|
||||
F: Documentation/ABI/testing/sysfs-bus-dfl*
|
||||
F: Documentation/fpga/dfl.rst
|
||||
F: drivers/fpga/dfl*
|
||||
F: include/linux/dfl.h
|
||||
F: include/uapi/linux/fpga-dfl.h
|
||||
|
||||
FPGA MANAGER FRAMEWORK
|
||||
|
@ -14686,9 +14703,11 @@ M: Stuart Yoder <stuyoder@gmail.com>
|
|||
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/stable/sysfs-bus-fsl-mc
|
||||
F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
|
||||
F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
|
||||
F: drivers/bus/fsl-mc/
|
||||
F: include/uapi/linux/fsl_mc.h
|
||||
|
||||
QT1010 MEDIA DRIVER
|
||||
M: Antti Palosaari <crope@iki.fi>
|
||||
|
@ -16731,6 +16750,7 @@ R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
|||
R: Sanyog Kale <sanyog.r.kale@intel.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git
|
||||
F: Documentation/driver-api/soundwire/
|
||||
F: drivers/soundwire/
|
||||
F: include/linux/soundwire/
|
||||
|
|
|
@ -191,6 +191,7 @@
|
|||
#define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6)
|
||||
|
||||
#define SYS_ZCR_EL1 sys_reg(3, 0, 1, 2, 0)
|
||||
#define SYS_TRFCR_EL1 sys_reg(3, 0, 1, 2, 1)
|
||||
|
||||
#define SYS_TTBR0_EL1 sys_reg(3, 0, 2, 0, 0)
|
||||
#define SYS_TTBR1_EL1 sys_reg(3, 0, 2, 0, 1)
|
||||
|
@ -475,6 +476,7 @@
|
|||
|
||||
#define SYS_SCTLR_EL2 sys_reg(3, 4, 1, 0, 0)
|
||||
#define SYS_ZCR_EL2 sys_reg(3, 4, 1, 2, 0)
|
||||
#define SYS_TRFCR_EL2 sys_reg(3, 4, 1, 2, 1)
|
||||
#define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0)
|
||||
#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
|
||||
#define SYS_ELR_EL2 sys_reg(3, 4, 4, 0, 1)
|
||||
|
@ -833,6 +835,7 @@
|
|||
#define ID_AA64MMFR2_CNP_SHIFT 0
|
||||
|
||||
/* id_aa64dfr0 */
|
||||
#define ID_AA64DFR0_TRACE_FILT_SHIFT 40
|
||||
#define ID_AA64DFR0_DOUBLELOCK_SHIFT 36
|
||||
#define ID_AA64DFR0_PMSVER_SHIFT 32
|
||||
#define ID_AA64DFR0_CTX_CMPS_SHIFT 28
|
||||
|
@ -1013,6 +1016,14 @@
|
|||
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
|
||||
#define SYS_MPIDR_SAFE_VAL (BIT(31))
|
||||
|
||||
#define TRFCR_ELx_TS_SHIFT 5
|
||||
#define TRFCR_ELx_TS_VIRTUAL ((0x1UL) << TRFCR_ELx_TS_SHIFT)
|
||||
#define TRFCR_ELx_TS_GUEST_PHYSICAL ((0x2UL) << TRFCR_ELx_TS_SHIFT)
|
||||
#define TRFCR_ELx_TS_PHYSICAL ((0x3UL) << TRFCR_ELx_TS_SHIFT)
|
||||
#define TRFCR_EL2_CX BIT(3)
|
||||
#define TRFCR_ELx_ExTRE BIT(1)
|
||||
#define TRFCR_ELx_E0TRE BIT(0)
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
.irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ACRN_H
|
||||
#define _ASM_X86_ACRN_H
|
||||
|
||||
/*
|
||||
* This CPUID returns feature bitmaps in EAX.
|
||||
* Guest VM uses this to detect the appropriate feature bit.
|
||||
*/
|
||||
#define ACRN_CPUID_FEATURES 0x40000001
|
||||
/* Bit 0 indicates whether guest VM is privileged */
|
||||
#define ACRN_FEATURE_PRIVILEGED_VM BIT(0)
|
||||
|
||||
void acrn_setup_intr_handler(void (*handler)(void));
|
||||
void acrn_remove_intr_handler(void);
|
||||
|
||||
static inline u32 acrn_cpuid_base(void)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||
return hypervisor_cpuid_base("ACRNACRNACRN", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hypercalls for ACRN
|
||||
*
|
||||
* - VMCALL instruction is used to implement ACRN hypercalls.
|
||||
* - ACRN hypercall ABI:
|
||||
* - Hypercall number is passed in R8 register.
|
||||
* - Up to 2 arguments are passed in RDI, RSI.
|
||||
* - Return value will be placed in RAX.
|
||||
*
|
||||
* Because GCC doesn't support R8 register as direct register constraints, use
|
||||
* supported constraint as input with a explicit MOV to R8 in beginning of asm.
|
||||
*/
|
||||
static inline long acrn_hypercall0(unsigned long hcall_id)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline long acrn_hypercall1(unsigned long hcall_id,
|
||||
unsigned long param1)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id), "D" (param1)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline long acrn_hypercall2(unsigned long hcall_id,
|
||||
unsigned long param1,
|
||||
unsigned long param2)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id), "D" (param1), "S" (param2)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_ACRN_H */
|
|
@ -10,6 +10,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/acrn.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/desc.h>
|
||||
|
@ -19,7 +21,7 @@
|
|||
|
||||
static u32 __init acrn_detect(void)
|
||||
{
|
||||
return hypervisor_cpuid_base("ACRNACRNACRN", 0);
|
||||
return acrn_cpuid_base();
|
||||
}
|
||||
|
||||
static void __init acrn_init_platform(void)
|
||||
|
@ -55,6 +57,18 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_acrn_hv_callback)
|
|||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
void acrn_setup_intr_handler(void (*handler)(void))
|
||||
{
|
||||
acrn_intr_handler = handler;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acrn_setup_intr_handler);
|
||||
|
||||
void acrn_remove_intr_handler(void)
|
||||
{
|
||||
acrn_intr_handler = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acrn_remove_intr_handler);
|
||||
|
||||
const __initconst struct hypervisor_x86 x86_hyper_acrn = {
|
||||
.name = "ACRN",
|
||||
.detect = acrn_detect,
|
||||
|
|
|
@ -27,11 +27,11 @@ static const struct old_serial_port *serstate;
|
|||
static int timeouts;
|
||||
|
||||
static int spk_serial_out(struct spk_synth *in_synth, const char ch);
|
||||
static void spk_serial_send_xchar(char ch);
|
||||
static void spk_serial_tiocmset(unsigned int set, unsigned int clear);
|
||||
static unsigned char spk_serial_in(void);
|
||||
static unsigned char spk_serial_in_nowait(void);
|
||||
static void spk_serial_flush_buffer(void);
|
||||
static void spk_serial_send_xchar(struct spk_synth *in_synth, char ch);
|
||||
static void spk_serial_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
|
||||
static unsigned char spk_serial_in(struct spk_synth *in_synth);
|
||||
static unsigned char spk_serial_in_nowait(struct spk_synth *in_synth);
|
||||
static void spk_serial_flush_buffer(struct spk_synth *in_synth);
|
||||
static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth);
|
||||
|
||||
struct spk_io_ops spk_serial_io_ops = {
|
||||
|
@ -150,7 +150,7 @@ static void start_serial_interrupt(int irq)
|
|||
outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */
|
||||
}
|
||||
|
||||
static void spk_serial_send_xchar(char ch)
|
||||
static void spk_serial_send_xchar(struct spk_synth *synth, char ch)
|
||||
{
|
||||
int timeout = SPK_XMITR_TIMEOUT;
|
||||
|
||||
|
@ -162,7 +162,7 @@ static void spk_serial_send_xchar(char ch)
|
|||
outb(ch, speakup_info.port_tts);
|
||||
}
|
||||
|
||||
static void spk_serial_tiocmset(unsigned int set, unsigned int clear)
|
||||
static void spk_serial_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
|
||||
{
|
||||
int old = inb(speakup_info.port_tts + UART_MCR);
|
||||
|
||||
|
@ -251,7 +251,7 @@ static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static unsigned char spk_serial_in(void)
|
||||
static unsigned char spk_serial_in(struct spk_synth *in_synth)
|
||||
{
|
||||
int tmout = SPK_SERIAL_TIMEOUT;
|
||||
|
||||
|
@ -265,7 +265,7 @@ static unsigned char spk_serial_in(void)
|
|||
return inb_p(speakup_info.port_tts + UART_RX);
|
||||
}
|
||||
|
||||
static unsigned char spk_serial_in_nowait(void)
|
||||
static unsigned char spk_serial_in_nowait(struct spk_synth *in_synth)
|
||||
{
|
||||
unsigned char lsr;
|
||||
|
||||
|
@ -275,7 +275,7 @@ static unsigned char spk_serial_in_nowait(void)
|
|||
return inb_p(speakup_info.port_tts + UART_RX);
|
||||
}
|
||||
|
||||
static void spk_serial_flush_buffer(void)
|
||||
static void spk_serial_flush_buffer(struct spk_synth *in_synth)
|
||||
{
|
||||
/* TODO: flush the UART 16550 buffer */
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ const char *spk_serial_synth_immediate(struct spk_synth *synth,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(spk_serial_synth_immediate);
|
||||
|
||||
void spk_serial_release(void)
|
||||
void spk_serial_release(struct spk_synth *synth)
|
||||
{
|
||||
spk_stop_serial_interrupt();
|
||||
if (speakup_info.port_tts == 0)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define PROCSPEECH '\r'
|
||||
|
||||
static int synth_probe(struct spk_synth *synth);
|
||||
static void accent_release(void);
|
||||
static void accent_release(struct spk_synth *synth);
|
||||
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
|
||||
static void do_catch_up(struct spk_synth *synth);
|
||||
static void synth_flush(struct spk_synth *synth);
|
||||
|
@ -294,7 +294,7 @@ static int synth_probe(struct spk_synth *synth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void accent_release(void)
|
||||
static void accent_release(struct spk_synth *synth)
|
||||
{
|
||||
spk_stop_serial_interrupt();
|
||||
if (speakup_info.port_tts)
|
||||
|
|
|
@ -163,8 +163,8 @@ static void do_catch_up(struct spk_synth *synth)
|
|||
full_time_val = full_time->u.n.value;
|
||||
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
|
||||
if (!synth->io_ops->synth_out(synth, ch)) {
|
||||
synth->io_ops->tiocmset(0, UART_MCR_RTS);
|
||||
synth->io_ops->tiocmset(UART_MCR_RTS, 0);
|
||||
synth->io_ops->tiocmset(synth, 0, UART_MCR_RTS);
|
||||
synth->io_ops->tiocmset(synth, UART_MCR_RTS, 0);
|
||||
schedule_timeout(msecs_to_jiffies(full_time_val));
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -119,8 +119,8 @@ static struct spk_synth synth_audptr = {
|
|||
|
||||
static void synth_flush(struct spk_synth *synth)
|
||||
{
|
||||
synth->io_ops->flush_buffer();
|
||||
synth->io_ops->send_xchar(SYNTH_CLEAR);
|
||||
synth->io_ops->flush_buffer(synth);
|
||||
synth->io_ops->send_xchar(synth, SYNTH_CLEAR);
|
||||
synth->io_ops->synth_out(synth, PROCSPEECH);
|
||||
}
|
||||
|
||||
|
@ -130,11 +130,11 @@ static void synth_version(struct spk_synth *synth)
|
|||
char synth_id[40] = "";
|
||||
|
||||
synth->synth_immediate(synth, "\x05[Q]");
|
||||
synth_id[test] = synth->io_ops->synth_in();
|
||||
synth_id[test] = synth->io_ops->synth_in(synth);
|
||||
if (synth_id[test] == 'A') {
|
||||
do {
|
||||
/* read version string from synth */
|
||||
synth_id[++test] = synth->io_ops->synth_in();
|
||||
synth_id[++test] = synth->io_ops->synth_in(synth);
|
||||
} while (synth_id[test] != '\n' && test < 32);
|
||||
synth_id[++test] = 0x00;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ static void do_catch_up(struct spk_synth *synth)
|
|||
static void synth_flush(struct spk_synth *synth)
|
||||
{
|
||||
in_escape = 0;
|
||||
synth->io_ops->flush_buffer();
|
||||
synth->io_ops->flush_buffer(synth);
|
||||
synth->synth_immediate(synth, "\033P;10z\033\\");
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ enum { PRIMARY_DIC = 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
|
|||
#define SYNTH_IO_EXTENT 8
|
||||
|
||||
static int synth_probe(struct spk_synth *synth);
|
||||
static void dtpc_release(void);
|
||||
static void dtpc_release(struct spk_synth *synth);
|
||||
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
|
||||
static void do_catch_up(struct spk_synth *synth);
|
||||
static void synth_flush(struct spk_synth *synth);
|
||||
|
@ -474,7 +474,7 @@ static int synth_probe(struct spk_synth *synth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dtpc_release(void)
|
||||
static void dtpc_release(struct spk_synth *synth)
|
||||
{
|
||||
spk_stop_serial_interrupt();
|
||||
if (speakup_info.port_tts)
|
||||
|
|
|
@ -78,6 +78,8 @@ static struct kobj_attribute direct_attribute =
|
|||
__ATTR(direct, 0644, spk_var_show, spk_var_store);
|
||||
static struct kobj_attribute full_time_attribute =
|
||||
__ATTR(full_time, 0644, spk_var_show, spk_var_store);
|
||||
static struct kobj_attribute flush_time_attribute =
|
||||
__ATTR(flush_time, 0644, spk_var_show, spk_var_store);
|
||||
static struct kobj_attribute jiffy_delta_attribute =
|
||||
__ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
|
||||
static struct kobj_attribute trigger_time_attribute =
|
||||
|
@ -99,6 +101,7 @@ static struct attribute *synth_attrs[] = {
|
|||
&delay_time_attribute.attr,
|
||||
&direct_attribute.attr,
|
||||
&full_time_attribute.attr,
|
||||
&flush_time_attribute.attr,
|
||||
&jiffy_delta_attribute.attr,
|
||||
&trigger_time_attribute.attr,
|
||||
NULL, /* need to NULL terminate the list of attributes */
|
||||
|
@ -118,6 +121,7 @@ static struct spk_synth synth_dectlk = {
|
|||
.trigger = 50,
|
||||
.jiffies = 50,
|
||||
.full = 40000,
|
||||
.flush_time = 4000,
|
||||
.dev_name = SYNTH_DEFAULT_DEV,
|
||||
.startup = SYNTH_START,
|
||||
.checkval = SYNTH_CHECK,
|
||||
|
@ -200,18 +204,23 @@ static void do_catch_up(struct spk_synth *synth)
|
|||
static u_char last = '\0';
|
||||
unsigned long flags;
|
||||
unsigned long jiff_max;
|
||||
unsigned long timeout = msecs_to_jiffies(4000);
|
||||
unsigned long timeout;
|
||||
DEFINE_WAIT(wait);
|
||||
struct var_t *jiffy_delta;
|
||||
struct var_t *delay_time;
|
||||
struct var_t *flush_time;
|
||||
int jiffy_delta_val;
|
||||
int delay_time_val;
|
||||
int timeout_val;
|
||||
|
||||
jiffy_delta = spk_get_var(JIFFY);
|
||||
delay_time = spk_get_var(DELAY);
|
||||
flush_time = spk_get_var(FLUSH);
|
||||
spin_lock_irqsave(&speakup_info.spinlock, flags);
|
||||
jiffy_delta_val = jiffy_delta->u.n.value;
|
||||
timeout_val = flush_time->u.n.value;
|
||||
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
|
||||
timeout = msecs_to_jiffies(timeout_val);
|
||||
jiff_max = jiffies + jiffy_delta_val;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
|
@ -289,7 +298,7 @@ static void synth_flush(struct spk_synth *synth)
|
|||
synth->io_ops->synth_out(synth, ']');
|
||||
in_escape = 0;
|
||||
is_flushing = 1;
|
||||
synth->io_ops->flush_buffer();
|
||||
synth->io_ops->flush_buffer(synth);
|
||||
synth->io_ops->synth_out(synth, SYNTH_CLEAR);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define PROCSPEECH 0x00
|
||||
|
||||
static int synth_probe(struct spk_synth *synth);
|
||||
static void dtlk_release(void);
|
||||
static void dtlk_release(struct spk_synth *synth);
|
||||
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
|
||||
static void do_catch_up(struct spk_synth *synth);
|
||||
static void synth_flush(struct spk_synth *synth);
|
||||
|
@ -365,7 +365,7 @@ static int synth_probe(struct spk_synth *synth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dtlk_release(void)
|
||||
static void dtlk_release(struct spk_synth *synth)
|
||||
{
|
||||
spk_stop_serial_interrupt();
|
||||
if (speakup_info.port_tts)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define SYNTH_CLEAR 0x03
|
||||
|
||||
static int synth_probe(struct spk_synth *synth);
|
||||
static void keynote_release(void);
|
||||
static void keynote_release(struct spk_synth *synth);
|
||||
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
|
||||
static void do_catch_up(struct spk_synth *synth);
|
||||
static void synth_flush(struct spk_synth *synth);
|
||||
|
@ -295,7 +295,7 @@ static int synth_probe(struct spk_synth *synth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void keynote_release(void)
|
||||
static void keynote_release(struct spk_synth *synth)
|
||||
{
|
||||
spk_stop_serial_interrupt();
|
||||
if (synth_port)
|
||||
|
|
|
@ -132,7 +132,7 @@ static void synth_interrogate(struct spk_synth *synth)
|
|||
|
||||
synth->synth_immediate(synth, "\x18\x01?");
|
||||
for (i = 0; i < 50; i++) {
|
||||
buf[i] = synth->io_ops->synth_in();
|
||||
buf[i] = synth->io_ops->synth_in(synth);
|
||||
if (i > 2 && buf[i] == 0x7f)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define CLEAR_SYNTH 0x18
|
||||
|
||||
static int softsynth_probe(struct spk_synth *synth);
|
||||
static void softsynth_release(void);
|
||||
static void softsynth_release(struct spk_synth *synth);
|
||||
static int softsynth_is_alive(struct spk_synth *synth);
|
||||
static unsigned char get_index(struct spk_synth *synth);
|
||||
|
||||
|
@ -402,7 +402,7 @@ static int softsynth_probe(struct spk_synth *synth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void softsynth_release(void)
|
||||
static void softsynth_release(struct spk_synth *synth)
|
||||
{
|
||||
misc_deregister(&synth_device);
|
||||
misc_deregister(&synthu_device);
|
||||
|
|
|
@ -117,8 +117,8 @@ static struct spk_synth synth_spkout = {
|
|||
|
||||
static void synth_flush(struct spk_synth *synth)
|
||||
{
|
||||
synth->io_ops->flush_buffer();
|
||||
synth->io_ops->send_xchar(SYNTH_CLEAR);
|
||||
synth->io_ops->flush_buffer(synth);
|
||||
synth->io_ops->send_xchar(synth, SYNTH_CLEAR);
|
||||
}
|
||||
|
||||
module_param_named(ser, synth_spkout.ser, int, 0444);
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
|
||||
const struct old_serial_port *spk_serial_init(int index);
|
||||
void spk_stop_serial_interrupt(void);
|
||||
void spk_serial_release(void);
|
||||
void spk_ttyio_release(void);
|
||||
void spk_serial_release(struct spk_synth *synth);
|
||||
void spk_ttyio_release(struct spk_synth *synth);
|
||||
void spk_ttyio_register_ldisc(void);
|
||||
void spk_ttyio_unregister_ldisc(void);
|
||||
|
||||
|
|
|
@ -12,14 +12,15 @@ struct spk_ldisc_data {
|
|||
char buf;
|
||||
struct completion completion;
|
||||
bool buf_free;
|
||||
struct spk_synth *synth;
|
||||
};
|
||||
|
||||
static struct spk_synth *spk_ttyio_synth;
|
||||
static struct tty_struct *speakup_tty;
|
||||
/* mutex to protect against speakup_tty disappearing from underneath us while
|
||||
* we are using it. this can happen when the device physically unplugged,
|
||||
* while in use. it also serialises access to speakup_tty.
|
||||
/*
|
||||
* This allows to catch within spk_ttyio_ldisc_open whether it is getting set
|
||||
* on for a speakup-driven device.
|
||||
*/
|
||||
static struct tty_struct *speakup_tty;
|
||||
/* This mutex serializes the use of such global speakup_tty variable */
|
||||
static DEFINE_MUTEX(speakup_tty_mutex);
|
||||
|
||||
static int ser_to_dev(int ser, dev_t *dev_no)
|
||||
|
@ -67,22 +68,20 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
|
|||
|
||||
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&speakup_tty_mutex);
|
||||
kfree(speakup_tty->disc_data);
|
||||
speakup_tty = NULL;
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
kfree(tty->disc_data);
|
||||
}
|
||||
|
||||
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
|
||||
const unsigned char *cp, char *fp, int count)
|
||||
{
|
||||
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
||||
struct spk_synth *synth = ldisc_data->synth;
|
||||
|
||||
if (spk_ttyio_synth->read_buff_add) {
|
||||
if (synth->read_buff_add) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
spk_ttyio_synth->read_buff_add(cp[i]);
|
||||
synth->read_buff_add(cp[i]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -114,11 +113,11 @@ static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
|
|||
|
||||
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
|
||||
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
|
||||
static void spk_ttyio_send_xchar(char ch);
|
||||
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
|
||||
static unsigned char spk_ttyio_in(void);
|
||||
static unsigned char spk_ttyio_in_nowait(void);
|
||||
static void spk_ttyio_flush_buffer(void);
|
||||
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch);
|
||||
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
|
||||
static unsigned char spk_ttyio_in(struct spk_synth *in_synth);
|
||||
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth);
|
||||
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth);
|
||||
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
|
||||
|
||||
struct spk_io_ops spk_ttyio_ops = {
|
||||
|
@ -187,13 +186,17 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
|
|||
mutex_lock(&speakup_tty_mutex);
|
||||
speakup_tty = tty;
|
||||
ret = tty_set_ldisc(tty, N_SPEAKUP);
|
||||
if (ret)
|
||||
speakup_tty = NULL;
|
||||
speakup_tty = NULL;
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
/* Success */
|
||||
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
||||
|
||||
ldisc_data->synth = synth;
|
||||
synth->dev = tty;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
|
||||
|
||||
|
@ -221,29 +224,30 @@ void spk_ttyio_unregister_ldisc(void)
|
|||
|
||||
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
|
||||
{
|
||||
mutex_lock(&speakup_tty_mutex);
|
||||
if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
|
||||
int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
int ret;
|
||||
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
if (ret == 0)
|
||||
/* No room */
|
||||
return 0;
|
||||
if (ret < 0) {
|
||||
pr_warn("%s: I/O error, deactivating speakup\n",
|
||||
in_synth->long_name);
|
||||
/* No synth any more, so nobody will restart TTYs,
|
||||
* and we thus need to do it ourselves. Now that there
|
||||
* is no synth we can let application flood anyway
|
||||
*/
|
||||
in_synth->alive = 0;
|
||||
speakup_start_ttys();
|
||||
return 0;
|
||||
}
|
||||
if (!in_synth->alive || !tty->ops->write)
|
||||
return 0;
|
||||
|
||||
ret = tty->ops->write(tty, &ch, 1);
|
||||
|
||||
if (ret == 0)
|
||||
/* No room */
|
||||
return 0;
|
||||
|
||||
if (ret > 0)
|
||||
/* Success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
pr_warn("%s: I/O error, deactivating speakup\n",
|
||||
in_synth->long_name);
|
||||
/* No synth any more, so nobody will restart TTYs,
|
||||
* and we thus need to do it ourselves. Now that there
|
||||
* is no synth we can let application flood anyway
|
||||
*/
|
||||
in_synth->alive = 0;
|
||||
speakup_start_ttys();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -264,47 +268,20 @@ static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_tty(struct tty_struct *tty)
|
||||
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch)
|
||||
{
|
||||
if (!tty) {
|
||||
pr_warn("%s: I/O error, deactivating speakup\n",
|
||||
spk_ttyio_synth->long_name);
|
||||
/* No synth any more, so nobody will restart TTYs, and we thus
|
||||
* need to do it ourselves. Now that there is no synth we can
|
||||
* let application flood anyway
|
||||
*/
|
||||
spk_ttyio_synth->alive = 0;
|
||||
speakup_start_ttys();
|
||||
return 1;
|
||||
}
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
|
||||
return 0;
|
||||
if (tty->ops->send_xchar)
|
||||
tty->ops->send_xchar(tty, ch);
|
||||
}
|
||||
|
||||
static void spk_ttyio_send_xchar(char ch)
|
||||
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
|
||||
{
|
||||
mutex_lock(&speakup_tty_mutex);
|
||||
if (check_tty(speakup_tty)) {
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
return;
|
||||
}
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
|
||||
if (speakup_tty->ops->send_xchar)
|
||||
speakup_tty->ops->send_xchar(speakup_tty, ch);
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
}
|
||||
|
||||
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
|
||||
{
|
||||
mutex_lock(&speakup_tty_mutex);
|
||||
if (check_tty(speakup_tty)) {
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (speakup_tty->ops->tiocmset)
|
||||
speakup_tty->ops->tiocmset(speakup_tty, set, clear);
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
if (tty->ops->tiocmset)
|
||||
tty->ops->tiocmset(tty, set, clear);
|
||||
}
|
||||
|
||||
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
|
||||
|
@ -312,9 +289,10 @@ static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static unsigned char ttyio_in(int timeout)
|
||||
static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout)
|
||||
{
|
||||
struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
||||
char rv;
|
||||
|
||||
if (!timeout) {
|
||||
|
@ -334,35 +312,29 @@ static unsigned char ttyio_in(int timeout)
|
|||
mb();
|
||||
ldisc_data->buf_free = true;
|
||||
/* Let TTY push more characters */
|
||||
tty_schedule_flip(speakup_tty->port);
|
||||
tty_schedule_flip(tty->port);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static unsigned char spk_ttyio_in(void)
|
||||
static unsigned char spk_ttyio_in(struct spk_synth *in_synth)
|
||||
{
|
||||
return ttyio_in(SPK_SYNTH_TIMEOUT);
|
||||
return ttyio_in(in_synth, SPK_SYNTH_TIMEOUT);
|
||||
}
|
||||
|
||||
static unsigned char spk_ttyio_in_nowait(void)
|
||||
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth)
|
||||
{
|
||||
u8 rv = ttyio_in(0);
|
||||
u8 rv = ttyio_in(in_synth, 0);
|
||||
|
||||
return (rv == 0xff) ? 0 : rv;
|
||||
}
|
||||
|
||||
static void spk_ttyio_flush_buffer(void)
|
||||
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth)
|
||||
{
|
||||
mutex_lock(&speakup_tty_mutex);
|
||||
if (check_tty(speakup_tty)) {
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
return;
|
||||
}
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
|
||||
if (speakup_tty->ops->flush_buffer)
|
||||
speakup_tty->ops->flush_buffer(speakup_tty);
|
||||
|
||||
mutex_unlock(&speakup_tty_mutex);
|
||||
if (tty->ops->flush_buffer)
|
||||
tty->ops->flush_buffer(tty);
|
||||
}
|
||||
|
||||
int spk_ttyio_synth_probe(struct spk_synth *synth)
|
||||
|
@ -373,37 +345,38 @@ int spk_ttyio_synth_probe(struct spk_synth *synth)
|
|||
return rv;
|
||||
|
||||
synth->alive = 1;
|
||||
spk_ttyio_synth = synth;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
|
||||
|
||||
void spk_ttyio_release(void)
|
||||
void spk_ttyio_release(struct spk_synth *in_synth)
|
||||
{
|
||||
if (!speakup_tty)
|
||||
return;
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
|
||||
tty_lock(speakup_tty);
|
||||
tty_lock(tty);
|
||||
|
||||
if (speakup_tty->ops->close)
|
||||
speakup_tty->ops->close(speakup_tty, NULL);
|
||||
if (tty->ops->close)
|
||||
tty->ops->close(tty, NULL);
|
||||
|
||||
tty_ldisc_flush(speakup_tty);
|
||||
tty_unlock(speakup_tty);
|
||||
tty_kclose(speakup_tty);
|
||||
tty_ldisc_flush(tty);
|
||||
tty_unlock(tty);
|
||||
tty_kclose(tty);
|
||||
|
||||
in_synth->dev = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spk_ttyio_release);
|
||||
|
||||
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
|
||||
const char *spk_ttyio_synth_immediate(struct spk_synth *in_synth, const char *buff)
|
||||
{
|
||||
struct tty_struct *tty = in_synth->dev;
|
||||
u_char ch;
|
||||
|
||||
while ((ch = *buff)) {
|
||||
if (ch == '\n')
|
||||
ch = synth->procspeech;
|
||||
if (tty_write_room(speakup_tty) < 1 ||
|
||||
!synth->io_ops->synth_out(synth, ch))
|
||||
ch = in_synth->procspeech;
|
||||
if (tty_write_room(tty) < 1 ||
|
||||
!in_synth->io_ops->synth_out(in_synth, ch))
|
||||
return buff;
|
||||
buff++;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ enum var_id_t {
|
|||
ATTRIB_BLEEP, BLEEPS,
|
||||
RATE, PITCH, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG,
|
||||
DIRECT, PAUSE,
|
||||
CAPS_START, CAPS_STOP, CHARTAB, INFLECTION,
|
||||
CAPS_START, CAPS_STOP, CHARTAB, INFLECTION, FLUSH,
|
||||
MAXVARS
|
||||
};
|
||||
|
||||
|
@ -157,11 +157,11 @@ struct spk_synth;
|
|||
struct spk_io_ops {
|
||||
int (*synth_out)(struct spk_synth *synth, const char ch);
|
||||
int (*synth_out_unicode)(struct spk_synth *synth, u16 ch);
|
||||
void (*send_xchar)(char ch);
|
||||
void (*tiocmset)(unsigned int set, unsigned int clear);
|
||||
unsigned char (*synth_in)(void);
|
||||
unsigned char (*synth_in_nowait)(void);
|
||||
void (*flush_buffer)(void);
|
||||
void (*send_xchar)(struct spk_synth *synth, char ch);
|
||||
void (*tiocmset)(struct spk_synth *synth, unsigned int set, unsigned int clear);
|
||||
unsigned char (*synth_in)(struct spk_synth *synth);
|
||||
unsigned char (*synth_in_nowait)(struct spk_synth *synth);
|
||||
void (*flush_buffer)(struct spk_synth *synth);
|
||||
int (*wait_for_xmitr)(struct spk_synth *synth);
|
||||
};
|
||||
|
||||
|
@ -178,6 +178,7 @@ struct spk_synth {
|
|||
int trigger;
|
||||
int jiffies;
|
||||
int full;
|
||||
int flush_time;
|
||||
int ser;
|
||||
char *dev_name;
|
||||
short flags;
|
||||
|
@ -188,7 +189,7 @@ struct spk_synth {
|
|||
int *default_vol;
|
||||
struct spk_io_ops *io_ops;
|
||||
int (*probe)(struct spk_synth *synth);
|
||||
void (*release)(void);
|
||||
void (*release)(struct spk_synth *synth);
|
||||
const char *(*synth_immediate)(struct spk_synth *synth,
|
||||
const char *buff);
|
||||
void (*catch_up)(struct spk_synth *synth);
|
||||
|
@ -200,6 +201,8 @@ struct spk_synth {
|
|||
struct synth_indexing indexing;
|
||||
int alive;
|
||||
struct attribute_group attributes;
|
||||
|
||||
void *dev;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -137,14 +137,14 @@ EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode);
|
|||
|
||||
void spk_synth_flush(struct spk_synth *synth)
|
||||
{
|
||||
synth->io_ops->flush_buffer();
|
||||
synth->io_ops->flush_buffer(synth);
|
||||
synth->io_ops->synth_out(synth, synth->clear);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spk_synth_flush);
|
||||
|
||||
unsigned char spk_synth_get_index(struct spk_synth *synth)
|
||||
{
|
||||
return synth->io_ops->synth_in_nowait();
|
||||
return synth->io_ops->synth_in_nowait(synth);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spk_synth_get_index);
|
||||
|
||||
|
@ -348,6 +348,7 @@ struct var_t synth_time_vars[] = {
|
|||
{ TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
|
||||
{ JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
|
||||
{ FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
|
||||
{ FLUSH, .u.n = {NULL, 4000, 100, 4000, 0, 0, NULL } },
|
||||
V_LAST_VAR
|
||||
};
|
||||
|
||||
|
@ -408,6 +409,8 @@ static int do_synth_init(struct spk_synth *in_synth)
|
|||
synth_time_vars[2].u.n.default_val = synth->jiffies;
|
||||
synth_time_vars[3].u.n.value =
|
||||
synth_time_vars[3].u.n.default_val = synth->full;
|
||||
synth_time_vars[4].u.n.value =
|
||||
synth_time_vars[4].u.n.default_val = synth->flush_time;
|
||||
synth_printf("%s", synth->init);
|
||||
for (var = synth->vars;
|
||||
(var->var_id >= 0) && (var->var_id < MAXVARS); var++)
|
||||
|
@ -440,7 +443,7 @@ void synth_release(void)
|
|||
sysfs_remove_group(speakup_kobj, &synth->attributes);
|
||||
for (var = synth->vars; var->var_id != MAXVARS; var++)
|
||||
speakup_unregister_var(var->var_id);
|
||||
synth->release();
|
||||
synth->release(synth);
|
||||
synth = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ static struct st_var_header var_headers[] = {
|
|||
{ "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
|
||||
{ "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
|
||||
{ "full_time", FULL, VAR_TIME, NULL, NULL },
|
||||
{ "flush_time", FLUSH, VAR_TIME, NULL, NULL },
|
||||
{ "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },
|
||||
{ "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },
|
||||
{ "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },
|
||||
|
|
|
@ -15,11 +15,11 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
|
|||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = sdw_write(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
|
||||
ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sdw_write(slave, reg, val & 0xff);
|
||||
return sdw_write_no_pm(slave, reg, val & 0xff);
|
||||
}
|
||||
|
||||
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
|
||||
|
@ -29,11 +29,11 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
|
|||
int read0;
|
||||
int read1;
|
||||
|
||||
read0 = sdw_read(slave, reg);
|
||||
read0 = sdw_read_no_pm(slave, reg);
|
||||
if (read0 < 0)
|
||||
return read0;
|
||||
|
||||
read1 = sdw_read(slave, SDW_SDCA_MBQ_CTL(reg));
|
||||
read1 = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg));
|
||||
if (read1 < 0)
|
||||
return read1;
|
||||
|
||||
|
@ -98,4 +98,4 @@ struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
|
|||
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
|
||||
|
||||
MODULE_DESCRIPTION("Regmap SoundWire MBQ Module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -13,7 +13,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val)
|
|||
struct device *dev = context;
|
||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
|
||||
return sdw_write(slave, reg, val);
|
||||
return sdw_write_no_pm(slave, reg, val);
|
||||
}
|
||||
|
||||
static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
|
||||
|
@ -22,7 +22,7 @@ static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
|
|||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
||||
int read;
|
||||
|
||||
read = sdw_read(slave, reg);
|
||||
read = sdw_read_no_pm(slave, reg);
|
||||
if (read < 0)
|
||||
return read;
|
||||
|
||||
|
|
|
@ -14,3 +14,10 @@ config FSL_MC_BUS
|
|||
architecture. The fsl-mc bus driver handles discovery of
|
||||
DPAA2 objects (which are represented as Linux devices) and
|
||||
binding objects to drivers.
|
||||
|
||||
config FSL_MC_UAPI_SUPPORT
|
||||
bool "Management Complex (MC) userspace support"
|
||||
depends on FSL_MC_BUS
|
||||
help
|
||||
Provides userspace support for interrogating, creating, destroying or
|
||||
configuring DPAA2 objects exported by the Management Complex.
|
||||
|
|
|
@ -16,3 +16,6 @@ mc-bus-driver-objs := fsl-mc-bus.o \
|
|||
fsl-mc-allocator.o \
|
||||
fsl-mc-msi.o \
|
||||
dpmcp.o
|
||||
|
||||
# MC userspace support
|
||||
obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
|
||||
|
|
|
@ -237,8 +237,8 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
|
|||
* populated before they can get allocation requests from probe callbacks
|
||||
* of the device drivers for the non-allocatable devices.
|
||||
*/
|
||||
static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||||
bool alloc_interrupts)
|
||||
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||||
bool alloc_interrupts)
|
||||
{
|
||||
int num_child_objects;
|
||||
int dprc_get_obj_failures;
|
||||
|
@ -458,8 +458,9 @@ out:
|
|||
/*
|
||||
* Disable and clear interrupt for a given DPRC object
|
||||
*/
|
||||
static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
|
||||
int disable_dprc_irq(struct fsl_mc_device *mc_dev)
|
||||
{
|
||||
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
|
||||
int error;
|
||||
struct fsl_mc_io *mc_io = mc_dev->mc_io;
|
||||
|
||||
|
@ -496,9 +497,18 @@ static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
|
|||
return error;
|
||||
}
|
||||
|
||||
mc_bus->irq_enabled = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_dprc_irq_state(struct fsl_mc_device *mc_dev)
|
||||
{
|
||||
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
|
||||
|
||||
return mc_bus->irq_enabled;
|
||||
}
|
||||
|
||||
static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
|
||||
{
|
||||
int error;
|
||||
|
@ -525,8 +535,9 @@ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
|
||||
int enable_dprc_irq(struct fsl_mc_device *mc_dev)
|
||||
{
|
||||
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
|
||||
int error;
|
||||
|
||||
/*
|
||||
|
@ -554,6 +565,8 @@ static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
|
|||
return error;
|
||||
}
|
||||
|
||||
mc_bus->irq_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -603,6 +616,7 @@ int dprc_setup(struct fsl_mc_device *mc_dev)
|
|||
struct irq_domain *mc_msi_domain;
|
||||
bool mc_io_created = false;
|
||||
bool msi_domain_set = false;
|
||||
bool uapi_created = false;
|
||||
u16 major_ver, minor_ver;
|
||||
size_t region_size;
|
||||
int error;
|
||||
|
@ -635,6 +649,11 @@ int dprc_setup(struct fsl_mc_device *mc_dev)
|
|||
return error;
|
||||
|
||||
mc_io_created = true;
|
||||
} else {
|
||||
error = fsl_mc_uapi_create_device_file(mc_bus);
|
||||
if (error < 0)
|
||||
return -EPROBE_DEFER;
|
||||
uapi_created = true;
|
||||
}
|
||||
|
||||
mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev);
|
||||
|
@ -692,6 +711,9 @@ error_cleanup_msi_domain:
|
|||
mc_dev->mc_io = NULL;
|
||||
}
|
||||
|
||||
if (uapi_created)
|
||||
fsl_mc_uapi_remove_device_file(mc_bus);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dprc_setup);
|
||||
|
@ -763,6 +785,7 @@ static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
|
|||
|
||||
int dprc_cleanup(struct fsl_mc_device *mc_dev)
|
||||
{
|
||||
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
|
||||
int error;
|
||||
|
||||
/* this function should be called only for DPRCs, it
|
||||
|
@ -793,6 +816,8 @@ int dprc_cleanup(struct fsl_mc_device *mc_dev)
|
|||
if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
|
||||
fsl_destroy_mc_io(mc_dev->mc_io);
|
||||
mc_dev->mc_io = NULL;
|
||||
} else {
|
||||
fsl_mc_uapi_remove_device_file(mc_bus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -41,7 +41,7 @@ struct fsl_mc {
|
|||
struct fsl_mc_device *root_mc_bus_dev;
|
||||
u8 num_translation_ranges;
|
||||
struct fsl_mc_addr_translation_range *translation_ranges;
|
||||
void *fsl_mc_regs;
|
||||
void __iomem *fsl_mc_regs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -208,12 +208,108 @@ static struct attribute *fsl_mc_dev_attrs[] = {
|
|||
|
||||
ATTRIBUTE_GROUPS(fsl_mc_dev);
|
||||
|
||||
static int scan_fsl_mc_bus(struct device *dev, void *data)
|
||||
{
|
||||
struct fsl_mc_device *root_mc_dev;
|
||||
struct fsl_mc_bus *root_mc_bus;
|
||||
|
||||
if (!fsl_mc_is_root_dprc(dev))
|
||||
goto exit;
|
||||
|
||||
root_mc_dev = to_fsl_mc_device(dev);
|
||||
root_mc_bus = to_fsl_mc_bus(root_mc_dev);
|
||||
mutex_lock(&root_mc_bus->scan_mutex);
|
||||
dprc_scan_objects(root_mc_dev, NULL);
|
||||
mutex_unlock(&root_mc_bus->scan_mutex);
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rescan_store(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 0, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus);
|
||||
|
||||
return count;
|
||||
}
|
||||
static BUS_ATTR_WO(rescan);
|
||||
|
||||
static int fsl_mc_bus_set_autorescan(struct device *dev, void *data)
|
||||
{
|
||||
struct fsl_mc_device *root_mc_dev;
|
||||
unsigned long val;
|
||||
char *buf = data;
|
||||
|
||||
if (!fsl_mc_is_root_dprc(dev))
|
||||
goto exit;
|
||||
|
||||
root_mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
if (kstrtoul(buf, 0, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
enable_dprc_irq(root_mc_dev);
|
||||
else
|
||||
disable_dprc_irq(root_mc_dev);
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mc_bus_get_autorescan(struct device *dev, void *data)
|
||||
{
|
||||
struct fsl_mc_device *root_mc_dev;
|
||||
char *buf = data;
|
||||
|
||||
if (!fsl_mc_is_root_dprc(dev))
|
||||
goto exit;
|
||||
|
||||
root_mc_dev = to_fsl_mc_device(dev);
|
||||
|
||||
sprintf(buf, "%d\n", get_dprc_irq_state(root_mc_dev));
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t autorescan_store(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_set_autorescan);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t autorescan_show(struct bus_type *bus, char *buf)
|
||||
{
|
||||
bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_get_autorescan);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static BUS_ATTR_RW(autorescan);
|
||||
|
||||
static struct attribute *fsl_mc_bus_attrs[] = {
|
||||
&bus_attr_rescan.attr,
|
||||
&bus_attr_autorescan.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(fsl_mc_bus);
|
||||
|
||||
struct bus_type fsl_mc_bus_type = {
|
||||
.name = "fsl-mc",
|
||||
.match = fsl_mc_bus_match,
|
||||
.uevent = fsl_mc_bus_uevent,
|
||||
.dma_configure = fsl_mc_dma_configure,
|
||||
.dev_groups = fsl_mc_dev_groups,
|
||||
.bus_groups = fsl_mc_bus_groups,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
|
||||
|
||||
|
@ -292,6 +388,11 @@ struct device_type fsl_mc_bus_dpdmai_type = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmai_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpdbg_type = {
|
||||
.name = "fsl_mc_bus_dpdbg"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdbg_type);
|
||||
|
||||
static struct device_type *fsl_mc_get_device_type(const char *type)
|
||||
{
|
||||
static const struct {
|
||||
|
@ -313,6 +414,7 @@ static struct device_type *fsl_mc_get_device_type(const char *type)
|
|||
{ &fsl_mc_bus_dpaiop_type, "dpaiop" },
|
||||
{ &fsl_mc_bus_dpci_type, "dpci" },
|
||||
{ &fsl_mc_bus_dpdmai_type, "dpdmai" },
|
||||
{ &fsl_mc_bus_dpdbg_type, "dpdbg" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int i;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <linux/fsl/mc.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
/*
|
||||
* Data Path Management Complex (DPMNG) General API
|
||||
|
@ -542,6 +544,22 @@ struct fsl_mc_resource_pool {
|
|||
struct fsl_mc_bus *mc_bus;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fsl_mc_uapi - information associated with a device file
|
||||
* @misc: struct miscdevice linked to the root dprc
|
||||
* @device: newly created device in /dev
|
||||
* @mutex: mutex lock to serialize the open/release operations
|
||||
* @local_instance_in_use: local MC I/O instance in use or not
|
||||
* @static_mc_io: pointer to the static MC I/O object
|
||||
*/
|
||||
struct fsl_mc_uapi {
|
||||
struct miscdevice misc;
|
||||
struct device *device;
|
||||
struct mutex mutex; /* serialize open/release operations */
|
||||
u32 local_instance_in_use;
|
||||
struct fsl_mc_io *static_mc_io;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
|
||||
* @mc_dev: fsl-mc device for the bus device itself.
|
||||
|
@ -551,6 +569,7 @@ struct fsl_mc_resource_pool {
|
|||
* @irq_resources: Pointer to array of IRQ objects for the IRQ pool
|
||||
* @scan_mutex: Serializes bus scanning
|
||||
* @dprc_attr: DPRC attributes
|
||||
* @uapi_misc: struct that abstracts the interaction with userspace
|
||||
*/
|
||||
struct fsl_mc_bus {
|
||||
struct fsl_mc_device mc_dev;
|
||||
|
@ -558,6 +577,8 @@ struct fsl_mc_bus {
|
|||
struct fsl_mc_device_irq *irq_resources;
|
||||
struct mutex scan_mutex; /* serializes bus scanning */
|
||||
struct dprc_attributes dprc_attr;
|
||||
struct fsl_mc_uapi uapi_misc;
|
||||
int irq_enabled;
|
||||
};
|
||||
|
||||
#define to_fsl_mc_bus(_mc_dev) \
|
||||
|
@ -574,6 +595,9 @@ int __init dprc_driver_init(void);
|
|||
|
||||
void dprc_driver_exit(void);
|
||||
|
||||
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
|
||||
bool alloc_interrupts);
|
||||
|
||||
int __init fsl_mc_allocator_driver_init(void);
|
||||
|
||||
void fsl_mc_allocator_driver_exit(void);
|
||||
|
@ -612,4 +636,29 @@ void fsl_mc_get_root_dprc(struct device *dev,
|
|||
struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
|
||||
struct fsl_mc_device *mc_bus_dev);
|
||||
|
||||
u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd);
|
||||
|
||||
#ifdef CONFIG_FSL_MC_UAPI_SUPPORT
|
||||
|
||||
int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus);
|
||||
|
||||
void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus);
|
||||
|
||||
#else
|
||||
|
||||
static inline int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int disable_dprc_irq(struct fsl_mc_device *mc_dev);
|
||||
int enable_dprc_irq(struct fsl_mc_device *mc_dev);
|
||||
int get_dprc_irq_state(struct fsl_mc_device *mc_dev);
|
||||
|
||||
#endif /* _FSL_MC_PRIVATE_H_ */
|
||||
|
|
|
@ -0,0 +1,597 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Management Complex (MC) userspace support
|
||||
*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#include "fsl-mc-private.h"
|
||||
|
||||
struct uapi_priv_data {
|
||||
struct fsl_mc_uapi *uapi;
|
||||
struct fsl_mc_io *mc_io;
|
||||
};
|
||||
|
||||
struct fsl_mc_cmd_desc {
|
||||
u16 cmdid_value;
|
||||
u16 cmdid_mask;
|
||||
int size;
|
||||
bool token;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define FSL_MC_CHECK_MODULE_ID BIT(0)
|
||||
#define FSL_MC_CAP_NET_ADMIN_NEEDED BIT(1)
|
||||
|
||||
enum fsl_mc_cmd_index {
|
||||
DPDBG_DUMP = 0,
|
||||
DPDBG_SET,
|
||||
DPRC_GET_CONTAINER_ID,
|
||||
DPRC_CREATE_CONT,
|
||||
DPRC_DESTROY_CONT,
|
||||
DPRC_ASSIGN,
|
||||
DPRC_UNASSIGN,
|
||||
DPRC_GET_OBJ_COUNT,
|
||||
DPRC_GET_OBJ,
|
||||
DPRC_GET_RES_COUNT,
|
||||
DPRC_GET_RES_IDS,
|
||||
DPRC_SET_OBJ_LABEL,
|
||||
DPRC_SET_LOCKED,
|
||||
DPRC_CONNECT,
|
||||
DPRC_DISCONNECT,
|
||||
DPRC_GET_POOL,
|
||||
DPRC_GET_POOL_COUNT,
|
||||
DPRC_GET_CONNECTION,
|
||||
DPCI_GET_LINK_STATE,
|
||||
DPCI_GET_PEER_ATTR,
|
||||
DPAIOP_GET_SL_VERSION,
|
||||
DPAIOP_GET_STATE,
|
||||
DPMNG_GET_VERSION,
|
||||
DPSECI_GET_TX_QUEUE,
|
||||
DPMAC_GET_COUNTER,
|
||||
DPMAC_GET_MAC_ADDR,
|
||||
DPNI_SET_PRIM_MAC,
|
||||
DPNI_GET_PRIM_MAC,
|
||||
DPNI_GET_STATISTICS,
|
||||
DPNI_GET_LINK_STATE,
|
||||
DPNI_GET_MAX_FRAME_LENGTH,
|
||||
DPSW_GET_TAILDROP,
|
||||
DPSW_SET_TAILDROP,
|
||||
DPSW_IF_GET_COUNTER,
|
||||
DPSW_IF_GET_MAX_FRAME_LENGTH,
|
||||
DPDMUX_GET_COUNTER,
|
||||
DPDMUX_IF_GET_MAX_FRAME_LENGTH,
|
||||
GET_ATTR,
|
||||
GET_IRQ_MASK,
|
||||
GET_IRQ_STATUS,
|
||||
CLOSE,
|
||||
OPEN,
|
||||
GET_API_VERSION,
|
||||
DESTROY,
|
||||
CREATE,
|
||||
};
|
||||
|
||||
static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
|
||||
[DPDBG_DUMP] = {
|
||||
.cmdid_value = 0x1300,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 28,
|
||||
},
|
||||
[DPDBG_SET] = {
|
||||
.cmdid_value = 0x1400,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 28,
|
||||
},
|
||||
[DPRC_GET_CONTAINER_ID] = {
|
||||
.cmdid_value = 0x8300,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = false,
|
||||
.size = 8,
|
||||
},
|
||||
[DPRC_CREATE_CONT] = {
|
||||
.cmdid_value = 0x1510,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 40,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_DESTROY_CONT] = {
|
||||
.cmdid_value = 0x1520,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 12,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_ASSIGN] = {
|
||||
.cmdid_value = 0x1570,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 40,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_UNASSIGN] = {
|
||||
.cmdid_value = 0x1580,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 40,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_GET_OBJ_COUNT] = {
|
||||
.cmdid_value = 0x1590,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 16,
|
||||
},
|
||||
[DPRC_GET_OBJ] = {
|
||||
.cmdid_value = 0x15A0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 12,
|
||||
},
|
||||
[DPRC_GET_RES_COUNT] = {
|
||||
.cmdid_value = 0x15B0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 32,
|
||||
},
|
||||
[DPRC_GET_RES_IDS] = {
|
||||
.cmdid_value = 0x15C0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 40,
|
||||
},
|
||||
[DPRC_SET_OBJ_LABEL] = {
|
||||
.cmdid_value = 0x1610,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 48,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_SET_LOCKED] = {
|
||||
.cmdid_value = 0x16B0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 16,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_CONNECT] = {
|
||||
.cmdid_value = 0x1670,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 56,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_DISCONNECT] = {
|
||||
.cmdid_value = 0x1680,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 32,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPRC_GET_POOL] = {
|
||||
.cmdid_value = 0x1690,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 12,
|
||||
},
|
||||
[DPRC_GET_POOL_COUNT] = {
|
||||
.cmdid_value = 0x16A0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPRC_GET_CONNECTION] = {
|
||||
.cmdid_value = 0x16C0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 32,
|
||||
},
|
||||
|
||||
[DPCI_GET_LINK_STATE] = {
|
||||
.cmdid_value = 0x0E10,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPCI_GET_PEER_ATTR] = {
|
||||
.cmdid_value = 0x0E20,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPAIOP_GET_SL_VERSION] = {
|
||||
.cmdid_value = 0x2820,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPAIOP_GET_STATE] = {
|
||||
.cmdid_value = 0x2830,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPMNG_GET_VERSION] = {
|
||||
.cmdid_value = 0x8310,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = false,
|
||||
.size = 8,
|
||||
},
|
||||
[DPSECI_GET_TX_QUEUE] = {
|
||||
.cmdid_value = 0x1970,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 14,
|
||||
},
|
||||
[DPMAC_GET_COUNTER] = {
|
||||
.cmdid_value = 0x0c40,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 9,
|
||||
},
|
||||
[DPMAC_GET_MAC_ADDR] = {
|
||||
.cmdid_value = 0x0c50,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPNI_SET_PRIM_MAC] = {
|
||||
.cmdid_value = 0x2240,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 16,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPNI_GET_PRIM_MAC] = {
|
||||
.cmdid_value = 0x2250,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPNI_GET_STATISTICS] = {
|
||||
.cmdid_value = 0x25D0,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 10,
|
||||
},
|
||||
[DPNI_GET_LINK_STATE] = {
|
||||
.cmdid_value = 0x2150,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPNI_GET_MAX_FRAME_LENGTH] = {
|
||||
.cmdid_value = 0x2170,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[DPSW_GET_TAILDROP] = {
|
||||
.cmdid_value = 0x0A80,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 14,
|
||||
},
|
||||
[DPSW_SET_TAILDROP] = {
|
||||
.cmdid_value = 0x0A90,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 24,
|
||||
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[DPSW_IF_GET_COUNTER] = {
|
||||
.cmdid_value = 0x0340,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 11,
|
||||
},
|
||||
[DPSW_IF_GET_MAX_FRAME_LENGTH] = {
|
||||
.cmdid_value = 0x0450,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 10,
|
||||
},
|
||||
[DPDMUX_GET_COUNTER] = {
|
||||
.cmdid_value = 0x0b20,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 11,
|
||||
},
|
||||
[DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
|
||||
.cmdid_value = 0x0a20,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 10,
|
||||
},
|
||||
[GET_ATTR] = {
|
||||
.cmdid_value = 0x0040,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
[GET_IRQ_MASK] = {
|
||||
.cmdid_value = 0x0150,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 13,
|
||||
},
|
||||
[GET_IRQ_STATUS] = {
|
||||
.cmdid_value = 0x0160,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 13,
|
||||
},
|
||||
[CLOSE] = {
|
||||
.cmdid_value = 0x8000,
|
||||
.cmdid_mask = 0xFFF0,
|
||||
.token = true,
|
||||
.size = 8,
|
||||
},
|
||||
|
||||
/* Common commands amongst all types of objects. Must be checked last. */
|
||||
[OPEN] = {
|
||||
.cmdid_value = 0x8000,
|
||||
.cmdid_mask = 0xFC00,
|
||||
.token = false,
|
||||
.size = 12,
|
||||
.flags = FSL_MC_CHECK_MODULE_ID,
|
||||
},
|
||||
[GET_API_VERSION] = {
|
||||
.cmdid_value = 0xA000,
|
||||
.cmdid_mask = 0xFC00,
|
||||
.token = false,
|
||||
.size = 8,
|
||||
.flags = FSL_MC_CHECK_MODULE_ID,
|
||||
},
|
||||
[DESTROY] = {
|
||||
.cmdid_value = 0x9800,
|
||||
.cmdid_mask = 0xFC00,
|
||||
.token = true,
|
||||
.size = 12,
|
||||
.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
[CREATE] = {
|
||||
.cmdid_value = 0x9000,
|
||||
.cmdid_mask = 0xFC00,
|
||||
.token = true,
|
||||
.size = 64,
|
||||
.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
|
||||
},
|
||||
};
|
||||
|
||||
#define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)
|
||||
|
||||
#define FSL_MC_MAX_MODULE_ID 0x10
|
||||
|
||||
static int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
|
||||
struct fsl_mc_command *mc_cmd)
|
||||
{
|
||||
struct fsl_mc_cmd_desc *desc = NULL;
|
||||
int mc_cmd_max_size, i;
|
||||
bool token_provided;
|
||||
u16 cmdid, module_id;
|
||||
char *mc_cmd_end;
|
||||
char sum = 0;
|
||||
|
||||
/* Check if this is an accepted MC command */
|
||||
cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
|
||||
for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
|
||||
desc = &fsl_mc_accepted_cmds[i];
|
||||
if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
|
||||
break;
|
||||
}
|
||||
if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
|
||||
dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* Check if the size of the command is honored. Anything beyond the
|
||||
* last valid byte of the command should be zeroed.
|
||||
*/
|
||||
mc_cmd_max_size = sizeof(*mc_cmd);
|
||||
mc_cmd_end = ((char *)mc_cmd) + desc->size;
|
||||
for (i = desc->size; i < mc_cmd_max_size; i++)
|
||||
sum |= *mc_cmd_end++;
|
||||
if (sum) {
|
||||
dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
|
||||
cmdid, desc->size);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* Some MC commands request a token to be passed so that object
|
||||
* identification is possible. Check if the token passed in the command
|
||||
* is as expected.
|
||||
*/
|
||||
token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
|
||||
if (token_provided != desc->token) {
|
||||
dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
|
||||
cmdid, mc_cmd_hdr_read_token(mc_cmd));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* If needed, check if the module ID passed is valid */
|
||||
if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
|
||||
/* The module ID is represented by bits [4:9] from the cmdid */
|
||||
module_id = (cmdid & GENMASK(9, 4)) >> 4;
|
||||
if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
|
||||
dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
|
||||
cmdid, module_id);
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
/* Some commands alter how hardware resources are managed. For these
|
||||
* commands, check for CAP_NET_ADMIN.
|
||||
*/
|
||||
if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
|
||||
cmdid);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
|
||||
struct fsl_mc_io *mc_io)
|
||||
{
|
||||
struct fsl_mc_command mc_cmd;
|
||||
int error;
|
||||
|
||||
error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
|
||||
if (error)
|
||||
return -EFAULT;
|
||||
|
||||
error = fsl_mc_command_check(mc_dev, &mc_cmd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = mc_send_command(mc_io, &mc_cmd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
|
||||
if (error)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
|
||||
{
|
||||
struct fsl_mc_device *root_mc_device;
|
||||
struct uapi_priv_data *priv_data;
|
||||
struct fsl_mc_io *dynamic_mc_io;
|
||||
struct fsl_mc_uapi *mc_uapi;
|
||||
struct fsl_mc_bus *mc_bus;
|
||||
int error;
|
||||
|
||||
priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
|
||||
if (!priv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
|
||||
mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
|
||||
root_mc_device = &mc_bus->mc_dev;
|
||||
|
||||
mutex_lock(&mc_uapi->mutex);
|
||||
|
||||
if (!mc_uapi->local_instance_in_use) {
|
||||
priv_data->mc_io = mc_uapi->static_mc_io;
|
||||
mc_uapi->local_instance_in_use = 1;
|
||||
} else {
|
||||
error = fsl_mc_portal_allocate(root_mc_device, 0,
|
||||
&dynamic_mc_io);
|
||||
if (error) {
|
||||
dev_dbg(&root_mc_device->dev,
|
||||
"Could not allocate MC portal\n");
|
||||
goto error_portal_allocate;
|
||||
}
|
||||
|
||||
priv_data->mc_io = dynamic_mc_io;
|
||||
}
|
||||
priv_data->uapi = mc_uapi;
|
||||
filep->private_data = priv_data;
|
||||
|
||||
mutex_unlock(&mc_uapi->mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
error_portal_allocate:
|
||||
mutex_unlock(&mc_uapi->mutex);
|
||||
kfree(priv_data);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
|
||||
{
|
||||
struct uapi_priv_data *priv_data;
|
||||
struct fsl_mc_uapi *mc_uapi;
|
||||
struct fsl_mc_io *mc_io;
|
||||
|
||||
priv_data = filep->private_data;
|
||||
mc_uapi = priv_data->uapi;
|
||||
mc_io = priv_data->mc_io;
|
||||
|
||||
mutex_lock(&mc_uapi->mutex);
|
||||
|
||||
if (mc_io == mc_uapi->static_mc_io)
|
||||
mc_uapi->local_instance_in_use = 0;
|
||||
else
|
||||
fsl_mc_portal_free(mc_io);
|
||||
|
||||
kfree(filep->private_data);
|
||||
filep->private_data = NULL;
|
||||
|
||||
mutex_unlock(&mc_uapi->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long fsl_mc_uapi_dev_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct uapi_priv_data *priv_data = file->private_data;
|
||||
struct fsl_mc_device *root_mc_device;
|
||||
struct fsl_mc_bus *mc_bus;
|
||||
int error;
|
||||
|
||||
mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
|
||||
root_mc_device = &mc_bus->mc_dev;
|
||||
|
||||
switch (cmd) {
|
||||
case FSL_MC_SEND_MC_COMMAND:
|
||||
error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static const struct file_operations fsl_mc_uapi_dev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fsl_mc_uapi_dev_open,
|
||||
.release = fsl_mc_uapi_dev_release,
|
||||
.unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
|
||||
};
|
||||
|
||||
int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
|
||||
{
|
||||
struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
|
||||
struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
|
||||
int error;
|
||||
|
||||
mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
mc_uapi->misc.name = dev_name(&mc_dev->dev);
|
||||
mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
|
||||
|
||||
error = misc_register(&mc_uapi->misc);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
|
||||
|
||||
mutex_init(&mc_uapi->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
|
||||
{
|
||||
misc_deregister(&mc_bus->uapi_misc.misc);
|
||||
}
|
|
@ -35,7 +35,7 @@ static enum mc_cmd_status mc_cmd_hdr_read_status(struct fsl_mc_command *cmd)
|
|||
return (enum mc_cmd_status)hdr->status;
|
||||
}
|
||||
|
||||
static u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd)
|
||||
u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd)
|
||||
{
|
||||
struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header;
|
||||
u16 cmd_id = le16_to_cpu(hdr->cmd_id);
|
||||
|
|
|
@ -151,12 +151,17 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
|
|||
{
|
||||
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
unsigned long irq_flags = IRQF_SHARED | IRQF_NO_SUSPEND;
|
||||
int i, ret;
|
||||
|
||||
/* if controller driver has set irq_flags, use it */
|
||||
if (mhi_cntrl->irq_flags)
|
||||
irq_flags = mhi_cntrl->irq_flags;
|
||||
|
||||
/* Setup BHI_INTVEC IRQ */
|
||||
ret = request_threaded_irq(mhi_cntrl->irq[0], mhi_intvec_handler,
|
||||
mhi_intvec_threaded_handler,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
irq_flags,
|
||||
"bhi", mhi_cntrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -174,7 +179,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
|
|||
|
||||
ret = request_irq(mhi_cntrl->irq[mhi_event->irq],
|
||||
mhi_irq_handler,
|
||||
IRQF_SHARED | IRQF_NO_SUSPEND,
|
||||
irq_flags,
|
||||
"mhi", mhi_event);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error requesting irq:%d for ev:%d\n",
|
||||
|
@ -552,6 +557,9 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
|||
tre_ring = &mhi_chan->tre_ring;
|
||||
chan_ctxt = &mhi_cntrl->mhi_ctxt->chan_ctxt[mhi_chan->chan];
|
||||
|
||||
if (!chan_ctxt->rbase) /* Already uninitialized */
|
||||
return;
|
||||
|
||||
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
|
||||
tre_ring->pre_aligned, tre_ring->dma_handle);
|
||||
vfree(buf_ring->base);
|
||||
|
|
|
@ -111,7 +111,14 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
|
|||
dma_addr_t db;
|
||||
|
||||
db = ring->iommu_base + (ring->wp - ring->base);
|
||||
|
||||
/*
|
||||
* Writes to the new ring element must be visible to the hardware
|
||||
* before letting h/w know there is new element to fetch.
|
||||
*/
|
||||
dma_wmb();
|
||||
*ring->ctxt_wp = db;
|
||||
|
||||
mhi_chan->db_cfg.process_db(mhi_cntrl, &mhi_chan->db_cfg,
|
||||
ring->db_addr, db);
|
||||
}
|
||||
|
@ -135,6 +142,19 @@ enum mhi_state mhi_get_mhi_state(struct mhi_controller *mhi_cntrl)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_get_mhi_state);
|
||||
|
||||
void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
if (mhi_cntrl->reset) {
|
||||
mhi_cntrl->reset(mhi_cntrl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generic MHI SoC reset */
|
||||
mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
|
||||
MHI_SOC_RESET_REQ);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_soc_reset);
|
||||
|
||||
int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_buf_info *buf_info)
|
||||
{
|
||||
|
@ -959,118 +979,88 @@ static bool mhi_is_ring_full(struct mhi_controller *mhi_cntrl,
|
|||
return (tmp == ring->rp);
|
||||
}
|
||||
|
||||
int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,
|
||||
struct sk_buff *skb, size_t len, enum mhi_flags mflags)
|
||||
static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
|
||||
enum dma_data_direction dir, enum mhi_flags mflags)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
|
||||
mhi_dev->dl_chan;
|
||||
struct mhi_ring *tre_ring = &mhi_chan->tre_ring;
|
||||
struct mhi_buf_info buf_info = { };
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* If MHI host pre-allocates buffers then client drivers cannot queue */
|
||||
if (mhi_chan->pre_alloc)
|
||||
return -EINVAL;
|
||||
|
||||
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
|
||||
return -ENOMEM;
|
||||
|
||||
read_lock_bh(&mhi_cntrl->pm_lock);
|
||||
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
|
||||
return -EIO;
|
||||
|
||||
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
|
||||
|
||||
ret = mhi_is_ring_full(mhi_cntrl, tre_ring);
|
||||
if (unlikely(ret)) {
|
||||
ret = -ENOMEM;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
/* we're in M3 or transitioning to M3 */
|
||||
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags);
|
||||
if (unlikely(ret))
|
||||
goto exit_unlock;
|
||||
|
||||
/* trigger M3 exit if necessary */
|
||||
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
|
||||
mhi_trigger_resume(mhi_cntrl);
|
||||
|
||||
/* Toggle wake to exit out of M2 */
|
||||
/* Assert dev_wake (to exit/prevent M1/M2)*/
|
||||
mhi_cntrl->wake_toggle(mhi_cntrl);
|
||||
|
||||
if (mhi_chan->dir == DMA_TO_DEVICE)
|
||||
atomic_inc(&mhi_cntrl->pending_pkts);
|
||||
|
||||
if (unlikely(!MHI_DB_ACCESS_VALID(mhi_cntrl))) {
|
||||
ret = -EIO;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
|
||||
|
||||
exit_unlock:
|
||||
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,
|
||||
struct sk_buff *skb, size_t len, enum mhi_flags mflags)
|
||||
{
|
||||
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
|
||||
mhi_dev->dl_chan;
|
||||
struct mhi_buf_info buf_info = { };
|
||||
|
||||
buf_info.v_addr = skb->data;
|
||||
buf_info.cb_buf = skb;
|
||||
buf_info.len = len;
|
||||
|
||||
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
|
||||
if (unlikely(ret)) {
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
return ret;
|
||||
}
|
||||
if (unlikely(mhi_chan->pre_alloc))
|
||||
return -EINVAL;
|
||||
|
||||
if (mhi_chan->dir == DMA_TO_DEVICE)
|
||||
atomic_inc(&mhi_cntrl->pending_pkts);
|
||||
|
||||
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
|
||||
read_lock_bh(&mhi_chan->lock);
|
||||
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
|
||||
read_unlock_bh(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
|
||||
return 0;
|
||||
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_queue_skb);
|
||||
|
||||
int mhi_queue_dma(struct mhi_device *mhi_dev, enum dma_data_direction dir,
|
||||
struct mhi_buf *mhi_buf, size_t len, enum mhi_flags mflags)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
|
||||
mhi_dev->dl_chan;
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
struct mhi_ring *tre_ring = &mhi_chan->tre_ring;
|
||||
struct mhi_buf_info buf_info = { };
|
||||
int ret;
|
||||
|
||||
/* If MHI host pre-allocates buffers then client drivers cannot queue */
|
||||
if (mhi_chan->pre_alloc)
|
||||
return -EINVAL;
|
||||
|
||||
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
|
||||
return -ENOMEM;
|
||||
|
||||
read_lock_bh(&mhi_cntrl->pm_lock);
|
||||
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
|
||||
dev_err(dev, "MHI is not in activate state, PM state: %s\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state));
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* we're in M3 or transitioning to M3 */
|
||||
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
|
||||
mhi_trigger_resume(mhi_cntrl);
|
||||
|
||||
/* Toggle wake to exit out of M2 */
|
||||
mhi_cntrl->wake_toggle(mhi_cntrl);
|
||||
|
||||
buf_info.p_addr = mhi_buf->dma_addr;
|
||||
buf_info.cb_buf = mhi_buf;
|
||||
buf_info.pre_mapped = true;
|
||||
buf_info.len = len;
|
||||
|
||||
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
|
||||
if (unlikely(ret)) {
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
return ret;
|
||||
}
|
||||
if (unlikely(mhi_chan->pre_alloc))
|
||||
return -EINVAL;
|
||||
|
||||
if (mhi_chan->dir == DMA_TO_DEVICE)
|
||||
atomic_inc(&mhi_cntrl->pending_pkts);
|
||||
|
||||
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
|
||||
read_lock_bh(&mhi_chan->lock);
|
||||
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
|
||||
read_unlock_bh(&mhi_chan->lock);
|
||||
}
|
||||
|
||||
read_unlock_bh(&mhi_cntrl->pm_lock);
|
||||
|
||||
return 0;
|
||||
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_queue_dma);
|
||||
|
||||
|
@ -1124,57 +1114,13 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
|
|||
int mhi_queue_buf(struct mhi_device *mhi_dev, enum dma_data_direction dir,
|
||||
void *buf, size_t len, enum mhi_flags mflags)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
|
||||
mhi_dev->dl_chan;
|
||||
struct mhi_ring *tre_ring;
|
||||
struct mhi_buf_info buf_info = { };
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* this check here only as a guard, it's always
|
||||
* possible mhi can enter error while executing rest of function,
|
||||
* which is not fatal so we do not need to hold pm_lock
|
||||
*/
|
||||
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
|
||||
return -EIO;
|
||||
|
||||
tre_ring = &mhi_chan->tre_ring;
|
||||
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
|
||||
return -ENOMEM;
|
||||
|
||||
buf_info.v_addr = buf;
|
||||
buf_info.cb_buf = buf;
|
||||
buf_info.len = len;
|
||||
|
||||
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
|
||||
|
||||
/* we're in M3 or transitioning to M3 */
|
||||
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
|
||||
mhi_trigger_resume(mhi_cntrl);
|
||||
|
||||
/* Toggle wake to exit out of M2 */
|
||||
mhi_cntrl->wake_toggle(mhi_cntrl);
|
||||
|
||||
if (mhi_chan->dir == DMA_TO_DEVICE)
|
||||
atomic_inc(&mhi_cntrl->pending_pkts);
|
||||
|
||||
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
|
||||
unsigned long flags;
|
||||
|
||||
read_lock_irqsave(&mhi_chan->lock, flags);
|
||||
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
|
||||
read_unlock_irqrestore(&mhi_chan->lock, flags);
|
||||
}
|
||||
|
||||
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
|
||||
|
||||
return 0;
|
||||
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_queue_buf);
|
||||
|
||||
|
|
|
@ -8,13 +8,21 @@
|
|||
* Copyright (C) 2020 Linaro Ltd <loic.poulain@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/aer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mhi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define MHI_PCI_DEFAULT_BAR_NUM 0
|
||||
|
||||
#define MHI_POST_RESET_DELAY_MS 500
|
||||
|
||||
#define HEALTH_CHECK_PERIOD (HZ * 2)
|
||||
|
||||
/**
|
||||
* struct mhi_pci_dev_info - MHI PCI device specific information
|
||||
* @config: MHI controller configuration
|
||||
|
@ -76,6 +84,36 @@ struct mhi_pci_dev_info {
|
|||
.offload_channel = false, \
|
||||
}
|
||||
|
||||
#define MHI_CHANNEL_CONFIG_HW_UL(ch_num, ch_name, el_count, ev_ring) \
|
||||
{ \
|
||||
.num = ch_num, \
|
||||
.name = ch_name, \
|
||||
.num_elements = el_count, \
|
||||
.event_ring = ev_ring, \
|
||||
.dir = DMA_TO_DEVICE, \
|
||||
.ee_mask = BIT(MHI_EE_AMSS), \
|
||||
.pollcfg = 0, \
|
||||
.doorbell = MHI_DB_BRST_ENABLE, \
|
||||
.lpm_notify = false, \
|
||||
.offload_channel = false, \
|
||||
.doorbell_mode_switch = true, \
|
||||
} \
|
||||
|
||||
#define MHI_CHANNEL_CONFIG_HW_DL(ch_num, ch_name, el_count, ev_ring) \
|
||||
{ \
|
||||
.num = ch_num, \
|
||||
.name = ch_name, \
|
||||
.num_elements = el_count, \
|
||||
.event_ring = ev_ring, \
|
||||
.dir = DMA_FROM_DEVICE, \
|
||||
.ee_mask = BIT(MHI_EE_AMSS), \
|
||||
.pollcfg = 0, \
|
||||
.doorbell = MHI_DB_BRST_ENABLE, \
|
||||
.lpm_notify = false, \
|
||||
.offload_channel = false, \
|
||||
.doorbell_mode_switch = true, \
|
||||
}
|
||||
|
||||
#define MHI_EVENT_CONFIG_DATA(ev_ring) \
|
||||
{ \
|
||||
.num_elements = 128, \
|
||||
|
@ -91,8 +129,8 @@ struct mhi_pci_dev_info {
|
|||
|
||||
#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, ch_num) \
|
||||
{ \
|
||||
.num_elements = 128, \
|
||||
.irq_moderation_ms = 5, \
|
||||
.num_elements = 2048, \
|
||||
.irq_moderation_ms = 1, \
|
||||
.irq = (ev_ring) + 1, \
|
||||
.priority = 1, \
|
||||
.mode = MHI_DB_BRST_DISABLE, \
|
||||
|
@ -104,27 +142,31 @@ struct mhi_pci_dev_info {
|
|||
}
|
||||
|
||||
static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 16, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 16, 1),
|
||||
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 4, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 4, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(100, "IP_HW0", 128, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(101, "IP_HW0", 128, 2),
|
||||
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
|
||||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
|
||||
};
|
||||
|
||||
static const struct mhi_event_config modem_qcom_v1_mhi_events[] = {
|
||||
static struct mhi_event_config modem_qcom_v1_mhi_events[] = {
|
||||
/* first ring is control+data ring */
|
||||
MHI_EVENT_CONFIG_CTRL(0),
|
||||
/* DIAG dedicated event ring */
|
||||
MHI_EVENT_CONFIG_DATA(1),
|
||||
/* Hardware channels request dedicated hardware event rings */
|
||||
MHI_EVENT_CONFIG_HW_DATA(1, 100),
|
||||
MHI_EVENT_CONFIG_HW_DATA(2, 101)
|
||||
MHI_EVENT_CONFIG_HW_DATA(2, 100),
|
||||
MHI_EVENT_CONFIG_HW_DATA(3, 101)
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
|
||||
static struct mhi_controller_config modem_qcom_v1_mhiv_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 5000,
|
||||
.timeout_ms = 8000,
|
||||
.num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
|
||||
.ch_cfg = modem_qcom_v1_mhi_channels,
|
||||
.num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
|
||||
|
@ -147,6 +189,18 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
|
||||
|
||||
enum mhi_pci_device_status {
|
||||
MHI_PCI_DEV_STARTED,
|
||||
};
|
||||
|
||||
struct mhi_pci_device {
|
||||
struct mhi_controller mhi_cntrl;
|
||||
struct pci_saved_state *pci_state;
|
||||
struct work_struct recovery_work;
|
||||
struct timer_list health_check_timer;
|
||||
unsigned long status;
|
||||
};
|
||||
|
||||
static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *addr, u32 *out)
|
||||
{
|
||||
|
@ -163,7 +217,31 @@ static void mhi_pci_write_reg(struct mhi_controller *mhi_cntrl,
|
|||
static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
|
||||
enum mhi_callback cb)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
|
||||
|
||||
/* Nothing to do for now */
|
||||
switch (cb) {
|
||||
case MHI_CB_FATAL_ERROR:
|
||||
case MHI_CB_SYS_ERROR:
|
||||
dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
|
||||
u16 vendor = 0;
|
||||
|
||||
if (pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor))
|
||||
return false;
|
||||
|
||||
if (vendor == (u16) ~0 || vendor == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
|
||||
|
@ -227,8 +305,12 @@ static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl,
|
|||
}
|
||||
|
||||
if (nr_vectors < mhi_cntrl->nr_irqs) {
|
||||
dev_warn(&pdev->dev, "Not enough MSI vectors (%d/%d), use shared MSI\n",
|
||||
nr_vectors, mhi_cntrl_config->num_events);
|
||||
dev_warn(&pdev->dev, "using shared MSI\n");
|
||||
|
||||
/* Patch msi vectors, use only one (shared) */
|
||||
for (i = 0; i < mhi_cntrl_config->num_events; i++)
|
||||
mhi_cntrl_config->event_cfg[i].irq = 0;
|
||||
mhi_cntrl->nr_irqs = 1;
|
||||
}
|
||||
|
||||
irq = devm_kcalloc(&pdev->dev, mhi_cntrl->nr_irqs, sizeof(int), GFP_KERNEL);
|
||||
|
@ -257,20 +339,89 @@ static void mhi_pci_runtime_put(struct mhi_controller *mhi_cntrl)
|
|||
/* no PM for now */
|
||||
}
|
||||
|
||||
static void mhi_pci_recovery_work(struct work_struct *work)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = container_of(work, struct mhi_pci_device,
|
||||
recovery_work);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
|
||||
int err;
|
||||
|
||||
dev_warn(&pdev->dev, "device recovery started\n");
|
||||
|
||||
del_timer(&mhi_pdev->health_check_timer);
|
||||
|
||||
/* Clean up MHI state */
|
||||
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
|
||||
mhi_power_down(mhi_cntrl, false);
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
}
|
||||
|
||||
/* Check if we can recover without full reset */
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_load_saved_state(pdev, mhi_pdev->pci_state);
|
||||
pci_restore_state(pdev);
|
||||
|
||||
if (!mhi_pci_is_alive(mhi_cntrl))
|
||||
goto err_try_reset;
|
||||
|
||||
err = mhi_prepare_for_power_up(mhi_cntrl);
|
||||
if (err)
|
||||
goto err_try_reset;
|
||||
|
||||
err = mhi_sync_power_up(mhi_cntrl);
|
||||
if (err)
|
||||
goto err_unprepare;
|
||||
|
||||
dev_dbg(&pdev->dev, "Recovery completed\n");
|
||||
|
||||
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
return;
|
||||
|
||||
err_unprepare:
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
err_try_reset:
|
||||
if (pci_reset_function(pdev))
|
||||
dev_err(&pdev->dev, "Recovery failed\n");
|
||||
}
|
||||
|
||||
static void health_check(struct timer_list *t)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
if (!mhi_pci_is_alive(mhi_cntrl)) {
|
||||
dev_err(mhi_cntrl->cntrl_dev, "Device died\n");
|
||||
queue_work(system_long_wq, &mhi_pdev->recovery_work);
|
||||
return;
|
||||
}
|
||||
|
||||
/* reschedule in two seconds */
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
}
|
||||
|
||||
static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
const struct mhi_pci_dev_info *info = (struct mhi_pci_dev_info *) id->driver_data;
|
||||
const struct mhi_controller_config *mhi_cntrl_config;
|
||||
struct mhi_pci_device *mhi_pdev;
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
int err;
|
||||
|
||||
dev_dbg(&pdev->dev, "MHI PCI device found: %s\n", info->name);
|
||||
|
||||
mhi_cntrl = mhi_alloc_controller();
|
||||
if (!mhi_cntrl)
|
||||
/* mhi_pdev.mhi_cntrl must be zero-initialized */
|
||||
mhi_pdev = devm_kzalloc(&pdev->dev, sizeof(*mhi_pdev), GFP_KERNEL);
|
||||
if (!mhi_pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&mhi_pdev->recovery_work, mhi_pci_recovery_work);
|
||||
timer_setup(&mhi_pdev->health_check_timer, health_check, 0);
|
||||
|
||||
mhi_cntrl_config = info->config;
|
||||
mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
mhi_cntrl->cntrl_dev = &pdev->dev;
|
||||
mhi_cntrl->iova_start = 0;
|
||||
mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(info->dma_data_width);
|
||||
|
@ -285,17 +436,23 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width));
|
||||
if (err)
|
||||
goto err_release;
|
||||
return err;
|
||||
|
||||
err = mhi_pci_get_irqs(mhi_cntrl, mhi_cntrl_config);
|
||||
if (err)
|
||||
goto err_release;
|
||||
return err;
|
||||
|
||||
pci_set_drvdata(pdev, mhi_cntrl);
|
||||
pci_set_drvdata(pdev, mhi_pdev);
|
||||
|
||||
/* Have stored pci confspace at hand for restore in sudden PCI error */
|
||||
pci_save_state(pdev);
|
||||
mhi_pdev->pci_state = pci_store_saved_state(pdev);
|
||||
|
||||
pci_enable_pcie_error_reporting(pdev);
|
||||
|
||||
err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config);
|
||||
if (err)
|
||||
goto err_release;
|
||||
return err;
|
||||
|
||||
/* MHI bus does not power up the controller by default */
|
||||
err = mhi_prepare_for_power_up(mhi_cntrl);
|
||||
|
@ -310,33 +467,209 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto err_unprepare;
|
||||
}
|
||||
|
||||
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
|
||||
|
||||
/* start health check */
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unprepare:
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
err_unregister:
|
||||
mhi_unregister_controller(mhi_cntrl);
|
||||
err_release:
|
||||
mhi_free_controller(mhi_cntrl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mhi_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = pci_get_drvdata(pdev);
|
||||
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
del_timer(&mhi_pdev->health_check_timer);
|
||||
cancel_work_sync(&mhi_pdev->recovery_work);
|
||||
|
||||
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
|
||||
mhi_power_down(mhi_cntrl, true);
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
}
|
||||
|
||||
mhi_power_down(mhi_cntrl, true);
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
mhi_unregister_controller(mhi_cntrl);
|
||||
mhi_free_controller(mhi_cntrl);
|
||||
}
|
||||
|
||||
static void mhi_pci_reset_prepare(struct pci_dev *pdev)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
dev_info(&pdev->dev, "reset\n");
|
||||
|
||||
del_timer(&mhi_pdev->health_check_timer);
|
||||
|
||||
/* Clean up MHI state */
|
||||
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
|
||||
mhi_power_down(mhi_cntrl, false);
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
}
|
||||
|
||||
/* cause internal device reset */
|
||||
mhi_soc_reset(mhi_cntrl);
|
||||
|
||||
/* Be sure device reset has been executed */
|
||||
msleep(MHI_POST_RESET_DELAY_MS);
|
||||
}
|
||||
|
||||
static void mhi_pci_reset_done(struct pci_dev *pdev)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
int err;
|
||||
|
||||
/* Restore initial known working PCI state */
|
||||
pci_load_saved_state(pdev, mhi_pdev->pci_state);
|
||||
pci_restore_state(pdev);
|
||||
|
||||
/* Is device status available ? */
|
||||
if (!mhi_pci_is_alive(mhi_cntrl)) {
|
||||
dev_err(&pdev->dev, "reset failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = mhi_prepare_for_power_up(mhi_cntrl);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to prepare MHI controller\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = mhi_sync_power_up(mhi_cntrl);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to power up MHI controller\n");
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
}
|
||||
|
||||
static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev,
|
||||
pci_channel_state_t state)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
dev_err(&pdev->dev, "PCI error detected, state = %u\n", state);
|
||||
|
||||
if (state == pci_channel_io_perm_failure)
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
|
||||
/* Clean up MHI state */
|
||||
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
|
||||
mhi_power_down(mhi_cntrl, false);
|
||||
mhi_unprepare_after_power_down(mhi_cntrl);
|
||||
} else {
|
||||
/* Nothing to do */
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return PCI_ERS_RESULT_NEED_RESET;
|
||||
}
|
||||
|
||||
static pci_ers_result_t mhi_pci_slot_reset(struct pci_dev *pdev)
|
||||
{
|
||||
if (pci_enable_device(pdev)) {
|
||||
dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
||||
static void mhi_pci_io_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
|
||||
|
||||
dev_err(&pdev->dev, "PCI slot reset done\n");
|
||||
|
||||
queue_work(system_long_wq, &mhi_pdev->recovery_work);
|
||||
}
|
||||
|
||||
static const struct pci_error_handlers mhi_pci_err_handler = {
|
||||
.error_detected = mhi_pci_error_detected,
|
||||
.slot_reset = mhi_pci_slot_reset,
|
||||
.resume = mhi_pci_io_resume,
|
||||
.reset_prepare = mhi_pci_reset_prepare,
|
||||
.reset_done = mhi_pci_reset_done,
|
||||
};
|
||||
|
||||
static int __maybe_unused mhi_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
|
||||
del_timer(&mhi_pdev->health_check_timer);
|
||||
cancel_work_sync(&mhi_pdev->recovery_work);
|
||||
|
||||
/* Transition to M3 state */
|
||||
mhi_pm_suspend(mhi_cntrl);
|
||||
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_wake_from_d3(pdev, true);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mhi_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
|
||||
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
|
||||
int err;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_set_master(pdev);
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
goto err_recovery;
|
||||
|
||||
/* Exit M3, transition to M0 state */
|
||||
err = mhi_pm_resume(mhi_cntrl);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to resume device: %d\n", err);
|
||||
goto err_recovery;
|
||||
}
|
||||
|
||||
/* Resume health check */
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
|
||||
return 0;
|
||||
|
||||
err_recovery:
|
||||
/* The device may have loose power or crashed, try recovering it */
|
||||
queue_work(system_long_wq, &mhi_pdev->recovery_work);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mhi_pci_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mhi_pci_suspend, mhi_pci_resume)
|
||||
};
|
||||
|
||||
static struct pci_driver mhi_pci_driver = {
|
||||
.name = "mhi-pci-generic",
|
||||
.id_table = mhi_pci_id_table,
|
||||
.probe = mhi_pci_probe,
|
||||
.remove = mhi_pci_remove
|
||||
.remove = mhi_pci_remove,
|
||||
.err_handler = &mhi_pci_err_handler,
|
||||
.driver.pm = &mhi_pci_pm_ops
|
||||
};
|
||||
module_pci_driver(mhi_pci_driver);
|
||||
|
||||
|
|
|
@ -1959,7 +1959,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
|||
return -EPERM;
|
||||
if (crng_init < 2)
|
||||
return -ENODATA;
|
||||
crng_reseed(&primary_crng, NULL);
|
||||
crng_reseed(&primary_crng, &input_pool);
|
||||
crng_global_init_time = jiffies - 1;
|
||||
return 0;
|
||||
default:
|
||||
|
|
|
@ -192,7 +192,9 @@ static int fw_unit_remove(struct device *dev)
|
|||
struct fw_driver *driver =
|
||||
container_of(dev->driver, struct fw_driver, driver);
|
||||
|
||||
return driver->remove(fw_unit(dev)), 0;
|
||||
driver->remove(fw_unit(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
|
||||
|
|
|
@ -46,14 +46,13 @@ static int coreboot_bus_probe(struct device *dev)
|
|||
|
||||
static int coreboot_bus_remove(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct coreboot_device *device = CB_DEV(dev);
|
||||
struct coreboot_driver *driver = CB_DRV(dev->driver);
|
||||
|
||||
if (driver->remove)
|
||||
ret = driver->remove(device);
|
||||
driver->remove(device);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bus_type coreboot_bus_type = {
|
||||
|
|
|
@ -72,7 +72,7 @@ struct coreboot_device {
|
|||
/* A driver for handling devices described in coreboot tables. */
|
||||
struct coreboot_driver {
|
||||
int (*probe)(struct coreboot_device *);
|
||||
int (*remove)(struct coreboot_device *);
|
||||
void (*remove)(struct coreboot_device *);
|
||||
struct device_driver drv;
|
||||
u32 tag;
|
||||
};
|
||||
|
|
|
@ -72,13 +72,11 @@ static int framebuffer_probe(struct coreboot_device *dev)
|
|||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
|
||||
static int framebuffer_remove(struct coreboot_device *dev)
|
||||
static void framebuffer_remove(struct coreboot_device *dev)
|
||||
{
|
||||
struct platform_device *pdev = dev_get_drvdata(&dev->dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct coreboot_driver framebuffer_driver = {
|
||||
|
|
|
@ -91,11 +91,9 @@ static int memconsole_probe(struct coreboot_device *dev)
|
|||
return memconsole_sysfs_init();
|
||||
}
|
||||
|
||||
static int memconsole_remove(struct coreboot_device *dev)
|
||||
static void memconsole_remove(struct coreboot_device *dev)
|
||||
{
|
||||
memconsole_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct coreboot_driver memconsole_driver = {
|
||||
|
|
|
@ -298,14 +298,12 @@ static int vpd_probe(struct coreboot_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vpd_remove(struct coreboot_device *dev)
|
||||
static void vpd_remove(struct coreboot_device *dev)
|
||||
{
|
||||
vpd_section_destroy(&ro_vpd);
|
||||
vpd_section_destroy(&rw_vpd);
|
||||
|
||||
kobject_put(vpd_kobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct coreboot_driver vpd_driver = {
|
||||
|
|
|
@ -192,6 +192,17 @@ config FPGA_DFL_AFU
|
|||
to the FPGA infrastructure via a Port. There may be more than one
|
||||
Port/AFU per DFL based FPGA device.
|
||||
|
||||
config FPGA_DFL_NIOS_INTEL_PAC_N3000
|
||||
tristate "FPGA DFL NIOS Driver for Intel PAC N3000"
|
||||
depends on FPGA_DFL
|
||||
select REGMAP
|
||||
help
|
||||
This is the driver for the N3000 Nios private feature on Intel
|
||||
PAC (Programmable Acceleration Card) N3000. It communicates
|
||||
with the embedded Nios processor to configure the retimers on
|
||||
the card. It also instantiates the SPI master (spi-altera) for
|
||||
the card's BMC (Board Management Controller).
|
||||
|
||||
config FPGA_DFL_PCI
|
||||
tristate "FPGA DFL PCIe Device Driver"
|
||||
depends on PCI && FPGA_DFL
|
||||
|
|
|
@ -44,5 +44,7 @@ dfl-fme-objs += dfl-fme-perf.o
|
|||
dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o
|
||||
dfl-afu-objs += dfl-afu-error.o
|
||||
|
||||
obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o
|
||||
|
||||
# Drivers for FPGAs which implement DFL
|
||||
obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o
|
||||
|
|
|
@ -192,7 +192,7 @@ static struct attribute *fme_perf_cpumask_attrs[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group fme_perf_cpumask_group = {
|
||||
static const struct attribute_group fme_perf_cpumask_group = {
|
||||
.attrs = fme_perf_cpumask_attrs,
|
||||
};
|
||||
|
||||
|
@ -225,7 +225,7 @@ static struct attribute *fme_perf_format_attrs[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group fme_perf_format_group = {
|
||||
static const struct attribute_group fme_perf_format_group = {
|
||||
.name = "format",
|
||||
.attrs = fme_perf_format_attrs,
|
||||
};
|
||||
|
@ -239,7 +239,7 @@ static struct attribute *fme_perf_events_attrs_empty[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group fme_perf_events_group = {
|
||||
static const struct attribute_group fme_perf_events_group = {
|
||||
.name = "events",
|
||||
.attrs = fme_perf_events_attrs_empty,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,588 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DFL device driver for Nios private feature on Intel PAC (Programmable
|
||||
* Acceleration Card) N3000
|
||||
*
|
||||
* Copyright (C) 2019-2020 Intel Corporation, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Wu Hao <hao.wu@intel.com>
|
||||
* Xu Yilun <yilun.xu@intel.com>
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dfl.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/spi/altera.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* N3000 Nios private feature registers, named as NIOS_SPI_XX on spec.
|
||||
* NS is the abbreviation of NIOS_SPI.
|
||||
*/
|
||||
#define N3000_NS_PARAM 0x8
|
||||
#define N3000_NS_PARAM_SHIFT_MODE_MSK BIT_ULL(1)
|
||||
#define N3000_NS_PARAM_SHIFT_MODE_MSB 0
|
||||
#define N3000_NS_PARAM_SHIFT_MODE_LSB 1
|
||||
#define N3000_NS_PARAM_DATA_WIDTH GENMASK_ULL(7, 2)
|
||||
#define N3000_NS_PARAM_NUM_CS GENMASK_ULL(13, 8)
|
||||
#define N3000_NS_PARAM_CLK_POL BIT_ULL(14)
|
||||
#define N3000_NS_PARAM_CLK_PHASE BIT_ULL(15)
|
||||
#define N3000_NS_PARAM_PERIPHERAL_ID GENMASK_ULL(47, 32)
|
||||
|
||||
#define N3000_NS_CTRL 0x10
|
||||
#define N3000_NS_CTRL_WR_DATA GENMASK_ULL(31, 0)
|
||||
#define N3000_NS_CTRL_ADDR GENMASK_ULL(44, 32)
|
||||
#define N3000_NS_CTRL_CMD_MSK GENMASK_ULL(63, 62)
|
||||
#define N3000_NS_CTRL_CMD_NOP 0
|
||||
#define N3000_NS_CTRL_CMD_RD 1
|
||||
#define N3000_NS_CTRL_CMD_WR 2
|
||||
|
||||
#define N3000_NS_STAT 0x18
|
||||
#define N3000_NS_STAT_RD_DATA GENMASK_ULL(31, 0)
|
||||
#define N3000_NS_STAT_RW_VAL BIT_ULL(32)
|
||||
|
||||
/* Nios handshake registers, indirect access */
|
||||
#define N3000_NIOS_INIT 0x1000
|
||||
#define N3000_NIOS_INIT_DONE BIT(0)
|
||||
#define N3000_NIOS_INIT_START BIT(1)
|
||||
/* Mode for retimer A, link 0, the same below */
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK GENMASK(9, 8)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK GENMASK(11, 10)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK GENMASK(13, 12)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK GENMASK(15, 14)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK GENMASK(17, 16)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK GENMASK(19, 18)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK GENMASK(21, 20)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK GENMASK(23, 22)
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_NO 0x0
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_KR 0x1
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_RS 0x2
|
||||
|
||||
#define N3000_NIOS_FW_VERSION 0x1004
|
||||
#define N3000_NIOS_FW_VERSION_PATCH GENMASK(23, 20)
|
||||
#define N3000_NIOS_FW_VERSION_MINOR GENMASK(27, 24)
|
||||
#define N3000_NIOS_FW_VERSION_MAJOR GENMASK(31, 28)
|
||||
|
||||
/* The retimers we use on Intel PAC N3000 is Parkvale, abbreviated to PKVL */
|
||||
#define N3000_NIOS_PKVL_A_MODE_STS 0x1020
|
||||
#define N3000_NIOS_PKVL_B_MODE_STS 0x1024
|
||||
#define N3000_NIOS_PKVL_MODE_STS_GROUP_MSK GENMASK(15, 8)
|
||||
#define N3000_NIOS_PKVL_MODE_STS_GROUP_OK 0x0
|
||||
#define N3000_NIOS_PKVL_MODE_STS_ID_MSK GENMASK(7, 0)
|
||||
/* When GROUP MASK field == GROUP_OK */
|
||||
#define N3000_NIOS_PKVL_MODE_ID_RESET 0x0
|
||||
#define N3000_NIOS_PKVL_MODE_ID_4X10G 0x1
|
||||
#define N3000_NIOS_PKVL_MODE_ID_4X25G 0x2
|
||||
#define N3000_NIOS_PKVL_MODE_ID_2X25G 0x3
|
||||
#define N3000_NIOS_PKVL_MODE_ID_2X25G_2X10G 0x4
|
||||
#define N3000_NIOS_PKVL_MODE_ID_1X25G 0x5
|
||||
|
||||
#define N3000_NIOS_REGBUS_RETRY_COUNT 10000 /* loop count */
|
||||
|
||||
#define N3000_NIOS_INIT_TIMEOUT 10000000 /* usec */
|
||||
#define N3000_NIOS_INIT_TIME_INTV 100000 /* usec */
|
||||
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL \
|
||||
(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK | \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK)
|
||||
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL \
|
||||
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_NO))
|
||||
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL \
|
||||
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_KR))
|
||||
|
||||
#define N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL \
|
||||
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
|
||||
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
|
||||
N3000_NIOS_INIT_REQ_FEC_MODE_RS))
|
||||
|
||||
struct n3000_nios {
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct platform_device *altera_spi;
|
||||
};
|
||||
|
||||
static ssize_t nios_fw_version_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct n3000_nios *nn = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%x.%x.%x\n",
|
||||
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val),
|
||||
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_MINOR, val),
|
||||
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_PATCH, val));
|
||||
}
|
||||
static DEVICE_ATTR_RO(nios_fw_version);
|
||||
|
||||
#define IS_MODE_STATUS_OK(mode_stat) \
|
||||
(FIELD_GET(N3000_NIOS_PKVL_MODE_STS_GROUP_MSK, (mode_stat)) == \
|
||||
N3000_NIOS_PKVL_MODE_STS_GROUP_OK)
|
||||
|
||||
#define IS_RETIMER_FEC_SUPPORTED(retimer_mode) \
|
||||
((retimer_mode) != N3000_NIOS_PKVL_MODE_ID_RESET && \
|
||||
(retimer_mode) != N3000_NIOS_PKVL_MODE_ID_4X10G)
|
||||
|
||||
static int get_retimer_mode(struct n3000_nios *nn, unsigned int mode_stat_reg,
|
||||
unsigned int *retimer_mode)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(nn->regmap, mode_stat_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!IS_MODE_STATUS_OK(val))
|
||||
return -EFAULT;
|
||||
|
||||
*retimer_mode = FIELD_GET(N3000_NIOS_PKVL_MODE_STS_ID_MSK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t retimer_A_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct n3000_nios *nn = dev_get_drvdata(dev);
|
||||
unsigned int mode;
|
||||
int ret;
|
||||
|
||||
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "0x%x\n", mode);
|
||||
}
|
||||
static DEVICE_ATTR_RO(retimer_A_mode);
|
||||
|
||||
static ssize_t retimer_B_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct n3000_nios *nn = dev_get_drvdata(dev);
|
||||
unsigned int mode;
|
||||
int ret;
|
||||
|
||||
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "0x%x\n", mode);
|
||||
}
|
||||
static DEVICE_ATTR_RO(retimer_B_mode);
|
||||
|
||||
static ssize_t fec_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned int val, retimer_a_mode, retimer_b_mode, fec_modes;
|
||||
struct n3000_nios *nn = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/* FEC mode setting is not supported in early FW versions */
|
||||
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) < 3)
|
||||
return sysfs_emit(buf, "not supported\n");
|
||||
|
||||
/* If no 25G links, FEC mode setting is not supported either */
|
||||
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &retimer_a_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &retimer_b_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!IS_RETIMER_FEC_SUPPORTED(retimer_a_mode) &&
|
||||
!IS_RETIMER_FEC_SUPPORTED(retimer_b_mode))
|
||||
return sysfs_emit(buf, "not supported\n");
|
||||
|
||||
/* get the valid FEC mode for 25G links */
|
||||
ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* FEC mode should always be the same for all links, as we set them
|
||||
* in this way.
|
||||
*/
|
||||
fec_modes = (val & N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL);
|
||||
if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL)
|
||||
return sysfs_emit(buf, "no\n");
|
||||
else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL)
|
||||
return sysfs_emit(buf, "kr\n");
|
||||
else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL)
|
||||
return sysfs_emit(buf, "rs\n");
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
static DEVICE_ATTR_RO(fec_mode);
|
||||
|
||||
static struct attribute *n3000_nios_attrs[] = {
|
||||
&dev_attr_nios_fw_version.attr,
|
||||
&dev_attr_retimer_A_mode.attr,
|
||||
&dev_attr_retimer_B_mode.attr,
|
||||
&dev_attr_fec_mode.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(n3000_nios);
|
||||
|
||||
static int n3000_nios_init_done_check(struct n3000_nios *nn)
|
||||
{
|
||||
unsigned int val, state_a, state_b;
|
||||
struct device *dev = nn->dev;
|
||||
int ret, ret2;
|
||||
|
||||
/*
|
||||
* The SPI is shared by the Nios core inside the FPGA, Nios will use
|
||||
* this SPI master to do some one time initialization after power up,
|
||||
* and then release the control to OS. The driver needs to poll on
|
||||
* INIT_DONE to see when driver could take the control.
|
||||
*
|
||||
* Please note that after Nios firmware version 3.0.0, INIT_START is
|
||||
* introduced, so driver needs to trigger START firstly and then check
|
||||
* INIT_DONE.
|
||||
*/
|
||||
|
||||
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If Nios version register is totally uninitialized(== 0x0), then the
|
||||
* Nios firmware is missing. So host could take control of SPI master
|
||||
* safely, but initialization work for Nios is not done. To restore the
|
||||
* card, we need to reprogram a new Nios firmware via the BMC chip on
|
||||
* SPI bus. So the driver doesn't error out, it continues to create the
|
||||
* spi controller device and spi_board_info for BMC.
|
||||
*/
|
||||
if (val == 0) {
|
||||
dev_err(dev, "Nios version reg = 0x%x, skip INIT_DONE check, but the retimer may be uninitialized\n",
|
||||
val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) >= 3) {
|
||||
/* read NIOS_INIT to check if retimer initialization is done */
|
||||
ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* check if retimers are initialized already */
|
||||
if (val & (N3000_NIOS_INIT_DONE | N3000_NIOS_INIT_START))
|
||||
goto nios_init_done;
|
||||
|
||||
/* configure FEC mode per module param */
|
||||
val = N3000_NIOS_INIT_START;
|
||||
|
||||
/*
|
||||
* When the retimer is to be set to 10G mode, there is no FEC
|
||||
* mode setting, so the REQ_FEC_MODE field will be ignored by
|
||||
* Nios firmware in this case. But we should still fill the FEC
|
||||
* mode field cause host could not get the retimer working mode
|
||||
* until the Nios init is done.
|
||||
*
|
||||
* For now the driver doesn't support the retimer FEC mode
|
||||
* switching per user's request. It is always set to Reed
|
||||
* Solomon FEC.
|
||||
*
|
||||
* The driver will set the same FEC mode for all links.
|
||||
*/
|
||||
val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL;
|
||||
|
||||
ret = regmap_write(nn->regmap, N3000_NIOS_INIT, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
nios_init_done:
|
||||
/* polls on NIOS_INIT_DONE */
|
||||
ret = regmap_read_poll_timeout(nn->regmap, N3000_NIOS_INIT, val,
|
||||
val & N3000_NIOS_INIT_DONE,
|
||||
N3000_NIOS_INIT_TIME_INTV,
|
||||
N3000_NIOS_INIT_TIMEOUT);
|
||||
if (ret)
|
||||
dev_err(dev, "NIOS_INIT_DONE %s\n",
|
||||
(ret == -ETIMEDOUT) ? "timed out" : "check error");
|
||||
|
||||
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_A_MODE_STS, &state_a);
|
||||
if (ret2)
|
||||
return ret2;
|
||||
|
||||
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_B_MODE_STS, &state_b);
|
||||
if (ret2)
|
||||
return ret2;
|
||||
|
||||
if (!ret) {
|
||||
/*
|
||||
* After INIT_DONE is detected, it still needs to check if the
|
||||
* Nios firmware reports any error during the retimer
|
||||
* configuration.
|
||||
*/
|
||||
if (IS_MODE_STATUS_OK(state_a) && IS_MODE_STATUS_OK(state_b))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the retimer configuration is failed, the Nios firmware
|
||||
* will still release the spi controller for host to
|
||||
* communicate with the BMC. It makes possible for people to
|
||||
* reprogram a new Nios firmware and restore the card. So the
|
||||
* driver doesn't error out, it continues to create the spi
|
||||
* controller device and spi_board_info for BMC.
|
||||
*/
|
||||
dev_err(dev, "NIOS_INIT_DONE OK, but err on retimer init\n");
|
||||
}
|
||||
|
||||
dev_err(nn->dev, "PKVL_A_MODE_STS 0x%x\n", state_a);
|
||||
dev_err(nn->dev, "PKVL_B_MODE_STS 0x%x\n", state_b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct spi_board_info m10_n3000_info = {
|
||||
.modalias = "m10-n3000",
|
||||
.max_speed_hz = 12500000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
};
|
||||
|
||||
static int create_altera_spi_controller(struct n3000_nios *nn)
|
||||
{
|
||||
struct altera_spi_platform_data pdata = { 0 };
|
||||
struct platform_device_info pdevinfo = { 0 };
|
||||
void __iomem *base = nn->base;
|
||||
u64 v;
|
||||
|
||||
v = readq(base + N3000_NS_PARAM);
|
||||
|
||||
pdata.mode_bits = SPI_CS_HIGH;
|
||||
if (FIELD_GET(N3000_NS_PARAM_CLK_POL, v))
|
||||
pdata.mode_bits |= SPI_CPOL;
|
||||
if (FIELD_GET(N3000_NS_PARAM_CLK_PHASE, v))
|
||||
pdata.mode_bits |= SPI_CPHA;
|
||||
|
||||
pdata.num_chipselect = FIELD_GET(N3000_NS_PARAM_NUM_CS, v);
|
||||
pdata.bits_per_word_mask =
|
||||
SPI_BPW_RANGE_MASK(1, FIELD_GET(N3000_NS_PARAM_DATA_WIDTH, v));
|
||||
|
||||
pdata.num_devices = 1;
|
||||
pdata.devices = &m10_n3000_info;
|
||||
|
||||
dev_dbg(nn->dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
|
||||
pdata.num_chipselect, pdata.bits_per_word_mask,
|
||||
pdata.mode_bits);
|
||||
|
||||
pdevinfo.name = "subdev_spi_altera";
|
||||
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
||||
pdevinfo.parent = nn->dev;
|
||||
pdevinfo.data = &pdata;
|
||||
pdevinfo.size_data = sizeof(pdata);
|
||||
|
||||
nn->altera_spi = platform_device_register_full(&pdevinfo);
|
||||
return PTR_ERR_OR_ZERO(nn->altera_spi);
|
||||
}
|
||||
|
||||
static void destroy_altera_spi_controller(struct n3000_nios *nn)
|
||||
{
|
||||
platform_device_unregister(nn->altera_spi);
|
||||
}
|
||||
|
||||
static int n3000_nios_poll_stat_timeout(void __iomem *base, u64 *v)
|
||||
{
|
||||
int loops;
|
||||
|
||||
/*
|
||||
* We don't use the time based timeout here for performance.
|
||||
*
|
||||
* The regbus read/write is on the critical path of Intel PAC N3000
|
||||
* image programing. The time based timeout checking will add too much
|
||||
* overhead on it. Usually the state changes in 1 or 2 loops on the
|
||||
* test server, and we set 10000 times loop here for safety.
|
||||
*/
|
||||
for (loops = N3000_NIOS_REGBUS_RETRY_COUNT; loops > 0 ; loops--) {
|
||||
*v = readq(base + N3000_NS_STAT);
|
||||
if (*v & N3000_NS_STAT_RW_VAL)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
return (loops > 0) ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int n3000_nios_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct n3000_nios *nn = context;
|
||||
u64 v;
|
||||
int ret;
|
||||
|
||||
v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_WR) |
|
||||
FIELD_PREP(N3000_NS_CTRL_ADDR, reg) |
|
||||
FIELD_PREP(N3000_NS_CTRL_WR_DATA, val);
|
||||
writeq(v, nn->base + N3000_NS_CTRL);
|
||||
|
||||
ret = n3000_nios_poll_stat_timeout(nn->base, &v);
|
||||
if (ret)
|
||||
dev_err(nn->dev, "fail to write reg 0x%x val 0x%x: %d\n",
|
||||
reg, val, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int n3000_nios_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct n3000_nios *nn = context;
|
||||
u64 v;
|
||||
int ret;
|
||||
|
||||
v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_RD) |
|
||||
FIELD_PREP(N3000_NS_CTRL_ADDR, reg);
|
||||
writeq(v, nn->base + N3000_NS_CTRL);
|
||||
|
||||
ret = n3000_nios_poll_stat_timeout(nn->base, &v);
|
||||
if (ret)
|
||||
dev_err(nn->dev, "fail to read reg 0x%x: %d\n", reg, ret);
|
||||
else
|
||||
*val = FIELD_GET(N3000_NS_STAT_RD_DATA, v);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct regmap_config n3000_nios_regbus_cfg = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
|
||||
.reg_write = n3000_nios_reg_write,
|
||||
.reg_read = n3000_nios_reg_read,
|
||||
};
|
||||
|
||||
static int n3000_nios_probe(struct dfl_device *ddev)
|
||||
{
|
||||
struct device *dev = &ddev->dev;
|
||||
struct n3000_nios *nn;
|
||||
int ret;
|
||||
|
||||
nn = devm_kzalloc(dev, sizeof(*nn), GFP_KERNEL);
|
||||
if (!nn)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&ddev->dev, nn);
|
||||
|
||||
nn->dev = dev;
|
||||
|
||||
nn->base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res);
|
||||
if (IS_ERR(nn->base))
|
||||
return PTR_ERR(nn->base);
|
||||
|
||||
nn->regmap = devm_regmap_init(dev, NULL, nn, &n3000_nios_regbus_cfg);
|
||||
if (IS_ERR(nn->regmap))
|
||||
return PTR_ERR(nn->regmap);
|
||||
|
||||
ret = n3000_nios_init_done_check(nn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = create_altera_spi_controller(nn);
|
||||
if (ret)
|
||||
dev_err(dev, "altera spi controller create failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void n3000_nios_remove(struct dfl_device *ddev)
|
||||
{
|
||||
struct n3000_nios *nn = dev_get_drvdata(&ddev->dev);
|
||||
|
||||
destroy_altera_spi_controller(nn);
|
||||
}
|
||||
|
||||
#define FME_FEATURE_ID_N3000_NIOS 0xd
|
||||
|
||||
static const struct dfl_device_id n3000_nios_ids[] = {
|
||||
{ FME_ID, FME_FEATURE_ID_N3000_NIOS },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dfl, n3000_nios_ids);
|
||||
|
||||
static struct dfl_driver n3000_nios_driver = {
|
||||
.drv = {
|
||||
.name = "dfl-n3000-nios",
|
||||
.dev_groups = n3000_nios_groups,
|
||||
},
|
||||
.id_table = n3000_nios_ids,
|
||||
.probe = n3000_nios_probe,
|
||||
.remove = n3000_nios_remove,
|
||||
};
|
||||
|
||||
module_dfl_driver(n3000_nios_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for Nios private feature on Intel PAC N3000");
|
||||
MODULE_AUTHOR("Intel Corporation");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -27,6 +27,14 @@
|
|||
#define DRV_VERSION "0.8"
|
||||
#define DRV_NAME "dfl-pci"
|
||||
|
||||
#define PCI_VSEC_ID_INTEL_DFLS 0x43
|
||||
|
||||
#define PCI_VNDR_DFLS_CNT 0x8
|
||||
#define PCI_VNDR_DFLS_RES 0xc
|
||||
|
||||
#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
|
||||
#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
|
||||
|
||||
struct cci_drvdata {
|
||||
struct dfl_fpga_cdev *cdev; /* container device */
|
||||
};
|
||||
|
@ -119,49 +127,94 @@ static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
|
|||
return table;
|
||||
}
|
||||
|
||||
/* enumerate feature devices under pci device */
|
||||
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
static int find_dfls_by_vsec(struct pci_dev *pcidev, struct dfl_fpga_enum_info *info)
|
||||
{
|
||||
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
|
||||
int port_num, bar, i, nvec, ret = 0;
|
||||
struct dfl_fpga_enum_info *info;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
u32 bir, offset, vndr_hdr, dfl_cnt, dfl_res;
|
||||
int dfl_res_off, i, bars, voff = 0;
|
||||
resource_size_t start, len;
|
||||
|
||||
while ((voff = pci_find_next_ext_capability(pcidev, voff, PCI_EXT_CAP_ID_VNDR))) {
|
||||
vndr_hdr = 0;
|
||||
pci_read_config_dword(pcidev, voff + PCI_VNDR_HEADER, &vndr_hdr);
|
||||
|
||||
if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
|
||||
pcidev->vendor == PCI_VENDOR_ID_INTEL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!voff) {
|
||||
dev_dbg(&pcidev->dev, "%s no DFL VSEC found\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dfl_cnt = 0;
|
||||
pci_read_config_dword(pcidev, voff + PCI_VNDR_DFLS_CNT, &dfl_cnt);
|
||||
if (dfl_cnt > PCI_STD_NUM_BARS) {
|
||||
dev_err(&pcidev->dev, "%s too many DFLs %d > %d\n",
|
||||
__func__, dfl_cnt, PCI_STD_NUM_BARS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dfl_res_off = voff + PCI_VNDR_DFLS_RES;
|
||||
if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
|
||||
dev_err(&pcidev->dev, "%s DFL VSEC too big for PCIe config space\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0, bars = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
|
||||
dfl_res = GENMASK(31, 0);
|
||||
pci_read_config_dword(pcidev, dfl_res_off, &dfl_res);
|
||||
|
||||
bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
|
||||
if (bir >= PCI_STD_NUM_BARS) {
|
||||
dev_err(&pcidev->dev, "%s bad bir number %d\n",
|
||||
__func__, bir);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bars & BIT(bir)) {
|
||||
dev_err(&pcidev->dev, "%s DFL for BAR %d already specified\n",
|
||||
__func__, bir);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bars |= BIT(bir);
|
||||
|
||||
len = pci_resource_len(pcidev, bir);
|
||||
offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
|
||||
if (offset >= len) {
|
||||
dev_err(&pcidev->dev, "%s bad offset %u >= %pa\n",
|
||||
__func__, offset, &len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pcidev->dev, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
|
||||
|
||||
len -= offset;
|
||||
|
||||
start = pci_resource_start(pcidev, bir) + offset;
|
||||
|
||||
dfl_fpga_enum_info_add_dfl(info, start, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* default method of finding dfls starting at offset 0 of bar 0 */
|
||||
static int find_dfls_by_default(struct pci_dev *pcidev,
|
||||
struct dfl_fpga_enum_info *info)
|
||||
{
|
||||
int port_num, bar, i, ret = 0;
|
||||
resource_size_t start, len;
|
||||
void __iomem *base;
|
||||
int *irq_table;
|
||||
u32 offset;
|
||||
u64 v;
|
||||
|
||||
/* allocate enumeration info via pci_dev */
|
||||
info = dfl_fpga_enum_info_alloc(&pcidev->dev);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* add irq info for enumeration if the device support irq */
|
||||
nvec = cci_pci_alloc_irq(pcidev);
|
||||
if (nvec < 0) {
|
||||
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
|
||||
ret = nvec;
|
||||
goto enum_info_free_exit;
|
||||
} else if (nvec) {
|
||||
irq_table = cci_pci_create_irq_table(pcidev, nvec);
|
||||
if (!irq_table) {
|
||||
ret = -ENOMEM;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
|
||||
kfree(irq_table);
|
||||
if (ret)
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
/* start to find Device Feature List in Bar 0 */
|
||||
/* start to find Device Feature List from Bar 0 */
|
||||
base = cci_pci_ioremap_bar0(pcidev);
|
||||
if (!base) {
|
||||
ret = -ENOMEM;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* PF device has FME and Ports/AFUs, and VF device only has one
|
||||
|
@ -208,12 +261,54 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
|||
dfl_fpga_enum_info_add_dfl(info, start, len);
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
/* release I/O mappings for next step enumeration */
|
||||
pcim_iounmap_regions(pcidev, BIT(0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enumerate feature devices under pci device */
|
||||
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
{
|
||||
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
|
||||
struct dfl_fpga_enum_info *info;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
int nvec, ret = 0;
|
||||
int *irq_table;
|
||||
|
||||
/* allocate enumeration info via pci_dev */
|
||||
info = dfl_fpga_enum_info_alloc(&pcidev->dev);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* add irq info for enumeration if the device support irq */
|
||||
nvec = cci_pci_alloc_irq(pcidev);
|
||||
if (nvec < 0) {
|
||||
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
|
||||
ret = nvec;
|
||||
goto enum_info_free_exit;
|
||||
} else if (nvec) {
|
||||
irq_table = cci_pci_create_irq_table(pcidev, nvec);
|
||||
if (!irq_table) {
|
||||
ret = -ENOMEM;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
|
||||
kfree(irq_table);
|
||||
if (ret)
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
ret = find_dfls_by_vsec(pcidev, info);
|
||||
if (ret == -ENODEV)
|
||||
ret = find_dfls_by_default(pcidev, info);
|
||||
|
||||
if (ret)
|
||||
goto irq_free_exit;
|
||||
|
||||
/* start enumeration with prepared enumeration information */
|
||||
cdev = dfl_fpga_feature_devs_enumerate(info);
|
||||
if (IS_ERR(cdev)) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* Wu Hao <hao.wu@intel.com>
|
||||
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
|
||||
*/
|
||||
#include <linux/dfl.h>
|
||||
#include <linux/fpga-dfl.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
@ -298,8 +299,7 @@ static int dfl_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
{
|
||||
struct dfl_device *ddev = to_dfl_dev(dev);
|
||||
|
||||
/* The type has 4 valid bits and feature_id has 12 valid bits */
|
||||
return add_uevent_var(env, "MODALIAS=dfl:t%01Xf%03X",
|
||||
return add_uevent_var(env, "MODALIAS=dfl:t%04Xf%04X",
|
||||
ddev->type, ddev->feature_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uuid.h>
|
||||
|
@ -516,88 +517,4 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
|
|||
struct dfl_feature *feature,
|
||||
unsigned long arg);
|
||||
|
||||
/**
|
||||
* enum dfl_id_type - define the DFL FIU types
|
||||
*/
|
||||
enum dfl_id_type {
|
||||
FME_ID,
|
||||
PORT_ID,
|
||||
DFL_ID_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_device_id - dfl device identifier
|
||||
* @type: contains 4 bits DFL FIU type of the device. See enum dfl_id_type.
|
||||
* @feature_id: contains 12 bits feature identifier local to its DFL FIU type.
|
||||
* @driver_data: driver specific data.
|
||||
*/
|
||||
struct dfl_device_id {
|
||||
u8 type;
|
||||
u16 feature_id;
|
||||
unsigned long driver_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_device - represent an dfl device on dfl bus
|
||||
*
|
||||
* @dev: generic device interface.
|
||||
* @id: id of the dfl device.
|
||||
* @type: type of DFL FIU of the device. See enum dfl_id_type.
|
||||
* @feature_id: 16 bits feature identifier local to its DFL FIU type.
|
||||
* @mmio_res: mmio resource of this dfl device.
|
||||
* @irqs: list of Linux IRQ numbers of this dfl device.
|
||||
* @num_irqs: number of IRQs supported by this dfl device.
|
||||
* @cdev: pointer to DFL FPGA container device this dfl device belongs to.
|
||||
* @id_entry: matched id entry in dfl driver's id table.
|
||||
*/
|
||||
struct dfl_device {
|
||||
struct device dev;
|
||||
int id;
|
||||
u8 type;
|
||||
u16 feature_id;
|
||||
struct resource mmio_res;
|
||||
int *irqs;
|
||||
unsigned int num_irqs;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
const struct dfl_device_id *id_entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_driver - represent an dfl device driver
|
||||
*
|
||||
* @drv: driver model structure.
|
||||
* @id_table: pointer to table of device IDs the driver is interested in.
|
||||
* { } member terminated.
|
||||
* @probe: mandatory callback for device binding.
|
||||
* @remove: callback for device unbinding.
|
||||
*/
|
||||
struct dfl_driver {
|
||||
struct device_driver drv;
|
||||
const struct dfl_device_id *id_table;
|
||||
|
||||
int (*probe)(struct dfl_device *dfl_dev);
|
||||
void (*remove)(struct dfl_device *dfl_dev);
|
||||
};
|
||||
|
||||
#define to_dfl_dev(d) container_of(d, struct dfl_device, dev)
|
||||
#define to_dfl_drv(d) container_of(d, struct dfl_driver, drv)
|
||||
|
||||
/*
|
||||
* use a macro to avoid include chaining to get THIS_MODULE.
|
||||
*/
|
||||
#define dfl_driver_register(drv) \
|
||||
__dfl_driver_register(drv, THIS_MODULE)
|
||||
int __dfl_driver_register(struct dfl_driver *dfl_drv, struct module *owner);
|
||||
void dfl_driver_unregister(struct dfl_driver *dfl_drv);
|
||||
|
||||
/*
|
||||
* module_dfl_driver() - Helper macro for drivers that don't do
|
||||
* anything special in module init/exit. This eliminates a lot of
|
||||
* boilerplate. Each module may only use this macro once, and
|
||||
* calling it replaces module_init() and module_exit().
|
||||
*/
|
||||
#define module_dfl_driver(__dfl_driver) \
|
||||
module_driver(__dfl_driver, dfl_driver_register, \
|
||||
dfl_driver_unregister)
|
||||
|
||||
#endif /* __FPGA_DFL_H */
|
||||
|
|
|
@ -17,7 +17,7 @@ static DEFINE_IDA(fpga_bridge_ida);
|
|||
static struct class *fpga_bridge_class;
|
||||
|
||||
/* Lock for adding/removing bridges to linked lists*/
|
||||
static spinlock_t bridge_list_lock;
|
||||
static DEFINE_SPINLOCK(bridge_list_lock);
|
||||
|
||||
/**
|
||||
* fpga_bridge_enable - Enable transactions on the bridge
|
||||
|
@ -479,8 +479,6 @@ static void fpga_bridge_dev_release(struct device *dev)
|
|||
|
||||
static int __init fpga_bridge_dev_init(void)
|
||||
{
|
||||
spin_lock_init(&bridge_list_lock);
|
||||
|
||||
fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge");
|
||||
if (IS_ERR(fpga_bridge_class))
|
||||
return PTR_ERR(fpga_bridge_class);
|
||||
|
|
|
@ -567,12 +567,9 @@ static int cport_enable(struct gb_host_device *hd, u16 cport_id,
|
|||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_INTERFACE, cport_id, 0,
|
||||
req, sizeof(*req), ES2_USB_CTRL_TIMEOUT);
|
||||
if (ret != sizeof(*req)) {
|
||||
if (ret < 0) {
|
||||
dev_err(&udev->dev, "failed to set cport flags for port %d\n",
|
||||
cport_id);
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -961,12 +958,10 @@ static int arpc_send(struct es2_ap_dev *es2, struct arpc *rpc, int timeout)
|
|||
0, 0,
|
||||
rpc->req, le16_to_cpu(rpc->req->size),
|
||||
ES2_USB_CTRL_TIMEOUT);
|
||||
if (retval != le16_to_cpu(rpc->req->size)) {
|
||||
if (retval < 0) {
|
||||
dev_err(&udev->dev,
|
||||
"failed to send ARPC request %d: %d\n",
|
||||
rpc->req->type, retval);
|
||||
if (retval > 0)
|
||||
retval = -EIO;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ DECLARE_EVENT_CLASS(gb_message,
|
|||
__entry->result = message->header->result;
|
||||
),
|
||||
|
||||
TP_printk("size=%hu operation_id=0x%04x type=0x%02x result=0x%02x",
|
||||
TP_printk("size=%u operation_id=0x%04x type=0x%02x result=0x%02x",
|
||||
__entry->size, __entry->operation_id,
|
||||
__entry->type, __entry->result)
|
||||
);
|
||||
|
@ -317,7 +317,7 @@ DECLARE_EVENT_CLASS(gb_interface,
|
|||
__entry->mode_switch = intf->mode_switch;
|
||||
),
|
||||
|
||||
TP_printk("intf_id=%hhu device_id=%hhu module_id=%hhu D=%d J=%d A=%d E=%d M=%d",
|
||||
TP_printk("intf_id=%u device_id=%u module_id=%u D=%d J=%d A=%d E=%d M=%d",
|
||||
__entry->id, __entry->device_id, __entry->module_id,
|
||||
__entry->disconnected, __entry->ejected, __entry->active,
|
||||
__entry->enabled, __entry->mode_switch)
|
||||
|
@ -391,7 +391,7 @@ DECLARE_EVENT_CLASS(gb_module,
|
|||
__entry->disconnected = module->disconnected;
|
||||
),
|
||||
|
||||
TP_printk("hd_bus_id=%d module_id=%hhu num_interfaces=%zu disconnected=%d",
|
||||
TP_printk("hd_bus_id=%d module_id=%u num_interfaces=%zu disconnected=%d",
|
||||
__entry->hd_bus_id, __entry->module_id,
|
||||
__entry->num_interfaces, __entry->disconnected)
|
||||
);
|
||||
|
|
|
@ -401,8 +401,9 @@ static const struct attribute_group *catu_groups[] = {
|
|||
|
||||
static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
|
||||
{
|
||||
return coresight_timeout(drvdata->base,
|
||||
CATU_STATUS, CATU_STATUS_READY, 1);
|
||||
struct csdev_access *csa = &drvdata->csdev->access;
|
||||
|
||||
return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
|
||||
}
|
||||
|
||||
static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
|
||||
|
@ -411,6 +412,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
|
|||
u32 control, mode;
|
||||
struct etr_buf *etr_buf = data;
|
||||
struct device *dev = &drvdata->csdev->dev;
|
||||
struct coresight_device *csdev = drvdata->csdev;
|
||||
|
||||
if (catu_wait_for_ready(drvdata))
|
||||
dev_warn(dev, "Timeout while waiting for READY\n");
|
||||
|
@ -421,7 +423,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
rc = coresight_claim_device_unlocked(drvdata->base);
|
||||
rc = coresight_claim_device_unlocked(csdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -465,9 +467,10 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
|
|||
{
|
||||
int rc = 0;
|
||||
struct device *dev = &drvdata->csdev->dev;
|
||||
struct coresight_device *csdev = drvdata->csdev;
|
||||
|
||||
catu_write_control(drvdata, 0);
|
||||
coresight_disclaim_device_unlocked(drvdata->base);
|
||||
coresight_disclaim_device_unlocked(csdev);
|
||||
if (catu_wait_for_ready(drvdata)) {
|
||||
dev_info(dev, "Timeout while waiting for READY\n");
|
||||
rc = -EAGAIN;
|
||||
|
@ -551,6 +554,7 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
dev->platform_data = pdata;
|
||||
|
||||
drvdata->base = base;
|
||||
catu_desc.access = CSDEV_ACCESS_IOMEM(base);
|
||||
catu_desc.pdata = pdata;
|
||||
catu_desc.dev = dev;
|
||||
catu_desc.groups = catu_groups;
|
||||
|
|
|
@ -145,30 +145,32 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline u32 coresight_read_claim_tags(void __iomem *base)
|
||||
static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
|
||||
{
|
||||
return readl_relaxed(base + CORESIGHT_CLAIMCLR);
|
||||
return csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR);
|
||||
}
|
||||
|
||||
static inline bool coresight_is_claimed_self_hosted(void __iomem *base)
|
||||
static inline bool coresight_is_claimed_self_hosted(struct coresight_device *csdev)
|
||||
{
|
||||
return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED;
|
||||
return coresight_read_claim_tags(csdev) == CORESIGHT_CLAIM_SELF_HOSTED;
|
||||
}
|
||||
|
||||
static inline bool coresight_is_claimed_any(void __iomem *base)
|
||||
static inline bool coresight_is_claimed_any(struct coresight_device *csdev)
|
||||
{
|
||||
return coresight_read_claim_tags(base) != 0;
|
||||
return coresight_read_claim_tags(csdev) != 0;
|
||||
}
|
||||
|
||||
static inline void coresight_set_claim_tags(void __iomem *base)
|
||||
static inline void coresight_set_claim_tags(struct coresight_device *csdev)
|
||||
{
|
||||
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET);
|
||||
csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
|
||||
CORESIGHT_CLAIMSET);
|
||||
isb();
|
||||
}
|
||||
|
||||
static inline void coresight_clear_claim_tags(void __iomem *base)
|
||||
static inline void coresight_clear_claim_tags(struct coresight_device *csdev)
|
||||
{
|
||||
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR);
|
||||
csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
|
||||
CORESIGHT_CLAIMCLR);
|
||||
isb();
|
||||
}
|
||||
|
||||
|
@ -182,27 +184,33 @@ static inline void coresight_clear_claim_tags(void __iomem *base)
|
|||
* Called with CS_UNLOCKed for the component.
|
||||
* Returns : 0 on success
|
||||
*/
|
||||
int coresight_claim_device_unlocked(void __iomem *base)
|
||||
int coresight_claim_device_unlocked(struct coresight_device *csdev)
|
||||
{
|
||||
if (coresight_is_claimed_any(base))
|
||||
if (WARN_ON(!csdev))
|
||||
return -EINVAL;
|
||||
|
||||
if (coresight_is_claimed_any(csdev))
|
||||
return -EBUSY;
|
||||
|
||||
coresight_set_claim_tags(base);
|
||||
if (coresight_is_claimed_self_hosted(base))
|
||||
coresight_set_claim_tags(csdev);
|
||||
if (coresight_is_claimed_self_hosted(csdev))
|
||||
return 0;
|
||||
/* There was a race setting the tags, clean up and fail */
|
||||
coresight_clear_claim_tags(base);
|
||||
coresight_clear_claim_tags(csdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_claim_device_unlocked);
|
||||
|
||||
int coresight_claim_device(void __iomem *base)
|
||||
int coresight_claim_device(struct coresight_device *csdev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
CS_UNLOCK(base);
|
||||
rc = coresight_claim_device_unlocked(base);
|
||||
CS_LOCK(base);
|
||||
if (WARN_ON(!csdev))
|
||||
return -EINVAL;
|
||||
|
||||
CS_UNLOCK(csdev->access.base);
|
||||
rc = coresight_claim_device_unlocked(csdev);
|
||||
CS_LOCK(csdev->access.base);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -212,11 +220,14 @@ EXPORT_SYMBOL_GPL(coresight_claim_device);
|
|||
* coresight_disclaim_device_unlocked : Clear the claim tags for the device.
|
||||
* Called with CS_UNLOCKed for the component.
|
||||
*/
|
||||
void coresight_disclaim_device_unlocked(void __iomem *base)
|
||||
void coresight_disclaim_device_unlocked(struct coresight_device *csdev)
|
||||
{
|
||||
|
||||
if (coresight_is_claimed_self_hosted(base))
|
||||
coresight_clear_claim_tags(base);
|
||||
if (WARN_ON(!csdev))
|
||||
return;
|
||||
|
||||
if (coresight_is_claimed_self_hosted(csdev))
|
||||
coresight_clear_claim_tags(csdev);
|
||||
else
|
||||
/*
|
||||
* The external agent may have not honoured our claim
|
||||
|
@ -227,11 +238,14 @@ void coresight_disclaim_device_unlocked(void __iomem *base)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_disclaim_device_unlocked);
|
||||
|
||||
void coresight_disclaim_device(void __iomem *base)
|
||||
void coresight_disclaim_device(struct coresight_device *csdev)
|
||||
{
|
||||
CS_UNLOCK(base);
|
||||
coresight_disclaim_device_unlocked(base);
|
||||
CS_LOCK(base);
|
||||
if (WARN_ON(!csdev))
|
||||
return;
|
||||
|
||||
CS_UNLOCK(csdev->access.base);
|
||||
coresight_disclaim_device_unlocked(csdev);
|
||||
CS_LOCK(csdev->access.base);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_disclaim_device);
|
||||
|
||||
|
@ -1418,23 +1432,24 @@ static void coresight_remove_conns(struct coresight_device *csdev)
|
|||
}
|
||||
|
||||
/**
|
||||
* coresight_timeout - loop until a bit has changed to a specific state.
|
||||
* @addr: base address of the area of interest.
|
||||
* @offset: address of a register, starting from @addr.
|
||||
* coresight_timeout - loop until a bit has changed to a specific register
|
||||
* state.
|
||||
* @csa: coresight device access for the device
|
||||
* @offset: Offset of the register from the base of the device.
|
||||
* @position: the position of the bit of interest.
|
||||
* @value: the value the bit should have.
|
||||
*
|
||||
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
|
||||
* TIMEOUT_US has elapsed, which ever happens first.
|
||||
*/
|
||||
|
||||
int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
|
||||
int coresight_timeout(struct csdev_access *csa, u32 offset,
|
||||
int position, int value)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
for (i = TIMEOUT_US; i > 0; i--) {
|
||||
val = __raw_readl(addr + offset);
|
||||
val = csdev_access_read32(csa, offset);
|
||||
/* waiting on the bit to go from 0 to 1 */
|
||||
if (value) {
|
||||
if (val & BIT(position))
|
||||
|
@ -1458,6 +1473,48 @@ int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(coresight_timeout);
|
||||
|
||||
u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
return csdev_access_relaxed_read32(&csdev->access, offset);
|
||||
}
|
||||
|
||||
u32 coresight_read32(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
return csdev_access_read32(&csdev->access, offset);
|
||||
}
|
||||
|
||||
void coresight_relaxed_write32(struct coresight_device *csdev,
|
||||
u32 val, u32 offset)
|
||||
{
|
||||
csdev_access_relaxed_write32(&csdev->access, val, offset);
|
||||
}
|
||||
|
||||
void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset)
|
||||
{
|
||||
csdev_access_write32(&csdev->access, val, offset);
|
||||
}
|
||||
|
||||
u64 coresight_relaxed_read64(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
return csdev_access_relaxed_read64(&csdev->access, offset);
|
||||
}
|
||||
|
||||
u64 coresight_read64(struct coresight_device *csdev, u32 offset)
|
||||
{
|
||||
return csdev_access_read64(&csdev->access, offset);
|
||||
}
|
||||
|
||||
void coresight_relaxed_write64(struct coresight_device *csdev,
|
||||
u64 val, u32 offset)
|
||||
{
|
||||
csdev_access_relaxed_write64(&csdev->access, val, offset);
|
||||
}
|
||||
|
||||
void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
|
||||
{
|
||||
csdev_access_write64(&csdev->access, val, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* coresight_release_platform_data: Release references to the devices connected
|
||||
* to the output port of this device.
|
||||
|
@ -1522,6 +1579,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
|||
csdev->type = desc->type;
|
||||
csdev->subtype = desc->subtype;
|
||||
csdev->ops = desc->ops;
|
||||
csdev->access = desc->access;
|
||||
csdev->orphan = false;
|
||||
|
||||
csdev->dev.type = &coresight_dev_type[desc->type];
|
||||
|
|
|
@ -102,7 +102,7 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
|
|||
goto cti_state_unchanged;
|
||||
|
||||
/* claim the device */
|
||||
rc = coresight_claim_device(drvdata->base);
|
||||
rc = coresight_claim_device(drvdata->csdev);
|
||||
if (rc)
|
||||
goto cti_err_not_enabled;
|
||||
|
||||
|
@ -136,7 +136,7 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
|
|||
goto cti_hp_not_enabled;
|
||||
|
||||
/* try to claim the device */
|
||||
if (coresight_claim_device(drvdata->base))
|
||||
if (coresight_claim_device(drvdata->csdev))
|
||||
goto cti_hp_not_enabled;
|
||||
|
||||
cti_write_all_hw_regs(drvdata);
|
||||
|
@ -154,6 +154,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
|
|||
{
|
||||
struct cti_config *config = &drvdata->config;
|
||||
struct device *dev = &drvdata->csdev->dev;
|
||||
struct coresight_device *csdev = drvdata->csdev;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
|
||||
|
@ -171,7 +172,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
|
|||
writel_relaxed(0, drvdata->base + CTICONTROL);
|
||||
config->hw_enabled = false;
|
||||
|
||||
coresight_disclaim_device_unlocked(drvdata->base);
|
||||
coresight_disclaim_device_unlocked(csdev);
|
||||
CS_LOCK(drvdata->base);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
pm_runtime_put(dev);
|
||||
|
@ -655,6 +656,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
|
|||
void *v)
|
||||
{
|
||||
struct cti_drvdata *drvdata;
|
||||
struct coresight_device *csdev;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int notify_res = NOTIFY_OK;
|
||||
|
||||
|
@ -662,6 +664,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
|
|||
return NOTIFY_OK;
|
||||
|
||||
drvdata = cti_cpu_drvdata[cpu];
|
||||
csdev = drvdata->csdev;
|
||||
|
||||
if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))
|
||||
return NOTIFY_BAD;
|
||||
|
@ -673,13 +676,13 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
|
|||
/* CTI regs all static - we have a copy & nothing to save */
|
||||
drvdata->config.hw_powered = false;
|
||||
if (drvdata->config.hw_enabled)
|
||||
coresight_disclaim_device(drvdata->base);
|
||||
coresight_disclaim_device(csdev);
|
||||
break;
|
||||
|
||||
case CPU_PM_ENTER_FAILED:
|
||||
drvdata->config.hw_powered = true;
|
||||
if (drvdata->config.hw_enabled) {
|
||||
if (coresight_claim_device(drvdata->base))
|
||||
if (coresight_claim_device(csdev))
|
||||
drvdata->config.hw_enabled = false;
|
||||
}
|
||||
break;
|
||||
|
@ -692,7 +695,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
|
|||
/* check enable reference count to enable HW */
|
||||
if (atomic_read(&drvdata->config.enable_req_count)) {
|
||||
/* check we can claim the device as we re-power */
|
||||
if (coresight_claim_device(drvdata->base))
|
||||
if (coresight_claim_device(csdev))
|
||||
goto cti_notify_exit;
|
||||
|
||||
drvdata->config.hw_enabled = true;
|
||||
|
@ -736,7 +739,7 @@ static int cti_dying_cpu(unsigned int cpu)
|
|||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->config.hw_powered = false;
|
||||
if (drvdata->config.hw_enabled)
|
||||
coresight_disclaim_device(drvdata->base);
|
||||
coresight_disclaim_device(drvdata->csdev);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -868,6 +871,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
return PTR_ERR(base);
|
||||
|
||||
drvdata->base = base;
|
||||
cti_desc.access = CSDEV_ACCESS_IOMEM(base);
|
||||
|
||||
dev_set_drvdata(dev, drvdata);
|
||||
|
||||
|
|
|
@ -343,7 +343,6 @@ static int cti_plat_create_connection(struct device *dev,
|
|||
{
|
||||
struct cti_trig_con *tc = NULL;
|
||||
int cpuid = -1, err = 0;
|
||||
struct fwnode_handle *cs_fwnode = NULL;
|
||||
struct coresight_device *csdev = NULL;
|
||||
const char *assoc_name = "unknown";
|
||||
char cpu_name_str[16];
|
||||
|
@ -397,8 +396,9 @@ static int cti_plat_create_connection(struct device *dev,
|
|||
assoc_name = cpu_name_str;
|
||||
} else {
|
||||
/* associated device ? */
|
||||
cs_fwnode = fwnode_find_reference(fwnode,
|
||||
CTI_DT_CSDEV_ASSOC, 0);
|
||||
struct fwnode_handle *cs_fwnode = fwnode_find_reference(fwnode,
|
||||
CTI_DT_CSDEV_ASSOC,
|
||||
0);
|
||||
if (!IS_ERR(cs_fwnode)) {
|
||||
assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode,
|
||||
&csdev);
|
||||
|
|
|
@ -132,7 +132,7 @@ static void __etb_enable_hw(struct etb_drvdata *drvdata)
|
|||
|
||||
static int etb_enable_hw(struct etb_drvdata *drvdata)
|
||||
{
|
||||
int rc = coresight_claim_device(drvdata->base);
|
||||
int rc = coresight_claim_device(drvdata->csdev);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -252,6 +252,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
|
|||
{
|
||||
u32 ffcr;
|
||||
struct device *dev = &drvdata->csdev->dev;
|
||||
struct csdev_access *csa = &drvdata->csdev->access;
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
|
@ -263,7 +264,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
|
|||
ffcr |= ETB_FFCR_FON_MAN;
|
||||
writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
|
||||
|
||||
if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
|
||||
if (coresight_timeout(csa, ETB_FFCR, ETB_FFCR_BIT, 0)) {
|
||||
dev_err(dev,
|
||||
"timeout while waiting for completion of Manual Flush\n");
|
||||
}
|
||||
|
@ -271,7 +272,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
|
|||
/* disable trace capture */
|
||||
writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
|
||||
|
||||
if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
|
||||
if (coresight_timeout(csa, ETB_FFSR, ETB_FFSR_BIT, 1)) {
|
||||
dev_err(dev,
|
||||
"timeout while waiting for Formatter to Stop\n");
|
||||
}
|
||||
|
@ -344,7 +345,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
|
|||
{
|
||||
__etb_disable_hw(drvdata);
|
||||
etb_dump_hw(drvdata);
|
||||
coresight_disclaim_device(drvdata->base);
|
||||
coresight_disclaim_device(drvdata->csdev);
|
||||
}
|
||||
|
||||
static int etb_disable(struct coresight_device *csdev)
|
||||
|
@ -757,6 +758,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
return PTR_ERR(base);
|
||||
|
||||
drvdata->base = base;
|
||||
desc.access = CSDEV_ACCESS_IOMEM(base);
|
||||
|
||||
spin_lock_init(&drvdata->spinlock);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue