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:
Linus Torvalds 2023-09-01 09:23:34 -07:00
commit 51e7accbe8
211 changed files with 7352 additions and 1890 deletions

11
CREDITS
View File

@ -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).

View 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)
================= ==============================================

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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)

View 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)>;
};

View 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>;
};

View File

@ -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

View 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 = <&reg_1v2_usb>;
vdd2-supply = <&reg_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 = <&reg_1v2_usb>;
vdd2-supply = <&reg_3v3_usb>;
};
};

View File

@ -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

View File

@ -17,6 +17,7 @@ properties:
enum:
- usb5e3,608
- usb5e3,610
- usb5e3,620
reg: true

View File

@ -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:

View File

@ -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:

View File

@ -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)
======= ======================================================

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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", },
{},
};

View File

@ -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

View File

@ -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"

View File

@ -26,6 +26,7 @@ obj-y += allwinner/ \
mscc/ \
qualcomm/ \
ralink/ \
realtek/ \
renesas/ \
rockchip/ \
samsung/ \

View 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.

View 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

File diff suppressed because it is too large Load Diff

View 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");

View File

@ -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);

View File

@ -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 @@ out_put:
* 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;
}
/**

View File

@ -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)

View File

@ -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;
}

View File

@ -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; }

View File

@ -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;

View File

@ -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"

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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>");

View File

@ -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; }

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View File

@ -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>

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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 @@ out:
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 @@ fail:
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;
}

View File

@ -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");

View File

@ -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);
}
/*

View File

@ -8,7 +8,6 @@
*/
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/usb/of.h>
/**

View File

@ -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;

View File

@ -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);

View File

@ -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 @@ hub_init_failed:
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();

View File

@ -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;

View File

@ -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);

View File

@ -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>

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 @@ err:
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,

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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,
}, {
}
};

View File

@ -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,

View File

@ -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[] = {

View File

@ -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;
}

View File

@ -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");

View File

@ -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" },

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -211,9 +211,7 @@ autoconf_fail:
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;
}

View File

@ -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);

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -436,9 +436,7 @@ no_iso:
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>");

View File

@ -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;

View File

@ -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. */

View File

@ -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;

View File

@ -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