mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
USB / Thunderbolt / PHY driver update for 6.6-rc1
Here is the big set of USB, Thunderbolt, and PHY driver updates for 6.6-rc1. Included in here are: - PHY driver additions and cleanups - Thunderbolt minor additions and fixes - USB MIDI 2 gadget support added - dwc3 driver updates and additions - Removal of some old USB wireless code that was missed when that codebase was originally removed a few years ago, cleaning up some core USB code paths - USB core potential use-after-free fixes that syzbot from different people/groups keeps tripping over - typec updates and additions - gadget fixes and cleanups - loads of smaller USB core and driver cleanups all over the place Full details are in the shortlog. All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZPIAOQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yn80gCgybzMp0YnSildFetSC8lUJTnzjQcAn3KWzb75 Zt72jxGl4ZOXHEpozG4O =FLrK -----END PGP SIGNATURE----- Merge tag 'usb-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt / PHY driver updates from Greg KH: "Here is the big set of USB, Thunderbolt, and PHY driver updates for 6.6-rc1. Included in here are: - PHY driver additions and cleanups - Thunderbolt minor additions and fixes - USB MIDI 2 gadget support added - dwc3 driver updates and additions - Removal of some old USB wireless code that was missed when that codebase was originally removed a few years ago, cleaning up some core USB code paths - USB core potential use-after-free fixes that syzbot from different people/groups keeps tripping over - typec updates and additions - gadget fixes and cleanups - loads of smaller USB core and driver cleanups all over the place Full details are in the shortlog. All of these have been in linux-next for a while with no reported problems" * tag 'usb-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (154 commits) platform/chrome: cros_ec_typec: Configure Retimer cable type tcpm: Avoid soft reset when partner does not support get_status usb: typec: tcpm: reset counter when enter into unattached state after try role usb: typec: tcpm: set initial svdm version based on pd revision USB: serial: option: add FOXCONN T99W368/T99W373 product USB: serial: option: add Quectel EM05G variant (0x030e) usb: dwc2: add pci_device_id driver_data parse support usb: gadget: remove max support speed info in bind operation usb: gadget: composite: cleanup function config_ep_by_speed_and_alt() usb: gadget: config: remove max speed check in usb_assign_descriptors() usb: gadget: unconditionally allocate hs/ss descriptor in bind operation usb: gadget: f_uvc: change endpoint allocation in uvc_function_bind() usb: gadget: add a inline function gether_bitrate() usb: gadget: use working speed to calcaulate network bitrate and qlen dt-bindings: usb: samsung,exynos-dwc3: Add Exynos850 support usb: dwc3: exynos: Add support for Exynos850 variant usb: gadget: udc-xilinx: fix incorrect type in assignment warning usb: gadget: udc-xilinx: fix cast from restricted __le16 warning usb: gadget: udc-xilinx: fix restricted __le16 degrades to integer warning USB: dwc2: hande irq on dead controller correctly ...
This commit is contained in:
commit
51e7accbe8
11
CREDITS
11
CREDITS
@ -666,11 +666,6 @@ S: Tamsui town, Taipei county,
|
||||
S: Taiwan 251
|
||||
S: Republic of China
|
||||
|
||||
N: Reinette Chatre
|
||||
E: reinette.chatre@intel.com
|
||||
D: WiMedia Link Protocol implementation
|
||||
D: UWB stack bits and pieces
|
||||
|
||||
N: Michael Elizabeth Chastain
|
||||
E: mec@shout.net
|
||||
D: Configure, Menuconfig, xconfig
|
||||
@ -3023,12 +3018,6 @@ S: Demonstratsii 8-382
|
||||
S: Tula 300000
|
||||
S: Russia
|
||||
|
||||
N: Inaky Perez-Gonzalez
|
||||
E: inaky.perez-gonzalez@intel.com
|
||||
D: UWB stack, HWA-RC driver and HWA-HC drivers
|
||||
D: Wireless USB additions to the USB stack
|
||||
D: WiMedia Link Protocol bits and pieces
|
||||
|
||||
N: Gordon Peters
|
||||
E: GordPeters@smarttech.com
|
||||
D: Isochronous receive for IEEE 1394 driver (OHCI module).
|
||||
|
54
Documentation/ABI/testing/configfs-usb-gadget-midi2
Normal file
54
Documentation/ABI/testing/configfs-usb-gadget-midi2
Normal file
@ -0,0 +1,54 @@
|
||||
What: /config/usb-gadget/gadget/functions/midi2.name
|
||||
Date: Jul 2023
|
||||
KernelVersion: 6.6
|
||||
Description:
|
||||
The attributes:
|
||||
|
||||
============ ===============================================
|
||||
process_ump Flag to process UMP Stream messages (0 or 1)
|
||||
static_block Flag for static blocks (0 or 1)
|
||||
iface_name MIDI interface name string
|
||||
============ ===============================================
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/midi2.name/ep.number
|
||||
Date: Jul 2023
|
||||
KernelVersion: 6.6
|
||||
Description:
|
||||
This group contains a UMP Endpoint configuration.
|
||||
A new Endpoint starts from 0, and can be up to 3.
|
||||
|
||||
The attributes:
|
||||
|
||||
============= ===============================================
|
||||
protocol_caps MIDI protocol capabilities (1, 2 or 3 for both)
|
||||
protocol Default MIDI protocol (1 or 2)
|
||||
ep_name UMP Endpoint name string
|
||||
product_id Product ID string
|
||||
manufacturer Manufacture ID (24 bit)
|
||||
family Device family ID (16 bit)
|
||||
model Device model ID (16 bit)
|
||||
sw_revision Software Revision (32 bit)
|
||||
============= ===============================================
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/midi2.name/ep.number/block.number
|
||||
Date: Jul 2023
|
||||
KernelVersion: 6.6
|
||||
Description:
|
||||
This group contains a UMP Function Block configuration.
|
||||
A new block starts from 0, and can be up to 31.
|
||||
|
||||
The attributes:
|
||||
|
||||
================= ==============================================
|
||||
name Function Block name string
|
||||
direction 1: input, 2: output, 3: bidirectional
|
||||
first_group The first UMP Group number (0-15)
|
||||
num_groups The number of groups in this FB (1-16)
|
||||
midi1_first_group The first UMP Group number for MIDI 1.0 (0-15)
|
||||
midi1_num_groups The number of groups for MIDI 1.0 (0-16)
|
||||
ui_hint 0: unknown, 1: receiver, 2: sender, 3: both
|
||||
midi_ci_verison Supported MIDI-CI version number (8 bit)
|
||||
is_midi1 Legacy MIDI 1.0 device (0, 1 or 2)
|
||||
sysex8_streams Max number of SysEx8 streams (8 bit)
|
||||
active Active FB flag (0 or 1)
|
||||
================= ==============================================
|
@ -1,7 +1,7 @@
|
||||
What: /sys/bus/thunderbolt/devices/.../domainX/boot_acl
|
||||
Date: Jun 2018
|
||||
KernelVersion: 4.17
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: Holds a comma separated list of device unique_ids that
|
||||
are allowed to be connected automatically during system
|
||||
startup (e.g boot devices). The list always contains
|
||||
@ -33,7 +33,7 @@ Description: This attribute tells whether the system supports
|
||||
What: /sys/bus/thunderbolt/devices/.../domainX/iommu_dma_protection
|
||||
Date: Mar 2019
|
||||
KernelVersion: 4.21
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute tells whether the system uses IOMMU
|
||||
for DMA protection. Value of 1 means IOMMU is used 0 means
|
||||
it is not (DMA protection is solely based on Thunderbolt
|
||||
@ -42,7 +42,7 @@ Description: This attribute tells whether the system uses IOMMU
|
||||
What: /sys/bus/thunderbolt/devices/.../domainX/security
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute holds current Thunderbolt security level
|
||||
set by the system BIOS. Possible values are:
|
||||
|
||||
@ -64,7 +64,7 @@ Description: This attribute holds current Thunderbolt security level
|
||||
What: /sys/bus/thunderbolt/devices/.../authorized
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute is used to authorize Thunderbolt devices
|
||||
after they have been connected. If the device is not
|
||||
authorized, no PCIe devices are available to the system.
|
||||
@ -98,7 +98,7 @@ Description: This attribute is used to authorize Thunderbolt devices
|
||||
What: /sys/bus/thunderbolt/devices/.../boot
|
||||
Date: Jun 2018
|
||||
KernelVersion: 4.17
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains 1 if Thunderbolt device was already
|
||||
authorized on boot and 0 otherwise.
|
||||
|
||||
@ -113,7 +113,7 @@ Description: This attribute contains the generation of the Thunderbolt
|
||||
What: /sys/bus/thunderbolt/devices/.../key
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: When a devices supports Thunderbolt secure connect it will
|
||||
have this attribute. Writing 32 byte hex string changes
|
||||
authorization to use the secure connection method instead.
|
||||
@ -123,14 +123,14 @@ Description: When a devices supports Thunderbolt secure connect it will
|
||||
What: /sys/bus/thunderbolt/devices/.../device
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains id of this device extracted from
|
||||
the device DROM.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/.../device_name
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains name of this device extracted from
|
||||
the device DROM.
|
||||
|
||||
@ -172,21 +172,21 @@ Description: This attribute reports number of TX lanes the device is
|
||||
What: /sys/bus/thunderbolt/devices/.../vendor
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains vendor id of this device extracted
|
||||
from the device DROM.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/.../vendor_name
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains vendor name of this device extracted
|
||||
from the device DROM.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/.../unique_id
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This attribute contains unique_id string of this device.
|
||||
This is either read from hardware registers (UUID on
|
||||
newer hardware) or based on UID from the device DROM.
|
||||
@ -195,7 +195,7 @@ Description: This attribute contains unique_id string of this device.
|
||||
What: /sys/bus/thunderbolt/devices/.../nvm_version
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: If the device has upgradeable firmware the version
|
||||
number is available here. Format: %x.%x, major.minor.
|
||||
If the device is in safe mode reading the file returns
|
||||
@ -204,7 +204,7 @@ Description: If the device has upgradeable firmware the version
|
||||
What: /sys/bus/thunderbolt/devices/.../nvm_authenticate
|
||||
Date: Sep 2017
|
||||
KernelVersion: 4.13
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: When new NVM image is written to the non-active NVM
|
||||
area (through non_activeX NVMem device), the
|
||||
authentication procedure is started by writing to
|
||||
@ -246,7 +246,7 @@ Description: For supported devices, automatically authenticate the new Thunderbo
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/key
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This contains name of the property directory the XDomain
|
||||
service exposes. This entry describes the protocol in
|
||||
question. Following directories are already reserved by
|
||||
@ -261,35 +261,35 @@ Description: This contains name of the property directory the XDomain
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/modalias
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: Stores the same MODALIAS value emitted by uevent for
|
||||
the XDomain service. Format: tbtsvc:kSpNvNrN
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/prtcid
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This contains XDomain protocol identifier the XDomain
|
||||
service supports.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/prtcvers
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This contains XDomain protocol version the XDomain
|
||||
service supports.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/prtcrevs
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This contains XDomain software version the XDomain
|
||||
service supports.
|
||||
|
||||
What: /sys/bus/thunderbolt/devices/<xdomain>.<service>/prtcstns
|
||||
Date: Jan 2018
|
||||
KernelVersion: 4.15
|
||||
Contact: thunderbolt-software@lists.01.org
|
||||
Contact: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
Description: This contains XDomain service specific settings as
|
||||
bitmask. Format: %x
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
What: /sys/bus/umc/
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The Wireless Host Controller Interface (WHCI)
|
||||
specification describes a PCI-based device with
|
||||
multiple capabilities; the UWB Multi-interface
|
||||
Controller (UMC).
|
||||
|
||||
The umc bus presents each of the individual
|
||||
capabilities as a device.
|
||||
|
||||
What: /sys/bus/umc/devices/.../capability_id
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The ID of this capability, with 0 being the radio
|
||||
controller capability.
|
||||
|
||||
What: /sys/bus/umc/devices/.../version
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The specification version this capability's hardware
|
||||
interface complies with.
|
@ -28,40 +28,6 @@ Description:
|
||||
drivers, non-authorized one are not. By default, wired
|
||||
USB devices are authorized.
|
||||
|
||||
Certified Wireless USB devices are not authorized
|
||||
initially and should be (by writing 1) after the
|
||||
device has been authenticated.
|
||||
|
||||
What: /sys/bus/usb/device/.../wusb_cdid
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
For Certified Wireless USB devices only.
|
||||
|
||||
A devices's CDID, as 16 space-separated hex octets.
|
||||
|
||||
What: /sys/bus/usb/device/.../wusb_ck
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
For Certified Wireless USB devices only.
|
||||
|
||||
Write the device's connection key (CK) to start the
|
||||
authentication of the device. The CK is 16
|
||||
space-separated hex octets.
|
||||
|
||||
What: /sys/bus/usb/device/.../wusb_disconnect
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
For Certified Wireless USB devices only.
|
||||
|
||||
Write a 1 to force the device to disconnect
|
||||
(equivalent to unplugging a wired USB device).
|
||||
|
||||
What: /sys/bus/usb/drivers/.../new_id
|
||||
Date: October 2011
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
|
@ -1,156 +0,0 @@
|
||||
What: /sys/class/uwb_rc
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
Interfaces for WiMedia Ultra Wideband Common Radio
|
||||
Platform (UWB) radio controllers.
|
||||
|
||||
Familiarity with the ECMA-368 'High Rate Ultra
|
||||
Wideband MAC and PHY Specification' is assumed.
|
||||
|
||||
What: /sys/class/uwb_rc/beacon_timeout_ms
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Description:
|
||||
If no beacons are received from a device for at least
|
||||
this time, the device will be considered to have gone
|
||||
and it will be removed. The default is 3 superframes
|
||||
(~197 ms) as required by the specification.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
An individual UWB radio controller.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/beacon
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
Write:
|
||||
|
||||
<channel>
|
||||
|
||||
to force a specific channel to be used when beaconing,
|
||||
or, if <channel> is -1, to prohibit beaconing. If
|
||||
<channel> is 0, then the default channel selection
|
||||
algorithm will be used. Valid channels depends on the
|
||||
radio controller's supported band groups.
|
||||
|
||||
Reading returns the currently active channel, or -1 if
|
||||
the radio controller is not beaconing.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/ASIE
|
||||
Date: August 2014
|
||||
KernelVersion: 3.18
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
|
||||
The application-specific information element (ASIE)
|
||||
included in this device's beacon, in space separated
|
||||
hex octets.
|
||||
|
||||
Reading returns the current ASIE. Writing replaces
|
||||
the current ASIE with the one written.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/scan
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
Write:
|
||||
|
||||
<channel> <type> [<bpst offset>]
|
||||
|
||||
to start (or stop) scanning on a channel. <type> is one of:
|
||||
|
||||
== =======================================
|
||||
0 scan
|
||||
1 scan outside BP
|
||||
2 scan while inactive
|
||||
3 scanning disabled
|
||||
4 scan (with start time of <bpst offset>)
|
||||
== =======================================
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/mac_address
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
The EUI-48, in colon-separated hex octets, for this
|
||||
radio controller. A write will change the radio
|
||||
controller's EUI-48 but only do so while the device is
|
||||
not beaconing or scanning.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
A symlink to the device (if any) of the WUSB Host
|
||||
Controller PAL using this radio controller.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
A neighbour UWB device that has either been detected
|
||||
as part of a scan or is a member of the radio
|
||||
controllers beacon group.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/BPST
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
The time (using the radio controllers internal 1 ms
|
||||
interval superframe timer) of the last beacon from
|
||||
this device was received.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/DevAddr
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
The current DevAddr of this device in colon separated
|
||||
hex octets.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/EUI_48
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
|
||||
The EUI-48 of this device in colon separated hex
|
||||
octets.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/IEs
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
The latest IEs included in this device's beacon, in
|
||||
space separated hex octets with one IE per line.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/LQE
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
Link Quality Estimate - the Signal to Noise Ratio
|
||||
(SNR) of all packets received from this device in dB.
|
||||
This gives an estimate on a suitable PHY rate. Refer
|
||||
to [ECMA-368] section 13.3 for more details.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/<EUI-48>/RSSI
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
Received Signal Strength Indication - the strength of
|
||||
the received signal in dB. LQE is a more useful
|
||||
measure of the radio link quality.
|
@ -1,57 +0,0 @@
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc/wusb_chid
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
Write the CHID (16 space-separated hex octets) for this host controller.
|
||||
This starts the host controller, allowing it to accept connection from
|
||||
WUSB devices.
|
||||
|
||||
Set an all zero CHID to stop the host controller.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc/wusb_trust_timeout
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
Devices that haven't sent a WUSB packet to the host
|
||||
within 'wusb_trust_timeout' ms are considered to have
|
||||
disconnected and are removed. The default value of
|
||||
4000 ms is the value required by the WUSB
|
||||
specification.
|
||||
|
||||
Since this relates to security (specifically, the
|
||||
lifetime of PTKs and GTKs) it should not be changed
|
||||
from the default.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc/wusb_phy_rate
|
||||
Date: August 2009
|
||||
KernelVersion: 2.6.32
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The maximum PHY rate to use for all connected devices.
|
||||
This is only of limited use for testing and
|
||||
development as the hardware's automatic rate
|
||||
adaptation is better then this simple control.
|
||||
|
||||
Refer to [ECMA-368] section 10.3.1.1 for the value to
|
||||
use.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc/wusb_dnts
|
||||
Date: June 2013
|
||||
KernelVersion: 3.11
|
||||
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
|
||||
Description:
|
||||
The device notification time slot (DNTS) count and interval in
|
||||
milliseconds that the WUSB host should use. This controls how
|
||||
often the devices will have the opportunity to send
|
||||
notifications to the host.
|
||||
|
||||
What: /sys/class/uwb_rc/uwb<N>/wusbhc/wusb_retry_count
|
||||
Date: June 2013
|
||||
KernelVersion: 3.11
|
||||
Contact: Thomas Pugliese <thomas.pugliese@gmail.com>
|
||||
Description:
|
||||
The number of retries that the WUSB host should attempt
|
||||
before reporting an error for a bus transaction. The range of
|
||||
valid values is [0..15], where 0 indicates infinite retries.
|
@ -1,101 +0,0 @@
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_*
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
Various files for managing Cable Based Association of
|
||||
(wireless) USB devices.
|
||||
|
||||
The sequence of operations should be:
|
||||
|
||||
1. Device is plugged in.
|
||||
|
||||
2. The connection manager (CM) sees a device with CBA capability.
|
||||
(the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
|
||||
|
||||
3. The CM writes the host name, supported band groups,
|
||||
and the CHID (host ID) into the wusb_host_name,
|
||||
wusb_host_band_groups and wusb_chid files. These
|
||||
get sent to the device and the CDID (if any) for
|
||||
this host is requested.
|
||||
|
||||
4. The CM can verify that the device's supported band
|
||||
groups (wusb_device_band_groups) are compatible
|
||||
with the host.
|
||||
|
||||
5. The CM reads the wusb_cdid file.
|
||||
|
||||
6. The CM looks it up its database.
|
||||
|
||||
- If it has a matching CHID,CDID entry, the device
|
||||
has been authorized before and nothing further
|
||||
needs to be done.
|
||||
|
||||
- If the CDID is zero (or the CM doesn't find a
|
||||
matching CDID in its database), the device is
|
||||
assumed to be not known. The CM may associate
|
||||
the host with device by: writing a randomly
|
||||
generated CDID to wusb_cdid and then a random CK
|
||||
to wusb_ck (this uploads the new CC to the
|
||||
device).
|
||||
|
||||
CMD may choose to prompt the user before
|
||||
associating with a new device.
|
||||
|
||||
7. Device is unplugged.
|
||||
|
||||
References:
|
||||
[WUSB-AM]
|
||||
Association Models Supplement to the
|
||||
Certified Wireless Universal Serial Bus
|
||||
Specification, version 1.0.
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_chid
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The CHID of the host formatted as 16 space-separated
|
||||
hex octets.
|
||||
|
||||
Writes fetches device's supported band groups and the
|
||||
the CDID for any existing association with this host.
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_host_name
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
A friendly name for the host as a UTF-8 encoded string.
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_host_band_groups
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The band groups supported by the host, in the format
|
||||
defined in [WUSB-AM].
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_device_band_groups
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The band groups supported by the device, in the format
|
||||
defined in [WUSB-AM].
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_cdid
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
The device's CDID formatted as 16 space-separated hex
|
||||
octets.
|
||||
|
||||
What: /sys/bus/usb/drivers/wusb_cbaf/.../wusb_ck
|
||||
Date: August 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: David Vrabel <david.vrabel@csr.com>
|
||||
Description:
|
||||
Write 16 space-separated random, hex octets to
|
||||
associate with the device.
|
@ -6719,7 +6719,7 @@
|
||||
|
||||
usbcore.authorized_default=
|
||||
[USB] Default USB device authorization:
|
||||
(default -1 = authorized except for wireless USB,
|
||||
(default -1 = authorized (same as 1),
|
||||
0 = not authorized, 1 = authorized, 2 = authorized
|
||||
if device connected to internal port)
|
||||
|
||||
|
175
Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml
Normal file
175
Documentation/devicetree/bindings/phy/realtek,usb2phy.yaml
Normal file
@ -0,0 +1,175 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2023 Realtek Semiconductor Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/realtek,usb2phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek DHC SoCs USB 2.0 PHY
|
||||
|
||||
maintainers:
|
||||
- Stanley Chang <stanley_chang@realtek.com>
|
||||
|
||||
description: |
|
||||
Realtek USB 2.0 PHY support the digital home center (DHC) RTD series SoCs.
|
||||
The USB 2.0 PHY driver is designed to support the XHCI controller. The SoCs
|
||||
support multiple XHCI controllers. One PHY device node maps to one XHCI
|
||||
controller.
|
||||
|
||||
RTD1295/RTD1619 SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each XHCI maps to one USB 2.0 PHY and map one USB 3.0 PHY on some
|
||||
controllers.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
|
||||
RTD1395 SoCs USB
|
||||
The USB architecture includes two XHCI controllers.
|
||||
The controller#0 has one USB 2.0 PHY. The controller#1 includes two USB 2.0
|
||||
PHY.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
|- phy#1
|
||||
|
||||
RTD1319/RTD1619b SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each XHCI maps to one USB 2.0 PHY and map one USB 3.0 PHY on controllers#2.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
|
||||
RTD1319d SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each xhci maps to one USB 2.0 PHY and map one USB 3.0 PHY on controllers#0.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|
||||
RTD1312c/RTD1315e SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each XHCI maps to one USB 2.0 PHY.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- realtek,rtd1295-usb2phy
|
||||
- realtek,rtd1312c-usb2phy
|
||||
- realtek,rtd1315e-usb2phy
|
||||
- realtek,rtd1319-usb2phy
|
||||
- realtek,rtd1319d-usb2phy
|
||||
- realtek,rtd1395-usb2phy
|
||||
- realtek,rtd1395-usb2phy-2port
|
||||
- realtek,rtd1619-usb2phy
|
||||
- realtek,rtd1619b-usb2phy
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: PHY data registers
|
||||
- description: PHY control registers
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
nvmem-cells:
|
||||
maxItems: 2
|
||||
description:
|
||||
Phandles to nvmem cell that contains the trimming data.
|
||||
If unspecified, default value is used.
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: usb-dc-cal
|
||||
- const: usb-dc-dis
|
||||
description:
|
||||
The following names, which correspond to each nvmem-cells.
|
||||
usb-dc-cal is the driving level for each phy specified via efuse.
|
||||
usb-dc-dis is the disconnection level for each phy specified via efuse.
|
||||
|
||||
realtek,inverse-hstx-sync-clock:
|
||||
description:
|
||||
For one of the phys of RTD1619b SoC, the synchronous clock of the
|
||||
high-speed tx must be inverted.
|
||||
type: boolean
|
||||
|
||||
realtek,driving-level:
|
||||
description:
|
||||
Control the magnitude of High speed Dp/Dm output swing (mV).
|
||||
For a different board or port, the original magnitude maybe not meet
|
||||
the specification. In this situation we can adjust the value to meet
|
||||
the specification.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 8
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
|
||||
realtek,driving-level-compensate:
|
||||
description:
|
||||
For RTD1315e SoC, the driving level can be adjusted by reading the
|
||||
efuse table. This property provides drive compensation.
|
||||
If the magnitude of High speed Dp/Dm output swing still not meet the
|
||||
specification, then we can set this value to meet the specification.
|
||||
$ref: /schemas/types.yaml#/definitions/int32
|
||||
default: 0
|
||||
minimum: -8
|
||||
maximum: 8
|
||||
|
||||
realtek,disconnection-compensate:
|
||||
description:
|
||||
This adjusts the disconnection level compensation for the different
|
||||
boards with different disconnection level.
|
||||
$ref: /schemas/types.yaml#/definitions/int32
|
||||
default: 0
|
||||
minimum: -8
|
||||
maximum: 8
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- realtek,rtd1619b-usb2phy
|
||||
then:
|
||||
properties:
|
||||
realtek,inverse-hstx-sync-clock: false
|
||||
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- realtek,rtd1315e-usb2phy
|
||||
then:
|
||||
properties:
|
||||
realtek,driving-level-compensate: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usb-phy@13214 {
|
||||
compatible = "realtek,rtd1619b-usb2phy";
|
||||
reg = <0x13214 0x4>, <0x28280 0x4>;
|
||||
#phy-cells = <0>;
|
||||
nvmem-cells = <&otp_usb_port0_dc_cal>, <&otp_usb_port0_dc_dis>;
|
||||
nvmem-cell-names = "usb-dc-cal", "usb-dc-dis";
|
||||
|
||||
realtek,inverse-hstx-sync-clock;
|
||||
realtek,driving-level = <0xa>;
|
||||
realtek,disconnection-compensate = <(-1)>;
|
||||
};
|
107
Documentation/devicetree/bindings/phy/realtek,usb3phy.yaml
Normal file
107
Documentation/devicetree/bindings/phy/realtek,usb3phy.yaml
Normal file
@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2023 Realtek Semiconductor Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/realtek,usb3phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek DHC SoCs USB 3.0 PHY
|
||||
|
||||
maintainers:
|
||||
- Stanley Chang <stanley_chang@realtek.com>
|
||||
|
||||
description: |
|
||||
Realtek USB 3.0 PHY support the digital home center (DHC) RTD series SoCs.
|
||||
The USB 3.0 PHY driver is designed to support the XHCI controller. The SoCs
|
||||
support multiple XHCI controllers. One PHY device node maps to one XHCI
|
||||
controller.
|
||||
|
||||
RTD1295/RTD1619 SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each XHCI maps to one USB 2.0 PHY and map one USB 3.0 PHY on some
|
||||
controllers.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
|
||||
RTD1319/RTD1619b SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each XHCI maps to one USB 2.0 PHY and map one USB 3.0 PHY on controllers#2.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
|
||||
RTD1319d SoCs USB
|
||||
The USB architecture includes three XHCI controllers.
|
||||
Each xhci maps to one USB 2.0 PHY and map one USB 3.0 PHY on controllers#0.
|
||||
XHCI controller#0 -- usb2phy -- phy#0
|
||||
|- usb3phy -- phy#0
|
||||
XHCI controller#1 -- usb2phy -- phy#0
|
||||
XHCI controller#2 -- usb2phy -- phy#0
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- realtek,rtd1295-usb3phy
|
||||
- realtek,rtd1319-usb3phy
|
||||
- realtek,rtd1319d-usb3phy
|
||||
- realtek,rtd1619-usb3phy
|
||||
- realtek,rtd1619b-usb3phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
nvmem-cells:
|
||||
maxItems: 1
|
||||
description: A phandle to the tx lfps swing trim data provided by
|
||||
a nvmem device, if unspecified, default values shall be used.
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: usb_u3_tx_lfps_swing_trim
|
||||
|
||||
realtek,amplitude-control-coarse-tuning:
|
||||
description:
|
||||
This adjusts the signal amplitude for normal operation and beacon LFPS.
|
||||
This value is a parameter for coarse tuning.
|
||||
For different boards, if the default value is inappropriate, this
|
||||
property can be assigned to adjust.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 255
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
|
||||
realtek,amplitude-control-fine-tuning:
|
||||
description:
|
||||
This adjusts the signal amplitude for normal operation and beacon LFPS.
|
||||
This value is used for fine-tuning parameters.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 65535
|
||||
minimum: 0
|
||||
maximum: 65535
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usb-phy@13e10 {
|
||||
compatible = "realtek,rtd1319d-usb3phy";
|
||||
reg = <0x13e10 0x4>;
|
||||
#phy-cells = <0>;
|
||||
|
||||
nvmem-cells = <&otp_usb_u3_tx_lfps_swing_trim>;
|
||||
nvmem-cell-names = "usb_u3_tx_lfps_swing_trim";
|
||||
|
||||
realtek,amplitude-control-coarse-tuning = <0x77>;
|
||||
};
|
@ -34,6 +34,7 @@ properties:
|
||||
- fsl,imx23-usb
|
||||
- fsl,imx25-usb
|
||||
- fsl,imx28-usb
|
||||
- fsl,imx35-usb
|
||||
- fsl,imx50-usb
|
||||
- fsl,imx51-usb
|
||||
- fsl,imx53-usb
|
||||
@ -76,11 +77,11 @@ properties:
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
|
||||
dr_mode: true
|
||||
|
||||
@ -292,6 +293,18 @@ properties:
|
||||
minimum: 0x0
|
||||
maximum: 0xf
|
||||
|
||||
fsl,picophy-rise-fall-time-adjust:
|
||||
description:
|
||||
HS Transmitter Rise/Fall Time Adjustment. Adjust the rise/fall times
|
||||
of the high-speed transmitter waveform. It has no unit. The rise/fall
|
||||
time will be increased or decreased by a certain percentage relative
|
||||
to design default time. (0:-10%; 1:design default; 2:+15%; 3:+20%)
|
||||
Details can refer to TXRISETUNE0 bit of USBNC_n_PHY_CFG1.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
default: 1
|
||||
|
||||
usb-phy:
|
||||
description: phandle for the PHY device. Use "phys" instead.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
77
Documentation/devicetree/bindings/usb/cypress,hx3.yaml
Normal file
77
Documentation/devicetree/bindings/usb/cypress,hx3.yaml
Normal file
@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/cypress,hx3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cypress HX3 USB 3.0 hub controller family
|
||||
|
||||
maintainers:
|
||||
- Benjamin Bara <benjamin.bara@skidata.com>
|
||||
|
||||
allOf:
|
||||
- $ref: usb-device.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- usb4b4,6504
|
||||
- usb4b4,6506
|
||||
|
||||
reg: true
|
||||
|
||||
reset-gpios:
|
||||
items:
|
||||
- description: GPIO specifier for RESETN pin.
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
1V2 power supply (VDD_EFUSE, AVDD12, DVDD12).
|
||||
|
||||
vdd2-supply:
|
||||
description:
|
||||
3V3 power supply (AVDD33, VDD_IO).
|
||||
|
||||
peer-hub:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the peer hub on the controller.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- peer-hub
|
||||
- vdd-supply
|
||||
- vdd2-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
usb {
|
||||
dr_mode = "host";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* 2.0 hub on port 1 */
|
||||
hub_2_0: hub@1 {
|
||||
compatible = "usb4b4,6504";
|
||||
reg = <1>;
|
||||
peer-hub = <&hub_3_0>;
|
||||
reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
|
||||
vdd-supply = <®_1v2_usb>;
|
||||
vdd2-supply = <®_3v3_usb>;
|
||||
};
|
||||
|
||||
/* 3.0 hub on port 2 */
|
||||
hub_3_0: hub@2 {
|
||||
compatible = "usb4b4,6506";
|
||||
reg = <2>;
|
||||
peer-hub = <&hub_2_0>;
|
||||
reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
|
||||
vdd-supply = <®_1v2_usb>;
|
||||
vdd2-supply = <®_3v3_usb>;
|
||||
};
|
||||
};
|
@ -68,6 +68,7 @@ properties:
|
||||
- const: generic-ehci
|
||||
- items:
|
||||
- enum:
|
||||
- atmel,at91sam9g45-ehci
|
||||
- cavium,octeon-6335-ehci
|
||||
- ibm,usb-ehci-440epx
|
||||
- ibm,usb-ehci-460ex
|
||||
|
@ -17,6 +17,7 @@ properties:
|
||||
enum:
|
||||
- usb5e3,608
|
||||
- usb5e3,610
|
||||
- usb5e3,620
|
||||
|
||||
reg: true
|
||||
|
||||
|
@ -14,6 +14,7 @@ properties:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,ipq4019-dwc3
|
||||
- qcom,ipq5332-dwc3
|
||||
- qcom,ipq6018-dwc3
|
||||
- qcom,ipq8064-dwc3
|
||||
- qcom,ipq8074-dwc3
|
||||
@ -82,15 +83,6 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 9
|
||||
|
||||
assigned-clocks:
|
||||
items:
|
||||
- description: Phandle and clock specifier of MOCK_UTMI_CLK.
|
||||
- description: Phandle and clock specifoer of MASTER_CLK.
|
||||
|
||||
assigned-clock-rates:
|
||||
items:
|
||||
- description: Must be 19.2MHz (19200000).
|
||||
- description: Must be >= 60 MHz in HS mode, >= 125 MHz in SS mode.
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
@ -246,6 +238,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5332-dwc3
|
||||
- qcom,msm8994-dwc3
|
||||
- qcom,qcs404-dwc3
|
||||
then:
|
||||
@ -290,15 +283,23 @@ allOf:
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
clock-names:
|
||||
items:
|
||||
- const: cfg_noc
|
||||
- const: core
|
||||
- const: iface
|
||||
- const: sleep
|
||||
- const: mock_utmi
|
||||
- const: bus
|
||||
oneOf:
|
||||
- items:
|
||||
- const: cfg_noc
|
||||
- const: core
|
||||
- const: iface
|
||||
- const: sleep
|
||||
- const: mock_utmi
|
||||
- const: bus
|
||||
- items:
|
||||
- const: cfg_noc
|
||||
- const: core
|
||||
- const: sleep
|
||||
- const: mock_utmi
|
||||
- const: bus
|
||||
|
||||
- if:
|
||||
properties:
|
||||
@ -410,6 +411,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5332-dwc3
|
||||
- qcom,sdm660-dwc3
|
||||
then:
|
||||
properties:
|
||||
|
@ -15,6 +15,7 @@ properties:
|
||||
- samsung,exynos5250-dwusb3
|
||||
- samsung,exynos5433-dwusb3
|
||||
- samsung,exynos7-dwusb3
|
||||
- samsung,exynos850-dwusb3
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
@ -72,7 +73,7 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos54333-dwusb3
|
||||
const: samsung,exynos5433-dwusb3
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@ -82,8 +83,8 @@ allOf:
|
||||
items:
|
||||
- const: aclk
|
||||
- const: susp_clk
|
||||
- const: pipe_pclk
|
||||
- const: phyclk
|
||||
- const: pipe_pclk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
@ -101,6 +102,21 @@ allOf:
|
||||
- const: usbdrd30_susp_clk
|
||||
- const: usbdrd30_axius_clk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos850-dwusb3
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus_early
|
||||
- const: ref
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -420,6 +420,12 @@ USBDEVFS_CONNECTINFO
|
||||
know the devnum value already, it's the DDD value of the device file
|
||||
name.
|
||||
|
||||
USBDEVFS_GET_SPEED
|
||||
Returns the speed of the device. The speed is returned as a
|
||||
nummerical value in accordance with enum usb_device_speed
|
||||
|
||||
File modification time is not updated by this request.
|
||||
|
||||
USBDEVFS_GETDRIVER
|
||||
Returns the name of the kernel driver bound to a given interface (a
|
||||
string). Parameter is a pointer to this structure, which is
|
||||
@ -771,8 +777,7 @@ Speed may be:
|
||||
======= ======================================================
|
||||
1.5 Mbit/s for low speed USB
|
||||
12 Mbit/s for full speed USB
|
||||
480 Mbit/s for high speed USB (added for USB 2.0);
|
||||
also used for Wireless USB, which has no fixed speed
|
||||
480 Mbit/s for high speed USB (added for USB 2.0)
|
||||
5000 Mbit/s for SuperSpeed USB (added for USB 3.0)
|
||||
======= ======================================================
|
||||
|
||||
|
@ -33,12 +33,9 @@ Remove the lock down::
|
||||
|
||||
$ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
|
||||
|
||||
By default, Wired USB devices are authorized by default to
|
||||
connect. Wireless USB hosts deauthorize by default all new connected
|
||||
devices (this is so because we need to do an authentication phase
|
||||
before authorizing). Writing "2" to the authorized_default attribute
|
||||
causes kernel to only authorize by default devices connected to internal
|
||||
USB ports.
|
||||
By default, all USB devices are authorized. Writing "2" to the
|
||||
authorized_default attribute causes the kernel to authorize by default
|
||||
only devices connected to internal USB ports.
|
||||
|
||||
|
||||
Example system lockdown (lame)
|
||||
|
@ -27,6 +27,7 @@ provided by gadgets.
|
||||
18. UVC function
|
||||
19. PRINTER function
|
||||
20. UAC1 function (new API)
|
||||
21. MIDI2 function
|
||||
|
||||
|
||||
1. ACM function
|
||||
@ -965,3 +966,156 @@ e.g.::
|
||||
|
||||
$ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \
|
||||
aplay -D default:CARD=OdroidU3
|
||||
|
||||
|
||||
21. MIDI2 function
|
||||
==================
|
||||
|
||||
The function is provided by usb_f_midi2.ko module.
|
||||
It will create a virtual ALSA card containing a UMP rawmidi device
|
||||
where the UMP packet is looped back. In addition, a legacy rawmidi
|
||||
device is created. The UMP rawmidi is bound with ALSA sequencer
|
||||
clients, too.
|
||||
|
||||
Function-specific configfs interface
|
||||
------------------------------------
|
||||
|
||||
The function name to use when creating the function directory is "midi2".
|
||||
The midi2 function provides these attributes in its function directory
|
||||
as the card top-level information:
|
||||
|
||||
============= =================================================
|
||||
process_ump Bool flag to process UMP Stream messages (0 or 1)
|
||||
static_block Bool flag for static blocks (0 or 1)
|
||||
iface_name Optional interface name string
|
||||
============= =================================================
|
||||
|
||||
The directory contains a subdirectory "ep.0", and this provides the
|
||||
attributes for a UMP Endpoint (which is a pair of USB MIDI Endpoints):
|
||||
|
||||
============= =================================================
|
||||
protocol_caps MIDI protocol capabilities;
|
||||
1: MIDI 1.0, 2: MIDI 2.0, or 3: both protocols
|
||||
protocol Default MIDI protocol (either 1 or 2)
|
||||
ep_name UMP Endpoint name string
|
||||
product_id Product ID string
|
||||
manufacturer Manufacture ID number (24 bit)
|
||||
family Device family ID number (16 bit)
|
||||
model Device model ID number (16 bit)
|
||||
sw_revision Software revision (32 bit)
|
||||
============= =================================================
|
||||
|
||||
Each Endpoint subdirectory contains a subdirectory "block.0", which
|
||||
represents the Function Block for Block 0 information.
|
||||
Its attributes are:
|
||||
|
||||
================= ===============================================
|
||||
name Function Block name string
|
||||
direction Direction of this FB
|
||||
1: input, 2: output, or 3: bidirectional
|
||||
first_group The first UMP Group number (0-15)
|
||||
num_groups The number of groups in this FB (1-16)
|
||||
midi1_first_group The first UMP Group number for MIDI 1.0 (0-15)
|
||||
midi1_num_groups The number of groups for MIDI 1.0 (0-16)
|
||||
ui_hint UI-hint of this FB
|
||||
0: unknown, 1: receiver, 2: sender, 3: both
|
||||
midi_ci_verison Supported MIDI-CI version number (8 bit)
|
||||
is_midi1 Legacy MIDI 1.0 device (0-2)
|
||||
0: MIDI 2.0 device,
|
||||
1: MIDI 1.0 without restriction, or
|
||||
2: MIDI 1.0 with low speed
|
||||
sysex8_streams Max number of SysEx8 streams (8 bit)
|
||||
active Bool flag for FB activity (0 or 1)
|
||||
================= ===============================================
|
||||
|
||||
If multiple Function Blocks are required, you can add more Function
|
||||
Blocks by creating subdirectories "block.<num>" with the corresponding
|
||||
Function Block number (1, 2, ....). The FB subdirectories can be
|
||||
dynamically removed, too. Note that the Function Block numbers must be
|
||||
continuous.
|
||||
|
||||
Similarly, if you multiple UMP Endpoints are required, you can add
|
||||
more Endpoints by creating subdirectories "ep.<num>". The number must
|
||||
be continuous.
|
||||
|
||||
For emulating the old MIDI 2.0 device without UMP v1.1 support, pass 0
|
||||
to `process_ump` flag. Then the whole UMP v1.1 requests are ignored.
|
||||
|
||||
Testing the MIDI2 function
|
||||
--------------------------
|
||||
|
||||
On the device: run the gadget, and running::
|
||||
|
||||
$ cat /proc/asound/cards
|
||||
|
||||
will show a new sound card containing a MIDI2 device.
|
||||
|
||||
OTOH, on the host::
|
||||
|
||||
$ cat /proc/asound/cards
|
||||
|
||||
will show a new sound card containing either MIDI1 or MIDI2 device,
|
||||
depending on the USB audio driver configuration.
|
||||
|
||||
On both, when ALSA sequencer is enabled on the host, you can find the
|
||||
UMP MIDI client such as "MIDI 2.0 Gadget".
|
||||
|
||||
As the driver simply loops back the data, there is no need for a real
|
||||
device just for testing.
|
||||
|
||||
For testing a MIDI input from the gadget to the host (e.g. emulating a
|
||||
MIDI keyboard), you can send a MIDI stream like the following.
|
||||
|
||||
On the gadget::
|
||||
|
||||
$ aconnect -o
|
||||
....
|
||||
client 20: 'MIDI 2.0 Gadget' [type=kernel,card=1]
|
||||
0 'MIDI 2.0 '
|
||||
1 'Group 1 (MIDI 2.0 Gadget I/O)'
|
||||
$ aplaymidi -p 20:1 to_host.mid
|
||||
|
||||
On the host::
|
||||
|
||||
$ aconnect -i
|
||||
....
|
||||
client 24: 'MIDI 2.0 Gadget' [type=kernel,card=2]
|
||||
0 'MIDI 2.0 '
|
||||
1 'Group 1 (MIDI 2.0 Gadget I/O)'
|
||||
$ arecordmidi -p 24:1 from_gadget.mid
|
||||
|
||||
If you have a UMP-capable application, you can use the UMP port to
|
||||
send/receive the raw UMP packets, too. For example, aseqdump program
|
||||
with UMP support can receive from UMP port. On the host::
|
||||
|
||||
$ aseqdump -u 2 -p 24:1
|
||||
Waiting for data. Press Ctrl+C to end.
|
||||
Source Group Event Ch Data
|
||||
24:1 Group 0, Program change 0, program 0, Bank select 0:0
|
||||
24:1 Group 0, Channel pressure 0, value 0x80000000
|
||||
|
||||
For testing a MIDI output to the gadget to the host (e.g. emulating a
|
||||
MIDI synth), it'll be just other way round.
|
||||
|
||||
On the gadget::
|
||||
|
||||
$ arecordmidi -p 20:1 from_host.mid
|
||||
|
||||
On the host::
|
||||
|
||||
$ aplaymidi -p 24:1 to_gadget.mid
|
||||
|
||||
The access to MIDI 1.0 on altset 0 on the host is supported, and it's
|
||||
translated from/to UMP packets on the gadget. It's bound to only
|
||||
Function Block 0.
|
||||
|
||||
The current operation mode can be observed in ALSA control element
|
||||
"Operation Mode" for SND_CTL_IFACE_RAWMIDI. For example::
|
||||
|
||||
$ amixer -c1 contents
|
||||
numid=1,iface=RAWMIDI,name='Operation Mode'
|
||||
; type=INTEGER,access=r--v----,values=1,min=0,max=2,step=0
|
||||
: values=2
|
||||
|
||||
where 0 = unused, 1 = MIDI 1.0 (altset 0), 2 = MIDI 2.0 (altset 1).
|
||||
The example above shows it's running in 2, i.e. MIDI 2.0.
|
||||
|
@ -18,4 +18,3 @@ obj-y += crypto/
|
||||
obj-$(CONFIG_MTD) += flash_setup.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_OCTEON_ILM) += oct_ilm.o
|
||||
obj-$(CONFIG_USB) += octeon-usb.o
|
||||
|
@ -450,7 +450,6 @@ static const struct of_device_id octeon_ids[] __initconst = {
|
||||
{ .compatible = "cavium,octeon-3860-bootbus", },
|
||||
{ .compatible = "cavium,mdio-mux", },
|
||||
{ .compatible = "gpio-leds", },
|
||||
{ .compatible = "cavium,octeon-7130-usb-uctl", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -286,8 +286,7 @@ static bool mt76u_check_sg(struct mt76_dev *dev)
|
||||
struct usb_device *udev = interface_to_usbdev(uintf);
|
||||
|
||||
return (!disable_usb_sg && udev->bus->sg_tablesize > 0 &&
|
||||
(udev->bus->no_sg_constraint ||
|
||||
udev->speed == USB_SPEED_WIRELESS));
|
||||
udev->bus->no_sg_constraint);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -87,6 +87,7 @@ source "drivers/phy/motorola/Kconfig"
|
||||
source "drivers/phy/mscc/Kconfig"
|
||||
source "drivers/phy/qualcomm/Kconfig"
|
||||
source "drivers/phy/ralink/Kconfig"
|
||||
source "drivers/phy/realtek/Kconfig"
|
||||
source "drivers/phy/renesas/Kconfig"
|
||||
source "drivers/phy/rockchip/Kconfig"
|
||||
source "drivers/phy/samsung/Kconfig"
|
||||
|
@ -26,6 +26,7 @@ obj-y += allwinner/ \
|
||||
mscc/ \
|
||||
qualcomm/ \
|
||||
ralink/ \
|
||||
realtek/ \
|
||||
renesas/ \
|
||||
rockchip/ \
|
||||
samsung/ \
|
||||
|
27
drivers/phy/realtek/Kconfig
Normal file
27
drivers/phy/realtek/Kconfig
Normal file
@ -0,0 +1,27 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Phy drivers for Realtek platforms
|
||||
#
|
||||
config PHY_RTK_RTD_USB2PHY
|
||||
tristate "Realtek RTD USB2 PHY Transceiver Driver"
|
||||
depends on USB_SUPPORT
|
||||
select GENERIC_PHY
|
||||
select USB_PHY
|
||||
select USB_COMMON
|
||||
help
|
||||
Enable this to support Realtek SoC USB2 phy transceiver.
|
||||
The DHC (digital home center) RTD series SoCs used the Synopsys
|
||||
DWC3 USB IP. This driver will do the PHY initialization
|
||||
of the parameters.
|
||||
|
||||
config PHY_RTK_RTD_USB3PHY
|
||||
tristate "Realtek RTD USB3 PHY Transceiver Driver"
|
||||
depends on USB_SUPPORT
|
||||
select GENERIC_PHY
|
||||
select USB_PHY
|
||||
select USB_COMMON
|
||||
help
|
||||
Enable this to support Realtek SoC USB3 phy transceiver.
|
||||
The DHC (digital home center) RTD series SoCs used the Synopsys
|
||||
DWC3 USB IP. This driver will do the PHY initialization
|
||||
of the parameters.
|
3
drivers/phy/realtek/Makefile
Normal file
3
drivers/phy/realtek/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o
|
||||
obj-$(CONFIG_PHY_RTK_RTD_USB3PHY) += phy-rtk-usb3.o
|
1331
drivers/phy/realtek/phy-rtk-usb2.c
Normal file
1331
drivers/phy/realtek/phy-rtk-usb2.c
Normal file
File diff suppressed because it is too large
Load Diff
767
drivers/phy/realtek/phy-rtk-usb3.c
Normal file
767
drivers/phy/realtek/phy-rtk-usb3.c
Normal file
@ -0,0 +1,767 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* phy-rtk-usb3.c RTK usb3.0 phy driver
|
||||
*
|
||||
* copyright (c) 2023 realtek semiconductor corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
#define USB_MDIO_CTRL_PHY_BUSY BIT(7)
|
||||
#define USB_MDIO_CTRL_PHY_WRITE BIT(0)
|
||||
#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8
|
||||
#define USB_MDIO_CTRL_PHY_DATA_SHIFT 16
|
||||
|
||||
#define MAX_USB_PHY_DATA_SIZE 0x30
|
||||
#define PHY_ADDR_0X09 0x09
|
||||
#define PHY_ADDR_0X0B 0x0b
|
||||
#define PHY_ADDR_0X0D 0x0d
|
||||
#define PHY_ADDR_0X10 0x10
|
||||
#define PHY_ADDR_0X1F 0x1f
|
||||
#define PHY_ADDR_0X20 0x20
|
||||
#define PHY_ADDR_0X21 0x21
|
||||
#define PHY_ADDR_0X30 0x30
|
||||
|
||||
#define REG_0X09_FORCE_CALIBRATION BIT(9)
|
||||
#define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc
|
||||
#define REG_0X0D_RX_DEBUG_TEST_EN BIT(6)
|
||||
#define REG_0X10_DEBUG_MODE_SETTING 0x3c0
|
||||
#define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8
|
||||
#define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e
|
||||
|
||||
#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4
|
||||
#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf
|
||||
#define AMPLITUDE_CONTROL_COARSE_MASK 0xff
|
||||
#define AMPLITUDE_CONTROL_FINE_MASK 0xffff
|
||||
#define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff
|
||||
#define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff
|
||||
|
||||
#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr)
|
||||
#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index)
|
||||
|
||||
struct phy_reg {
|
||||
void __iomem *reg_mdio_ctl;
|
||||
};
|
||||
|
||||
struct phy_data {
|
||||
u8 addr;
|
||||
u16 data;
|
||||
};
|
||||
|
||||
struct phy_cfg {
|
||||
int param_size;
|
||||
struct phy_data param[MAX_USB_PHY_DATA_SIZE];
|
||||
|
||||
bool check_efuse;
|
||||
bool do_toggle;
|
||||
bool do_toggle_once;
|
||||
bool use_default_parameter;
|
||||
bool check_rx_front_end_offset;
|
||||
};
|
||||
|
||||
struct phy_parameter {
|
||||
struct phy_reg phy_reg;
|
||||
|
||||
/* Get from efuse */
|
||||
u8 efuse_usb_u3_tx_lfps_swing_trim;
|
||||
|
||||
/* Get from dts */
|
||||
u32 amplitude_control_coarse;
|
||||
u32 amplitude_control_fine;
|
||||
};
|
||||
|
||||
struct rtk_phy {
|
||||
struct usb_phy phy;
|
||||
struct device *dev;
|
||||
|
||||
struct phy_cfg *phy_cfg;
|
||||
int num_phy;
|
||||
struct phy_parameter *phy_parameter;
|
||||
|
||||
struct dentry *debug_dir;
|
||||
};
|
||||
|
||||
#define PHY_IO_TIMEOUT_USEC (50000)
|
||||
#define PHY_IO_DELAY_US (100)
|
||||
|
||||
static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = read_poll_timeout(readl, val, ((val & mask) == result),
|
||||
PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
|
||||
if (ret) {
|
||||
pr_err("%s can't program USB phy\n", __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg)
|
||||
{
|
||||
return utmi_wait_register(phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, 0);
|
||||
}
|
||||
|
||||
static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr)
|
||||
{
|
||||
unsigned int tmp;
|
||||
u32 value;
|
||||
|
||||
tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT);
|
||||
|
||||
writel(tmp, phy_reg->reg_mdio_ctl);
|
||||
|
||||
rtk_phy3_wait_vbusy(phy_reg);
|
||||
|
||||
value = readl(phy_reg->reg_mdio_ctl);
|
||||
value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT;
|
||||
|
||||
return (u16)value;
|
||||
}
|
||||
|
||||
static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = USB_MDIO_CTRL_PHY_WRITE |
|
||||
(addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) |
|
||||
(data << USB_MDIO_CTRL_PHY_DATA_SHIFT);
|
||||
|
||||
writel(val, phy_reg->reg_mdio_ctl);
|
||||
|
||||
rtk_phy3_wait_vbusy(phy_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect)
|
||||
{
|
||||
struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
|
||||
struct phy_reg *phy_reg;
|
||||
struct phy_parameter *phy_parameter;
|
||||
struct phy_data *phy_data;
|
||||
u8 addr;
|
||||
u16 data;
|
||||
int i;
|
||||
|
||||
phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
|
||||
phy_reg = &phy_parameter->phy_reg;
|
||||
|
||||
if (!phy_cfg->do_toggle)
|
||||
return;
|
||||
|
||||
i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09);
|
||||
phy_data = phy_cfg->param + i;
|
||||
addr = phy_data->addr;
|
||||
data = phy_data->data;
|
||||
|
||||
if (!addr && !data) {
|
||||
addr = PHY_ADDR_0X09;
|
||||
data = rtk_phy_read(phy_reg, addr);
|
||||
phy_data->addr = addr;
|
||||
phy_data->data = data;
|
||||
}
|
||||
|
||||
rtk_phy_write(phy_reg, addr, data & (~REG_0X09_FORCE_CALIBRATION));
|
||||
mdelay(1);
|
||||
rtk_phy_write(phy_reg, addr, data | REG_0X09_FORCE_CALIBRATION);
|
||||
}
|
||||
|
||||
static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
|
||||
{
|
||||
struct phy_cfg *phy_cfg;
|
||||
struct phy_reg *phy_reg;
|
||||
struct phy_parameter *phy_parameter;
|
||||
int i = 0;
|
||||
|
||||
phy_cfg = rtk_phy->phy_cfg;
|
||||
phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
|
||||
phy_reg = &phy_parameter->phy_reg;
|
||||
|
||||
if (phy_cfg->use_default_parameter)
|
||||
goto do_toggle;
|
||||
|
||||
for (i = 0; i < phy_cfg->param_size; i++) {
|
||||
struct phy_data *phy_data = phy_cfg->param + i;
|
||||
u8 addr = phy_data->addr;
|
||||
u16 data = phy_data->data;
|
||||
|
||||
if (!addr && !data)
|
||||
continue;
|
||||
|
||||
rtk_phy_write(phy_reg, addr, data);
|
||||
}
|
||||
|
||||
do_toggle:
|
||||
if (phy_cfg->do_toggle_once)
|
||||
phy_cfg->do_toggle = true;
|
||||
|
||||
do_rtk_usb3_phy_toggle(rtk_phy, index, false);
|
||||
|
||||
if (phy_cfg->do_toggle_once) {
|
||||
u16 check_value = 0;
|
||||
int count = 10;
|
||||
u16 value_0x0d, value_0x10;
|
||||
|
||||
/* Enable Debug mode by set 0x0D and 0x10 */
|
||||
value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D);
|
||||
value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10);
|
||||
|
||||
rtk_phy_write(phy_reg, PHY_ADDR_0X0D,
|
||||
value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN);
|
||||
rtk_phy_write(phy_reg, PHY_ADDR_0X10,
|
||||
(value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) |
|
||||
REG_0X10_DEBUG_MODE_SETTING);
|
||||
|
||||
check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
|
||||
|
||||
while (!(check_value & BIT(15))) {
|
||||
check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
|
||||
mdelay(1);
|
||||
if (count-- < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(check_value & BIT(15)))
|
||||
dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n",
|
||||
PHY_ADDR_0X30, check_value);
|
||||
|
||||
/* Disable Debug mode by set 0x0D and 0x10 to default*/
|
||||
rtk_phy_write(phy_reg, PHY_ADDR_0X0D, value_0x0d);
|
||||
rtk_phy_write(phy_reg, PHY_ADDR_0X10, value_0x10);
|
||||
|
||||
phy_cfg->do_toggle = false;
|
||||
}
|
||||
|
||||
if (phy_cfg->check_rx_front_end_offset) {
|
||||
u16 rx_offset_code, rx_offset_range;
|
||||
u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK;
|
||||
u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK;
|
||||
bool do_update = false;
|
||||
|
||||
rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F);
|
||||
if (((rx_offset_code & code_mask) == 0x0) ||
|
||||
((rx_offset_code & code_mask) == code_mask))
|
||||
do_update = true;
|
||||
|
||||
rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B);
|
||||
if (((rx_offset_range & range_mask) == range_mask) && do_update) {
|
||||
dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n",
|
||||
rx_offset_code, rx_offset_range);
|
||||
do_update = false;
|
||||
}
|
||||
|
||||
if (do_update) {
|
||||
u16 tmp1, tmp2;
|
||||
|
||||
tmp1 = rx_offset_range & (~range_mask);
|
||||
tmp2 = rx_offset_range & range_mask;
|
||||
tmp2 += (1 << 2);
|
||||
rx_offset_range = tmp1 | (tmp2 & range_mask);
|
||||
rtk_phy_write(phy_reg, PHY_ADDR_0X0B, rx_offset_range);
|
||||
goto do_toggle;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtk_phy_init(struct phy *phy)
|
||||
{
|
||||
struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
|
||||
int ret = 0;
|
||||
int i;
|
||||
unsigned long phy_init_time = jiffies;
|
||||
|
||||
for (i = 0; i < rtk_phy->num_phy; i++)
|
||||
ret = do_rtk_phy_init(rtk_phy, i);
|
||||
|
||||
dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n",
|
||||
jiffies_to_msecs(jiffies - phy_init_time));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_phy_exit(struct phy *phy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops ops = {
|
||||
.init = rtk_phy_init,
|
||||
.exit = rtk_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void rtk_phy_toggle(struct usb_phy *usb3_phy, bool connect, int port)
|
||||
{
|
||||
int index = port;
|
||||
struct rtk_phy *rtk_phy = NULL;
|
||||
|
||||
rtk_phy = dev_get_drvdata(usb3_phy->dev);
|
||||
|
||||
if (index > rtk_phy->num_phy) {
|
||||
dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
|
||||
__func__, index, rtk_phy->num_phy);
|
||||
return;
|
||||
}
|
||||
|
||||
do_rtk_usb3_phy_toggle(rtk_phy, index, connect);
|
||||
}
|
||||
|
||||
static int rtk_phy_notify_port_status(struct usb_phy *x, int port,
|
||||
u16 portstatus, u16 portchange)
|
||||
{
|
||||
bool connect = false;
|
||||
|
||||
pr_debug("%s port=%d portstatus=0x%x portchange=0x%x\n",
|
||||
__func__, port, (int)portstatus, (int)portchange);
|
||||
if (portstatus & USB_PORT_STAT_CONNECTION)
|
||||
connect = true;
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_CONNECTION)
|
||||
rtk_phy_toggle(x, connect, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static struct dentry *create_phy_debug_root(void)
|
||||
{
|
||||
struct dentry *phy_debug_root;
|
||||
|
||||
phy_debug_root = debugfs_lookup("phy", usb_debug_root);
|
||||
if (!phy_debug_root)
|
||||
phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
|
||||
|
||||
return phy_debug_root;
|
||||
}
|
||||
|
||||
static int rtk_usb3_parameter_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct rtk_phy *rtk_phy = s->private;
|
||||
struct phy_cfg *phy_cfg;
|
||||
int i, index;
|
||||
|
||||
phy_cfg = rtk_phy->phy_cfg;
|
||||
|
||||
seq_puts(s, "Property:\n");
|
||||
seq_printf(s, " check_efuse: %s\n",
|
||||
phy_cfg->check_efuse ? "Enable" : "Disable");
|
||||
seq_printf(s, " do_toggle: %s\n",
|
||||
phy_cfg->do_toggle ? "Enable" : "Disable");
|
||||
seq_printf(s, " do_toggle_once: %s\n",
|
||||
phy_cfg->do_toggle_once ? "Enable" : "Disable");
|
||||
seq_printf(s, " use_default_parameter: %s\n",
|
||||
phy_cfg->use_default_parameter ? "Enable" : "Disable");
|
||||
|
||||
for (index = 0; index < rtk_phy->num_phy; index++) {
|
||||
struct phy_reg *phy_reg;
|
||||
struct phy_parameter *phy_parameter;
|
||||
|
||||
phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
|
||||
phy_reg = &phy_parameter->phy_reg;
|
||||
|
||||
seq_printf(s, "PHY %d:\n", index);
|
||||
|
||||
for (i = 0; i < phy_cfg->param_size; i++) {
|
||||
struct phy_data *phy_data = phy_cfg->param + i;
|
||||
u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i);
|
||||
u16 data = phy_data->data;
|
||||
|
||||
if (!phy_data->addr && !data)
|
||||
seq_printf(s, " addr = 0x%02x, data = none ==> read value = 0x%04x\n",
|
||||
addr, rtk_phy_read(phy_reg, addr));
|
||||
else
|
||||
seq_printf(s, " addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n",
|
||||
addr, data, rtk_phy_read(phy_reg, addr));
|
||||
}
|
||||
|
||||
seq_puts(s, "PHY Property:\n");
|
||||
seq_printf(s, " efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n",
|
||||
(int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim);
|
||||
seq_printf(s, " amplitude_control_coarse: 0x%x\n",
|
||||
(int)phy_parameter->amplitude_control_coarse);
|
||||
seq_printf(s, " amplitude_control_fine: 0x%x\n",
|
||||
(int)phy_parameter->amplitude_control_fine);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter);
|
||||
|
||||
static inline void create_debug_files(struct rtk_phy *rtk_phy)
|
||||
{
|
||||
struct dentry *phy_debug_root = NULL;
|
||||
|
||||
phy_debug_root = create_phy_debug_root();
|
||||
|
||||
if (!phy_debug_root)
|
||||
return;
|
||||
|
||||
rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root);
|
||||
if (!rtk_phy->debug_dir)
|
||||
return;
|
||||
|
||||
if (!debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
|
||||
&rtk_usb3_parameter_fops))
|
||||
goto file_error;
|
||||
|
||||
return;
|
||||
|
||||
file_error:
|
||||
debugfs_remove_recursive(rtk_phy->debug_dir);
|
||||
}
|
||||
|
||||
static inline void remove_debug_files(struct rtk_phy *rtk_phy)
|
||||
{
|
||||
debugfs_remove_recursive(rtk_phy->debug_dir);
|
||||
}
|
||||
#else
|
||||
static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
|
||||
static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
|
||||
struct phy_parameter *phy_parameter, int index)
|
||||
{
|
||||
struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
|
||||
u8 value = 0;
|
||||
struct nvmem_cell *cell;
|
||||
|
||||
if (!phy_cfg->check_efuse)
|
||||
goto out;
|
||||
|
||||
cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim");
|
||||
if (IS_ERR(cell)) {
|
||||
dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n",
|
||||
__func__, PTR_ERR(cell));
|
||||
} else {
|
||||
unsigned char *buf;
|
||||
size_t buf_size;
|
||||
|
||||
buf = nvmem_cell_read(cell, &buf_size);
|
||||
if (!IS_ERR(buf)) {
|
||||
value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK;
|
||||
kfree(buf);
|
||||
}
|
||||
nvmem_cell_put(cell);
|
||||
}
|
||||
|
||||
if (value > 0 && value < 0x8)
|
||||
phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8;
|
||||
else
|
||||
phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_amplitude_control_value(struct rtk_phy *rtk_phy,
|
||||
struct phy_parameter *phy_parameter)
|
||||
{
|
||||
struct phy_cfg *phy_cfg;
|
||||
struct phy_reg *phy_reg;
|
||||
|
||||
phy_reg = &phy_parameter->phy_reg;
|
||||
phy_cfg = rtk_phy->phy_cfg;
|
||||
|
||||
if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) {
|
||||
u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK;
|
||||
u16 data;
|
||||
|
||||
if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
|
||||
phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
|
||||
data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
|
||||
} else {
|
||||
data = phy_cfg->param[PHY_ADDR_0X20].data;
|
||||
}
|
||||
|
||||
data &= (~val_mask);
|
||||
data |= (phy_parameter->amplitude_control_coarse & val_mask);
|
||||
|
||||
phy_cfg->param[PHY_ADDR_0X20].data = data;
|
||||
}
|
||||
|
||||
if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) {
|
||||
u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim;
|
||||
u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK;
|
||||
int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT;
|
||||
u16 data;
|
||||
|
||||
if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
|
||||
phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
|
||||
data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
|
||||
} else {
|
||||
data = phy_cfg->param[PHY_ADDR_0X20].data;
|
||||
}
|
||||
|
||||
data &= ~(val_mask << val_shift);
|
||||
data |= ((efuse_val & val_mask) << val_shift);
|
||||
|
||||
phy_cfg->param[PHY_ADDR_0X20].data = data;
|
||||
}
|
||||
|
||||
if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) {
|
||||
u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK;
|
||||
|
||||
if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data)
|
||||
phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21;
|
||||
|
||||
phy_cfg->param[PHY_ADDR_0X21].data =
|
||||
phy_parameter->amplitude_control_fine & val_mask;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_phy_data(struct rtk_phy *rtk_phy)
|
||||
{
|
||||
struct device *dev = rtk_phy->dev;
|
||||
struct phy_parameter *phy_parameter;
|
||||
int ret = 0;
|
||||
int index;
|
||||
|
||||
rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
|
||||
rtk_phy->num_phy, GFP_KERNEL);
|
||||
if (!rtk_phy->phy_parameter)
|
||||
return -ENOMEM;
|
||||
|
||||
for (index = 0; index < rtk_phy->num_phy; index++) {
|
||||
phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
|
||||
|
||||
phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(dev->of_node, 0) + index;
|
||||
|
||||
/* Amplitude control address 0x20 bit 0 to bit 7 */
|
||||
if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-coarse-tuning",
|
||||
&phy_parameter->amplitude_control_coarse))
|
||||
phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT;
|
||||
|
||||
/* Amplitude control address 0x21 bit 0 to bit 16 */
|
||||
if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-fine-tuning",
|
||||
&phy_parameter->amplitude_control_fine))
|
||||
phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT;
|
||||
|
||||
get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
|
||||
|
||||
update_amplitude_control_value(rtk_phy, phy_parameter);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_usb3phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rtk_phy *rtk_phy;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy *generic_phy;
|
||||
struct phy_provider *phy_provider;
|
||||
const struct phy_cfg *phy_cfg;
|
||||
int ret;
|
||||
|
||||
phy_cfg = of_device_get_match_data(dev);
|
||||
if (!phy_cfg) {
|
||||
dev_err(dev, "phy config are not assigned!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
|
||||
if (!rtk_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
rtk_phy->dev = &pdev->dev;
|
||||
rtk_phy->phy.dev = rtk_phy->dev;
|
||||
rtk_phy->phy.label = "rtk-usb3phy";
|
||||
rtk_phy->phy.notify_port_status = rtk_phy_notify_port_status;
|
||||
|
||||
rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
|
||||
|
||||
memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
|
||||
|
||||
rtk_phy->num_phy = 1;
|
||||
|
||||
ret = parse_phy_data(rtk_phy);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
platform_set_drvdata(pdev, rtk_phy);
|
||||
|
||||
generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
|
||||
if (IS_ERR(generic_phy))
|
||||
return PTR_ERR(generic_phy);
|
||||
|
||||
phy_set_drvdata(generic_phy, rtk_phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
ret = usb_add_phy_dev(&rtk_phy->phy);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
create_debug_files(rtk_phy);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rtk_usb3phy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
|
||||
|
||||
remove_debug_files(rtk_phy);
|
||||
|
||||
usb_remove_phy(&rtk_phy->phy);
|
||||
}
|
||||
|
||||
static const struct phy_cfg rtd1295_phy_cfg = {
|
||||
.param_size = MAX_USB_PHY_DATA_SIZE,
|
||||
.param = { [0] = {0x01, 0x4008}, [1] = {0x01, 0xe046},
|
||||
[2] = {0x02, 0x6046}, [3] = {0x03, 0x2779},
|
||||
[4] = {0x04, 0x72f5}, [5] = {0x05, 0x2ad3},
|
||||
[6] = {0x06, 0x000e}, [7] = {0x07, 0x2e00},
|
||||
[8] = {0x08, 0x3591}, [9] = {0x09, 0x525c},
|
||||
[10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904},
|
||||
[12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c},
|
||||
[14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000},
|
||||
[16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00},
|
||||
[18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81},
|
||||
[20] = {0x14, 0xde01}, [21] = {0x15, 0x0000},
|
||||
[22] = {0x16, 0x0000}, [23] = {0x17, 0x0000},
|
||||
[24] = {0x18, 0x0000}, [25] = {0x19, 0x4004},
|
||||
[26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00},
|
||||
[28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f},
|
||||
[30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807},
|
||||
[32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa},
|
||||
[34] = {0x22, 0x0057}, [35] = {0x23, 0xab66},
|
||||
[36] = {0x24, 0x0800}, [37] = {0x25, 0x0000},
|
||||
[38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6},
|
||||
[40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080},
|
||||
[42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078},
|
||||
[44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff},
|
||||
[46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, },
|
||||
.check_efuse = false,
|
||||
.do_toggle = true,
|
||||
.do_toggle_once = false,
|
||||
.use_default_parameter = false,
|
||||
.check_rx_front_end_offset = false,
|
||||
};
|
||||
|
||||
static const struct phy_cfg rtd1619_phy_cfg = {
|
||||
.param_size = MAX_USB_PHY_DATA_SIZE,
|
||||
.param = { [8] = {0x08, 0x3591},
|
||||
[38] = {0x26, 0x840b},
|
||||
[40] = {0x28, 0xf842}, },
|
||||
.check_efuse = false,
|
||||
.do_toggle = true,
|
||||
.do_toggle_once = false,
|
||||
.use_default_parameter = false,
|
||||
.check_rx_front_end_offset = false,
|
||||
};
|
||||
|
||||
static const struct phy_cfg rtd1319_phy_cfg = {
|
||||
.param_size = MAX_USB_PHY_DATA_SIZE,
|
||||
.param = { [1] = {0x01, 0xac86},
|
||||
[6] = {0x06, 0x0003},
|
||||
[9] = {0x09, 0x924c},
|
||||
[10] = {0x0a, 0xa608},
|
||||
[11] = {0x0b, 0xb905},
|
||||
[14] = {0x0e, 0x2010},
|
||||
[32] = {0x20, 0x705a},
|
||||
[33] = {0x21, 0xf645},
|
||||
[34] = {0x22, 0x0013},
|
||||
[35] = {0x23, 0xcb66},
|
||||
[41] = {0x29, 0xff00}, },
|
||||
.check_efuse = true,
|
||||
.do_toggle = true,
|
||||
.do_toggle_once = false,
|
||||
.use_default_parameter = false,
|
||||
.check_rx_front_end_offset = false,
|
||||
};
|
||||
|
||||
static const struct phy_cfg rtd1619b_phy_cfg = {
|
||||
.param_size = MAX_USB_PHY_DATA_SIZE,
|
||||
.param = { [1] = {0x01, 0xac8c},
|
||||
[6] = {0x06, 0x0017},
|
||||
[9] = {0x09, 0x724c},
|
||||
[10] = {0x0a, 0xb610},
|
||||
[11] = {0x0b, 0xb90d},
|
||||
[13] = {0x0d, 0xef2a},
|
||||
[15] = {0x0f, 0x9050},
|
||||
[16] = {0x10, 0x000c},
|
||||
[32] = {0x20, 0x70ff},
|
||||
[34] = {0x22, 0x0013},
|
||||
[35] = {0x23, 0xdb66},
|
||||
[38] = {0x26, 0x8609},
|
||||
[41] = {0x29, 0xff13},
|
||||
[42] = {0x2a, 0x3070}, },
|
||||
.check_efuse = true,
|
||||
.do_toggle = false,
|
||||
.do_toggle_once = true,
|
||||
.use_default_parameter = false,
|
||||
.check_rx_front_end_offset = false,
|
||||
};
|
||||
|
||||
static const struct phy_cfg rtd1319d_phy_cfg = {
|
||||
.param_size = MAX_USB_PHY_DATA_SIZE,
|
||||
.param = { [1] = {0x01, 0xac89},
|
||||
[4] = {0x04, 0xf2f5},
|
||||
[6] = {0x06, 0x0017},
|
||||
[9] = {0x09, 0x424c},
|
||||
[10] = {0x0a, 0x9610},
|
||||
[11] = {0x0b, 0x9901},
|
||||
[12] = {0x0c, 0xf000},
|
||||
[13] = {0x0d, 0xef2a},
|
||||
[14] = {0x0e, 0x1000},
|
||||
[15] = {0x0f, 0x9050},
|
||||
[32] = {0x20, 0x7077},
|
||||
[35] = {0x23, 0x0b62},
|
||||
[37] = {0x25, 0x10ec},
|
||||
[42] = {0x2a, 0x3070}, },
|
||||
.check_efuse = true,
|
||||
.do_toggle = false,
|
||||
.do_toggle_once = true,
|
||||
.use_default_parameter = false,
|
||||
.check_rx_front_end_offset = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id usbphy_rtk_dt_match[] = {
|
||||
{ .compatible = "realtek,rtd1295-usb3phy", .data = &rtd1295_phy_cfg },
|
||||
{ .compatible = "realtek,rtd1319-usb3phy", .data = &rtd1319_phy_cfg },
|
||||
{ .compatible = "realtek,rtd1319d-usb3phy", .data = &rtd1319d_phy_cfg },
|
||||
{ .compatible = "realtek,rtd1619-usb3phy", .data = &rtd1619_phy_cfg },
|
||||
{ .compatible = "realtek,rtd1619b-usb3phy", .data = &rtd1619b_phy_cfg },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
|
||||
|
||||
static struct platform_driver rtk_usb3phy_driver = {
|
||||
.probe = rtk_usb3phy_probe,
|
||||
.remove_new = rtk_usb3phy_remove,
|
||||
.driver = {
|
||||
.name = "rtk-usb3phy",
|
||||
.of_match_table = usbphy_rtk_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(rtk_usb3phy_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform: rtk-usb3phy");
|
||||
MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
|
||||
MODULE_DESCRIPTION("Realtek usb 3.0 phy driver");
|
@ -406,6 +406,27 @@ static int cros_typec_usb_safe_state(struct cros_typec_port *port)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_typec_get_cable_vdo() - Get Cable VDO of the connected cable
|
||||
* @port: Type-C port data
|
||||
* @svid: Standard or Vendor ID to match
|
||||
*
|
||||
* Returns the Cable VDO if match is found and returns 0 if match is not found.
|
||||
*/
|
||||
static int cros_typec_get_cable_vdo(struct cros_typec_port *port, u16 svid)
|
||||
{
|
||||
struct list_head *head = &port->plug_mode_list;
|
||||
struct cros_typec_altmode_node *node;
|
||||
u32 ret = 0;
|
||||
|
||||
list_for_each_entry(node, head, list) {
|
||||
if (node->amode->svid == svid)
|
||||
return node->amode->vdo;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spoof the VDOs that were likely communicated by the partner for TBT alt
|
||||
* mode.
|
||||
@ -432,6 +453,9 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec,
|
||||
|
||||
/* Cable Discover Mode VDO */
|
||||
data.cable_mode = TBT_MODE;
|
||||
|
||||
data.cable_mode |= cros_typec_get_cable_vdo(port, USB_TYPEC_TBT_SID);
|
||||
|
||||
data.cable_mode |= TBT_SET_CABLE_SPEED(pd_ctrl->cable_speed);
|
||||
|
||||
if (pd_ctrl->control_flags & USB_PD_CTRL_OPTICAL_CABLE)
|
||||
@ -522,8 +546,10 @@ static int cros_typec_enable_usb4(struct cros_typec_data *typec,
|
||||
/* Cable Type */
|
||||
if (pd_ctrl->control_flags & USB_PD_CTRL_OPTICAL_CABLE)
|
||||
data.eudo |= EUDO_CABLE_TYPE_OPTICAL << EUDO_CABLE_TYPE_SHIFT;
|
||||
else if (pd_ctrl->control_flags & USB_PD_CTRL_ACTIVE_CABLE)
|
||||
else if (cros_typec_get_cable_vdo(port, USB_TYPEC_TBT_SID) & TBT_CABLE_RETIMER)
|
||||
data.eudo |= EUDO_CABLE_TYPE_RE_TIMER << EUDO_CABLE_TYPE_SHIFT;
|
||||
else if (pd_ctrl->control_flags & USB_PD_CTRL_ACTIVE_CABLE)
|
||||
data.eudo |= EUDO_CABLE_TYPE_RE_DRIVER << EUDO_CABLE_TYPE_SHIFT;
|
||||
|
||||
data.active_link_training = !!(pd_ctrl->control_flags &
|
||||
USB_PD_CTRL_ACTIVE_LINK_UNIDIR);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "tb.h"
|
||||
|
||||
static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
void **return_value)
|
||||
void **ret)
|
||||
{
|
||||
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
|
||||
struct fwnode_handle *fwnode;
|
||||
@ -84,6 +84,7 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
if (link) {
|
||||
dev_dbg(&nhi->pdev->dev, "created link from %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
*(bool *)ret = true;
|
||||
} else {
|
||||
dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
|
||||
dev_name(&pdev->dev));
|
||||
@ -104,22 +105,29 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
* Goes over ACPI namespace finding tunneled ports that reference to
|
||||
* @nhi ACPI node. For each reference a device link is added. The link
|
||||
* is automatically removed by the driver core.
|
||||
*
|
||||
* Returns %true if at least one link was created.
|
||||
*/
|
||||
void tb_acpi_add_links(struct tb_nhi *nhi)
|
||||
bool tb_acpi_add_links(struct tb_nhi *nhi)
|
||||
{
|
||||
acpi_status status;
|
||||
bool ret = false;
|
||||
|
||||
if (!has_acpi_companion(&nhi->pdev->dev))
|
||||
return;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Find all devices that have usb4-host-controller interface
|
||||
* property that references to this NHI.
|
||||
*/
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 32,
|
||||
tb_acpi_add_link, NULL, nhi, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
tb_acpi_add_link, NULL, nhi, (void **)&ret);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_warn(&nhi->pdev->dev, "failed to enumerate tunneled ports\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2188,46 +2188,47 @@ struct device_type tb_switch_type = {
|
||||
|
||||
static int tb_switch_get_generation(struct tb_switch *sw)
|
||||
{
|
||||
switch (sw->config.device_id) {
|
||||
case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_EAGLE_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_LIGHT_PEAK:
|
||||
case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_2C:
|
||||
case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C:
|
||||
case PCI_DEVICE_ID_INTEL_PORT_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_BRIDGE:
|
||||
return 1;
|
||||
if (tb_switch_is_usb4(sw))
|
||||
return 4;
|
||||
|
||||
case PCI_DEVICE_ID_INTEL_WIN_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE:
|
||||
return 2;
|
||||
if (sw->config.vendor_id == PCI_VENDOR_ID_INTEL) {
|
||||
switch (sw->config.device_id) {
|
||||
case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_EAGLE_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_LIGHT_PEAK:
|
||||
case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_2C:
|
||||
case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C:
|
||||
case PCI_DEVICE_ID_INTEL_PORT_RIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_BRIDGE:
|
||||
return 1;
|
||||
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ICL_NHI0:
|
||||
case PCI_DEVICE_ID_INTEL_ICL_NHI1:
|
||||
return 3;
|
||||
case PCI_DEVICE_ID_INTEL_WIN_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
if (tb_switch_is_usb4(sw))
|
||||
return 4;
|
||||
|
||||
/*
|
||||
* For unknown switches assume generation to be 1 to be
|
||||
* on the safe side.
|
||||
*/
|
||||
tb_sw_warn(sw, "unsupported switch device id %#x\n",
|
||||
sw->config.device_id);
|
||||
return 1;
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE:
|
||||
case PCI_DEVICE_ID_INTEL_ICL_NHI0:
|
||||
case PCI_DEVICE_ID_INTEL_ICL_NHI1:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For unknown switches assume generation to be 1 to be on the
|
||||
* safe side.
|
||||
*/
|
||||
tb_sw_warn(sw, "unsupported switch device id %#x\n",
|
||||
sw->config.device_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool tb_switch_exceeds_max_depth(const struct tb_switch *sw, int depth)
|
||||
|
@ -2368,12 +2368,13 @@ static const struct tb_cm_ops tb_cm_ops = {
|
||||
* downstream ports and the NHI so that the device core will make sure
|
||||
* NHI is resumed first before the rest.
|
||||
*/
|
||||
static void tb_apple_add_links(struct tb_nhi *nhi)
|
||||
static bool tb_apple_add_links(struct tb_nhi *nhi)
|
||||
{
|
||||
struct pci_dev *upstream, *pdev;
|
||||
bool ret;
|
||||
|
||||
if (!x86_apple_machine)
|
||||
return;
|
||||
return false;
|
||||
|
||||
switch (nhi->pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
|
||||
@ -2382,26 +2383,27 @@ static void tb_apple_add_links(struct tb_nhi *nhi)
|
||||
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
upstream = pci_upstream_bridge(nhi->pdev);
|
||||
while (upstream) {
|
||||
if (!pci_is_pcie(upstream))
|
||||
return;
|
||||
return false;
|
||||
if (pci_pcie_type(upstream) == PCI_EXP_TYPE_UPSTREAM)
|
||||
break;
|
||||
upstream = pci_upstream_bridge(upstream);
|
||||
}
|
||||
|
||||
if (!upstream)
|
||||
return;
|
||||
return false;
|
||||
|
||||
/*
|
||||
* For each hotplug downstream port, create add device link
|
||||
* back to NHI so that PCIe tunnels can be re-established after
|
||||
* sleep.
|
||||
*/
|
||||
ret = false;
|
||||
for_each_pci_bridge(pdev, upstream->subordinate) {
|
||||
const struct device_link *link;
|
||||
|
||||
@ -2417,11 +2419,14 @@ static void tb_apple_add_links(struct tb_nhi *nhi)
|
||||
if (link) {
|
||||
dev_dbg(&nhi->pdev->dev, "created link from %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
ret = true;
|
||||
} else {
|
||||
dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
|
||||
dev_name(&pdev->dev));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct tb *tb_probe(struct tb_nhi *nhi)
|
||||
@ -2448,8 +2453,13 @@ struct tb *tb_probe(struct tb_nhi *nhi)
|
||||
|
||||
tb_dbg(tb, "using software connection manager\n");
|
||||
|
||||
tb_apple_add_links(nhi);
|
||||
tb_acpi_add_links(nhi);
|
||||
/*
|
||||
* Device links are needed to make sure we establish tunnels
|
||||
* before the PCIe/USB stack is resumed so complain here if we
|
||||
* found them missing.
|
||||
*/
|
||||
if (!tb_apple_add_links(nhi) && !tb_acpi_add_links(nhi))
|
||||
tb_warn(tb, "device links to tunneled native ports are missing!\n");
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
@ -1333,7 +1333,7 @@ static inline bool usb4_port_device_is_offline(const struct usb4_port *usb4)
|
||||
void tb_check_quirks(struct tb_switch *sw);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
void tb_acpi_add_links(struct tb_nhi *nhi);
|
||||
bool tb_acpi_add_links(struct tb_nhi *nhi);
|
||||
|
||||
bool tb_acpi_is_native(void);
|
||||
bool tb_acpi_may_tunnel_usb3(void);
|
||||
@ -1346,7 +1346,7 @@ void tb_acpi_exit(void);
|
||||
int tb_acpi_power_on_retimers(struct tb_port *port);
|
||||
int tb_acpi_power_off_retimers(struct tb_port *port);
|
||||
#else
|
||||
static inline void tb_acpi_add_links(struct tb_nhi *nhi) { }
|
||||
static inline bool tb_acpi_add_links(struct tb_nhi *nhi) { return false; }
|
||||
|
||||
static inline bool tb_acpi_is_native(void) { return true; }
|
||||
static inline bool tb_acpi_may_tunnel_usb3(void) { return true; }
|
||||
|
@ -19,7 +19,7 @@ static const unsigned int tmu_rates[] = {
|
||||
[TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI] = 16,
|
||||
};
|
||||
|
||||
const struct {
|
||||
static const struct {
|
||||
unsigned int freq_meas_window;
|
||||
unsigned int avg_const;
|
||||
unsigned int delta_avg_const;
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gadget-export.h"
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
@ -255,9 +256,10 @@ static int cdns3_controller_resume(struct device *dev, pm_message_t msg)
|
||||
cdns3_set_platform_suspend(cdns->dev, false, false);
|
||||
|
||||
spin_lock_irqsave(&cdns->lock, flags);
|
||||
cdns_resume(cdns, !PMSG_IS_AUTO(msg));
|
||||
cdns_resume(cdns);
|
||||
cdns->in_lpm = false;
|
||||
spin_unlock_irqrestore(&cdns->lock, flags);
|
||||
cdns_set_active(cdns, !PMSG_IS_AUTO(msg));
|
||||
if (cdns->wakeup_pending) {
|
||||
cdns->wakeup_pending = false;
|
||||
enable_irq(cdns->wakeup_irq);
|
||||
|
@ -166,7 +166,7 @@ static int cdns_starfive_remove_core(struct device *dev, void *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_starfive_remove(struct platform_device *pdev)
|
||||
static void cdns_starfive_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cdns_starfive *data = dev_get_drvdata(dev);
|
||||
@ -178,8 +178,6 @@ static int cdns_starfive_remove(struct platform_device *pdev)
|
||||
pm_runtime_put_noidle(dev);
|
||||
cdns_clk_rst_deinit(data);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -232,7 +230,7 @@ MODULE_DEVICE_TABLE(of, cdns_starfive_of_match);
|
||||
|
||||
static struct platform_driver cdns_starfive_driver = {
|
||||
.probe = cdns_starfive_probe,
|
||||
.remove = cdns_starfive_remove,
|
||||
.remove_new = cdns_starfive_remove,
|
||||
.driver = {
|
||||
.name = "cdns3-starfive",
|
||||
.of_match_table = cdns_starfive_of_match,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/* USB Wrapper register offsets */
|
||||
#define USBSS_PID 0x0
|
||||
|
@ -208,8 +208,9 @@ static int __maybe_unused cdnsp_pci_resume(struct device *dev)
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&cdns->lock, flags);
|
||||
ret = cdns_resume(cdns, 1);
|
||||
ret = cdns_resume(cdns);
|
||||
spin_unlock_irqrestore(&cdns->lock, flags);
|
||||
cdns_set_active(cdns, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@ -522,9 +523,8 @@ int cdns_suspend(struct cdns *cdns)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_suspend);
|
||||
|
||||
int cdns_resume(struct cdns *cdns, u8 set_active)
|
||||
int cdns_resume(struct cdns *cdns)
|
||||
{
|
||||
struct device *dev = cdns->dev;
|
||||
enum usb_role real_role;
|
||||
bool role_changed = false;
|
||||
int ret = 0;
|
||||
@ -556,15 +556,23 @@ int cdns_resume(struct cdns *cdns, u8 set_active)
|
||||
if (cdns->roles[cdns->role]->resume)
|
||||
cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_resume);
|
||||
|
||||
void cdns_set_active(struct cdns *cdns, u8 set_active)
|
||||
{
|
||||
struct device *dev = cdns->dev;
|
||||
|
||||
if (set_active) {
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_resume);
|
||||
EXPORT_SYMBOL_GPL(cdns_set_active);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
|
||||
|
@ -125,10 +125,13 @@ int cdns_init(struct cdns *cdns);
|
||||
int cdns_remove(struct cdns *cdns);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int cdns_resume(struct cdns *cdns, u8 set_active);
|
||||
int cdns_resume(struct cdns *cdns);
|
||||
int cdns_suspend(struct cdns *cdns);
|
||||
void cdns_set_active(struct cdns *cdns, u8 set_active);
|
||||
#else /* CONFIG_PM_SLEEP */
|
||||
static inline int cdns_resume(struct cdns *cdns, u8 set_active)
|
||||
static inline int cdns_resume(struct cdns *cdns)
|
||||
{ return 0; }
|
||||
static inline int cdns_set_active(struct cdns *cdns, u8 set_active)
|
||||
{ return 0; }
|
||||
static inline int cdns_suspend(struct cdns *cdns)
|
||||
{ return 0; }
|
||||
|
@ -196,6 +196,7 @@ int cdns_drd_host_on(struct cdns *cdns)
|
||||
if (ret)
|
||||
dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
|
||||
|
||||
phy_set_mode(cdns->usb2_phy, PHY_MODE_USB_HOST);
|
||||
phy_set_mode(cdns->usb3_phy, PHY_MODE_USB_HOST);
|
||||
return ret;
|
||||
}
|
||||
@ -216,6 +217,7 @@ void cdns_drd_host_off(struct cdns *cdns)
|
||||
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
|
||||
!(val & OTGSTATE_HOST_STATE_MASK),
|
||||
1, 2000000);
|
||||
phy_set_mode(cdns->usb2_phy, PHY_MODE_INVALID);
|
||||
phy_set_mode(cdns->usb3_phy, PHY_MODE_INVALID);
|
||||
}
|
||||
|
||||
@ -248,6 +250,7 @@ int cdns_drd_gadget_on(struct cdns *cdns)
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_set_mode(cdns->usb2_phy, PHY_MODE_USB_DEVICE);
|
||||
phy_set_mode(cdns->usb3_phy, PHY_MODE_USB_DEVICE);
|
||||
return 0;
|
||||
}
|
||||
@ -273,6 +276,7 @@ void cdns_drd_gadget_off(struct cdns *cdns)
|
||||
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
|
||||
!(val & OTGSTATE_DEV_STATE_MASK),
|
||||
1, 2000000);
|
||||
phy_set_mode(cdns->usb2_phy, PHY_MODE_INVALID);
|
||||
phy_set_mode(cdns->usb3_phy, PHY_MODE_INVALID);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_drd_gadget_off);
|
||||
|
@ -257,6 +257,7 @@ struct ci_hdrc {
|
||||
bool id_event;
|
||||
bool b_sess_valid_event;
|
||||
bool imx28_write_fix;
|
||||
bool has_portsc_pec_bug;
|
||||
bool supports_runtime_pm;
|
||||
bool in_lpm;
|
||||
bool wakeup_int;
|
||||
@ -281,8 +282,19 @@ static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
|
||||
return -ENXIO;
|
||||
|
||||
ret = ci->roles[role]->start(ci);
|
||||
if (!ret)
|
||||
ci->role = role;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ci->role = role;
|
||||
|
||||
if (ci->usb_phy) {
|
||||
if (role == CI_ROLE_HOST)
|
||||
usb_phy_set_event(ci->usb_phy, USB_EVENT_ID);
|
||||
else
|
||||
/* in device mode but vbus is invalid*/
|
||||
usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -296,6 +308,9 @@ static inline void ci_role_stop(struct ci_hdrc *ci)
|
||||
ci->role = CI_ROLE_END;
|
||||
|
||||
ci->roles[role]->stop(ci);
|
||||
|
||||
if (ci->usb_phy)
|
||||
usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE);
|
||||
}
|
||||
|
||||
static inline enum usb_role ci_role_to_usb_role(struct ci_hdrc *ci)
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -67,11 +68,13 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_HAS_PORTSC_PEC_MISSED |
|
||||
CI_HDRC_PMQOS,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_HAS_PORTSC_PEC_MISSED,
|
||||
};
|
||||
|
||||
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
||||
@ -175,10 +178,15 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
|
||||
if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
|
||||
data->ulpi = 1;
|
||||
|
||||
of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control",
|
||||
&data->emp_curr_control);
|
||||
of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust",
|
||||
&data->dc_vol_level_adjust);
|
||||
if (of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control",
|
||||
&data->emp_curr_control))
|
||||
data->emp_curr_control = -1;
|
||||
if (of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust",
|
||||
&data->dc_vol_level_adjust))
|
||||
data->dc_vol_level_adjust = -1;
|
||||
if (of_property_read_u32(np, "fsl,picophy-rise-fall-time-adjust",
|
||||
&data->rise_fall_time_adjust))
|
||||
data->rise_fall_time_adjust = -1;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ struct imx_usbmisc_data {
|
||||
enum usb_dr_mode available_role; /* runtime usb dr mode */
|
||||
int emp_curr_control;
|
||||
int dc_vol_level_adjust;
|
||||
int rise_fall_time_adjust;
|
||||
};
|
||||
|
||||
int imx_usbmisc_init(struct imx_usbmisc_data *data);
|
||||
|
@ -6,7 +6,8 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
|
@ -1028,8 +1028,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
@ -1045,6 +1044,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
CI_HDRC_IMX28_WRITE_FIX);
|
||||
ci->supports_runtime_pm = !!(ci->platdata->flags &
|
||||
CI_HDRC_SUPPORTS_RUNTIME_PM);
|
||||
ci->has_portsc_pec_bug = !!(ci->platdata->flags &
|
||||
CI_HDRC_HAS_PORTSC_PEC_MISSED);
|
||||
platform_set_drvdata(pdev, ci);
|
||||
|
||||
ret = hw_device_init(ci, base);
|
||||
|
@ -151,6 +151,7 @@ static int host_start(struct ci_hdrc *ci)
|
||||
ehci->has_hostpc = ci->hw_bank.lpm;
|
||||
ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
|
||||
ehci->imx28_write_fix = ci->imx28_write_fix;
|
||||
ehci->has_ci_pec_bug = ci->has_portsc_pec_bug;
|
||||
|
||||
priv = (struct ehci_ci_priv *)ehci->priv;
|
||||
priv->reg_vbus = NULL;
|
||||
|
@ -1463,7 +1463,7 @@ static int ep_disable(struct usb_ep *ep)
|
||||
*/
|
||||
static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
|
||||
{
|
||||
struct ci_hw_req *hwreq = NULL;
|
||||
struct ci_hw_req *hwreq;
|
||||
|
||||
if (ep == NULL)
|
||||
return NULL;
|
||||
@ -1718,6 +1718,13 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
|
||||
ret = ci->platdata->notify_event(ci,
|
||||
CI_HDRC_CONTROLLER_VBUS_EVENT);
|
||||
|
||||
if (ci->usb_phy) {
|
||||
if (is_active)
|
||||
usb_phy_set_event(ci->usb_phy, USB_EVENT_VBUS);
|
||||
else
|
||||
usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE);
|
||||
}
|
||||
|
||||
if (ci->driver)
|
||||
ci_hdrc_gadget_connect(_gadget, is_active);
|
||||
|
||||
@ -2034,6 +2041,9 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
|
||||
if (USBi_PCI & intr) {
|
||||
ci->gadget.speed = hw_port_is_high_speed(ci) ?
|
||||
USB_SPEED_HIGH : USB_SPEED_FULL;
|
||||
if (ci->usb_phy)
|
||||
usb_phy_set_event(ci->usb_phy,
|
||||
USB_EVENT_ENUMERATED);
|
||||
if (ci->suspended) {
|
||||
if (ci->driver->resume) {
|
||||
spin_unlock(&ci->lock);
|
||||
|
@ -4,10 +4,11 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#include "ci_hdrc_imx.h"
|
||||
@ -130,6 +131,8 @@
|
||||
#define MX7D_USB_OTG_PHY_CFG1 0x30
|
||||
#define TXPREEMPAMPTUNE0_BIT 28
|
||||
#define TXPREEMPAMPTUNE0_MASK (3 << 28)
|
||||
#define TXRISETUNE0_BIT 24
|
||||
#define TXRISETUNE0_MASK (3 << 24)
|
||||
#define TXVREFTUNE0_BIT 20
|
||||
#define TXVREFTUNE0_MASK (0xf << 20)
|
||||
|
||||
@ -659,18 +662,27 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
|
||||
usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
/* PHY tuning for signal quality */
|
||||
reg = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG1);
|
||||
if (data->emp_curr_control && data->emp_curr_control <=
|
||||
if (data->emp_curr_control >= 0 &&
|
||||
data->emp_curr_control <=
|
||||
(TXPREEMPAMPTUNE0_MASK >> TXPREEMPAMPTUNE0_BIT)) {
|
||||
reg &= ~TXPREEMPAMPTUNE0_MASK;
|
||||
reg |= (data->emp_curr_control << TXPREEMPAMPTUNE0_BIT);
|
||||
}
|
||||
|
||||
if (data->dc_vol_level_adjust && data->dc_vol_level_adjust <=
|
||||
if (data->dc_vol_level_adjust >= 0 &&
|
||||
data->dc_vol_level_adjust <=
|
||||
(TXVREFTUNE0_MASK >> TXVREFTUNE0_BIT)) {
|
||||
reg &= ~TXVREFTUNE0_MASK;
|
||||
reg |= (data->dc_vol_level_adjust << TXVREFTUNE0_BIT);
|
||||
}
|
||||
|
||||
if (data->rise_fall_time_adjust >= 0 &&
|
||||
data->rise_fall_time_adjust <=
|
||||
(TXRISETUNE0_MASK >> TXRISETUNE0_BIT)) {
|
||||
reg &= ~TXRISETUNE0_MASK;
|
||||
reg |= (data->rise_fall_time_adjust << TXRISETUNE0_BIT);
|
||||
}
|
||||
|
||||
writel(reg, usbmisc->base + MX7D_USB_OTG_PHY_CFG1);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/tty_ldisc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/uaccess.h>
|
||||
@ -318,6 +319,16 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
||||
}
|
||||
|
||||
difference = acm->ctrlin ^ newctrl;
|
||||
|
||||
if ((difference & USB_CDC_SERIAL_STATE_DCD) && acm->port.tty) {
|
||||
struct tty_ldisc *ld = tty_ldisc_ref(acm->port.tty);
|
||||
if (ld) {
|
||||
if (ld->ops->dcd_change)
|
||||
ld->ops->dcd_change(acm->port.tty, newctrl & USB_CDC_SERIAL_STATE_DCD);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&acm->read_lock, flags);
|
||||
acm->ctrlin = newctrl;
|
||||
acm->oldcount = acm->iocount;
|
||||
@ -853,6 +864,19 @@ static unsigned int acm_tty_write_room(struct tty_struct *tty)
|
||||
return acm_wb_is_avail(acm) ? acm->writesize : 0;
|
||||
}
|
||||
|
||||
static void acm_tty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&acm->write_lock, flags);
|
||||
for (i = 0; i < ACM_NW; i++)
|
||||
if (acm->wb[i].use)
|
||||
usb_unlink_urb(acm->wb[i].urb);
|
||||
spin_unlock_irqrestore(&acm->write_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
@ -2016,6 +2040,7 @@ static const struct tty_operations acm_ops = {
|
||||
.hangup = acm_tty_hangup,
|
||||
.write = acm_tty_write,
|
||||
.write_room = acm_tty_write_room,
|
||||
.flush_buffer = acm_tty_flush_buffer,
|
||||
.ioctl = acm_tty_ioctl,
|
||||
.throttle = acm_tty_throttle,
|
||||
.unthrottle = acm_tty_unthrottle,
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
@ -1051,9 +1051,6 @@ int usb_get_bos_descriptor(struct usb_device *dev)
|
||||
}
|
||||
|
||||
switch (cap_type) {
|
||||
case USB_CAP_TYPE_WIRELESS_USB:
|
||||
/* Wireless USB cap descriptor is handled by wusb */
|
||||
break;
|
||||
case USB_CAP_TYPE_EXT:
|
||||
dev->bos->ext_cap =
|
||||
(struct usb_ext_cap_descriptor *)buffer;
|
||||
|
@ -424,7 +424,6 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
|
||||
case USB_SPEED_UNKNOWN: /* usb 1.1 root hub code */
|
||||
case USB_SPEED_FULL:
|
||||
speed = "12"; break;
|
||||
case USB_SPEED_WIRELESS: /* Wireless has no real fixed speed */
|
||||
case USB_SPEED_HIGH:
|
||||
speed = "480"; break;
|
||||
case USB_SPEED_SUPER:
|
||||
|
@ -29,7 +29,6 @@
|
||||
#define MAX_USB_MINORS 256
|
||||
static const struct file_operations *usb_minors[MAX_USB_MINORS];
|
||||
static DECLARE_RWSEM(minor_rwsem);
|
||||
static DEFINE_MUTEX(init_usb_class_mutex);
|
||||
|
||||
static int usb_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
@ -57,11 +56,6 @@ static const struct file_operations usb_fops = {
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct usb_class {
|
||||
struct kref kref;
|
||||
struct class *class;
|
||||
} *usb_class;
|
||||
|
||||
static char *usb_devnode(const struct device *dev, umode_t *mode)
|
||||
{
|
||||
struct usb_class_driver *drv;
|
||||
@ -72,50 +66,10 @@ static char *usb_devnode(const struct device *dev, umode_t *mode)
|
||||
return drv->devnode(dev, mode);
|
||||
}
|
||||
|
||||
static int init_usb_class(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (usb_class != NULL) {
|
||||
kref_get(&usb_class->kref);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL);
|
||||
if (!usb_class) {
|
||||
result = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
kref_init(&usb_class->kref);
|
||||
usb_class->class = class_create("usbmisc");
|
||||
if (IS_ERR(usb_class->class)) {
|
||||
result = PTR_ERR(usb_class->class);
|
||||
printk(KERN_ERR "class_create failed for usb devices\n");
|
||||
kfree(usb_class);
|
||||
usb_class = NULL;
|
||||
goto exit;
|
||||
}
|
||||
usb_class->class->devnode = usb_devnode;
|
||||
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void release_usb_class(struct kref *kref)
|
||||
{
|
||||
/* Ok, we cheat as we know we only have one usb_class */
|
||||
class_destroy(usb_class->class);
|
||||
kfree(usb_class);
|
||||
usb_class = NULL;
|
||||
}
|
||||
|
||||
static void destroy_usb_class(void)
|
||||
{
|
||||
mutex_lock(&init_usb_class_mutex);
|
||||
kref_put(&usb_class->kref, release_usb_class);
|
||||
mutex_unlock(&init_usb_class_mutex);
|
||||
}
|
||||
const struct class usbmisc_class = {
|
||||
.name = "usbmisc",
|
||||
.devnode = usb_devnode,
|
||||
};
|
||||
|
||||
int usb_major_init(void)
|
||||
{
|
||||
@ -156,7 +110,7 @@ void usb_major_cleanup(void)
|
||||
int usb_register_dev(struct usb_interface *intf,
|
||||
struct usb_class_driver *class_driver)
|
||||
{
|
||||
int retval;
|
||||
int retval = 0;
|
||||
int minor_base = class_driver->minor_base;
|
||||
int minor;
|
||||
char name[20];
|
||||
@ -175,13 +129,6 @@ int usb_register_dev(struct usb_interface *intf,
|
||||
if (intf->minor >= 0)
|
||||
return -EADDRINUSE;
|
||||
|
||||
mutex_lock(&init_usb_class_mutex);
|
||||
retval = init_usb_class();
|
||||
mutex_unlock(&init_usb_class_mutex);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
@ -200,7 +147,7 @@ int usb_register_dev(struct usb_interface *intf,
|
||||
|
||||
/* create a usb class device for this usb interface */
|
||||
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
|
||||
intf->usb_dev = device_create(usb_class->class, &intf->dev,
|
||||
intf->usb_dev = device_create(&usbmisc_class, &intf->dev,
|
||||
MKDEV(USB_MAJOR, minor), class_driver,
|
||||
"%s", kbasename(name));
|
||||
if (IS_ERR(intf->usb_dev)) {
|
||||
@ -234,7 +181,7 @@ void usb_deregister_dev(struct usb_interface *intf,
|
||||
return;
|
||||
|
||||
dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
|
||||
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
|
||||
device_destroy(&usbmisc_class, MKDEV(USB_MAJOR, intf->minor));
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
usb_minors[intf->minor] = NULL;
|
||||
@ -242,6 +189,5 @@ void usb_deregister_dev(struct usb_interface *intf,
|
||||
|
||||
intf->usb_dev = NULL;
|
||||
intf->minor = -1;
|
||||
destroy_usb_class();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_deregister_dev);
|
||||
|
@ -156,27 +156,6 @@ static const u8 usb3_rh_dev_descriptor[18] = {
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
|
||||
static const u8 usb25_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
|
||||
0x50, 0x02, /* __le16 bcdUSB; v2.5 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
|
||||
0xFF, /* __u8 bMaxPacketSize0; always 0xFF (WUSB Spec 7.4.1). */
|
||||
|
||||
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
|
||||
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
|
||||
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
|
||||
|
||||
0x03, /* __u8 iManufacturer; */
|
||||
0x02, /* __u8 iProduct; */
|
||||
0x01, /* __u8 iSerialNumber; */
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* usb 2.0 root hub device descriptor */
|
||||
static const u8 usb2_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
@ -368,7 +347,7 @@ static const u8 ss_rh_config_descriptor[] = {
|
||||
};
|
||||
|
||||
/* authorized_default behaviour:
|
||||
* -1 is authorized for all devices except wireless (old behaviour)
|
||||
* -1 is authorized for all devices (leftover from wireless USB)
|
||||
* 0 is unauthorized for all devices
|
||||
* 1 is authorized for all devices
|
||||
* 2 is authorized for internal devices
|
||||
@ -383,7 +362,7 @@ module_param(authorized_default, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(authorized_default,
|
||||
"Default USB device authorization: 0 is not authorized, 1 is "
|
||||
"authorized, 2 is authorized for internal devices, -1 is "
|
||||
"authorized except for wireless USB (default, old behaviour)");
|
||||
"authorized (default, same as 1)");
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
@ -578,9 +557,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
case HCD_USB3:
|
||||
bufp = usb3_rh_dev_descriptor;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
bufp = usb25_rh_dev_descriptor;
|
||||
break;
|
||||
case HCD_USB2:
|
||||
bufp = usb2_rh_dev_descriptor;
|
||||
break;
|
||||
@ -602,7 +578,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
bufp = ss_rh_config_descriptor;
|
||||
len = sizeof ss_rh_config_descriptor;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
case HCD_USB2:
|
||||
bufp = hs_rh_config_descriptor;
|
||||
len = sizeof hs_rh_config_descriptor;
|
||||
@ -983,6 +958,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *parent_dev = hcd->self.controller;
|
||||
struct usb_device *usb_dev = hcd->self.root_hub;
|
||||
struct usb_device_descriptor *descr;
|
||||
const int devnum = 1;
|
||||
int retval;
|
||||
|
||||
@ -994,13 +970,16 @@ static int register_root_hub(struct usb_hcd *hcd)
|
||||
mutex_lock(&usb_bus_idr_lock);
|
||||
|
||||
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
|
||||
if (retval != sizeof usb_dev->descriptor) {
|
||||
descr = usb_get_device_descriptor(usb_dev);
|
||||
if (IS_ERR(descr)) {
|
||||
retval = PTR_ERR(descr);
|
||||
mutex_unlock(&usb_bus_idr_lock);
|
||||
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
|
||||
dev_name(&usb_dev->dev), retval);
|
||||
return (retval < 0) ? retval : -EMSGSIZE;
|
||||
return retval;
|
||||
}
|
||||
usb_dev->descriptor = *descr;
|
||||
kfree(descr);
|
||||
|
||||
if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
|
||||
retval = usb_get_bos_descriptor(usb_dev);
|
||||
@ -2844,18 +2823,14 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_NONE;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_ALL:
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_INTERNAL:
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_INTERNAL;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_ALL:
|
||||
case USB_AUTHORIZE_WIRED:
|
||||
default:
|
||||
hcd->dev_policy = hcd->wireless ?
|
||||
USB_DEVICE_AUTHORIZE_NONE : USB_DEVICE_AUTHORIZE_ALL;
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2899,9 +2874,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
case HCD_USB2:
|
||||
rhdev->speed = USB_SPEED_HIGH;
|
||||
break;
|
||||
case HCD_USB25:
|
||||
rhdev->speed = USB_SPEED_WIRELESS;
|
||||
break;
|
||||
case HCD_USB3:
|
||||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
|
@ -614,6 +614,29 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
|
||||
ret = 0;
|
||||
}
|
||||
mutex_unlock(&hub->status_mutex);
|
||||
|
||||
/*
|
||||
* There is no need to lock status_mutex here, because status_mutex
|
||||
* protects hub->status, and the phy driver only checks the port
|
||||
* status without changing the status.
|
||||
*/
|
||||
if (!ret) {
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
|
||||
/*
|
||||
* Only roothub will be notified of port state changes,
|
||||
* since the USB PHY only cares about changes at the next
|
||||
* level.
|
||||
*/
|
||||
if (is_root_hub(hdev)) {
|
||||
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
|
||||
|
||||
if (hcd->usb_phy)
|
||||
usb_phy_notify_port_status(hcd->usb_phy,
|
||||
port1 - 1, *status, *change);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2117,22 +2140,6 @@ EXPORT_SYMBOL_GPL(usb_set_device_state);
|
||||
* USB-3.0 buses the address is assigned by the controller hardware
|
||||
* and it usually is not the same as the device number.
|
||||
*
|
||||
* WUSB devices are simple: they have no hubs behind, so the mapping
|
||||
* device <-> virtual port number becomes 1:1. Why? to simplify the
|
||||
* life of the device connection logic in
|
||||
* drivers/usb/wusbcore/devconnect.c. When we do the initial secret
|
||||
* handshake we need to assign a temporary address in the unauthorized
|
||||
* space. For simplicity we use the first virtual port number found to
|
||||
* be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()]
|
||||
* and that becomes it's address [X < 128] or its unauthorized address
|
||||
* [X | 0x80].
|
||||
*
|
||||
* We add 1 as an offset to the one-based USB-stack port number
|
||||
* (zero-based wusb virtual port index) for two reasons: (a) dev addr
|
||||
* 0 is reserved by USB for default address; (b) Linux's USB stack
|
||||
* uses always #1 for the root hub of the controller. So USB stack's
|
||||
* port #1, which is wusb virtual-port #0 has address #2.
|
||||
*
|
||||
* Devices connected under xHCI are not as simple. The host controller
|
||||
* supports virtualization, so the hardware assigns device addresses and
|
||||
* the HCD must setup data structures before issuing a set address
|
||||
@ -2145,19 +2152,13 @@ static void choose_devnum(struct usb_device *udev)
|
||||
|
||||
/* be safe when more hub events are proceed in parallel */
|
||||
mutex_lock(&bus->devnum_next_mutex);
|
||||
if (udev->wusb) {
|
||||
devnum = udev->portnum + 1;
|
||||
BUG_ON(test_bit(devnum, bus->devmap.devicemap));
|
||||
} else {
|
||||
/* Try to allocate the next devnum beginning at
|
||||
* bus->devnum_next. */
|
||||
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
|
||||
bus->devnum_next);
|
||||
if (devnum >= 128)
|
||||
devnum = find_next_zero_bit(bus->devmap.devicemap,
|
||||
128, 1);
|
||||
bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);
|
||||
}
|
||||
|
||||
/* Try to allocate the next devnum beginning at bus->devnum_next. */
|
||||
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
|
||||
bus->devnum_next);
|
||||
if (devnum >= 128)
|
||||
devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
|
||||
bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);
|
||||
if (devnum < 128) {
|
||||
set_bit(devnum, bus->devmap.devicemap);
|
||||
udev->devnum = devnum;
|
||||
@ -2175,9 +2176,7 @@ static void release_devnum(struct usb_device *udev)
|
||||
|
||||
static void update_devnum(struct usb_device *udev, int devnum)
|
||||
{
|
||||
/* The address for a WUSB device is managed by wusbcore. */
|
||||
if (!udev->wusb)
|
||||
udev->devnum = devnum;
|
||||
udev->devnum = devnum;
|
||||
if (!udev->devaddr)
|
||||
udev->devaddr = (u8)devnum;
|
||||
}
|
||||
@ -2670,15 +2669,6 @@ int usb_authorize_device(struct usb_device *usb_dev)
|
||||
goto error_autoresume;
|
||||
}
|
||||
|
||||
if (usb_dev->wusb) {
|
||||
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
|
||||
if (result < 0) {
|
||||
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
|
||||
"authorization: %d\n", result);
|
||||
goto error_device_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
usb_dev->authorized = 1;
|
||||
/* Choose and set the configuration. This registers the interfaces
|
||||
* with the driver core and lets interface drivers bind to them.
|
||||
@ -2695,7 +2685,6 @@ int usb_authorize_device(struct usb_device *usb_dev)
|
||||
}
|
||||
dev_info(&usb_dev->dev, "authorized to connect\n");
|
||||
|
||||
error_device_descriptor:
|
||||
usb_autosuspend_device(usb_dev);
|
||||
error_autoresume:
|
||||
out_authorized:
|
||||
@ -2778,17 +2767,6 @@ static enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev,
|
||||
return USB_SSP_GEN_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
|
||||
static unsigned hub_is_wusb(struct usb_hub *hub)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
if (hub->hdev->parent != NULL) /* not a root hub? */
|
||||
return 0;
|
||||
hcd = bus_to_hcd(hub->hdev->bus);
|
||||
return hcd->wireless;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_FEW_INIT_RETRIES
|
||||
#define PORT_RESET_TRIES 2
|
||||
#define SET_ADDRESS_TRIES 1
|
||||
@ -2941,9 +2919,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
||||
udev->tx_lanes = 1;
|
||||
udev->ssp_rate = USB_SSP_GEN_UNKNOWN;
|
||||
}
|
||||
if (hub_is_wusb(hub))
|
||||
udev->speed = USB_SPEED_WIRELESS;
|
||||
else if (udev->ssp_rate != USB_SSP_GEN_UNKNOWN)
|
||||
if (udev->ssp_rate != USB_SSP_GEN_UNKNOWN)
|
||||
udev->speed = USB_SPEED_SUPER_PLUS;
|
||||
else if (hub_is_superspeed(hub->hdev))
|
||||
udev->speed = USB_SPEED_SUPER;
|
||||
@ -4718,6 +4694,67 @@ static int hub_enable_device(struct usb_device *udev)
|
||||
return hcd->driver->enable_device(hcd, udev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the bMaxPacketSize0 value during initialization by reading the
|
||||
* device's device descriptor. Since we don't already know this value,
|
||||
* the transfer is unsafe and it ignores I/O errors, only testing for
|
||||
* reasonable received values.
|
||||
*
|
||||
* For "old scheme" initialization, size will be 8 so we read just the
|
||||
* start of the device descriptor, which should work okay regardless of
|
||||
* the actual bMaxPacketSize0 value. For "new scheme" initialization,
|
||||
* size will be 64 (and buf will point to a sufficiently large buffer),
|
||||
* which might not be kosher according to the USB spec but it's what
|
||||
* Windows does and what many devices expect.
|
||||
*
|
||||
* Returns: bMaxPacketSize0 or a negative error code.
|
||||
*/
|
||||
static int get_bMaxPacketSize0(struct usb_device *udev,
|
||||
struct usb_device_descriptor *buf, int size, bool first_time)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
/*
|
||||
* Retry on all errors; some devices are flakey.
|
||||
* 255 is for WUSB devices, we actually need to use
|
||||
* 512 (WUSB1.0[4.8.1]).
|
||||
*/
|
||||
for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) {
|
||||
/* Start with invalid values in case the transfer fails */
|
||||
buf->bDescriptorType = buf->bMaxPacketSize0 = 0;
|
||||
rc = usb_control_msg(udev, usb_rcvaddr0pipe(),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
USB_DT_DEVICE << 8, 0,
|
||||
buf, size,
|
||||
initial_descriptor_timeout);
|
||||
switch (buf->bMaxPacketSize0) {
|
||||
case 8: case 16: case 32: case 64: case 9:
|
||||
if (buf->bDescriptorType == USB_DT_DEVICE) {
|
||||
rc = buf->bMaxPacketSize0;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
if (rc >= 0)
|
||||
rc = -EPROTO;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some devices time out if they are powered on
|
||||
* when already connected. They need a second
|
||||
* reset, so return early. But only on the first
|
||||
* attempt, lest we get into a time-out/reset loop.
|
||||
*/
|
||||
if (rc > 0 || (rc == -ETIMEDOUT && first_time &&
|
||||
udev->speed > USB_SPEED_FULL))
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define GET_DESCRIPTOR_BUFSIZE 64
|
||||
|
||||
/* Reset device, (re)assign address, get device descriptor.
|
||||
* Device connection must be stable, no more debouncing needed.
|
||||
* Returns device in USB_STATE_ADDRESS, except on error.
|
||||
@ -4727,10 +4764,17 @@ static int hub_enable_device(struct usb_device *udev)
|
||||
* the port lock. For a newly detected device that is not accessible
|
||||
* through any global pointers, it's not necessary to lock the device,
|
||||
* but it is still necessary to lock the port.
|
||||
*
|
||||
* For a newly detected device, @dev_descr must be NULL. The device
|
||||
* descriptor retrieved from the device will then be stored in
|
||||
* @udev->descriptor. For an already existing device, @dev_descr
|
||||
* must be non-NULL. The device descriptor will be stored there,
|
||||
* not in @udev->descriptor, because descriptors for registered
|
||||
* devices are meant to be immutable.
|
||||
*/
|
||||
static int
|
||||
hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
int retry_counter)
|
||||
int retry_counter, struct usb_device_descriptor *dev_descr)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
|
||||
@ -4742,6 +4786,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
int devnum = udev->devnum;
|
||||
const char *driver_name;
|
||||
bool do_new_scheme;
|
||||
const bool initial = !dev_descr;
|
||||
int maxp0;
|
||||
struct usb_device_descriptor *buf, *descr;
|
||||
|
||||
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* root hub ports have a slightly longer reset period
|
||||
* (from USB 2.0 spec, section 7.1.7.5)
|
||||
@ -4774,38 +4825,34 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
}
|
||||
oldspeed = udev->speed;
|
||||
|
||||
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
|
||||
* it's fixed size except for full speed devices.
|
||||
* For Wireless USB devices, ep0 max packet is always 512 (tho
|
||||
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
|
||||
*/
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_WIRELESS: /* fixed at 512 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
break;
|
||||
case USB_SPEED_HIGH: /* fixed at 64 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
|
||||
/* to determine the ep0 maxpacket size, try to read
|
||||
* the device descriptor to get bMaxPacketSize0 and
|
||||
* then correct our initial guess.
|
||||
if (initial) {
|
||||
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
|
||||
* it's fixed size except for full speed devices.
|
||||
*/
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_LOW: /* fixed at 8 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
case USB_SPEED_SUPER:
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
break;
|
||||
case USB_SPEED_HIGH: /* fixed at 64 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
|
||||
/* to determine the ep0 maxpacket size, try to read
|
||||
* the device descriptor to get bMaxPacketSize0 and
|
||||
* then correct our initial guess.
|
||||
*/
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_LOW: /* fixed at 8 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (udev->speed == USB_SPEED_WIRELESS)
|
||||
speed = "variable speed Wireless";
|
||||
else
|
||||
speed = usb_speed_string(udev->speed);
|
||||
speed = usb_speed_string(udev->speed);
|
||||
|
||||
/*
|
||||
* The controller driver may be NULL if the controller device
|
||||
@ -4822,22 +4869,24 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
if (udev->speed < USB_SPEED_SUPER)
|
||||
dev_info(&udev->dev,
|
||||
"%s %s USB device number %d using %s\n",
|
||||
(udev->config) ? "reset" : "new", speed,
|
||||
(initial ? "new" : "reset"), speed,
|
||||
devnum, driver_name);
|
||||
|
||||
/* Set up TT records, if needed */
|
||||
if (hdev->tt) {
|
||||
udev->tt = hdev->tt;
|
||||
udev->ttport = hdev->ttport;
|
||||
} else if (udev->speed != USB_SPEED_HIGH
|
||||
&& hdev->speed == USB_SPEED_HIGH) {
|
||||
if (!hub->tt.hub) {
|
||||
dev_err(&udev->dev, "parent hub has no TT\n");
|
||||
retval = -EINVAL;
|
||||
goto fail;
|
||||
if (initial) {
|
||||
/* Set up TT records, if needed */
|
||||
if (hdev->tt) {
|
||||
udev->tt = hdev->tt;
|
||||
udev->ttport = hdev->ttport;
|
||||
} else if (udev->speed != USB_SPEED_HIGH
|
||||
&& hdev->speed == USB_SPEED_HIGH) {
|
||||
if (!hub->tt.hub) {
|
||||
dev_err(&udev->dev, "parent hub has no TT\n");
|
||||
retval = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
udev->tt = &hub->tt;
|
||||
udev->ttport = port1;
|
||||
}
|
||||
udev->tt = &hub->tt;
|
||||
udev->ttport = port1;
|
||||
}
|
||||
|
||||
/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
|
||||
@ -4861,9 +4910,6 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
}
|
||||
|
||||
if (do_new_scheme) {
|
||||
struct usb_device_descriptor *buf;
|
||||
int r = 0;
|
||||
|
||||
retval = hub_enable_device(udev);
|
||||
if (retval < 0) {
|
||||
dev_err(&udev->dev,
|
||||
@ -4872,53 +4918,15 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#define GET_DESCRIPTOR_BUFSIZE 64
|
||||
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
||||
if (!buf) {
|
||||
retval = -ENOMEM;
|
||||
continue;
|
||||
maxp0 = get_bMaxPacketSize0(udev, buf,
|
||||
GET_DESCRIPTOR_BUFSIZE, retries == 0);
|
||||
if (maxp0 > 0 && !initial &&
|
||||
maxp0 != udev->descriptor.bMaxPacketSize0) {
|
||||
dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
|
||||
retval = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Retry on all errors; some devices are flakey.
|
||||
* 255 is for WUSB devices, we actually need to use
|
||||
* 512 (WUSB1.0[4.8.1]).
|
||||
*/
|
||||
for (operations = 0; operations < GET_MAXPACKET0_TRIES;
|
||||
++operations) {
|
||||
buf->bMaxPacketSize0 = 0;
|
||||
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
USB_DT_DEVICE << 8, 0,
|
||||
buf, GET_DESCRIPTOR_BUFSIZE,
|
||||
initial_descriptor_timeout);
|
||||
switch (buf->bMaxPacketSize0) {
|
||||
case 8: case 16: case 32: case 64: case 255:
|
||||
if (buf->bDescriptorType ==
|
||||
USB_DT_DEVICE) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
if (r == 0)
|
||||
r = -EPROTO;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Some devices time out if they are powered on
|
||||
* when already connected. They need a second
|
||||
* reset. But only on the first attempt,
|
||||
* lest we get into a time out/reset loop
|
||||
*/
|
||||
if (r == 0 || (r == -ETIMEDOUT &&
|
||||
retries == 0 &&
|
||||
udev->speed > USB_SPEED_FULL))
|
||||
break;
|
||||
}
|
||||
udev->descriptor.bMaxPacketSize0 =
|
||||
buf->bMaxPacketSize0;
|
||||
kfree(buf);
|
||||
|
||||
retval = hub_port_reset(hub, port1, udev, delay, false);
|
||||
if (retval < 0) /* error or disconnect */
|
||||
goto fail;
|
||||
@ -4928,71 +4936,68 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
retval = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
if (r) {
|
||||
if (r != -ENODEV)
|
||||
if (maxp0 < 0) {
|
||||
if (maxp0 != -ENODEV)
|
||||
dev_err(&udev->dev, "device descriptor read/64, error %d\n",
|
||||
r);
|
||||
retval = -EMSGSIZE;
|
||||
maxp0);
|
||||
retval = maxp0;
|
||||
continue;
|
||||
}
|
||||
#undef GET_DESCRIPTOR_BUFSIZE
|
||||
}
|
||||
|
||||
for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
|
||||
retval = hub_set_address(udev, devnum);
|
||||
if (retval >= 0)
|
||||
break;
|
||||
msleep(200);
|
||||
}
|
||||
if (retval < 0) {
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device not accepting address %d, error %d\n",
|
||||
devnum, retval);
|
||||
goto fail;
|
||||
}
|
||||
if (udev->speed >= USB_SPEED_SUPER) {
|
||||
devnum = udev->devnum;
|
||||
dev_info(&udev->dev,
|
||||
"%s SuperSpeed%s%s USB device number %d using %s\n",
|
||||
(udev->config) ? "reset" : "new",
|
||||
(udev->speed == USB_SPEED_SUPER_PLUS) ?
|
||||
" Plus" : "",
|
||||
(udev->ssp_rate == USB_SSP_GEN_2x2) ?
|
||||
" Gen 2x2" :
|
||||
(udev->ssp_rate == USB_SSP_GEN_2x1) ?
|
||||
" Gen 2x1" :
|
||||
(udev->ssp_rate == USB_SSP_GEN_1x2) ?
|
||||
" Gen 1x2" : "",
|
||||
devnum, driver_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* If device is WUSB, we already assigned an
|
||||
* unauthorized address in the Connect Ack sequence;
|
||||
* authorization will assign the final address.
|
||||
* cope with hardware quirkiness:
|
||||
* - let SET_ADDRESS settle, some device hardware wants it
|
||||
* - read ep0 maxpacket even for high and low speed,
|
||||
*/
|
||||
if (udev->wusb == 0) {
|
||||
for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
|
||||
retval = hub_set_address(udev, devnum);
|
||||
if (retval >= 0)
|
||||
break;
|
||||
msleep(200);
|
||||
}
|
||||
if (retval < 0) {
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device not accepting address %d, error %d\n",
|
||||
devnum, retval);
|
||||
goto fail;
|
||||
}
|
||||
if (udev->speed >= USB_SPEED_SUPER) {
|
||||
devnum = udev->devnum;
|
||||
dev_info(&udev->dev,
|
||||
"%s SuperSpeed%s%s USB device number %d using %s\n",
|
||||
(udev->config) ? "reset" : "new",
|
||||
(udev->speed == USB_SPEED_SUPER_PLUS) ?
|
||||
" Plus" : "",
|
||||
(udev->ssp_rate == USB_SSP_GEN_2x2) ?
|
||||
" Gen 2x2" :
|
||||
(udev->ssp_rate == USB_SSP_GEN_2x1) ?
|
||||
" Gen 2x1" :
|
||||
(udev->ssp_rate == USB_SSP_GEN_1x2) ?
|
||||
" Gen 1x2" : "",
|
||||
devnum, driver_name);
|
||||
}
|
||||
msleep(10);
|
||||
|
||||
/* cope with hardware quirkiness:
|
||||
* - let SET_ADDRESS settle, some device hardware wants it
|
||||
* - read ep0 maxpacket even for high and low speed,
|
||||
*/
|
||||
msleep(10);
|
||||
if (do_new_scheme)
|
||||
break;
|
||||
}
|
||||
if (do_new_scheme)
|
||||
break;
|
||||
|
||||
retval = usb_get_device_descriptor(udev, 8);
|
||||
if (retval < 8) {
|
||||
maxp0 = get_bMaxPacketSize0(udev, buf, 8, retries == 0);
|
||||
if (maxp0 < 0) {
|
||||
retval = maxp0;
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev,
|
||||
"device descriptor read/8, error %d\n",
|
||||
retval);
|
||||
if (retval >= 0)
|
||||
retval = -EMSGSIZE;
|
||||
} else {
|
||||
u32 delay;
|
||||
|
||||
retval = 0;
|
||||
if (!initial && maxp0 != udev->descriptor.bMaxPacketSize0) {
|
||||
dev_err(&udev->dev, "device reset changed ep0 maxpacket size!\n");
|
||||
retval = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
delay = udev->parent->hub_delay;
|
||||
udev->hub_delay = min_t(u32, delay,
|
||||
@ -5010,6 +5015,51 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Check the ep0 maxpacket guess and correct it if necessary.
|
||||
* maxp0 is the value stored in the device descriptor;
|
||||
* i is the value it encodes (logarithmic for SuperSpeed or greater).
|
||||
*/
|
||||
i = maxp0;
|
||||
if (udev->speed >= USB_SPEED_SUPER) {
|
||||
if (maxp0 <= 16)
|
||||
i = 1 << maxp0;
|
||||
else
|
||||
i = 0; /* Invalid */
|
||||
}
|
||||
if (usb_endpoint_maxp(&udev->ep0.desc) == i) {
|
||||
; /* Initial ep0 maxpacket guess is right */
|
||||
} else if ((udev->speed == USB_SPEED_FULL ||
|
||||
udev->speed == USB_SPEED_HIGH) &&
|
||||
(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
/* Initial guess is wrong; use the descriptor's value */
|
||||
if (udev->speed == USB_SPEED_FULL)
|
||||
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
else
|
||||
dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
|
||||
usb_ep0_reinit(udev);
|
||||
} else {
|
||||
/* Initial guess is wrong and descriptor's value is invalid */
|
||||
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", maxp0);
|
||||
retval = -EMSGSIZE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
descr = usb_get_device_descriptor(udev);
|
||||
if (IS_ERR(descr)) {
|
||||
retval = PTR_ERR(descr);
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
||||
retval);
|
||||
goto fail;
|
||||
}
|
||||
if (initial)
|
||||
udev->descriptor = *descr;
|
||||
else
|
||||
*dev_descr = *descr;
|
||||
kfree(descr);
|
||||
|
||||
/*
|
||||
* Some superspeed devices have finished the link training process
|
||||
* and attached to a superspeed hub port, but the device descriptor
|
||||
@ -5018,47 +5068,15 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
*/
|
||||
if ((udev->speed >= USB_SPEED_SUPER) &&
|
||||
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
|
||||
dev_err(&udev->dev, "got a wrong device descriptor, "
|
||||
"warm reset device\n");
|
||||
hub_port_reset(hub, port1, udev,
|
||||
HUB_BH_RESET_TIME, true);
|
||||
dev_err(&udev->dev, "got a wrong device descriptor, warm reset device\n");
|
||||
hub_port_reset(hub, port1, udev, HUB_BH_RESET_TIME, true);
|
||||
retval = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
|
||||
udev->speed >= USB_SPEED_SUPER)
|
||||
i = 512;
|
||||
else
|
||||
i = udev->descriptor.bMaxPacketSize0;
|
||||
if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
|
||||
if (udev->speed == USB_SPEED_LOW ||
|
||||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
|
||||
retval = -EMSGSIZE;
|
||||
goto fail;
|
||||
}
|
||||
if (udev->speed == USB_SPEED_FULL)
|
||||
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
else
|
||||
dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
|
||||
usb_ep0_reinit(udev);
|
||||
}
|
||||
|
||||
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
|
||||
if (retval < (signed)sizeof(udev->descriptor)) {
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
||||
retval);
|
||||
if (retval >= 0)
|
||||
retval = -ENOMSG;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
usb_detect_quirks(udev);
|
||||
|
||||
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
|
||||
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
|
||||
retval = usb_get_bos_descriptor(udev);
|
||||
if (!retval) {
|
||||
udev->lpm_capable = usb_device_supports_lpm(udev);
|
||||
@ -5078,6 +5096,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
hub_port_disable(hub, port1, 0);
|
||||
update_devnum(udev, devnum); /* for disconnect processing */
|
||||
}
|
||||
kfree(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -5158,7 +5177,7 @@ hub_power_remaining(struct usb_hub *hub)
|
||||
|
||||
|
||||
static int descriptors_changed(struct usb_device *udev,
|
||||
struct usb_device_descriptor *old_device_descriptor,
|
||||
struct usb_device_descriptor *new_device_descriptor,
|
||||
struct usb_host_bos *old_bos)
|
||||
{
|
||||
int changed = 0;
|
||||
@ -5169,8 +5188,8 @@ static int descriptors_changed(struct usb_device *udev,
|
||||
int length;
|
||||
char *buf;
|
||||
|
||||
if (memcmp(&udev->descriptor, old_device_descriptor,
|
||||
sizeof(*old_device_descriptor)) != 0)
|
||||
if (memcmp(&udev->descriptor, new_device_descriptor,
|
||||
sizeof(*new_device_descriptor)) != 0)
|
||||
return 1;
|
||||
|
||||
if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
|
||||
@ -5333,7 +5352,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
||||
usb_set_device_state(udev, USB_STATE_POWERED);
|
||||
udev->bus_mA = hub->mA_per_port;
|
||||
udev->level = hdev->level + 1;
|
||||
udev->wusb = hub_is_wusb(hub);
|
||||
|
||||
/* Devices connected to SuperSpeed hubs are USB 3.0 or later */
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
@ -5348,7 +5366,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
||||
}
|
||||
|
||||
/* reset (non-USB 3.0 devices) and get descriptor */
|
||||
status = hub_port_init(hub, udev, port1, i);
|
||||
status = hub_port_init(hub, udev, port1, i, NULL);
|
||||
if (status < 0)
|
||||
goto loop;
|
||||
|
||||
@ -5495,9 +5513,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
{
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
struct usb_device *udev = port_dev->child;
|
||||
struct usb_device_descriptor descriptor;
|
||||
struct usb_device_descriptor *descr;
|
||||
int status = -ENODEV;
|
||||
int retval;
|
||||
|
||||
dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus,
|
||||
portchange, portspeed(hub, portstatus));
|
||||
@ -5524,23 +5541,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
* changed device descriptors before resuscitating the
|
||||
* device.
|
||||
*/
|
||||
descriptor = udev->descriptor;
|
||||
retval = usb_get_device_descriptor(udev,
|
||||
sizeof(udev->descriptor));
|
||||
if (retval < 0) {
|
||||
descr = usb_get_device_descriptor(udev);
|
||||
if (IS_ERR(descr)) {
|
||||
dev_dbg(&udev->dev,
|
||||
"can't read device descriptor %d\n",
|
||||
retval);
|
||||
"can't read device descriptor %ld\n",
|
||||
PTR_ERR(descr));
|
||||
} else {
|
||||
if (descriptors_changed(udev, &descriptor,
|
||||
if (descriptors_changed(udev, descr,
|
||||
udev->bos)) {
|
||||
dev_dbg(&udev->dev,
|
||||
"device descriptor has changed\n");
|
||||
/* for disconnect() calls */
|
||||
udev->descriptor = descriptor;
|
||||
} else {
|
||||
status = 0; /* Nothing to do */
|
||||
}
|
||||
kfree(descr);
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
} else if (udev->state == USB_STATE_SUSPENDED &&
|
||||
@ -5982,7 +5996,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||
struct usb_device *parent_hdev = udev->parent;
|
||||
struct usb_hub *parent_hub;
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
struct usb_device_descriptor descriptor = udev->descriptor;
|
||||
struct usb_device_descriptor descriptor;
|
||||
struct usb_host_bos *bos;
|
||||
int i, j, ret = 0;
|
||||
int port1 = udev->portnum;
|
||||
@ -6018,7 +6032,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||
/* ep0 maxpacket size may change; let the HCD know about it.
|
||||
* Other endpoints will be handled by re-enumeration. */
|
||||
usb_ep0_reinit(udev);
|
||||
ret = hub_port_init(parent_hub, udev, port1, i);
|
||||
ret = hub_port_init(parent_hub, udev, port1, i, &descriptor);
|
||||
if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
|
||||
break;
|
||||
}
|
||||
@ -6030,7 +6044,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||
/* Device might have changed firmware (DFU or similar) */
|
||||
if (descriptors_changed(udev, &descriptor, bos)) {
|
||||
dev_info(&udev->dev, "device firmware changed\n");
|
||||
udev->descriptor = descriptor; /* for disconnect() calls */
|
||||
goto re_enumerate;
|
||||
}
|
||||
|
||||
|
@ -350,18 +350,7 @@ static struct led_trigger usbport_led_trigger = {
|
||||
.deactivate = usbport_trig_deactivate,
|
||||
};
|
||||
|
||||
static int __init usbport_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&usbport_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit usbport_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&usbport_led_trigger);
|
||||
}
|
||||
|
||||
module_init(usbport_trig_init);
|
||||
module_exit(usbport_trig_exit);
|
||||
module_led_trigger(usbport_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");
|
||||
MODULE_DESCRIPTION("USB port trigger");
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/pci.h> /* for scatterlist macros */
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timer.h>
|
||||
@ -1040,40 +1041,35 @@ char *usb_cache_string(struct usb_device *udev, int index)
|
||||
EXPORT_SYMBOL_GPL(usb_cache_string);
|
||||
|
||||
/*
|
||||
* usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
|
||||
* @dev: the device whose device descriptor is being updated
|
||||
* @size: how much of the descriptor to read
|
||||
* usb_get_device_descriptor - read the device descriptor
|
||||
* @udev: the device whose device descriptor should be read
|
||||
*
|
||||
* Context: task context, might sleep.
|
||||
*
|
||||
* Updates the copy of the device descriptor stored in the device structure,
|
||||
* which dedicates space for this purpose.
|
||||
*
|
||||
* Not exported, only for use by the core. If drivers really want to read
|
||||
* the device descriptor directly, they can call usb_get_descriptor() with
|
||||
* type = USB_DT_DEVICE and index = 0.
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*
|
||||
* Return: The number of bytes received on success, or else the status code
|
||||
* returned by the underlying usb_control_msg() call.
|
||||
* Returns: a pointer to a dynamically allocated usb_device_descriptor
|
||||
* structure (which the caller must deallocate), or an ERR_PTR value.
|
||||
*/
|
||||
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
|
||||
struct usb_device_descriptor *usb_get_device_descriptor(struct usb_device *udev)
|
||||
{
|
||||
struct usb_device_descriptor *desc;
|
||||
int ret;
|
||||
|
||||
if (size > sizeof(*desc))
|
||||
return -EINVAL;
|
||||
desc = kmalloc(sizeof(*desc), GFP_NOIO);
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = usb_get_descriptor(udev, USB_DT_DEVICE, 0, desc, sizeof(*desc));
|
||||
if (ret == sizeof(*desc))
|
||||
return desc;
|
||||
|
||||
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
|
||||
if (ret >= 0)
|
||||
memcpy(&dev->descriptor, desc, size);
|
||||
ret = -EMSGSIZE;
|
||||
kfree(desc);
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
||||
/**
|
||||
|
@ -161,9 +161,6 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
|
||||
case USB_SPEED_HIGH:
|
||||
speed = "480";
|
||||
break;
|
||||
case USB_SPEED_WIRELESS:
|
||||
speed = "480";
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
speed = "5000";
|
||||
break;
|
||||
|
@ -480,8 +480,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
urb->iso_frame_desc[n].status = -EXDEV;
|
||||
urb->iso_frame_desc[n].actual_length = 0;
|
||||
}
|
||||
} else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
|
||||
dev->speed != USB_SPEED_WIRELESS) {
|
||||
} else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint) {
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
||||
@ -540,17 +539,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
/* too small? */
|
||||
switch (dev->speed) {
|
||||
case USB_SPEED_WIRELESS:
|
||||
if ((urb->interval < 6)
|
||||
&& (xfertype == USB_ENDPOINT_XFER_INT))
|
||||
return -EINVAL;
|
||||
fallthrough;
|
||||
default:
|
||||
if (urb->interval <= 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (urb->interval <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* too big? */
|
||||
switch (dev->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
@ -560,10 +551,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
return -EINVAL;
|
||||
max = 1 << 15;
|
||||
break;
|
||||
case USB_SPEED_WIRELESS:
|
||||
if (urb->interval > 16)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case USB_SPEED_HIGH: /* units are microframes */
|
||||
/* NOTE usb handles 2^15 */
|
||||
if (urb->interval > (1024 * 8))
|
||||
@ -587,10 +574,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (dev->speed != USB_SPEED_WIRELESS) {
|
||||
/* Round down to a power of 2, no more than max */
|
||||
urb->interval = min(max, 1 << ilog2(urb->interval));
|
||||
}
|
||||
/* Round down to a power of 2, no more than max */
|
||||
urb->interval = min(max, 1 << ilog2(urb->interval));
|
||||
}
|
||||
|
||||
return usb_hcd_submit_urb(urb, mem_flags);
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
@ -601,14 +602,6 @@ struct device_type usb_device_type = {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
|
||||
static unsigned usb_bus_is_wusb(struct usb_bus *bus)
|
||||
{
|
||||
struct usb_hcd *hcd = bus_to_hcd(bus);
|
||||
return hcd->wireless;
|
||||
}
|
||||
|
||||
static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
@ -652,7 +645,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
{
|
||||
struct usb_device *dev;
|
||||
struct usb_hcd *usb_hcd = bus_to_hcd(bus);
|
||||
unsigned root_hub = 0;
|
||||
unsigned raw_port = port1;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
@ -702,7 +694,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
dev->dev.parent = bus->controller;
|
||||
device_set_of_node_from_dev(&dev->dev, bus->sysdev);
|
||||
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
||||
root_hub = 1;
|
||||
} else {
|
||||
/* match any labeling on the hubs; it's one-based */
|
||||
if (parent->devpath[0] == '0') {
|
||||
@ -748,9 +739,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
#endif
|
||||
|
||||
dev->authorized = usb_dev_authorized(dev, usb_hcd);
|
||||
if (!root_hub)
|
||||
dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0;
|
||||
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_alloc_dev);
|
||||
@ -1101,6 +1089,9 @@ static int __init usb_init(void)
|
||||
retval = usb_major_init();
|
||||
if (retval)
|
||||
goto major_init_failed;
|
||||
retval = class_register(&usbmisc_class);
|
||||
if (retval)
|
||||
goto class_register_failed;
|
||||
retval = usb_register(&usbfs_driver);
|
||||
if (retval)
|
||||
goto driver_register_failed;
|
||||
@ -1120,6 +1111,8 @@ static int __init usb_init(void)
|
||||
usb_devio_init_failed:
|
||||
usb_deregister(&usbfs_driver);
|
||||
driver_register_failed:
|
||||
class_unregister(&usbmisc_class);
|
||||
class_register_failed:
|
||||
usb_major_cleanup();
|
||||
major_init_failed:
|
||||
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
@ -1147,6 +1140,7 @@ static void __exit usb_exit(void)
|
||||
usb_deregister(&usbfs_driver);
|
||||
usb_devio_cleanup();
|
||||
usb_hub_cleanup();
|
||||
class_unregister(&usbmisc_class);
|
||||
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
bus_unregister(&usb_bus_type);
|
||||
usb_acpi_unregister();
|
||||
|
@ -43,8 +43,8 @@ extern bool usb_endpoint_is_ignored(struct usb_device *udev,
|
||||
struct usb_endpoint_descriptor *epd);
|
||||
extern int usb_remove_device(struct usb_device *udev);
|
||||
|
||||
extern int usb_get_device_descriptor(struct usb_device *dev,
|
||||
unsigned int size);
|
||||
extern struct usb_device_descriptor *usb_get_device_descriptor(
|
||||
struct usb_device *udev);
|
||||
extern int usb_set_isoch_delay(struct usb_device *dev);
|
||||
extern int usb_get_bos_descriptor(struct usb_device *dev);
|
||||
extern void usb_release_bos_descriptor(struct usb_device *dev);
|
||||
@ -141,6 +141,7 @@ static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
|
||||
|
||||
#endif
|
||||
|
||||
extern const struct class usbmisc_class;
|
||||
extern const struct bus_type usb_bus_type;
|
||||
extern struct mutex usb_port_peer_mutex;
|
||||
extern struct device_type usb_device_type;
|
||||
|
@ -1330,6 +1330,7 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
|
||||
/* The device ID match table */
|
||||
extern const struct of_device_id dwc2_of_match_table[];
|
||||
extern const struct acpi_device_id dwc2_acpi_match[];
|
||||
extern const struct pci_device_id dwc2_pci_ids[];
|
||||
|
||||
int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
@ -2203,11 +2203,13 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
|
||||
irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 gintsts, dbg_gintsts;
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
irqreturn_t retval = IRQ_HANDLED;
|
||||
|
||||
if (!dwc2_is_controller_alive(hsotg)) {
|
||||
dev_warn(hsotg->dev, "Controller is dead\n");
|
||||
return retval;
|
||||
} else {
|
||||
retval = IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_lock(&hsotg->lock);
|
||||
|
@ -7,9 +7,14 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
|
||||
#define PCI_DEVICE_ID_LOONGSON_DWC2 0x7a04
|
||||
|
||||
static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
@ -55,6 +60,14 @@ static void dwc2_set_jz4775_params(struct dwc2_hsotg *hsotg)
|
||||
!device_property_read_bool(hsotg->dev, "disable-over-current");
|
||||
}
|
||||
|
||||
static void dwc2_set_loongson_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->phy_utmi_width = 8;
|
||||
p->power_down = DWC2_POWER_DOWN_PARAM_PARTIAL;
|
||||
}
|
||||
|
||||
static void dwc2_set_x1600_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
@ -302,6 +315,23 @@ const struct acpi_device_id dwc2_acpi_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwc2_acpi_match);
|
||||
|
||||
const struct pci_device_id dwc2_pci_ids[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
|
||||
PCI_DEVICE_ID_STMICRO_USB_OTG),
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DWC2),
|
||||
.driver_data = (unsigned long)dwc2_set_loongson_params,
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
|
||||
EXPORT_SYMBOL_GPL(dwc2_pci_ids);
|
||||
|
||||
static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
switch (hsotg->hw_params.op_mode) {
|
||||
@ -948,13 +978,20 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg)
|
||||
if (match && match->data) {
|
||||
set_params = match->data;
|
||||
set_params(hsotg);
|
||||
} else {
|
||||
} else if (!match) {
|
||||
const struct acpi_device_id *amatch;
|
||||
const struct pci_device_id *pmatch = NULL;
|
||||
|
||||
amatch = acpi_match_device(dwc2_acpi_match, hsotg->dev);
|
||||
if (amatch && amatch->driver_data) {
|
||||
set_params = (set_params_cb)amatch->driver_data;
|
||||
set_params(hsotg);
|
||||
} else if (!amatch)
|
||||
pmatch = pci_match_id(dwc2_pci_ids, to_pci_dev(hsotg->dev->parent));
|
||||
|
||||
if (pmatch && pmatch->driver_data) {
|
||||
set_params = (set_params_cb)pmatch->driver_data;
|
||||
set_params(hsotg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/usb_phy_generic.h>
|
||||
|
||||
#define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
|
||||
#include "core.h"
|
||||
|
||||
static const char dwc2_driver_name[] = "dwc2-pci";
|
||||
|
||||
@ -122,18 +122,6 @@ static int dwc2_pci_probe(struct pci_dev *pci,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct pci_device_id dwc2_pci_ids[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
|
||||
PCI_DEVICE_ID_STMICRO_USB_OTG),
|
||||
},
|
||||
{ /* end: all zeroes */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
|
||||
|
||||
static struct pci_driver dwc2_pci_driver = {
|
||||
.name = dwc2_driver_name,
|
||||
.id_table = dwc2_pci_ids,
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
@ -168,4 +168,14 @@ config USB_DWC3_AM62
|
||||
The Designware Core USB3 IP is programmed to operate in
|
||||
in USB 2.0 mode only.
|
||||
Say 'Y' or 'M' here if you have one such device
|
||||
|
||||
config USB_DWC3_OCTEON
|
||||
tristate "Cavium Octeon Platforms"
|
||||
depends on CAVIUM_OCTEON_SOC || COMPILE_TEST
|
||||
default USB_DWC3
|
||||
help
|
||||
Support Cavium Octeon platforms with DesignWare Core USB3 IP.
|
||||
Only the host mode is currently supported.
|
||||
Say 'Y' or 'M' here if you have one such device.
|
||||
|
||||
endif
|
||||
|
@ -54,3 +54,4 @@ obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o
|
||||
obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o
|
||||
obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o
|
||||
obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o
|
||||
obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o
|
||||
|
@ -102,7 +102,7 @@
|
||||
|
||||
#define DWC3_AM62_AUTOSUSPEND_DELAY 100
|
||||
|
||||
struct dwc3_data {
|
||||
struct dwc3_am62 {
|
||||
struct device *dev;
|
||||
void __iomem *usbss;
|
||||
struct clk *usb2_refclk;
|
||||
@ -129,19 +129,19 @@ static const int dwc3_ti_rate_table[] = { /* in KHZ */
|
||||
52000,
|
||||
};
|
||||
|
||||
static inline u32 dwc3_ti_readl(struct dwc3_data *data, u32 offset)
|
||||
static inline u32 dwc3_ti_readl(struct dwc3_am62 *am62, u32 offset)
|
||||
{
|
||||
return readl((data->usbss) + offset);
|
||||
return readl((am62->usbss) + offset);
|
||||
}
|
||||
|
||||
static inline void dwc3_ti_writel(struct dwc3_data *data, u32 offset, u32 value)
|
||||
static inline void dwc3_ti_writel(struct dwc3_am62 *am62, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, (data->usbss) + offset);
|
||||
writel(value, (am62->usbss) + offset);
|
||||
}
|
||||
|
||||
static int phy_syscon_pll_refclk(struct dwc3_data *data)
|
||||
static int phy_syscon_pll_refclk(struct dwc3_am62 *am62)
|
||||
{
|
||||
struct device *dev = data->dev;
|
||||
struct device *dev = am62->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct of_phandle_args args;
|
||||
struct regmap *syscon;
|
||||
@ -153,16 +153,16 @@ static int phy_syscon_pll_refclk(struct dwc3_data *data)
|
||||
return PTR_ERR(syscon);
|
||||
}
|
||||
|
||||
data->syscon = syscon;
|
||||
am62->syscon = syscon;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-phy-pll-refclk", 1,
|
||||
0, &args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->offset = args.args[0];
|
||||
am62->offset = args.args[0];
|
||||
|
||||
ret = regmap_update_bits(data->syscon, data->offset, PHY_PLL_REFCLK_MASK, data->rate_code);
|
||||
ret = regmap_update_bits(am62->syscon, am62->offset, PHY_PLL_REFCLK_MASK, am62->rate_code);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set phy pll reference clock rate\n");
|
||||
return ret;
|
||||
@ -175,32 +175,32 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct dwc3_data *data;
|
||||
struct dwc3_am62 *am62;
|
||||
int i, ret;
|
||||
unsigned long rate;
|
||||
u32 reg;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
am62 = devm_kzalloc(dev, sizeof(*am62), GFP_KERNEL);
|
||||
if (!am62)
|
||||
return -ENOMEM;
|
||||
|
||||
data->dev = dev;
|
||||
platform_set_drvdata(pdev, data);
|
||||
am62->dev = dev;
|
||||
platform_set_drvdata(pdev, am62);
|
||||
|
||||
data->usbss = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->usbss)) {
|
||||
am62->usbss = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(am62->usbss)) {
|
||||
dev_err(dev, "can't map IOMEM resource\n");
|
||||
return PTR_ERR(data->usbss);
|
||||
return PTR_ERR(am62->usbss);
|
||||
}
|
||||
|
||||
data->usb2_refclk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(data->usb2_refclk)) {
|
||||
am62->usb2_refclk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(am62->usb2_refclk)) {
|
||||
dev_err(dev, "can't get usb2_refclk\n");
|
||||
return PTR_ERR(data->usb2_refclk);
|
||||
return PTR_ERR(am62->usb2_refclk);
|
||||
}
|
||||
|
||||
/* Calculate the rate code */
|
||||
rate = clk_get_rate(data->usb2_refclk);
|
||||
rate = clk_get_rate(am62->usb2_refclk);
|
||||
rate /= 1000; // To KHz
|
||||
for (i = 0; i < ARRAY_SIZE(dwc3_ti_rate_table); i++) {
|
||||
if (dwc3_ti_rate_table[i] == rate)
|
||||
@ -212,20 +212,20 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->rate_code = i;
|
||||
am62->rate_code = i;
|
||||
|
||||
/* Read the syscon property and set the rate code */
|
||||
ret = phy_syscon_pll_refclk(data);
|
||||
ret = phy_syscon_pll_refclk(am62);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* VBUS divider select */
|
||||
data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
|
||||
reg = dwc3_ti_readl(data, USBSS_PHY_CONFIG);
|
||||
if (data->vbus_divider)
|
||||
am62->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
|
||||
reg = dwc3_ti_readl(am62, USBSS_PHY_CONFIG);
|
||||
if (am62->vbus_divider)
|
||||
reg |= 1 << USBSS_PHY_VBUS_SEL_SHIFT;
|
||||
|
||||
dwc3_ti_writel(data, USBSS_PHY_CONFIG, reg);
|
||||
dwc3_ti_writel(am62, USBSS_PHY_CONFIG, reg);
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
@ -233,7 +233,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
* Don't ignore its dependencies with its children
|
||||
*/
|
||||
pm_suspend_ignore_children(dev, false);
|
||||
clk_prepare_enable(data->usb2_refclk);
|
||||
clk_prepare_enable(am62->usb2_refclk);
|
||||
pm_runtime_get_noresume(dev);
|
||||
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
@ -243,9 +243,9 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Set mode valid bit to indicate role is valid */
|
||||
reg = dwc3_ti_readl(data, USBSS_MODE_CONTROL);
|
||||
reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
|
||||
reg |= USBSS_MODE_VALID;
|
||||
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
|
||||
dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
|
||||
|
||||
/* Device has capability to wakeup system from sleep */
|
||||
device_set_wakeup_capable(dev, true);
|
||||
@ -261,7 +261,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_pm_disable:
|
||||
clk_disable_unprepare(data->usb2_refclk);
|
||||
clk_disable_unprepare(am62->usb2_refclk);
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
return ret;
|
||||
@ -278,36 +278,34 @@ static int dwc3_ti_remove_core(struct device *dev, void *c)
|
||||
static void dwc3_ti_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dwc3_data *data = platform_get_drvdata(pdev);
|
||||
struct dwc3_am62 *am62 = platform_get_drvdata(pdev);
|
||||
u32 reg;
|
||||
|
||||
device_for_each_child(dev, NULL, dwc3_ti_remove_core);
|
||||
|
||||
/* Clear mode valid bit */
|
||||
reg = dwc3_ti_readl(data, USBSS_MODE_CONTROL);
|
||||
reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
|
||||
reg &= ~USBSS_MODE_VALID;
|
||||
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);
|
||||
dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
clk_disable_unprepare(data->usb2_refclk);
|
||||
clk_disable_unprepare(am62->usb2_refclk);
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dwc3_ti_suspend_common(struct device *dev)
|
||||
{
|
||||
struct dwc3_data *data = dev_get_drvdata(dev);
|
||||
struct dwc3_am62 *am62 = dev_get_drvdata(dev);
|
||||
u32 reg, current_prtcap_dir;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
reg = dwc3_ti_readl(data, USBSS_CORE_STAT);
|
||||
reg = dwc3_ti_readl(am62, USBSS_CORE_STAT);
|
||||
current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK)
|
||||
>> USBSS_CORE_OPERATIONAL_MODE_SHIFT;
|
||||
/* Set wakeup config enable bits */
|
||||
reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG);
|
||||
reg = dwc3_ti_readl(am62, USBSS_WAKEUP_CONFIG);
|
||||
if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) {
|
||||
reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN;
|
||||
} else {
|
||||
@ -317,30 +315,30 @@ static int dwc3_ti_suspend_common(struct device *dev)
|
||||
* and in U2/L3 state else it causes spurious wake-up.
|
||||
*/
|
||||
}
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg);
|
||||
dwc3_ti_writel(am62, USBSS_WAKEUP_CONFIG, reg);
|
||||
/* clear wakeup status so we know what caused the wake up */
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR);
|
||||
dwc3_ti_writel(am62, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(data->usb2_refclk);
|
||||
clk_disable_unprepare(am62->usb2_refclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ti_resume_common(struct device *dev)
|
||||
{
|
||||
struct dwc3_data *data = dev_get_drvdata(dev);
|
||||
struct dwc3_am62 *am62 = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
|
||||
clk_prepare_enable(data->usb2_refclk);
|
||||
clk_prepare_enable(am62->usb2_refclk);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
/* Clear wakeup config enable bits */
|
||||
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE);
|
||||
dwc3_ti_writel(am62, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE);
|
||||
}
|
||||
|
||||
reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT);
|
||||
data->wakeup_stat = reg;
|
||||
reg = dwc3_ti_readl(am62, USBSS_WAKEUP_STAT);
|
||||
am62->wakeup_stat = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -163,6 +163,12 @@ static const struct dwc3_exynos_driverdata exynos7_drvdata = {
|
||||
.suspend_clk_idx = 1,
|
||||
};
|
||||
|
||||
static const struct dwc3_exynos_driverdata exynos850_drvdata = {
|
||||
.clk_names = { "bus_early", "ref" },
|
||||
.num_clks = 2,
|
||||
.suspend_clk_idx = -1,
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos_dwc3_match[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5250-dwusb3",
|
||||
@ -173,6 +179,9 @@ static const struct of_device_id exynos_dwc3_match[] = {
|
||||
}, {
|
||||
.compatible = "samsung,exynos7-dwusb3",
|
||||
.data = &exynos7_drvdata,
|
||||
}, {
|
||||
.compatible = "samsung,exynos850-dwusb3",
|
||||
.data = &exynos850_drvdata,
|
||||
}, {
|
||||
}
|
||||
};
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -279,7 +280,6 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static int __maybe_unused dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -196,8 +197,6 @@ static void kdwc3_remove(struct platform_device *pdev)
|
||||
phy_power_off(kdwc->usb3_phy);
|
||||
phy_exit(kdwc->usb3_phy);
|
||||
phy_pm_runtime_put_sync(kdwc->usb3_phy);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static const struct of_device_id kdwc3_of_match[] = {
|
||||
|
@ -926,6 +926,12 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->drvdata->usb_post_init) {
|
||||
ret = priv->drvdata->usb_post_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* XHCI HCD glue for Cavium Octeon III SOCs.
|
||||
* DWC3 glue for Cavium Octeon III SOCs.
|
||||
*
|
||||
* Copyright (C) 2010-2017 Cavium Networks
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
* Copyright (C) 2023 RACOM s.r.o.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
@ -24,9 +22,9 @@
|
||||
/* BIST fast-clear mode select. A BIST run with this bit set
|
||||
* clears all entries in USBH RAMs to 0x0.
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_CLEAR_BIST BIT(63)
|
||||
# define USBDRD_UCTL_CTL_CLEAR_BIST BIT_ULL(63)
|
||||
/* 1 = Start BIST and cleared by hardware */
|
||||
# define USBDRD_UCTL_CTL_START_BIST BIT(62)
|
||||
# define USBDRD_UCTL_CTL_START_BIST BIT_ULL(62)
|
||||
/* Reference clock select for SuperSpeed and HighSpeed PLLs:
|
||||
* 0x0 = Both PLLs use DLMC_REF_CLK0 for reference clock
|
||||
* 0x1 = Both PLLs use DLMC_REF_CLK1 for reference clock
|
||||
@ -35,32 +33,32 @@
|
||||
* 0x3 = SuperSpeed PLL uses DLMC_REF_CLK1 for reference clock &
|
||||
* HighSpeed PLL uses PLL_REF_CLK for reference clck
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_SEL GENMASK(61, 60)
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_SEL GENMASK_ULL(61, 60)
|
||||
/* 1 = Spread-spectrum clock enable, 0 = SS clock disable */
|
||||
# define USBDRD_UCTL_CTL_SSC_EN BIT(59)
|
||||
# define USBDRD_UCTL_CTL_SSC_EN BIT_ULL(59)
|
||||
/* Spread-spectrum clock modulation range:
|
||||
* 0x0 = -4980 ppm downspread
|
||||
* 0x1 = -4492 ppm downspread
|
||||
* 0x2 = -4003 ppm downspread
|
||||
* 0x3 - 0x7 = Reserved
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_SSC_RANGE GENMASK(58, 56)
|
||||
# define USBDRD_UCTL_CTL_SSC_RANGE GENMASK_ULL(58, 56)
|
||||
/* Enable non-standard oscillator frequencies:
|
||||
* [55:53] = modules -1
|
||||
* [52:47] = 2's complement push amount, 0 = Feature disabled
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_SSC_REF_CLK_SEL GENMASK(55, 47)
|
||||
# define USBDRD_UCTL_CTL_SSC_REF_CLK_SEL GENMASK_ULL(55, 47)
|
||||
/* Reference clock multiplier for non-standard frequencies:
|
||||
* 0x19 = 100MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
|
||||
* 0x28 = 125MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
|
||||
* 0x32 = 50MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
|
||||
* Other Values = Reserved
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_MPLL_MULTIPLIER GENMASK(46, 40)
|
||||
# define USBDRD_UCTL_CTL_MPLL_MULTIPLIER GENMASK_ULL(46, 40)
|
||||
/* Enable reference clock to prescaler for SuperSpeed functionality.
|
||||
* Should always be set to "1"
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_REF_SSP_EN BIT(39)
|
||||
# define USBDRD_UCTL_CTL_REF_SSP_EN BIT_ULL(39)
|
||||
/* Divide the reference clock by 2 before entering the
|
||||
* REF_CLK_FSEL divider:
|
||||
* If REF_CLK_SEL = 0x0 or 0x1, then only 0x0 is legal
|
||||
@ -68,21 +66,21 @@
|
||||
* 0x1 = DLMC_REF_CLK* is 125MHz
|
||||
* 0x0 = DLMC_REF_CLK* is another supported frequency
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_DIV2 BIT(38)
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_DIV2 BIT_ULL(38)
|
||||
/* Select reference clock freqnuency for both PLL blocks:
|
||||
* 0x27 = REF_CLK_SEL is 0x0 or 0x1
|
||||
* 0x07 = REF_CLK_SEL is 0x2 or 0x3
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_FSEL GENMASK(37, 32)
|
||||
# define USBDRD_UCTL_CTL_REF_CLK_FSEL GENMASK_ULL(37, 32)
|
||||
/* Controller clock enable. */
|
||||
# define USBDRD_UCTL_CTL_H_CLK_EN BIT(30)
|
||||
# define USBDRD_UCTL_CTL_H_CLK_EN BIT_ULL(30)
|
||||
/* Select bypass input to controller clock divider:
|
||||
* 0x0 = Use divided coprocessor clock from H_CLKDIV
|
||||
* 0x1 = Use clock from GPIO pins
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_H_CLK_BYP_SEL BIT(29)
|
||||
# define USBDRD_UCTL_CTL_H_CLK_BYP_SEL BIT_ULL(29)
|
||||
/* Reset controller clock divider. */
|
||||
# define USBDRD_UCTL_CTL_H_CLKDIV_RST BIT(28)
|
||||
# define USBDRD_UCTL_CTL_H_CLKDIV_RST BIT_ULL(28)
|
||||
/* Clock divider select:
|
||||
* 0x0 = divide by 1
|
||||
* 0x1 = divide by 2
|
||||
@ -93,29 +91,29 @@
|
||||
* 0x6 = divide by 24
|
||||
* 0x7 = divide by 32
|
||||
*/
|
||||
# define USBDRD_UCTL_CTL_H_CLKDIV_SEL GENMASK(26, 24)
|
||||
# define USBDRD_UCTL_CTL_H_CLKDIV_SEL GENMASK_ULL(26, 24)
|
||||
/* USB3 port permanently attached: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_USB3_PORT_PERM_ATTACH BIT(21)
|
||||
# define USBDRD_UCTL_CTL_USB3_PORT_PERM_ATTACH BIT_ULL(21)
|
||||
/* USB2 port permanently attached: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_USB2_PORT_PERM_ATTACH BIT(20)
|
||||
# define USBDRD_UCTL_CTL_USB2_PORT_PERM_ATTACH BIT_ULL(20)
|
||||
/* Disable SuperSpeed PHY: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_USB3_PORT_DISABLE BIT(18)
|
||||
# define USBDRD_UCTL_CTL_USB3_PORT_DISABLE BIT_ULL(18)
|
||||
/* Disable HighSpeed PHY: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_USB2_PORT_DISABLE BIT(16)
|
||||
# define USBDRD_UCTL_CTL_USB2_PORT_DISABLE BIT_ULL(16)
|
||||
/* Enable PHY SuperSpeed block power: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_SS_POWER_EN BIT(14)
|
||||
# define USBDRD_UCTL_CTL_SS_POWER_EN BIT_ULL(14)
|
||||
/* Enable PHY HighSpeed block power: 0x0 = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_HS_POWER_EN BIT(12)
|
||||
# define USBDRD_UCTL_CTL_HS_POWER_EN BIT_ULL(12)
|
||||
/* Enable USB UCTL interface clock: 0xx = No, 0x1 = Yes */
|
||||
# define USBDRD_UCTL_CTL_CSCLK_EN BIT(4)
|
||||
# define USBDRD_UCTL_CTL_CSCLK_EN BIT_ULL(4)
|
||||
/* Controller mode: 0x0 = Host, 0x1 = Device */
|
||||
# define USBDRD_UCTL_CTL_DRD_MODE BIT(3)
|
||||
# define USBDRD_UCTL_CTL_DRD_MODE BIT_ULL(3)
|
||||
/* PHY reset */
|
||||
# define USBDRD_UCTL_CTL_UPHY_RST BIT(2)
|
||||
# define USBDRD_UCTL_CTL_UPHY_RST BIT_ULL(2)
|
||||
/* Software reset UAHC */
|
||||
# define USBDRD_UCTL_CTL_UAHC_RST BIT(1)
|
||||
# define USBDRD_UCTL_CTL_UAHC_RST BIT_ULL(1)
|
||||
/* Software resets UCTL */
|
||||
# define USBDRD_UCTL_CTL_UCTL_RST BIT(0)
|
||||
# define USBDRD_UCTL_CTL_UCTL_RST BIT_ULL(0)
|
||||
|
||||
#define USBDRD_UCTL_BIST_STATUS 0x08
|
||||
#define USBDRD_UCTL_SPARE0 0x10
|
||||
@ -130,64 +128,69 @@
|
||||
*/
|
||||
#define USBDRD_UCTL_HOST_CFG 0xe0
|
||||
/* Indicates minimum value of all received BELT values */
|
||||
# define USBDRD_UCTL_HOST_CFG_HOST_CURRENT_BELT GENMASK(59, 48)
|
||||
# define USBDRD_UCTL_HOST_CFG_HOST_CURRENT_BELT GENMASK_ULL(59, 48)
|
||||
/* HS jitter adjustment */
|
||||
# define USBDRD_UCTL_HOST_CFG_FLA GENMASK(37, 32)
|
||||
# define USBDRD_UCTL_HOST_CFG_FLA GENMASK_ULL(37, 32)
|
||||
/* Bus-master enable: 0x0 = Disabled (stall DMAs), 0x1 = enabled */
|
||||
# define USBDRD_UCTL_HOST_CFG_BME BIT(28)
|
||||
# define USBDRD_UCTL_HOST_CFG_BME BIT_ULL(28)
|
||||
/* Overcurrent protection enable: 0x0 = unavailable, 0x1 = available */
|
||||
# define USBDRD_UCTL_HOST_OCI_EN BIT(27)
|
||||
# define USBDRD_UCTL_HOST_OCI_EN BIT_ULL(27)
|
||||
/* Overcurrent sene selection:
|
||||
* 0x0 = Overcurrent indication from off-chip is active-low
|
||||
* 0x1 = Overcurrent indication from off-chip is active-high
|
||||
*/
|
||||
# define USBDRD_UCTL_HOST_OCI_ACTIVE_HIGH_EN BIT(26)
|
||||
# define USBDRD_UCTL_HOST_OCI_ACTIVE_HIGH_EN BIT_ULL(26)
|
||||
/* Port power control enable: 0x0 = unavailable, 0x1 = available */
|
||||
# define USBDRD_UCTL_HOST_PPC_EN BIT(25)
|
||||
# define USBDRD_UCTL_HOST_PPC_EN BIT_ULL(25)
|
||||
/* Port power control sense selection:
|
||||
* 0x0 = Port power to off-chip is active-low
|
||||
* 0x1 = Port power to off-chip is active-high
|
||||
*/
|
||||
# define USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN BIT(24)
|
||||
# define USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN BIT_ULL(24)
|
||||
|
||||
/*
|
||||
* UCTL Shim Features Register
|
||||
*/
|
||||
#define USBDRD_UCTL_SHIM_CFG 0xe8
|
||||
/* Out-of-bound UAHC register access: 0 = read, 1 = write */
|
||||
# define USBDRD_UCTL_SHIM_CFG_XS_NCB_OOB_WRN BIT(63)
|
||||
# define USBDRD_UCTL_SHIM_CFG_XS_NCB_OOB_WRN BIT_ULL(63)
|
||||
/* SRCID error log for out-of-bound UAHC register access:
|
||||
* [59:58] = chipID
|
||||
* [57] = Request source: 0 = core, 1 = NCB-device
|
||||
* [56:51] = Core/NCB-device number, [56] always 0 for NCB devices
|
||||
* [50:48] = SubID
|
||||
*/
|
||||
# define USBDRD_UCTL_SHIM_CFG_XS_NCB_OOB_OSRC GENMASK(59, 48)
|
||||
# define USBDRD_UCTL_SHIM_CFG_XS_NCB_OOB_OSRC GENMASK_ULL(59, 48)
|
||||
/* Error log for bad UAHC DMA access: 0 = Read log, 1 = Write log */
|
||||
# define USBDRD_UCTL_SHIM_CFG_XM_BAD_DMA_WRN BIT(47)
|
||||
# define USBDRD_UCTL_SHIM_CFG_XM_BAD_DMA_WRN BIT_ULL(47)
|
||||
/* Encoded error type for bad UAHC DMA */
|
||||
# define USBDRD_UCTL_SHIM_CFG_XM_BAD_DMA_TYPE GENMASK(43, 40)
|
||||
# define USBDRD_UCTL_SHIM_CFG_XM_BAD_DMA_TYPE GENMASK_ULL(43, 40)
|
||||
/* Select the IOI read command used by DMA accesses */
|
||||
# define USBDRD_UCTL_SHIM_CFG_DMA_READ_CMD BIT(12)
|
||||
# define USBDRD_UCTL_SHIM_CFG_DMA_READ_CMD BIT_ULL(12)
|
||||
/* Select endian format for DMA accesses to the L2C:
|
||||
* 0x0 = Little endian
|
||||
* 0x1 = Big endian
|
||||
* 0x2 = Reserved
|
||||
* 0x3 = Reserved
|
||||
*/
|
||||
# define USBDRD_UCTL_SHIM_CFG_DMA_ENDIAN_MODE GENMASK(9, 8)
|
||||
# define USBDRD_UCTL_SHIM_CFG_DMA_ENDIAN_MODE GENMASK_ULL(9, 8)
|
||||
/* Select endian format for IOI CSR access to UAHC:
|
||||
* 0x0 = Little endian
|
||||
* 0x1 = Big endian
|
||||
* 0x2 = Reserved
|
||||
* 0x3 = Reserved
|
||||
*/
|
||||
# define USBDRD_UCTL_SHIM_CFG_CSR_ENDIAN_MODE GENMASK(1, 0)
|
||||
# define USBDRD_UCTL_SHIM_CFG_CSR_ENDIAN_MODE GENMASK_ULL(1, 0)
|
||||
|
||||
#define USBDRD_UCTL_ECC 0xf0
|
||||
#define USBDRD_UCTL_SPARE1 0xf8
|
||||
|
||||
static DEFINE_MUTEX(dwc3_octeon_clocks_mutex);
|
||||
struct dwc3_octeon {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
#define DWC3_GPIO_POWER_NONE (-1)
|
||||
|
||||
#ifdef CONFIG_CAVIUM_OCTEON_SOC
|
||||
#include <asm/octeon/octeon.h>
|
||||
@ -233,6 +236,11 @@ static inline uint64_t dwc3_octeon_readq(void __iomem *addr)
|
||||
static inline void dwc3_octeon_writeq(void __iomem *base, uint64_t val) { }
|
||||
|
||||
static inline void dwc3_octeon_config_gpio(int index, int gpio) { }
|
||||
|
||||
static uint64_t octeon_get_io_clock_rate(void)
|
||||
{
|
||||
return 150000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dwc3_octeon_get_divider(void)
|
||||
@ -243,115 +251,22 @@ static int dwc3_octeon_get_divider(void)
|
||||
while (div < ARRAY_SIZE(clk_div)) {
|
||||
uint64_t rate = octeon_get_io_clock_rate() / clk_div[div];
|
||||
if (rate <= 300000000 && rate >= 150000000)
|
||||
break;
|
||||
return div;
|
||||
div++;
|
||||
}
|
||||
|
||||
return div;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dwc3_octeon_config_power(struct device *dev, void __iomem *base)
|
||||
static int dwc3_octeon_setup(struct dwc3_octeon *octeon,
|
||||
int ref_clk_sel, int ref_clk_fsel, int mpll_mul,
|
||||
int power_gpio, int power_active_low)
|
||||
{
|
||||
uint32_t gpio_pwr[3];
|
||||
int gpio, len, power_active_low;
|
||||
struct device_node *node = dev->of_node;
|
||||
u64 val;
|
||||
void __iomem *uctl_host_cfg_reg = base + USBDRD_UCTL_HOST_CFG;
|
||||
|
||||
if (of_find_property(node, "power", &len) != NULL) {
|
||||
if (len == 12) {
|
||||
of_property_read_u32_array(node, "power", gpio_pwr, 3);
|
||||
power_active_low = gpio_pwr[2] & 0x01;
|
||||
gpio = gpio_pwr[1];
|
||||
} else if (len == 8) {
|
||||
of_property_read_u32_array(node, "power", gpio_pwr, 2);
|
||||
power_active_low = 0;
|
||||
gpio = gpio_pwr[1];
|
||||
} else {
|
||||
dev_err(dev, "invalid power configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dwc3_octeon_config_gpio(((u64)base >> 24) & 1, gpio);
|
||||
|
||||
/* Enable XHCI power control and set if active high or low. */
|
||||
val = dwc3_octeon_readq(uctl_host_cfg_reg);
|
||||
val |= USBDRD_UCTL_HOST_PPC_EN;
|
||||
if (power_active_low)
|
||||
val &= ~USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN;
|
||||
else
|
||||
val |= USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN;
|
||||
dwc3_octeon_writeq(uctl_host_cfg_reg, val);
|
||||
} else {
|
||||
/* Disable XHCI power control and set if active high. */
|
||||
val = dwc3_octeon_readq(uctl_host_cfg_reg);
|
||||
val &= ~USBDRD_UCTL_HOST_PPC_EN;
|
||||
val &= ~USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN;
|
||||
dwc3_octeon_writeq(uctl_host_cfg_reg, val);
|
||||
dev_info(dev, "power control disabled\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
{
|
||||
int i, div, mpll_mul, ref_clk_fsel, ref_clk_sel = 2;
|
||||
u32 clock_rate;
|
||||
u64 val;
|
||||
void __iomem *uctl_ctl_reg = base + USBDRD_UCTL_CTL;
|
||||
|
||||
if (dev->of_node) {
|
||||
const char *ss_clock_type;
|
||||
const char *hs_clock_type;
|
||||
|
||||
i = of_property_read_u32(dev->of_node,
|
||||
"refclk-frequency", &clock_rate);
|
||||
if (i) {
|
||||
dev_err(dev, "No UCTL \"refclk-frequency\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
i = of_property_read_string(dev->of_node,
|
||||
"refclk-type-ss", &ss_clock_type);
|
||||
if (i) {
|
||||
dev_err(dev, "No UCTL \"refclk-type-ss\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
i = of_property_read_string(dev->of_node,
|
||||
"refclk-type-hs", &hs_clock_type);
|
||||
if (i) {
|
||||
dev_err(dev, "No UCTL \"refclk-type-hs\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strcmp("dlmc_ref_clk0", ss_clock_type) == 0) {
|
||||
if (strcmp(hs_clock_type, "dlmc_ref_clk0") == 0)
|
||||
ref_clk_sel = 0;
|
||||
else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
|
||||
ref_clk_sel = 2;
|
||||
else
|
||||
dev_warn(dev, "Invalid HS clock type %s, using pll_ref_clk instead\n",
|
||||
hs_clock_type);
|
||||
} else if (strcmp(ss_clock_type, "dlmc_ref_clk1") == 0) {
|
||||
if (strcmp(hs_clock_type, "dlmc_ref_clk1") == 0)
|
||||
ref_clk_sel = 1;
|
||||
else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
|
||||
ref_clk_sel = 3;
|
||||
else {
|
||||
dev_warn(dev, "Invalid HS clock type %s, using pll_ref_clk instead\n",
|
||||
hs_clock_type);
|
||||
ref_clk_sel = 3;
|
||||
}
|
||||
} else
|
||||
dev_warn(dev, "Invalid SS clock type %s, using dlmc_ref_clk0 instead\n",
|
||||
ss_clock_type);
|
||||
|
||||
if ((ref_clk_sel == 0 || ref_clk_sel == 1) &&
|
||||
(clock_rate != 100000000))
|
||||
dev_warn(dev, "Invalid UCTL clock rate of %u, using 100000000 instead\n",
|
||||
clock_rate);
|
||||
|
||||
} else {
|
||||
dev_err(dev, "No USB UCTL device node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
int div;
|
||||
struct device *dev = octeon->dev;
|
||||
void __iomem *uctl_ctl_reg = octeon->base + USBDRD_UCTL_CTL;
|
||||
void __iomem *uctl_host_cfg_reg = octeon->base + USBDRD_UCTL_HOST_CFG;
|
||||
|
||||
/*
|
||||
* Step 1: Wait for all voltages to be stable...that surely
|
||||
@ -374,6 +289,10 @@ static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
|
||||
/* Step 4b: Select controller clock frequency. */
|
||||
div = dwc3_octeon_get_divider();
|
||||
if (div < 0) {
|
||||
dev_err(dev, "clock divider invalid\n");
|
||||
return div;
|
||||
}
|
||||
val = dwc3_octeon_readq(uctl_ctl_reg);
|
||||
val &= ~USBDRD_UCTL_CTL_H_CLKDIV_SEL;
|
||||
val |= FIELD_PREP(USBDRD_UCTL_CTL_H_CLKDIV_SEL, div);
|
||||
@ -382,8 +301,8 @@ static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
val = dwc3_octeon_readq(uctl_ctl_reg);
|
||||
if ((div != FIELD_GET(USBDRD_UCTL_CTL_H_CLKDIV_SEL, val)) ||
|
||||
(!(FIELD_GET(USBDRD_UCTL_CTL_H_CLK_EN, val)))) {
|
||||
dev_err(dev, "dwc3 controller clock init failure.\n");
|
||||
return -EINVAL;
|
||||
dev_err(dev, "clock init failure (UCTL_CTL=%016llx)\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Step 4c: Deassert the controller clock divider reset. */
|
||||
@ -396,24 +315,6 @@ static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
val &= ~USBDRD_UCTL_CTL_REF_CLK_SEL;
|
||||
val |= FIELD_PREP(USBDRD_UCTL_CTL_REF_CLK_SEL, ref_clk_sel);
|
||||
|
||||
ref_clk_fsel = 0x07;
|
||||
switch (clock_rate) {
|
||||
default:
|
||||
dev_warn(dev, "Invalid ref_clk %u, using 100000000 instead\n",
|
||||
clock_rate);
|
||||
fallthrough;
|
||||
case 100000000:
|
||||
mpll_mul = 0x19;
|
||||
if (ref_clk_sel < 2)
|
||||
ref_clk_fsel = 0x27;
|
||||
break;
|
||||
case 50000000:
|
||||
mpll_mul = 0x32;
|
||||
break;
|
||||
case 125000000:
|
||||
mpll_mul = 0x28;
|
||||
break;
|
||||
}
|
||||
val &= ~USBDRD_UCTL_CTL_REF_CLK_FSEL;
|
||||
val |= FIELD_PREP(USBDRD_UCTL_CTL_REF_CLK_FSEL, ref_clk_fsel);
|
||||
|
||||
@ -444,9 +345,22 @@ static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
/* Step 8b: Wait 10 controller-clock cycles. */
|
||||
udelay(10);
|
||||
|
||||
/* Steo 8c: Setup power-power control. */
|
||||
if (dwc3_octeon_config_power(dev, base))
|
||||
return -EINVAL;
|
||||
/* Step 8c: Setup power control. */
|
||||
val = dwc3_octeon_readq(uctl_host_cfg_reg);
|
||||
val |= USBDRD_UCTL_HOST_PPC_EN;
|
||||
if (power_gpio == DWC3_GPIO_POWER_NONE) {
|
||||
val &= ~USBDRD_UCTL_HOST_PPC_EN;
|
||||
} else {
|
||||
val |= USBDRD_UCTL_HOST_PPC_EN;
|
||||
dwc3_octeon_config_gpio(((__force uintptr_t)octeon->base >> 24) & 1,
|
||||
power_gpio);
|
||||
dev_dbg(dev, "power control is using gpio%d\n", power_gpio);
|
||||
}
|
||||
if (power_active_low)
|
||||
val &= ~USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN;
|
||||
else
|
||||
val |= USBDRD_UCTL_HOST_PPC_ACTIVE_HIGH_EN;
|
||||
dwc3_octeon_writeq(uctl_host_cfg_reg, val);
|
||||
|
||||
/* Step 8d: Deassert UAHC reset signal. */
|
||||
val = dwc3_octeon_readq(uctl_ctl_reg);
|
||||
@ -469,10 +383,10 @@ static int dwc3_octeon_clocks_start(struct device *dev, void __iomem *base)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init dwc3_octeon_set_endian_mode(void __iomem *base)
|
||||
static void dwc3_octeon_set_endian_mode(struct dwc3_octeon *octeon)
|
||||
{
|
||||
u64 val;
|
||||
void __iomem *uctl_shim_cfg_reg = base + USBDRD_UCTL_SHIM_CFG;
|
||||
void __iomem *uctl_shim_cfg_reg = octeon->base + USBDRD_UCTL_SHIM_CFG;
|
||||
|
||||
val = dwc3_octeon_readq(uctl_shim_cfg_reg);
|
||||
val &= ~USBDRD_UCTL_SHIM_CFG_DMA_ENDIAN_MODE;
|
||||
@ -484,68 +398,146 @@ static void __init dwc3_octeon_set_endian_mode(void __iomem *base)
|
||||
dwc3_octeon_writeq(uctl_shim_cfg_reg, val);
|
||||
}
|
||||
|
||||
static void __init dwc3_octeon_phy_reset(void __iomem *base)
|
||||
static void dwc3_octeon_phy_reset(struct dwc3_octeon *octeon)
|
||||
{
|
||||
u64 val;
|
||||
void __iomem *uctl_ctl_reg = base + USBDRD_UCTL_CTL;
|
||||
void __iomem *uctl_ctl_reg = octeon->base + USBDRD_UCTL_CTL;
|
||||
|
||||
val = dwc3_octeon_readq(uctl_ctl_reg);
|
||||
val &= ~USBDRD_UCTL_CTL_UPHY_RST;
|
||||
dwc3_octeon_writeq(uctl_ctl_reg, val);
|
||||
}
|
||||
|
||||
static int __init dwc3_octeon_device_init(void)
|
||||
static int dwc3_octeon_probe(struct platform_device *pdev)
|
||||
{
|
||||
const char compat_node_name[] = "cavium,octeon-7130-usb-uctl";
|
||||
struct platform_device *pdev;
|
||||
struct device_node *node;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct dwc3_octeon *octeon;
|
||||
const char *hs_clock_type, *ss_clock_type;
|
||||
int ref_clk_sel, ref_clk_fsel, mpll_mul;
|
||||
int power_active_low, power_gpio;
|
||||
int err, len;
|
||||
u32 clock_rate;
|
||||
|
||||
/*
|
||||
* There should only be three universal controllers, "uctl"
|
||||
* in the device tree. Two USB and a SATA, which we ignore.
|
||||
*/
|
||||
node = NULL;
|
||||
do {
|
||||
node = of_find_node_by_name(node, "uctl");
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
if (of_property_read_u32(node, "refclk-frequency", &clock_rate)) {
|
||||
dev_err(dev, "No UCTL \"refclk-frequency\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (of_property_read_string(node, "refclk-type-ss", &ss_clock_type)) {
|
||||
dev_err(dev, "No UCTL \"refclk-type-ss\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (of_property_read_string(node, "refclk-type-hs", &hs_clock_type)) {
|
||||
dev_err(dev, "No UCTL \"refclk-type-hs\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(node, compat_node_name)) {
|
||||
pdev = of_find_device_by_node(node);
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* The code below maps in the registers necessary for
|
||||
* setting up the clocks and reseting PHYs. We must
|
||||
* release the resources so the dwc3 subsystem doesn't
|
||||
* know the difference.
|
||||
*/
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(base)) {
|
||||
put_device(&pdev->dev);
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
mutex_lock(&dwc3_octeon_clocks_mutex);
|
||||
if (dwc3_octeon_clocks_start(&pdev->dev, base) == 0)
|
||||
dev_info(&pdev->dev, "clocks initialized.\n");
|
||||
dwc3_octeon_set_endian_mode(base);
|
||||
dwc3_octeon_phy_reset(base);
|
||||
mutex_unlock(&dwc3_octeon_clocks_mutex);
|
||||
devm_iounmap(&pdev->dev, base);
|
||||
devm_release_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
put_device(&pdev->dev);
|
||||
ref_clk_sel = 2;
|
||||
if (strcmp("dlmc_ref_clk0", ss_clock_type) == 0) {
|
||||
if (strcmp(hs_clock_type, "dlmc_ref_clk0") == 0)
|
||||
ref_clk_sel = 0;
|
||||
else if (strcmp(hs_clock_type, "pll_ref_clk"))
|
||||
dev_warn(dev, "Invalid HS clock type %s, using pll_ref_clk instead\n",
|
||||
hs_clock_type);
|
||||
} else if (strcmp(ss_clock_type, "dlmc_ref_clk1") == 0) {
|
||||
if (strcmp(hs_clock_type, "dlmc_ref_clk1") == 0) {
|
||||
ref_clk_sel = 1;
|
||||
} else {
|
||||
ref_clk_sel = 3;
|
||||
if (strcmp(hs_clock_type, "pll_ref_clk"))
|
||||
dev_warn(dev, "Invalid HS clock type %s, using pll_ref_clk instead\n",
|
||||
hs_clock_type);
|
||||
}
|
||||
} while (node != NULL);
|
||||
} else {
|
||||
dev_warn(dev, "Invalid SS clock type %s, using dlmc_ref_clk0 instead\n",
|
||||
ss_clock_type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
ref_clk_fsel = 0x07;
|
||||
switch (clock_rate) {
|
||||
default:
|
||||
dev_warn(dev, "Invalid ref_clk %u, using 100000000 instead\n",
|
||||
clock_rate);
|
||||
fallthrough;
|
||||
case 100000000:
|
||||
mpll_mul = 0x19;
|
||||
if (ref_clk_sel < 2)
|
||||
ref_clk_fsel = 0x27;
|
||||
break;
|
||||
case 50000000:
|
||||
mpll_mul = 0x32;
|
||||
break;
|
||||
case 125000000:
|
||||
mpll_mul = 0x28;
|
||||
break;
|
||||
}
|
||||
|
||||
power_gpio = DWC3_GPIO_POWER_NONE;
|
||||
power_active_low = 0;
|
||||
if (of_find_property(node, "power", &len)) {
|
||||
u32 gpio_pwr[3];
|
||||
|
||||
switch (len) {
|
||||
case 8:
|
||||
of_property_read_u32_array(node, "power", gpio_pwr, 2);
|
||||
break;
|
||||
case 12:
|
||||
of_property_read_u32_array(node, "power", gpio_pwr, 3);
|
||||
power_active_low = gpio_pwr[2] & 0x01;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid power configuration\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
power_gpio = gpio_pwr[1];
|
||||
}
|
||||
|
||||
octeon = devm_kzalloc(dev, sizeof(*octeon), GFP_KERNEL);
|
||||
if (!octeon)
|
||||
return -ENOMEM;
|
||||
|
||||
octeon->dev = dev;
|
||||
octeon->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(octeon->base))
|
||||
return PTR_ERR(octeon->base);
|
||||
|
||||
err = dwc3_octeon_setup(octeon, ref_clk_sel, ref_clk_fsel, mpll_mul,
|
||||
power_gpio, power_active_low);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dwc3_octeon_set_endian_mode(octeon);
|
||||
dwc3_octeon_phy_reset(octeon);
|
||||
|
||||
platform_set_drvdata(pdev, octeon);
|
||||
|
||||
return of_platform_populate(node, NULL, NULL, dev);
|
||||
}
|
||||
device_initcall(dwc3_octeon_device_init);
|
||||
|
||||
MODULE_AUTHOR("David Daney <david.daney@cavium.com>");
|
||||
static void dwc3_octeon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_octeon *octeon = platform_get_drvdata(pdev);
|
||||
|
||||
of_platform_depopulate(octeon->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id dwc3_octeon_of_match[] = {
|
||||
{ .compatible = "cavium,octeon-7130-usb-uctl" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc3_octeon_of_match);
|
||||
|
||||
static struct platform_driver dwc3_octeon_driver = {
|
||||
.probe = dwc3_octeon_probe,
|
||||
.remove_new = dwc3_octeon_remove,
|
||||
.driver = {
|
||||
.name = "dwc3-octeon",
|
||||
.of_match_table = dwc3_octeon_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(dwc3_octeon_driver);
|
||||
|
||||
MODULE_ALIAS("platform:dwc3-octeon");
|
||||
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("USB driver for OCTEON III SoC");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 OCTEON III Glue Layer");
|
@ -170,7 +170,6 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
|
||||
|
||||
static const struct of_device_id of_dwc3_simple_match[] = {
|
||||
{ .compatible = "rockchip,rk3399-dwc3" },
|
||||
{ .compatible = "cavium,octeon-7130-usb-uctl" },
|
||||
{ .compatible = "sprd,sc9860-dwc3" },
|
||||
{ .compatible = "allwinner,sun50i-h6-dwc3" },
|
||||
{ .compatible = "hisilicon,hi3670-dwc3" },
|
||||
|
@ -208,6 +208,9 @@ config USB_F_UVC
|
||||
config USB_F_MIDI
|
||||
tristate
|
||||
|
||||
config USB_F_MIDI2
|
||||
tristate
|
||||
|
||||
config USB_F_HID
|
||||
tristate
|
||||
|
||||
@ -436,6 +439,21 @@ config USB_CONFIGFS_F_MIDI
|
||||
connections can then be made on the gadget system, using
|
||||
ALSA's aconnect utility etc.
|
||||
|
||||
config USB_CONFIGFS_F_MIDI2
|
||||
bool "MIDI 2.0 function"
|
||||
depends on USB_CONFIGFS
|
||||
depends on SND
|
||||
select USB_LIBCOMPOSITE
|
||||
select SND_UMP
|
||||
select SND_UMP_LEGACY_RAWMIDI
|
||||
select USB_F_MIDI2
|
||||
help
|
||||
The MIDI 2.0 function driver provides the generic emulated
|
||||
USB MIDI 2.0 interface, looped back to ALSA UMP rawmidi
|
||||
device on the gadget host. It supports UMP 1.1 spec and
|
||||
responds UMP Stream messages for UMP Endpoint and Function
|
||||
Block information / configuration.
|
||||
|
||||
config USB_CONFIGFS_F_HID
|
||||
bool "HID function"
|
||||
depends on USB_CONFIGFS
|
||||
|
@ -170,33 +170,27 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g,
|
||||
/* select desired speed */
|
||||
switch (g->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
if (gadget_is_superspeed_plus(g)) {
|
||||
if (f->ssp_descriptors) {
|
||||
speed_desc = f->ssp_descriptors;
|
||||
want_comp_desc = 1;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
if (f->ssp_descriptors) {
|
||||
speed_desc = f->ssp_descriptors;
|
||||
want_comp_desc = 1;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
fallthrough;
|
||||
case USB_SPEED_SUPER:
|
||||
if (gadget_is_superspeed(g)) {
|
||||
if (f->ss_descriptors) {
|
||||
speed_desc = f->ss_descriptors;
|
||||
want_comp_desc = 1;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
if (f->ss_descriptors) {
|
||||
speed_desc = f->ss_descriptors;
|
||||
want_comp_desc = 1;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
fallthrough;
|
||||
case USB_SPEED_HIGH:
|
||||
if (gadget_is_dualspeed(g)) {
|
||||
if (f->hs_descriptors) {
|
||||
speed_desc = f->hs_descriptors;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
if (f->hs_descriptors) {
|
||||
speed_desc = f->hs_descriptors;
|
||||
break;
|
||||
}
|
||||
incomplete_desc = true;
|
||||
fallthrough;
|
||||
default:
|
||||
speed_desc = f->fs_descriptors;
|
||||
|
@ -162,8 +162,6 @@ int usb_assign_descriptors(struct usb_function *f,
|
||||
struct usb_descriptor_header **ss,
|
||||
struct usb_descriptor_header **ssp)
|
||||
{
|
||||
struct usb_gadget *g = f->config->cdev->gadget;
|
||||
|
||||
/* super-speed-plus descriptor falls back to super-speed one,
|
||||
* if such a descriptor was provided, thus avoiding a NULL
|
||||
* pointer dereference if a 5gbps capable gadget is used with
|
||||
@ -177,17 +175,17 @@ int usb_assign_descriptors(struct usb_function *f,
|
||||
if (!f->fs_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (hs && gadget_is_dualspeed(g)) {
|
||||
if (hs) {
|
||||
f->hs_descriptors = usb_copy_descriptors(hs);
|
||||
if (!f->hs_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (ss && gadget_is_superspeed(g)) {
|
||||
if (ss) {
|
||||
f->ss_descriptors = usb_copy_descriptors(ss);
|
||||
if (!f->ss_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (ssp && gadget_is_superspeed_plus(g)) {
|
||||
if (ssp) {
|
||||
f->ssp_descriptors = usb_copy_descriptors(ssp);
|
||||
if (!f->ssp_descriptors)
|
||||
goto err;
|
||||
|
@ -44,6 +44,8 @@ usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
|
||||
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
|
||||
usb_f_midi-y := f_midi.o
|
||||
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
|
||||
usb_f_midi2-y := f_midi2.o
|
||||
obj-$(CONFIG_USB_F_MIDI2) += usb_f_midi2.o
|
||||
usb_f_hid-y := f_hid.o
|
||||
obj-$(CONFIG_USB_F_HID) += usb_f_hid.o
|
||||
usb_f_printer-y := f_printer.o
|
||||
|
@ -691,10 +691,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
goto fail;
|
||||
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
"acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
"acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n",
|
||||
acm->port_num,
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
acm->port.in->name, acm->port.out->name,
|
||||
acm->notify->name);
|
||||
return 0;
|
||||
|
@ -65,17 +65,6 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)
|
||||
return container_of(f, struct f_ecm, port.func);
|
||||
}
|
||||
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
static inline unsigned ecm_bitrate(struct usb_gadget *g)
|
||||
{
|
||||
if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
|
||||
return 13 * 1024 * 8 * 1000 * 8;
|
||||
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return 13 * 512 * 8 * 1000 * 8;
|
||||
else
|
||||
return 19 * 64 * 1 * 1000 * 8;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -411,10 +400,10 @@ static void ecm_do_notify(struct f_ecm *ecm)
|
||||
|
||||
/* SPEED_CHANGE data is up/down speeds in bits/sec */
|
||||
data = req->buf + sizeof *event;
|
||||
data[0] = cpu_to_le32(ecm_bitrate(cdev->gadget));
|
||||
data[0] = cpu_to_le32(gether_bitrate(cdev->gadget));
|
||||
data[1] = data[0];
|
||||
|
||||
DBG(cdev, "notify speed %d\n", ecm_bitrate(cdev->gadget));
|
||||
DBG(cdev, "notify speed %d\n", gether_bitrate(cdev->gadget));
|
||||
ecm->notify_state = ECM_NOTIFY_NONE;
|
||||
break;
|
||||
}
|
||||
@ -799,9 +788,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
ecm->port.open = ecm_open;
|
||||
ecm->port.close = ecm_close;
|
||||
|
||||
DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n",
|
||||
ecm->port.in_ep->name, ecm->port.out_ep->name,
|
||||
ecm->notify->name);
|
||||
return 0;
|
||||
|
@ -311,9 +311,7 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
DBG(cdev, "CDC Ethernet (EEM): IN/%s OUT/%s\n",
|
||||
eem->port.in_ep->name, eem->port.out_ep->name);
|
||||
return 0;
|
||||
|
||||
|
@ -211,9 +211,7 @@ static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
|
||||
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
|
||||
DBG(cdev, "%s: IN/%s, OUT/%s\n",
|
||||
f->name, loop->in_ep->name, loop->out_ep->name);
|
||||
return 0;
|
||||
}
|
||||
|
@ -927,7 +927,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
|
||||
{
|
||||
struct file *filp = curlun->filp;
|
||||
struct inode *inode = file_inode(filp);
|
||||
unsigned long rc;
|
||||
unsigned long __maybe_unused rc;
|
||||
|
||||
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
|
||||
VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
|
||||
|
@ -1023,40 +1023,30 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!f->fs_descriptors)
|
||||
goto fail_f_midi;
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
f->hs_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail_f_midi;
|
||||
}
|
||||
bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
f->hs_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail_f_midi;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024);
|
||||
bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024);
|
||||
i = endpoint_descriptor_index;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_out_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_out_ss_comp_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&ms_out_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_in_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_in_ss_comp_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&ms_in_desc;
|
||||
f->ss_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail_f_midi;
|
||||
|
||||
if (gadget_is_superspeed_plus(c->cdev->gadget)) {
|
||||
f->ssp_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->ssp_descriptors)
|
||||
goto fail_f_midi;
|
||||
}
|
||||
}
|
||||
bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024);
|
||||
bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024);
|
||||
i = endpoint_descriptor_index;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_out_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_out_ss_comp_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&ms_out_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_in_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&bulk_in_ss_comp_desc;
|
||||
midi_function[i++] = (struct usb_descriptor_header *)
|
||||
&ms_in_desc;
|
||||
f->ss_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail_f_midi;
|
||||
|
||||
kfree(midi_function);
|
||||
|
||||
|
2871
drivers/usb/gadget/function/f_midi2.c
Normal file
2871
drivers/usb/gadget/function/f_midi2.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -80,21 +80,6 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
|
||||
return container_of(f, struct f_ncm, port.func);
|
||||
}
|
||||
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
static inline unsigned ncm_bitrate(struct usb_gadget *g)
|
||||
{
|
||||
if (!g)
|
||||
return 0;
|
||||
else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
|
||||
return 4250000000U;
|
||||
else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
|
||||
return 3750000000U;
|
||||
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return 13 * 512 * 8 * 1000 * 8;
|
||||
else
|
||||
return 19 * 64 * 1 * 1000 * 8;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -576,10 +561,10 @@ static void ncm_do_notify(struct f_ncm *ncm)
|
||||
|
||||
/* SPEED_CHANGE data is up/down speeds in bits/sec */
|
||||
data = req->buf + sizeof *event;
|
||||
data[0] = cpu_to_le32(ncm_bitrate(cdev->gadget));
|
||||
data[0] = cpu_to_le32(gether_bitrate(cdev->gadget));
|
||||
data[1] = data[0];
|
||||
|
||||
DBG(cdev, "notify speed %u\n", ncm_bitrate(cdev->gadget));
|
||||
DBG(cdev, "notify speed %u\n", gether_bitrate(cdev->gadget));
|
||||
ncm->notify_state = NCM_NOTIFY_CONNECT;
|
||||
break;
|
||||
}
|
||||
@ -1544,9 +1529,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
|
||||
ncm->task_timer.function = ncm_tx_timeout;
|
||||
|
||||
DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
|
||||
ncm->port.in_ep->name, ncm->port.out_ep->name,
|
||||
ncm->notify->name);
|
||||
return 0;
|
||||
|
@ -365,9 +365,8 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: IN/%s OUT/%s\n",
|
||||
obex->port_num,
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
obex->port.in->name, obex->port.out->name);
|
||||
|
||||
return 0;
|
||||
|
@ -84,19 +84,6 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
|
||||
return container_of(f, struct f_rndis, port.func);
|
||||
}
|
||||
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
static unsigned int bitrate(struct usb_gadget *g)
|
||||
{
|
||||
if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
|
||||
return 4250000000U;
|
||||
if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
|
||||
return 3750000000U;
|
||||
else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return 13 * 512 * 8 * 1000 * 8;
|
||||
else
|
||||
return 19 * 64 * 1 * 1000 * 8;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -640,7 +627,7 @@ static void rndis_open(struct gether *geth)
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
|
||||
rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3,
|
||||
bitrate(cdev->gadget) / 100);
|
||||
gether_bitrate(cdev->gadget) / 100);
|
||||
rndis_signal_connect(rndis->params);
|
||||
}
|
||||
|
||||
@ -811,9 +798,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
* until we're activated via set_alt().
|
||||
*/
|
||||
|
||||
DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
DBG(cdev, "RNDIS: IN/%s OUT/%s NOTIFY/%s\n",
|
||||
rndis->port.in_ep->name, rndis->port.out_ep->name,
|
||||
rndis->notify->name);
|
||||
return 0;
|
||||
|
@ -236,10 +236,8 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
gser_ss_function, gser_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: IN/%s OUT/%s\n",
|
||||
gser->port_num,
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
gser->port.in->name, gser->port.out->name);
|
||||
return 0;
|
||||
|
||||
|
@ -436,9 +436,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
|
||||
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
|
||||
DBG(cdev, "%s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
|
||||
f->name, ss->in_ep->name, ss->out_ep->name,
|
||||
ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
|
||||
ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
|
||||
|
@ -367,9 +367,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
* until we're activated via set_alt().
|
||||
*/
|
||||
|
||||
DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
DBG(cdev, "CDC Subset: IN/%s OUT/%s\n",
|
||||
geth->port.in_ep->name, geth->port.out_ep->name);
|
||||
return 0;
|
||||
|
||||
|
@ -719,21 +719,13 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
}
|
||||
uvc->enable_interrupt_ep = opts->enable_interrupt_ep;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
|
||||
&uvc_ss_streaming_comp);
|
||||
else if (gadget_is_dualspeed(cdev->gadget))
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
|
||||
else
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
|
||||
if (!ep) {
|
||||
uvcg_info(f, "Unable to allocate streaming EP\n");
|
||||
goto error;
|
||||
}
|
||||
uvc->video.ep = ep;
|
||||
|
||||
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
|
||||
@ -788,21 +780,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->fs_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
if (gadget_is_dualspeed(cdev->gadget)) {
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
if (IS_ERR(f->hs_descriptors)) {
|
||||
ret = PTR_ERR(f->hs_descriptors);
|
||||
f->hs_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
if (IS_ERR(f->hs_descriptors)) {
|
||||
ret = PTR_ERR(f->hs_descriptors);
|
||||
f->hs_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
|
||||
if (IS_ERR(f->ss_descriptors)) {
|
||||
ret = PTR_ERR(f->ss_descriptors);
|
||||
f->ss_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
|
||||
if (IS_ERR(f->ss_descriptors)) {
|
||||
ret = PTR_ERR(f->ss_descriptors);
|
||||
f->ss_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Preallocate control endpoint request. */
|
||||
|
@ -93,11 +93,10 @@ struct eth_dev {
|
||||
|
||||
#define DEFAULT_QLEN 2 /* double buffering by default */
|
||||
|
||||
/* for dual-speed hardware, use deeper queues at high/super speed */
|
||||
/* use deeper queues at high/super speed */
|
||||
static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
|
||||
{
|
||||
if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
|
||||
gadget->speed >= USB_SPEED_SUPER))
|
||||
if (gadget->speed == USB_SPEED_HIGH || gadget->speed >= USB_SPEED_SUPER)
|
||||
return qmult * DEFAULT_QLEN;
|
||||
else
|
||||
return DEFAULT_QLEN;
|
||||
|
@ -279,4 +279,17 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
static inline unsigned int gether_bitrate(struct usb_gadget *g)
|
||||
{
|
||||
if (g->speed >= USB_SPEED_SUPER_PLUS)
|
||||
return 4250000000U;
|
||||
if (g->speed == USB_SPEED_SUPER)
|
||||
return 3750000000U;
|
||||
else if (g->speed == USB_SPEED_HIGH)
|
||||
return 13 * 512 * 8 * 1000 * 8;
|
||||
else
|
||||
return 19 * 64 * 1 * 1000 * 8;
|
||||
}
|
||||
|
||||
#endif /* __U_ETHER_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user