ata changes for 6.1-rc1
* Print the timeout value for internal command failures due to a timeout (from Tomas). * Improve parameter names in ata_dev_set_feature() to clarify this function use (from Niklas). * Improve the ahci driver low power mode setting initialization to allow more flexibility for the user (from Rafael). * Several patches to remove redundant variables in libata-core, libata-eh and the pata_macio driver and to fix typos in comments (from Jinpeng, Shaomin, Ye). * Some code simplifications and macro renaming (for clarity) in various functions of libata-core (from me). * Add a missing check for a potential failure of sata_scr_read() in sata_print_link_status() (from Li). * Cleanup of libata Kconfig PATA_PLATFORM and PATA_OF_PLATFORM options (from Lukas). * Cleanups of ata dt-bindings and improvements of libahci_platform, ahci and libahci code (from Serge) * New driver for Synopsys AHCI SATA controllers, based of the generic ahci code (from Serge). One compilation warning fix is added for this driver (from me). * Several fixes to macros used to discover a drive capabilities to be consistent with the ACS specifications (from Niklas). * A couple of simplifcations to some libata functions, removing unnecessary arguments (from Niklas). * An improvements to libata-eh code to avoid unnecessary link reset when revalidating a drive after a failed command. In practice, this extra, unneeded reset, reset does not cause any arm beyond slightly slowing down error recovery (from Niklas). -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCYz0asgAKCRDdoc3SxdoY drHoAQCJhb6MuQHzbN/wR5cTGAfWXQJWBJx2mJr7oKJCrB34PwD/RzphcsuaXDta kwbTGlpitegByZTDKt9eMRLWmKgyngw= =CnJj -----END PGP SIGNATURE----- Merge tag 'ata-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata Pull ata updates from Damien Le Moal: - Print the timeout value for internal command failures due to a timeout (from Tomas) - Improve parameter names in ata_dev_set_feature() to clarify this function use (from Niklas) - Improve the ahci driver low power mode setting initialization to allow more flexibility for the user (from Rafael) - Several patches to remove redundant variables in libata-core, libata-eh and the pata_macio driver and to fix typos in comments (from Jinpeng, Shaomin, Ye) - Some code simplifications and macro renaming (for clarity) in various functions of libata-core (from me) - Add a missing check for a potential failure of sata_scr_read() in sata_print_link_status() (from Li) - Cleanup of libata Kconfig PATA_PLATFORM and PATA_OF_PLATFORM options (from Lukas) - Cleanups of ata dt-bindings and improvements of libahci_platform, ahci and libahci code (from Serge) - New driver for Synopsys AHCI SATA controllers, based of the generic ahci code (from Serge). One compilation warning fix is added for this driver (from me) - Several fixes to macros used to discover a drive capabilities to be consistent with the ACS specifications (from Niklas) - A couple of simplifcations to some libata functions, removing unnecessary arguments (from Niklas) - An improvements to libata-eh code to avoid unnecessary link reset when revalidating a drive after a failed command. In practice, this extra, unneeded reset, reset does not cause any arm beyond slightly slowing down error recovery (from Niklas) * tag 'ata-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata: (45 commits) ata: libata-eh: avoid needless hard reset when revalidating link ata: libata: drop superfluous ata_eh_analyze_tf() parameter ata: libata: drop superfluous ata_eh_request_sense() parameter ata: fix ata_id_has_dipm() ata: fix ata_id_has_ncq_autosense() ata: fix ata_id_has_devslp() ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting() ata: libata-eh: Remove the unneeded result variable ata: ahci_st: Enable compile test ata: ahci_st: Fix compilation warning MAINTAINERS: Add maintainers for DWC AHCI SATA driver ata: ahci-dwc: Add Baikal-T1 AHCI SATA interface support ata: ahci-dwc: Add platform-specific quirks support dt-bindings: ata: ahci: Add Baikal-T1 AHCI SATA controller DT schema ata: ahci: Add DWC AHCI SATA controller support ata: libahci_platform: Add function returning a clock-handle by id dt-bindings: ata: ahci: Add DWC AHCI SATA controller DT schema ata: ahci: Introduce firmware-specific caps initialization ata: ahci: Convert __ahci_port_base to accepting hpriv as arguments ata: libahci: Don't read AHCI version twice in the save-config method ...
This commit is contained in:
commit
4078aa6850
|
@ -0,0 +1,123 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/ahci-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common Properties for Serial ATA AHCI controllers
|
||||
|
||||
maintainers:
|
||||
- Hans de Goede <hdegoede@redhat.com>
|
||||
- Damien Le Moal <damien.lemoal@opensource.wdc.com>
|
||||
|
||||
description:
|
||||
This document defines device tree properties for a common AHCI SATA
|
||||
controller implementation. It's hardware interface is supposed to
|
||||
conform to the technical standard defined by Intel (see Serial ATA
|
||||
Advanced Host Controller Interface specification for details). The
|
||||
document doesn't constitute a DT-node binding by itself but merely
|
||||
defines a set of common properties for the AHCI-compatible devices.
|
||||
|
||||
select: false
|
||||
|
||||
allOf:
|
||||
- $ref: sata-common.yaml#
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
Generic AHCI registers space conforming to the Serial ATA AHCI
|
||||
specification.
|
||||
|
||||
reg-names:
|
||||
description: CSR space IDs
|
||||
contains:
|
||||
const: ahci
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
Generic AHCI state change interrupt. Can be implemented either as a
|
||||
single line attached to the controller or as a set of the signals
|
||||
indicating the particular port events.
|
||||
minItems: 1
|
||||
maxItems: 32
|
||||
|
||||
ahci-supply:
|
||||
description: Power regulator for AHCI controller
|
||||
|
||||
target-supply:
|
||||
description: Power regulator for SATA target device
|
||||
|
||||
phy-supply:
|
||||
description: Power regulator for SATA PHY
|
||||
|
||||
phys:
|
||||
description: Reference to the SATA PHY node
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: sata-phy
|
||||
|
||||
hba-cap:
|
||||
$ref: '/schemas/types.yaml#/definitions/uint32'
|
||||
description:
|
||||
Bitfield of the HBA generic platform capabilities like Staggered
|
||||
Spin-up or Mechanical Presence Switch support. It can be used to
|
||||
appropriately initialize the HWinit fields of the HBA CAP register
|
||||
in case if the system firmware hasn't done it.
|
||||
|
||||
ports-implemented:
|
||||
$ref: '/schemas/types.yaml#/definitions/uint32'
|
||||
description:
|
||||
Mask that indicates which ports the HBA supports. Useful if PI is not
|
||||
programmed by the BIOS, which is true for some embedded SoC's.
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-f]+$":
|
||||
$ref: '#/$defs/ahci-port'
|
||||
description:
|
||||
It is optionally possible to describe the ports as sub-nodes so
|
||||
to enable each port independently when dealing with multiple PHYs.
|
||||
|
||||
required:
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
$defs:
|
||||
ahci-port:
|
||||
$ref: /schemas/ata/sata-common.yaml#/$defs/sata-port
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
AHCI SATA port identifier. By design AHCI controller can't have
|
||||
more than 32 ports due to the CAP.NP fields and PI register size
|
||||
constraints.
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
|
||||
phys:
|
||||
description: Individual AHCI SATA port PHY
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
description: AHCI SATA port PHY ID
|
||||
const: sata-phy
|
||||
|
||||
target-supply:
|
||||
description: Power regulator for SATA port target device
|
||||
|
||||
hba-port-cap:
|
||||
$ref: '/schemas/types.yaml#/definitions/uint32'
|
||||
description:
|
||||
Bitfield of the HBA port-specific platform capabilities like Hot
|
||||
plugging, eSATA, FIS-based Switching, etc (see AHCI specification
|
||||
for details). It can be used to initialize the HWinit fields of
|
||||
the PxCMD register in case if the system firmware hasn't done it.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
...
|
|
@ -30,14 +30,11 @@ select:
|
|||
- marvell,armada-3700-ahci
|
||||
- marvell,armada-8k-ahci
|
||||
- marvell,berlin2q-ahci
|
||||
- snps,dwc-ahci
|
||||
- snps,spear-ahci
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: "sata-common.yaml#"
|
||||
|
||||
- $ref: "ahci-common.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -49,17 +46,11 @@ properties:
|
|||
- marvell,berlin2-ahci
|
||||
- marvell,berlin2q-ahci
|
||||
- const: generic-ahci
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3568-dwc-ahci
|
||||
- const: snps,dwc-ahci
|
||||
- enum:
|
||||
- cavium,octeon-7130-ahci
|
||||
- hisilicon,hisi-ahci
|
||||
- ibm,476gtr-ahci
|
||||
- marvell,armada-3700-ahci
|
||||
- snps,dwc-ahci
|
||||
- snps,spear-ahci
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
@ -69,92 +60,37 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Clock IDs array as required by the controller.
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
description:
|
||||
Names of clocks corresponding to IDs in the clock property.
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
ahci-supply:
|
||||
description:
|
||||
regulator for AHCI controller
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
phy-supply:
|
||||
description:
|
||||
regulator for PHY power
|
||||
|
||||
phys:
|
||||
description:
|
||||
List of all PHYs on this controller
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
description:
|
||||
Name specifier for the PHYs
|
||||
maxItems: 1
|
||||
|
||||
ports-implemented:
|
||||
$ref: '/schemas/types.yaml#/definitions/uint32'
|
||||
description: |
|
||||
Mask that indicates which ports that the HBA supports
|
||||
are available for software to use. Useful if PORTS_IMPL
|
||||
is not programmed by the BIOS, which is true with
|
||||
some embedded SoCs.
|
||||
maximum: 0x1f
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
target-supply:
|
||||
description:
|
||||
regulator for SATA target power
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-f]+$":
|
||||
$ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port
|
||||
|
||||
anyOf:
|
||||
- required: [ phys ]
|
||||
- required: [ target-supply ]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description:
|
||||
Subnode with configuration of the Ports.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
maxItems: 1
|
||||
|
||||
target-supply:
|
||||
description:
|
||||
regulator for SATA target power
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
anyOf:
|
||||
- required: [ phys ]
|
||||
- required: [ target-supply ]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -167,6 +103,8 @@ examples:
|
|||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/berlin2q.h>
|
||||
#include <dt-bindings/ata/ahci.h>
|
||||
|
||||
sata@f7e90000 {
|
||||
compatible = "marvell,berlin2q-ahci", "generic-ahci";
|
||||
reg = <0xf7e90000 0x1000>;
|
||||
|
@ -175,15 +113,23 @@ examples:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hba-cap = <HBA_SMPS>;
|
||||
|
||||
sata0: sata-port@0 {
|
||||
reg = <0>;
|
||||
|
||||
phys = <&sata_phy 0>;
|
||||
target-supply = <®_sata0>;
|
||||
|
||||
hba-port-cap = <(HBA_PORT_FBSCP | HBA_PORT_ESP)>;
|
||||
};
|
||||
|
||||
sata1: sata-port@1 {
|
||||
reg = <1>;
|
||||
|
||||
phys = <&sata_phy 1>;
|
||||
target-supply = <®_sata1>;
|
||||
|
||||
hba-port-cap = <(HBA_PORT_HPCP | HBA_PORT_MPSP | HBA_PORT_FBSCP)>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/baikal,bt1-ahci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Baikal-T1 SoC AHCI SATA controller
|
||||
|
||||
maintainers:
|
||||
- Serge Semin <fancer.lancer@gmail.com>
|
||||
|
||||
description:
|
||||
AHCI SATA controller embedded into the Baikal-T1 SoC is based on the
|
||||
DWC AHCI SATA v4.10a IP-core.
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwc-ahci-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: baikal,bt1-ahci
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Peripheral APB bus clock
|
||||
- description: Application AXI BIU clock
|
||||
- description: SATA Ports reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: aclk
|
||||
- const: ref
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: Application AXI BIU domain reset
|
||||
- description: SATA Ports clock domain reset
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: arst
|
||||
- const: ref
|
||||
|
||||
ports-implemented:
|
||||
maximum: 0x3
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-1]$":
|
||||
$ref: /schemas/ata/snps,dwc-ahci-common.yaml#/$defs/dwc-ahci-port
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
snps,tx-ts-max:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Due to having AXI3 bus interface utilized the maximum Tx DMA
|
||||
transaction size can't exceed 16 beats (AxLEN[3:0]).
|
||||
enum: [ 1, 2, 4, 8, 16 ]
|
||||
|
||||
snps,rx-ts-max:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Due to having AXI3 bus interface utilized the maximum Rx DMA
|
||||
transaction size can't exceed 16 beats (AxLEN[3:0]).
|
||||
enum: [ 1, 2, 4, 8, 16 ]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sata@1f050000 {
|
||||
compatible = "baikal,bt1-ahci";
|
||||
reg = <0x1f050000 0x2000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
interrupts = <0 64 4>;
|
||||
|
||||
clocks = <&ccu_sys 1>, <&ccu_axi 2>, <&sata_ref_clk>;
|
||||
clock-names = "pclk", "aclk", "ref";
|
||||
|
||||
resets = <&ccu_axi 2>, <&ccu_sys 0>;
|
||||
reset-names = "arst", "ref";
|
||||
|
||||
ports-implemented = <0x3>;
|
||||
|
||||
sata-port@0 {
|
||||
reg = <0>;
|
||||
|
||||
snps,tx-ts-max = <4>;
|
||||
snps,rx-ts-max = <4>;
|
||||
};
|
||||
|
||||
sata-port@1 {
|
||||
reg = <1>;
|
||||
|
||||
snps,tx-ts-max = <4>;
|
||||
snps,rx-ts-max = <4>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -14,7 +14,7 @@ maintainers:
|
|||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: sata-common.yaml#
|
||||
- $ref: ahci-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -41,8 +41,6 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -31,22 +31,27 @@ properties:
|
|||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-e]$":
|
||||
$ref: '#/$defs/sata-port'
|
||||
description: |
|
||||
DT nodes for ports connected on the SATA host. The SATA port
|
||||
nodes will be named "sata-port".
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
$defs:
|
||||
sata-port:
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 14
|
||||
description:
|
||||
The ID number of the drive port SATA can potentially use a port
|
||||
multiplier making it possible to connect up to 15 disks to a single
|
||||
SATA port.
|
||||
|
||||
additionalProperties: true
|
||||
The ID number of the SATA port. Aside with being directly used,
|
||||
each port can have a Port Multiplier attached thus allowing to
|
||||
access more than one drive by means of a single SATA port.
|
||||
|
||||
...
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/snps,dwc-ahci-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Synopsys DWC AHCI SATA controller properties
|
||||
|
||||
maintainers:
|
||||
- Serge Semin <fancer.lancer@gmail.com>
|
||||
|
||||
description:
|
||||
This document defines device tree schema for the generic Synopsys DWC
|
||||
AHCI controller properties.
|
||||
|
||||
select: false
|
||||
|
||||
allOf:
|
||||
- $ref: ahci-common.yaml#
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Basic DWC AHCI SATA clock sources like application AXI/AHB BIU clock,
|
||||
PM-alive clock, RxOOB detection clock, embedded PHYs reference (Rx/Tx)
|
||||
clock, etc.
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
oneOf:
|
||||
- description: Application APB/AHB/AXI BIU clock
|
||||
enum:
|
||||
- pclk
|
||||
- aclk
|
||||
- hclk
|
||||
- sata
|
||||
- description: Power Module keep-alive clock
|
||||
const: pmalive
|
||||
- description: RxOOB detection clock
|
||||
const: rxoob
|
||||
- description: SATA Ports reference clock
|
||||
const: ref
|
||||
|
||||
resets:
|
||||
description:
|
||||
At least basic application and reference clock domains resets are
|
||||
normally supported by the DWC AHCI SATA controller.
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
reset-names:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
oneOf:
|
||||
- description: Application AHB/AXI BIU clock domain reset control
|
||||
enum:
|
||||
- arst
|
||||
- hrst
|
||||
- description: Power Module keep-alive clock domain reset control
|
||||
const: pmalive
|
||||
- description: RxOOB detection clock domain reset control
|
||||
const: rxoob
|
||||
- description: Reference clock domain reset control
|
||||
const: ref
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-e]$":
|
||||
$ref: '#/$defs/dwc-ahci-port'
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
$defs:
|
||||
dwc-ahci-port:
|
||||
$ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
|
||||
snps,tx-ts-max:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Maximal size of Tx DMA transactions in FIFO words
|
||||
enum: [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ]
|
||||
|
||||
snps,rx-ts-max:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Maximal size of Rx DMA transactions in FIFO words
|
||||
enum: [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ]
|
||||
|
||||
...
|
|
@ -0,0 +1,75 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/snps,dwc-ahci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Synopsys DWC AHCI SATA controller
|
||||
|
||||
maintainers:
|
||||
- Serge Semin <fancer.lancer@gmail.com>
|
||||
|
||||
description:
|
||||
This document defines device tree bindings for the generic Synopsys DWC
|
||||
implementation of the AHCI SATA controller.
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwc-ahci-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: Synopsys AHCI SATA-compatible devices
|
||||
const: snps,dwc-ahci
|
||||
- description: SPEAr1340 AHCI SATA device
|
||||
const: snps,spear-ahci
|
||||
- description: Rockhip RK3568 AHCI controller
|
||||
items:
|
||||
- const: rockchip,rk3568-dwc-ahci
|
||||
- const: snps,dwc-ahci
|
||||
|
||||
patternProperties:
|
||||
"^sata-port@[0-9a-e]$":
|
||||
$ref: /schemas/ata/snps,dwc-ahci-common.yaml#/$defs/dwc-ahci-port
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/ata/ahci.h>
|
||||
|
||||
sata@122f0000 {
|
||||
compatible = "snps,dwc-ahci";
|
||||
reg = <0x122F0000 0x1ff>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
clocks = <&clock1>, <&clock2>;
|
||||
clock-names = "aclk", "ref";
|
||||
|
||||
phys = <&sata_phy>;
|
||||
phy-names = "sata-phy";
|
||||
|
||||
ports-implemented = <0x1>;
|
||||
|
||||
sata-port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hba-port-cap = <HBA_PORT_FBSCP>;
|
||||
|
||||
snps,tx-ts-max = <512>;
|
||||
snps,rx-ts-max = <512>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -11584,6 +11584,15 @@ F: drivers/ata/ahci_platform.c
|
|||
F: drivers/ata/libahci_platform.c
|
||||
F: include/linux/ahci_platform.h
|
||||
|
||||
LIBATA SATA AHCI SYNOPSYS DWC CONTROLLER DRIVER
|
||||
M: Serge Semin <fancer.lancer@gmail.com>
|
||||
L: linux-ide@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git
|
||||
F: Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
|
||||
F: Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
|
||||
F: drivers/ata/ahci_dwc.c
|
||||
|
||||
LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
|
||||
M: Mikael Pettersson <mikpelinux@gmail.com>
|
||||
L: linux-ide@vger.kernel.org
|
||||
|
|
|
@ -256,7 +256,6 @@ menuconfig ARCH_VEXPRESS
|
|||
select GPIOLIB
|
||||
select HAVE_ARM_SCU if SMP
|
||||
select HAVE_ARM_TWD if SMP
|
||||
select HAVE_PATA_PLATFORM
|
||||
select CLK_ICST
|
||||
select NO_IOPORT_MAP
|
||||
select PLAT_VERSATILE
|
||||
|
|
|
@ -195,7 +195,6 @@ config ARM64
|
|||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select HAVE_KVM
|
||||
select HAVE_NMI
|
||||
select HAVE_PATA_PLATFORM
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
select HAVE_PERF_USER_STACK_DUMP
|
||||
|
|
|
@ -176,9 +176,19 @@ config AHCI_DM816
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config AHCI_DWC
|
||||
tristate "Synopsys DWC AHCI SATA support"
|
||||
select SATA_HOST
|
||||
select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
|
||||
help
|
||||
This option enables support for the Synopsys DWC AHCI SATA
|
||||
controller implementation.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config AHCI_ST
|
||||
tristate "ST AHCI SATA support"
|
||||
depends on ARCH_STI
|
||||
depends on ARCH_STI || COMPILE_TEST
|
||||
select SATA_HOST
|
||||
help
|
||||
This option enables support for ST AHCI SATA controller.
|
||||
|
@ -1102,8 +1112,7 @@ config PATA_PCMCIA
|
|||
If unsure, say N.
|
||||
|
||||
config PATA_PLATFORM
|
||||
tristate "Generic platform device PATA support"
|
||||
depends on EXPERT || PPC || HAVE_PATA_PLATFORM
|
||||
tristate "Generic platform device PATA support" if HAVE_PATA_PLATFORM
|
||||
help
|
||||
This option enables support for generic directly connected ATA
|
||||
devices commonly found on embedded systems.
|
||||
|
@ -1112,7 +1121,8 @@ config PATA_PLATFORM
|
|||
|
||||
config PATA_OF_PLATFORM
|
||||
tristate "OpenFirmware platform device PATA support"
|
||||
depends on PATA_PLATFORM && OF
|
||||
depends on OF
|
||||
select PATA_PLATFORM
|
||||
help
|
||||
This option enables support for generic directly connected ATA
|
||||
devices commonly found on embedded systems with OpenFirmware
|
||||
|
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o
|
|||
obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_DM816) += ahci_dm816.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_DWC) += ahci_dwc.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_MTK) += ahci_mtk.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
|
||||
|
|
|
@ -657,7 +657,7 @@ static void ahci_pci_save_initial_config(struct pci_dev *pdev,
|
|||
{
|
||||
if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
|
||||
dev_info(&pdev->dev, "JMB361 has only one port\n");
|
||||
hpriv->force_port_map = 1;
|
||||
hpriv->saved_port_map = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -690,7 +690,7 @@ static void ahci_pci_init_controller(struct ata_host *host)
|
|||
mv = 2;
|
||||
else
|
||||
mv = 4;
|
||||
port_mmio = __ahci_port_base(host, mv);
|
||||
port_mmio = __ahci_port_base(hpriv, mv);
|
||||
|
||||
writel(0, port_mmio + PORT_IRQ_MASK);
|
||||
|
||||
|
@ -1609,15 +1609,12 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap,
|
|||
goto update_policy;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (policy > ATA_LPM_MED_POWER &&
|
||||
(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
|
||||
if (policy > ATA_LPM_MED_POWER && pm_suspend_default_s2idle()) {
|
||||
if (hpriv->cap & HOST_CAP_PART)
|
||||
policy = ATA_LPM_MIN_POWER_WITH_PARTIAL;
|
||||
else if (hpriv->cap & HOST_CAP_SSC)
|
||||
policy = ATA_LPM_MIN_POWER;
|
||||
}
|
||||
#endif
|
||||
|
||||
update_policy:
|
||||
if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER)
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
|
||||
enum {
|
||||
AHCI_MAX_PORTS = 32,
|
||||
AHCI_MAX_CLKS = 5,
|
||||
AHCI_MAX_SG = 168, /* hardware max is 64K */
|
||||
AHCI_DMA_BOUNDARY = 0xffffffff,
|
||||
AHCI_MAX_CMDS = 32,
|
||||
|
@ -139,7 +138,7 @@ enum {
|
|||
PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
|
||||
|
||||
PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
|
||||
PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
|
||||
PORT_IRQ_DMPS = (1 << 7), /* mechanical presence status */
|
||||
PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
|
||||
PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
|
||||
PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
|
||||
|
@ -167,6 +166,8 @@ enum {
|
|||
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
|
||||
PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
|
||||
PORT_CMD_ESP = (1 << 21), /* External Sata Port */
|
||||
PORT_CMD_CPD = (1 << 20), /* Cold Presence Detection */
|
||||
PORT_CMD_MPSP = (1 << 19), /* Mechanical Presence Switch */
|
||||
PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */
|
||||
PORT_CMD_PMP = (1 << 17), /* PMP attached */
|
||||
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
|
||||
|
@ -182,6 +183,10 @@ enum {
|
|||
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
|
||||
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
|
||||
|
||||
/* PORT_CMD capabilities mask */
|
||||
PORT_CMD_CAP = PORT_CMD_HPCP | PORT_CMD_MPSP |
|
||||
PORT_CMD_CPD | PORT_CMD_ESP | PORT_CMD_FBSCP,
|
||||
|
||||
/* PORT_FBS bits */
|
||||
PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */
|
||||
PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
|
||||
|
@ -323,7 +328,6 @@ struct ahci_port_priv {
|
|||
struct ahci_host_priv {
|
||||
/* Input fields */
|
||||
unsigned int flags; /* AHCI_HFLAG_* */
|
||||
u32 force_port_map; /* force port map */
|
||||
u32 mask_port_map; /* mask out particular bits */
|
||||
|
||||
void __iomem * mmio; /* bus-independent mem map */
|
||||
|
@ -334,12 +338,15 @@ struct ahci_host_priv {
|
|||
u32 saved_cap; /* saved initial cap */
|
||||
u32 saved_cap2; /* saved initial cap2 */
|
||||
u32 saved_port_map; /* saved initial port_map */
|
||||
u32 saved_port_cap[AHCI_MAX_PORTS]; /* saved port_cap */
|
||||
u32 em_loc; /* enclosure management location */
|
||||
u32 em_buf_sz; /* EM buffer size in byte */
|
||||
u32 em_msg_type; /* EM message type */
|
||||
u32 remapped_nvme; /* NVMe remapped device count */
|
||||
bool got_runtime_pm; /* Did we do pm_runtime_get? */
|
||||
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
|
||||
unsigned int n_clks;
|
||||
struct clk_bulk_data *clks; /* Optional */
|
||||
unsigned int f_rsts;
|
||||
struct reset_control *rsts; /* Optional */
|
||||
struct regulator **target_pwrs; /* Optional */
|
||||
struct regulator *ahci_regulator;/* Optional */
|
||||
|
@ -426,10 +433,9 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
|
|||
void ahci_error_handler(struct ata_port *ap);
|
||||
u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
|
||||
|
||||
static inline void __iomem *__ahci_port_base(struct ata_host *host,
|
||||
static inline void __iomem *__ahci_port_base(struct ahci_host_priv *hpriv,
|
||||
unsigned int port_no)
|
||||
{
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
void __iomem *mmio = hpriv->mmio;
|
||||
|
||||
return mmio + 0x100 + (port_no * 0x80);
|
||||
|
@ -437,7 +443,9 @@ static inline void __iomem *__ahci_port_base(struct ata_host *host,
|
|||
|
||||
static inline void __iomem *ahci_port_base(struct ata_port *ap)
|
||||
{
|
||||
return __ahci_port_base(ap->host, ap->port_no);
|
||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
|
||||
return __ahci_port_base(hpriv, ap->port_no);
|
||||
}
|
||||
|
||||
static inline int ahci_nr_ports(u32 cap)
|
||||
|
|
|
@ -163,7 +163,6 @@ static int ahci_da850_probe(struct platform_device *pdev)
|
|||
struct ahci_host_priv *hpriv;
|
||||
void __iomem *pwrdn_reg;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
u32 mpy;
|
||||
int rc;
|
||||
|
||||
|
@ -172,36 +171,28 @@ static int ahci_da850_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(hpriv);
|
||||
|
||||
/*
|
||||
* Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
|
||||
* when trying to obtain the functional clock. This SATA controller
|
||||
* uses two clocks for which we specify two connection ids. If we don't
|
||||
* have the functional clock at this point - call clk_get() again with
|
||||
* con_id = "fck".
|
||||
* Internally ahci_platform_get_resources() calls the bulk clocks
|
||||
* get method or falls back to using a single clk_get_optional().
|
||||
* This AHCI SATA controller uses two clocks: functional clock
|
||||
* with "fck" connection id and external reference clock with
|
||||
* "refclk" id. If we haven't got all of them re-try the clocks
|
||||
* getting procedure with the explicitly specified ids.
|
||||
*/
|
||||
if (!hpriv->clks[0]) {
|
||||
clk = clk_get(dev, "fck");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
if (hpriv->n_clks < 2) {
|
||||
hpriv->clks = devm_kcalloc(dev, 2, sizeof(*hpriv->clks), GFP_KERNEL);
|
||||
if (!hpriv->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
hpriv->clks[0] = clk;
|
||||
hpriv->clks[0].id = "fck";
|
||||
hpriv->clks[1].id = "refclk";
|
||||
hpriv->n_clks = 2;
|
||||
|
||||
rc = devm_clk_bulk_get(dev, hpriv->n_clks, hpriv->clks);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The second clock used by ahci-da850 is the external REFCLK. If we
|
||||
* didn't get it from ahci_platform_get_resources(), let's try to
|
||||
* specify the con_id in clk_get().
|
||||
*/
|
||||
if (!hpriv->clks[1]) {
|
||||
clk = clk_get(dev, "refclk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "unable to obtain the reference clock");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hpriv->clks[1] = clk;
|
||||
}
|
||||
|
||||
mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
|
||||
mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1].clk));
|
||||
if (mpy == 0) {
|
||||
dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
|
||||
return -EINVAL;
|
||||
|
|
|
@ -69,12 +69,12 @@ static int ahci_dm816_phy_init(struct ahci_host_priv *hpriv, struct device *dev)
|
|||
* keep-alive clock and the external reference clock. We need the
|
||||
* rate of the latter to calculate the correct value of MPY bits.
|
||||
*/
|
||||
if (!hpriv->clks[1]) {
|
||||
if (hpriv->n_clks < 2) {
|
||||
dev_err(dev, "reference clock not supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
refclk_rate = clk_get_rate(hpriv->clks[1]);
|
||||
refclk_rate = clk_get_rate(hpriv->clks[1].clk);
|
||||
if ((refclk_rate % 100) != 0) {
|
||||
dev_err(dev, "reference clock rate must be divisible by 100\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* DWC AHCI SATA Platform driver
|
||||
*
|
||||
* Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
|
||||
*/
|
||||
|
||||
#include <linux/ahci_platform.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "ahci.h"
|
||||
|
||||
#define DRV_NAME "ahci-dwc"
|
||||
|
||||
#define AHCI_DWC_FBS_PMPN_MAX 15
|
||||
|
||||
/* DWC AHCI SATA controller specific registers */
|
||||
#define AHCI_DWC_HOST_OOBR 0xbc
|
||||
#define AHCI_DWC_HOST_OOB_WE BIT(31)
|
||||
#define AHCI_DWC_HOST_CWMIN_MASK GENMASK(30, 24)
|
||||
#define AHCI_DWC_HOST_CWMAX_MASK GENMASK(23, 16)
|
||||
#define AHCI_DWC_HOST_CIMIN_MASK GENMASK(15, 8)
|
||||
#define AHCI_DWC_HOST_CIMAX_MASK GENMASK(7, 0)
|
||||
|
||||
#define AHCI_DWC_HOST_GPCR 0xd0
|
||||
#define AHCI_DWC_HOST_GPSR 0xd4
|
||||
|
||||
#define AHCI_DWC_HOST_TIMER1MS 0xe0
|
||||
#define AHCI_DWC_HOST_TIMV_MASK GENMASK(19, 0)
|
||||
|
||||
#define AHCI_DWC_HOST_GPARAM1R 0xe8
|
||||
#define AHCI_DWC_HOST_ALIGN_M BIT(31)
|
||||
#define AHCI_DWC_HOST_RX_BUFFER BIT(30)
|
||||
#define AHCI_DWC_HOST_PHY_DATA_MASK GENMASK(29, 28)
|
||||
#define AHCI_DWC_HOST_PHY_RST BIT(27)
|
||||
#define AHCI_DWC_HOST_PHY_CTRL_MASK GENMASK(26, 21)
|
||||
#define AHCI_DWC_HOST_PHY_STAT_MASK GENMASK(20, 15)
|
||||
#define AHCI_DWC_HOST_LATCH_M BIT(14)
|
||||
#define AHCI_DWC_HOST_PHY_TYPE_MASK GENMASK(13, 11)
|
||||
#define AHCI_DWC_HOST_RET_ERR BIT(10)
|
||||
#define AHCI_DWC_HOST_AHB_ENDIAN_MASK GENMASK(9, 8)
|
||||
#define AHCI_DWC_HOST_S_HADDR BIT(7)
|
||||
#define AHCI_DWC_HOST_M_HADDR BIT(6)
|
||||
#define AHCI_DWC_HOST_S_HDATA_MASK GENMASK(5, 3)
|
||||
#define AHCI_DWC_HOST_M_HDATA_MASK GENMASK(2, 0)
|
||||
|
||||
#define AHCI_DWC_HOST_GPARAM2R 0xec
|
||||
#define AHCI_DWC_HOST_FBS_MEM_S BIT(19)
|
||||
#define AHCI_DWC_HOST_FBS_PMPN_MASK GENMASK(17, 16)
|
||||
#define AHCI_DWC_HOST_FBS_SUP BIT(15)
|
||||
#define AHCI_DWC_HOST_DEV_CP BIT(14)
|
||||
#define AHCI_DWC_HOST_DEV_MP BIT(13)
|
||||
#define AHCI_DWC_HOST_ENCODE_M BIT(12)
|
||||
#define AHCI_DWC_HOST_RXOOB_CLK_M BIT(11)
|
||||
#define AHCI_DWC_HOST_RXOOB_M BIT(10)
|
||||
#define AHCI_DWC_HOST_TXOOB_M BIT(9)
|
||||
#define AHCI_DWC_HOST_RXOOB_M BIT(10)
|
||||
#define AHCI_DWC_HOST_RXOOB_CLK_MASK GENMASK(8, 0)
|
||||
|
||||
#define AHCI_DWC_HOST_PPARAMR 0xf0
|
||||
#define AHCI_DWC_HOST_TX_MEM_M BIT(11)
|
||||
#define AHCI_DWC_HOST_TX_MEM_S BIT(10)
|
||||
#define AHCI_DWC_HOST_RX_MEM_M BIT(9)
|
||||
#define AHCI_DWC_HOST_RX_MEM_S BIT(8)
|
||||
#define AHCI_DWC_HOST_TXFIFO_DEPTH GENMASK(7, 4)
|
||||
#define AHCI_DWC_HOST_RXFIFO_DEPTH GENMASK(3, 0)
|
||||
|
||||
#define AHCI_DWC_HOST_TESTR 0xf4
|
||||
#define AHCI_DWC_HOST_PSEL_MASK GENMASK(18, 16)
|
||||
#define AHCI_DWC_HOST_TEST_IF BIT(0)
|
||||
|
||||
#define AHCI_DWC_HOST_VERSIONR 0xf8
|
||||
#define AHCI_DWC_HOST_IDR 0xfc
|
||||
|
||||
#define AHCI_DWC_PORT_DMACR 0x70
|
||||
#define AHCI_DWC_PORT_RXABL_MASK GENMASK(15, 12)
|
||||
#define AHCI_DWC_PORT_TXABL_MASK GENMASK(11, 8)
|
||||
#define AHCI_DWC_PORT_RXTS_MASK GENMASK(7, 4)
|
||||
#define AHCI_DWC_PORT_TXTS_MASK GENMASK(3, 0)
|
||||
#define AHCI_DWC_PORT_PHYCR 0x74
|
||||
#define AHCI_DWC_PORT_PHYSR 0x78
|
||||
|
||||
/* Baikal-T1 AHCI SATA specific registers */
|
||||
#define AHCI_BT1_HOST_PHYCR AHCI_DWC_HOST_GPCR
|
||||
#define AHCI_BT1_HOST_MPLM_MASK GENMASK(29, 23)
|
||||
#define AHCI_BT1_HOST_LOSDT_MASK GENMASK(22, 20)
|
||||
#define AHCI_BT1_HOST_CRR BIT(19)
|
||||
#define AHCI_BT1_HOST_CRW BIT(18)
|
||||
#define AHCI_BT1_HOST_CRCD BIT(17)
|
||||
#define AHCI_BT1_HOST_CRCA BIT(16)
|
||||
#define AHCI_BT1_HOST_CRDI_MASK GENMASK(15, 0)
|
||||
|
||||
#define AHCI_BT1_HOST_PHYSR AHCI_DWC_HOST_GPSR
|
||||
#define AHCI_BT1_HOST_CRA BIT(16)
|
||||
#define AHCI_BT1_HOST_CRDO_MASK GENMASK(15, 0)
|
||||
|
||||
struct ahci_dwc_plat_data {
|
||||
unsigned int pflags;
|
||||
unsigned int hflags;
|
||||
int (*init)(struct ahci_host_priv *hpriv);
|
||||
int (*reinit)(struct ahci_host_priv *hpriv);
|
||||
void (*clear)(struct ahci_host_priv *hpriv);
|
||||
};
|
||||
|
||||
struct ahci_dwc_host_priv {
|
||||
const struct ahci_dwc_plat_data *pdata;
|
||||
struct platform_device *pdev;
|
||||
|
||||
u32 timv;
|
||||
u32 dmacr[AHCI_MAX_PORTS];
|
||||
};
|
||||
|
||||
static int ahci_bt1_init(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
int ret;
|
||||
|
||||
/* APB, application and reference clocks are required */
|
||||
if (!ahci_platform_find_clk(hpriv, "pclk") ||
|
||||
!ahci_platform_find_clk(hpriv, "aclk") ||
|
||||
!ahci_platform_find_clk(hpriv, "ref")) {
|
||||
dev_err(&dpriv->pdev->dev, "No system clocks specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fully reset the SATA AXI and ref clocks domain to ensure the state
|
||||
* machine is working from scratch especially if the reference clocks
|
||||
* source has been changed.
|
||||
*/
|
||||
ret = ahci_platform_assert_rsts(hpriv);
|
||||
if (ret) {
|
||||
dev_err(&dpriv->pdev->dev, "Couldn't assert the resets\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ahci_platform_deassert_rsts(hpriv);
|
||||
if (ret) {
|
||||
dev_err(&dpriv->pdev->dev, "Couldn't de-assert the resets\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv;
|
||||
struct ahci_host_priv *hpriv;
|
||||
|
||||
dpriv = devm_kzalloc(&pdev->dev, sizeof(*dpriv), GFP_KERNEL);
|
||||
if (!dpriv)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dpriv->pdev = pdev;
|
||||
dpriv->pdata = device_get_match_data(&pdev->dev);
|
||||
if (!dpriv->pdata)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
hpriv = ahci_platform_get_resources(pdev, dpriv->pdata->pflags);
|
||||
if (IS_ERR(hpriv))
|
||||
return hpriv;
|
||||
|
||||
hpriv->flags |= dpriv->pdata->hflags;
|
||||
hpriv->plat_data = (void *)dpriv;
|
||||
|
||||
return hpriv;
|
||||
}
|
||||
|
||||
static void ahci_dwc_check_cap(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
unsigned long port_map = hpriv->saved_port_map | hpriv->mask_port_map;
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
bool dev_mp, dev_cp, fbs_sup;
|
||||
unsigned int fbs_pmp;
|
||||
u32 param;
|
||||
int i;
|
||||
|
||||
param = readl(hpriv->mmio + AHCI_DWC_HOST_GPARAM2R);
|
||||
dev_mp = !!(param & AHCI_DWC_HOST_DEV_MP);
|
||||
dev_cp = !!(param & AHCI_DWC_HOST_DEV_CP);
|
||||
fbs_sup = !!(param & AHCI_DWC_HOST_FBS_SUP);
|
||||
fbs_pmp = 5 * FIELD_GET(AHCI_DWC_HOST_FBS_PMPN_MASK, param);
|
||||
|
||||
if (!dev_mp && hpriv->saved_cap & HOST_CAP_MPS) {
|
||||
dev_warn(&dpriv->pdev->dev, "MPS is unsupported\n");
|
||||
hpriv->saved_cap &= ~HOST_CAP_MPS;
|
||||
}
|
||||
|
||||
|
||||
if (fbs_sup && fbs_pmp < AHCI_DWC_FBS_PMPN_MAX) {
|
||||
dev_warn(&dpriv->pdev->dev, "PMPn is limited up to %u ports\n",
|
||||
fbs_pmp);
|
||||
}
|
||||
|
||||
for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
|
||||
if (!dev_mp && hpriv->saved_port_cap[i] & PORT_CMD_MPSP) {
|
||||
dev_warn(&dpriv->pdev->dev, "MPS incapable port %d\n", i);
|
||||
hpriv->saved_port_cap[i] &= ~PORT_CMD_MPSP;
|
||||
}
|
||||
|
||||
if (!dev_cp && hpriv->saved_port_cap[i] & PORT_CMD_CPD) {
|
||||
dev_warn(&dpriv->pdev->dev, "CPD incapable port %d\n", i);
|
||||
hpriv->saved_port_cap[i] &= ~PORT_CMD_CPD;
|
||||
}
|
||||
|
||||
if (!fbs_sup && hpriv->saved_port_cap[i] & PORT_CMD_FBSCP) {
|
||||
dev_warn(&dpriv->pdev->dev, "FBS incapable port %d\n", i);
|
||||
hpriv->saved_port_cap[i] &= ~PORT_CMD_FBSCP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ahci_dwc_init_timer(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
unsigned long rate;
|
||||
struct clk *aclk;
|
||||
u32 cap, cap2;
|
||||
|
||||
/* 1ms tick is generated only for the CCC or DevSleep features */
|
||||
cap = readl(hpriv->mmio + HOST_CAP);
|
||||
cap2 = readl(hpriv->mmio + HOST_CAP2);
|
||||
if (!(cap & HOST_CAP_CCC) && !(cap2 & HOST_CAP2_SDS))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Tick is generated based on the AXI/AHB application clocks signal
|
||||
* so we need to be sure in the clock we are going to use.
|
||||
*/
|
||||
aclk = ahci_platform_find_clk(hpriv, "aclk");
|
||||
if (!aclk)
|
||||
return;
|
||||
|
||||
/* 1ms timer interval is set as TIMV = AMBA_FREQ[MHZ] * 1000 */
|
||||
dpriv->timv = readl(hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
|
||||
dpriv->timv = FIELD_GET(AHCI_DWC_HOST_TIMV_MASK, dpriv->timv);
|
||||
rate = clk_get_rate(aclk) / 1000UL;
|
||||
if (rate == dpriv->timv)
|
||||
return;
|
||||
|
||||
dev_info(&dpriv->pdev->dev, "Update CCC/DevSlp timer for Fapp %lu MHz\n",
|
||||
rate / 1000UL);
|
||||
dpriv->timv = FIELD_PREP(AHCI_DWC_HOST_TIMV_MASK, rate);
|
||||
writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
|
||||
}
|
||||
|
||||
static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
struct device_node *child;
|
||||
void __iomem *port_mmio;
|
||||
u32 port, dmacr, ts;
|
||||
|
||||
/*
|
||||
* Update the DMA Tx/Rx transaction sizes in accordance with the
|
||||
* platform setup. Note values exceeding maximal or minimal limits will
|
||||
* be automatically clamped. Also note the register isn't affected by
|
||||
* the HBA global reset so we can freely initialize it once until the
|
||||
* next system reset.
|
||||
*/
|
||||
for_each_child_of_node(dpriv->pdev->dev.of_node, child) {
|
||||
if (!of_device_is_available(child))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &port)) {
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port_mmio = __ahci_port_base(hpriv, port);
|
||||
dmacr = readl(port_mmio + AHCI_DWC_PORT_DMACR);
|
||||
|
||||
if (!of_property_read_u32(child, "snps,tx-ts-max", &ts)) {
|
||||
ts = ilog2(ts);
|
||||
dmacr &= ~AHCI_DWC_PORT_TXTS_MASK;
|
||||
dmacr |= FIELD_PREP(AHCI_DWC_PORT_TXTS_MASK, ts);
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(child, "snps,rx-ts-max", &ts)) {
|
||||
ts = ilog2(ts);
|
||||
dmacr &= ~AHCI_DWC_PORT_RXTS_MASK;
|
||||
dmacr |= FIELD_PREP(AHCI_DWC_PORT_RXTS_MASK, ts);
|
||||
}
|
||||
|
||||
writel(dmacr, port_mmio + AHCI_DWC_PORT_DMACR);
|
||||
dpriv->dmacr[port] = dmacr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ahci_dwc_init_host(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
int rc;
|
||||
|
||||
rc = ahci_platform_enable_resources(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (dpriv->pdata->init) {
|
||||
rc = dpriv->pdata->init(hpriv);
|
||||
if (rc)
|
||||
goto err_disable_resources;
|
||||
}
|
||||
|
||||
ahci_dwc_check_cap(hpriv);
|
||||
|
||||
ahci_dwc_init_timer(hpriv);
|
||||
|
||||
rc = ahci_dwc_init_dmacr(hpriv);
|
||||
if (rc)
|
||||
goto err_clear_platform;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clear_platform:
|
||||
if (dpriv->pdata->clear)
|
||||
dpriv->pdata->clear(hpriv);
|
||||
|
||||
err_disable_resources:
|
||||
ahci_platform_disable_resources(hpriv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ahci_dwc_reinit_host(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
unsigned long port_map = hpriv->port_map;
|
||||
void __iomem *port_mmio;
|
||||
int i, rc;
|
||||
|
||||
rc = ahci_platform_enable_resources(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (dpriv->pdata->reinit) {
|
||||
rc = dpriv->pdata->reinit(hpriv);
|
||||
if (rc)
|
||||
goto err_disable_resources;
|
||||
}
|
||||
|
||||
writel(dpriv->timv, hpriv->mmio + AHCI_DWC_HOST_TIMER1MS);
|
||||
|
||||
for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
|
||||
port_mmio = __ahci_port_base(hpriv, i);
|
||||
writel(dpriv->dmacr[i], port_mmio + AHCI_DWC_PORT_DMACR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_resources:
|
||||
ahci_platform_disable_resources(hpriv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ahci_dwc_clear_host(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
||||
|
||||
if (dpriv->pdata->clear)
|
||||
dpriv->pdata->clear(hpriv);
|
||||
|
||||
ahci_platform_disable_resources(hpriv);
|
||||
}
|
||||
|
||||
static void ahci_dwc_stop_host(struct ata_host *host)
|
||||
{
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
|
||||
ahci_dwc_clear_host(hpriv);
|
||||
}
|
||||
|
||||
static struct ata_port_operations ahci_dwc_port_ops = {
|
||||
.inherits = &ahci_platform_ops,
|
||||
.host_stop = ahci_dwc_stop_host,
|
||||
};
|
||||
|
||||
static const struct ata_port_info ahci_dwc_port_info = {
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_dwc_port_ops,
|
||||
};
|
||||
|
||||
static struct scsi_host_template ahci_dwc_scsi_info = {
|
||||
AHCI_SHT(DRV_NAME),
|
||||
};
|
||||
|
||||
static int ahci_dwc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ahci_host_priv *hpriv;
|
||||
int rc;
|
||||
|
||||
hpriv = ahci_dwc_get_resources(pdev);
|
||||
if (IS_ERR(hpriv))
|
||||
return PTR_ERR(hpriv);
|
||||
|
||||
rc = ahci_dwc_init_host(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_dwc_port_info,
|
||||
&ahci_dwc_scsi_info);
|
||||
if (rc)
|
||||
goto err_clear_host;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clear_host:
|
||||
ahci_dwc_clear_host(hpriv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ahci_dwc_suspend(struct device *dev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(dev);
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
int rc;
|
||||
|
||||
rc = ahci_platform_suspend_host(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ahci_dwc_clear_host(hpriv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ahci_dwc_resume(struct device *dev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(dev);
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
int rc;
|
||||
|
||||
rc = ahci_dwc_reinit_host(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return ahci_platform_resume_host(dev);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ahci_dwc_pm_ops, ahci_dwc_suspend,
|
||||
ahci_dwc_resume);
|
||||
|
||||
static struct ahci_dwc_plat_data ahci_dwc_plat = {
|
||||
.pflags = AHCI_PLATFORM_GET_RESETS,
|
||||
};
|
||||
|
||||
static struct ahci_dwc_plat_data ahci_bt1_plat = {
|
||||
.pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER,
|
||||
.init = ahci_bt1_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id ahci_dwc_of_match[] = {
|
||||
{ .compatible = "snps,dwc-ahci", &ahci_dwc_plat },
|
||||
{ .compatible = "snps,spear-ahci", &ahci_dwc_plat },
|
||||
{ .compatible = "baikal,bt1-ahci", &ahci_bt1_plat },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);
|
||||
|
||||
static struct platform_driver ahci_dwc_driver = {
|
||||
.probe = ahci_dwc_probe,
|
||||
.remove = ata_platform_remove_one,
|
||||
.shutdown = ahci_platform_shutdown,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = ahci_dwc_of_match,
|
||||
.pm = &ahci_dwc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ahci_dwc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DWC AHCI SATA platform driver");
|
||||
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -118,8 +118,6 @@ static int mtk_ahci_parse_property(struct ahci_host_priv *hpriv,
|
|||
SYS_CFG_SATA_EN);
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "ports-implemented", &hpriv->force_port_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,9 +56,6 @@ static int ahci_probe(struct platform_device *pdev)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
of_property_read_u32(dev->of_node,
|
||||
"ports-implemented", &hpriv->force_port_map);
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
|
||||
hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
|
||||
|
||||
|
@ -83,9 +80,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
|
|||
static const struct of_device_id ahci_of_match[] = {
|
||||
{ .compatible = "generic-ahci", },
|
||||
/* Keep the following compatibles for device tree compatibility */
|
||||
{ .compatible = "snps,spear-ahci", },
|
||||
{ .compatible = "ibm,476gtr-ahci", },
|
||||
{ .compatible = "snps,dwc-ahci", },
|
||||
{ .compatible = "hisilicon,hisi-ahci", },
|
||||
{ .compatible = "cavium,octeon-7130-ahci", },
|
||||
{ /* sentinel */ }
|
||||
|
|
|
@ -144,7 +144,6 @@ static struct scsi_host_template ahci_platform_sht = {
|
|||
|
||||
static int st_ahci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct st_ahci_drv_data *drv_data;
|
||||
struct ahci_host_priv *hpriv;
|
||||
int err;
|
||||
|
@ -168,9 +167,6 @@ static int st_ahci_probe(struct platform_device *pdev)
|
|||
|
||||
st_ahci_configure_oob(hpriv->mmio);
|
||||
|
||||
of_property_read_u32(dev->of_node,
|
||||
"ports-implemented", &hpriv->force_port_map);
|
||||
|
||||
err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
|
||||
&ahci_platform_sht);
|
||||
if (err) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -443,17 +444,28 @@ static ssize_t ahci_show_em_supported(struct device *dev,
|
|||
void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
||||
{
|
||||
void __iomem *mmio = hpriv->mmio;
|
||||
u32 cap, cap2, vers, port_map;
|
||||
void __iomem *port_mmio;
|
||||
unsigned long port_map;
|
||||
u32 cap, cap2, vers;
|
||||
int i;
|
||||
|
||||
/* make sure AHCI mode is enabled before accessing CAP */
|
||||
ahci_enable_ahci(mmio);
|
||||
|
||||
/* Values prefixed with saved_ are written back to host after
|
||||
* reset. Values without are used for driver operation.
|
||||
/*
|
||||
* Values prefixed with saved_ are written back to the HBA and ports
|
||||
* registers after reset. Values without are used for driver operation.
|
||||
*/
|
||||
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
|
||||
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
|
||||
|
||||
/*
|
||||
* Override HW-init HBA capability fields with the platform-specific
|
||||
* values. The rest of the HBA capabilities are defined as Read-only
|
||||
* and can't be modified in CSR anyway.
|
||||
*/
|
||||
cap = readl(mmio + HOST_CAP);
|
||||
if (hpriv->saved_cap)
|
||||
cap = (cap & ~(HOST_CAP_SSS | HOST_CAP_MPS)) | hpriv->saved_cap;
|
||||
hpriv->saved_cap = cap;
|
||||
|
||||
/* CAP2 register is only defined for AHCI 1.2 and later */
|
||||
vers = readl(mmio + HOST_VERSION);
|
||||
|
@ -517,15 +529,18 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
|||
cap &= ~HOST_CAP_SXS;
|
||||
}
|
||||
|
||||
if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
|
||||
dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
|
||||
port_map, hpriv->force_port_map);
|
||||
port_map = hpriv->force_port_map;
|
||||
/* Override the HBA ports mapping if the platform needs it */
|
||||
port_map = readl(mmio + HOST_PORTS_IMPL);
|
||||
if (hpriv->saved_port_map && port_map != hpriv->saved_port_map) {
|
||||
dev_info(dev, "forcing port_map 0x%lx -> 0x%x\n",
|
||||
port_map, hpriv->saved_port_map);
|
||||
port_map = hpriv->saved_port_map;
|
||||
} else {
|
||||
hpriv->saved_port_map = port_map;
|
||||
}
|
||||
|
||||
if (hpriv->mask_port_map) {
|
||||
dev_warn(dev, "masking port_map 0x%x -> 0x%x\n",
|
||||
dev_warn(dev, "masking port_map 0x%lx -> 0x%lx\n",
|
||||
port_map,
|
||||
port_map & hpriv->mask_port_map);
|
||||
port_map &= hpriv->mask_port_map;
|
||||
|
@ -544,7 +559,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
|||
*/
|
||||
if (map_ports > ahci_nr_ports(cap)) {
|
||||
dev_warn(dev,
|
||||
"implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n",
|
||||
"implemented port map (0x%lx) contains more ports than nr_ports (%u), using nr_ports\n",
|
||||
port_map, ahci_nr_ports(cap));
|
||||
port_map = 0;
|
||||
}
|
||||
|
@ -553,16 +568,30 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
|||
/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
|
||||
if (!port_map && vers < 0x10300) {
|
||||
port_map = (1 << ahci_nr_ports(cap)) - 1;
|
||||
dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
|
||||
dev_warn(dev, "forcing PORTS_IMPL to 0x%lx\n", port_map);
|
||||
|
||||
/* write the fixed up value to the PI register */
|
||||
hpriv->saved_port_map = port_map;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preserve the ports capabilities defined by the platform. Note there
|
||||
* is no need in storing the rest of the P#.CMD fields since they are
|
||||
* volatile.
|
||||
*/
|
||||
for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
|
||||
if (hpriv->saved_port_cap[i])
|
||||
continue;
|
||||
|
||||
port_mmio = __ahci_port_base(hpriv, i);
|
||||
hpriv->saved_port_cap[i] =
|
||||
readl(port_mmio + PORT_CMD) & PORT_CMD_CAP;
|
||||
}
|
||||
|
||||
/* record values to use during operation */
|
||||
hpriv->cap = cap;
|
||||
hpriv->cap2 = cap2;
|
||||
hpriv->version = readl(mmio + HOST_VERSION);
|
||||
hpriv->version = vers;
|
||||
hpriv->port_map = port_map;
|
||||
|
||||
if (!hpriv->start_engine)
|
||||
|
@ -588,13 +617,21 @@ EXPORT_SYMBOL_GPL(ahci_save_initial_config);
|
|||
static void ahci_restore_initial_config(struct ata_host *host)
|
||||
{
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
unsigned long port_map = hpriv->port_map;
|
||||
void __iomem *mmio = hpriv->mmio;
|
||||
void __iomem *port_mmio;
|
||||
int i;
|
||||
|
||||
writel(hpriv->saved_cap, mmio + HOST_CAP);
|
||||
if (hpriv->saved_cap2)
|
||||
writel(hpriv->saved_cap2, mmio + HOST_CAP2);
|
||||
writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
|
||||
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
|
||||
|
||||
for_each_set_bit(i, &port_map, AHCI_MAX_PORTS) {
|
||||
port_mmio = __ahci_port_base(hpriv, i);
|
||||
writel(hpriv->saved_port_cap[i], port_mmio + PORT_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
|
||||
|
|
|
@ -93,32 +93,42 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
|
||||
|
||||
/**
|
||||
* ahci_platform_find_clk - Find platform clock
|
||||
* @hpriv: host private area to store config values
|
||||
* @con_id: clock connection ID
|
||||
*
|
||||
* This function returns a pointer to the clock descriptor of the clock with
|
||||
* the passed ID.
|
||||
*
|
||||
* RETURNS:
|
||||
* Pointer to the clock descriptor on success otherwise NULL
|
||||
*/
|
||||
struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hpriv->n_clks; i++) {
|
||||
if (!strcmp(hpriv->clks[i].id, con_id))
|
||||
return hpriv->clks[i].clk;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_find_clk);
|
||||
|
||||
/**
|
||||
* ahci_platform_enable_clks - Enable platform clocks
|
||||
* @hpriv: host private area to store config values
|
||||
*
|
||||
* This function enables all the clks found in hpriv->clks, starting at
|
||||
* index 0. If any clk fails to enable it disables all the clks already
|
||||
* enabled in reverse order, and then returns an error.
|
||||
* This function enables all the clks found for the AHCI device.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success otherwise a negative error code
|
||||
*/
|
||||
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
int c, rc;
|
||||
|
||||
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
|
||||
rc = clk_prepare_enable(hpriv->clks[c]);
|
||||
if (rc)
|
||||
goto disable_unprepare_clk;
|
||||
}
|
||||
return 0;
|
||||
|
||||
disable_unprepare_clk:
|
||||
while (--c >= 0)
|
||||
clk_disable_unprepare(hpriv->clks[c]);
|
||||
return rc;
|
||||
return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
|
||||
|
||||
|
@ -126,19 +136,54 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
|
|||
* ahci_platform_disable_clks - Disable platform clocks
|
||||
* @hpriv: host private area to store config values
|
||||
*
|
||||
* This function disables all the clks found in hpriv->clks, in reverse
|
||||
* order of ahci_platform_enable_clks (starting at the end of the array).
|
||||
* This function disables all the clocks enabled before
|
||||
* (bulk-clocks-disable function is supposed to do that in reverse
|
||||
* from the enabling procedure order).
|
||||
*/
|
||||
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
|
||||
if (hpriv->clks[c])
|
||||
clk_disable_unprepare(hpriv->clks[c]);
|
||||
clk_bulk_disable_unprepare(hpriv->n_clks, hpriv->clks);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
|
||||
|
||||
/**
|
||||
* ahci_platform_deassert_rsts - Deassert/trigger platform resets
|
||||
* @hpriv: host private area to store config values
|
||||
*
|
||||
* This function deasserts or triggers all the reset lines found for
|
||||
* the AHCI device.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success otherwise a negative error code
|
||||
*/
|
||||
int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
|
||||
return reset_control_reset(hpriv->rsts);
|
||||
|
||||
return reset_control_deassert(hpriv->rsts);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_deassert_rsts);
|
||||
|
||||
/**
|
||||
* ahci_platform_assert_rsts - Assert/rearm platform resets
|
||||
* @hpriv: host private area to store config values
|
||||
*
|
||||
* This function asserts or rearms (for self-deasserting resets) all
|
||||
* the reset controls found for the AHCI device.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success otherwise a negative error code
|
||||
*/
|
||||
int ahci_platform_assert_rsts(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
if (hpriv->f_rsts & AHCI_PLATFORM_RST_TRIGGER)
|
||||
return reset_control_rearm(hpriv->rsts);
|
||||
|
||||
return reset_control_assert(hpriv->rsts);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_platform_assert_rsts);
|
||||
|
||||
/**
|
||||
* ahci_platform_enable_regulators - Enable regulators
|
||||
* @hpriv: host private area to store config values
|
||||
|
@ -236,18 +281,18 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
|
|||
if (rc)
|
||||
goto disable_regulator;
|
||||
|
||||
rc = reset_control_deassert(hpriv->rsts);
|
||||
rc = ahci_platform_deassert_rsts(hpriv);
|
||||
if (rc)
|
||||
goto disable_clks;
|
||||
|
||||
rc = ahci_platform_enable_phys(hpriv);
|
||||
if (rc)
|
||||
goto disable_resets;
|
||||
goto disable_rsts;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_resets:
|
||||
reset_control_assert(hpriv->rsts);
|
||||
disable_rsts:
|
||||
ahci_platform_assert_rsts(hpriv);
|
||||
|
||||
disable_clks:
|
||||
ahci_platform_disable_clks(hpriv);
|
||||
|
@ -274,7 +319,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
|
|||
{
|
||||
ahci_platform_disable_phys(hpriv);
|
||||
|
||||
reset_control_assert(hpriv->rsts);
|
||||
ahci_platform_assert_rsts(hpriv);
|
||||
|
||||
ahci_platform_disable_clks(hpriv);
|
||||
|
||||
|
@ -292,8 +337,6 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
|
|||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
|
||||
clk_put(hpriv->clks[c]);
|
||||
/*
|
||||
* The regulators are tied to child node device and not to the
|
||||
* SATA device itself. So we can't use devm for automatically
|
||||
|
@ -363,6 +406,34 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
|
||||
struct device *dev)
|
||||
{
|
||||
struct device_node *child;
|
||||
u32 port;
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "hba-cap", &hpriv->saved_cap))
|
||||
hpriv->saved_cap &= (HOST_CAP_SSS | HOST_CAP_MPS);
|
||||
|
||||
of_property_read_u32(dev->of_node,
|
||||
"ports-implemented", &hpriv->saved_port_map);
|
||||
|
||||
for_each_child_of_node(dev->of_node, child) {
|
||||
if (!of_device_is_available(child))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &port)) {
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(child, "hba-port-cap", &hpriv->saved_port_cap[port]))
|
||||
hpriv->saved_port_cap[port] &= PORT_CMD_CAP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ahci_platform_get_resources - Get platform resources
|
||||
* @pdev: platform device to get resources for
|
||||
|
@ -374,8 +445,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
|
|||
* 1) mmio registers (IORESOURCE_MEM 0, mandatory)
|
||||
* 2) regulator for controlling the targets power (optional)
|
||||
* regulator for controlling the AHCI controller (optional)
|
||||
* 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
|
||||
* or for non devicetree enabled platforms a single clock
|
||||
* 3) all clocks specified in the devicetree node, or a single
|
||||
* clock for non-OF platforms (optional)
|
||||
* 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
|
||||
* 5) phys (optional)
|
||||
*
|
||||
|
@ -385,11 +456,10 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
|
|||
struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
||||
unsigned int flags)
|
||||
{
|
||||
int child_nodes, rc = -ENOMEM, enabled_ports = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct clk *clk;
|
||||
struct device_node *child;
|
||||
int i, enabled_ports = 0, rc = -ENOMEM, child_nodes;
|
||||
u32 mask_port_map = 0;
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
|
@ -402,32 +472,51 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
|||
|
||||
devres_add(dev, hpriv);
|
||||
|
||||
hpriv->mmio = devm_ioremap_resource(dev,
|
||||
platform_get_resource(pdev, IORESOURCE_MEM, 0));
|
||||
/*
|
||||
* If the DT provided an "ahci" named resource, use it. Otherwise,
|
||||
* fallback to using the default first resource for the device node.
|
||||
*/
|
||||
if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci"))
|
||||
hpriv->mmio = devm_platform_ioremap_resource_byname(pdev, "ahci");
|
||||
else
|
||||
hpriv->mmio = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hpriv->mmio)) {
|
||||
rc = PTR_ERR(hpriv->mmio);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < AHCI_MAX_CLKS; i++) {
|
||||
/*
|
||||
* For now we must use clk_get(dev, NULL) for the first clock,
|
||||
* because some platforms (da850, spear13xx) are not yet
|
||||
* converted to use devicetree for clocks. For new platforms
|
||||
* this is equivalent to of_clk_get(dev->of_node, 0).
|
||||
*/
|
||||
if (i == 0)
|
||||
clk = clk_get(dev, NULL);
|
||||
else
|
||||
clk = of_clk_get(dev->of_node, i);
|
||||
/*
|
||||
* Bulk clocks getting procedure can fail to find any clock due to
|
||||
* running on a non-OF platform or due to the clocks being defined in
|
||||
* bypass of the DT firmware (like da850, spear13xx). In that case we
|
||||
* fallback to getting a single clock source right from the dev clocks
|
||||
* list.
|
||||
*/
|
||||
rc = devm_clk_bulk_get_all(dev, &hpriv->clks);
|
||||
if (rc < 0)
|
||||
goto err_out;
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
rc = PTR_ERR(clk);
|
||||
if (rc == -EPROBE_DEFER)
|
||||
goto err_out;
|
||||
break;
|
||||
if (rc > 0) {
|
||||
/* Got clocks in bulk */
|
||||
hpriv->n_clks = rc;
|
||||
} else {
|
||||
/*
|
||||
* No clock bulk found: fallback to manually getting
|
||||
* the optional clock.
|
||||
*/
|
||||
hpriv->clks = devm_kzalloc(dev, sizeof(*hpriv->clks), GFP_KERNEL);
|
||||
if (!hpriv->clks) {
|
||||
rc = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
hpriv->clks->clk = devm_clk_get_optional(dev, NULL);
|
||||
if (IS_ERR(hpriv->clks->clk)) {
|
||||
rc = PTR_ERR(hpriv->clks->clk);
|
||||
goto err_out;
|
||||
} else if (hpriv->clks->clk) {
|
||||
hpriv->clks->id = "ahci";
|
||||
hpriv->n_clks = 1;
|
||||
}
|
||||
hpriv->clks[i] = clk;
|
||||
}
|
||||
|
||||
hpriv->ahci_regulator = devm_regulator_get(dev, "ahci");
|
||||
|
@ -449,16 +538,28 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
|||
rc = PTR_ERR(hpriv->rsts);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
hpriv->f_rsts = flags & AHCI_PLATFORM_RST_TRIGGER;
|
||||
}
|
||||
|
||||
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
|
||||
/*
|
||||
* Too many sub-nodes most likely means having something wrong with
|
||||
* the firmware.
|
||||
*/
|
||||
child_nodes = of_get_child_count(dev->of_node);
|
||||
if (child_nodes > AHCI_MAX_PORTS) {
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no sub-node was found, we still need to set nports to
|
||||
* one in order to be able to use the
|
||||
* ahci_platform_[en|dis]able_[phys|regulators] functions.
|
||||
*/
|
||||
if (!child_nodes)
|
||||
if (child_nodes)
|
||||
hpriv->nports = child_nodes;
|
||||
else
|
||||
hpriv->nports = 1;
|
||||
|
||||
hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
|
||||
|
@ -540,6 +641,15 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
|||
if (rc == -EPROBE_DEFER)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve firmware-specific flags which then will be used to set
|
||||
* the HW-init fields of HBA and its ports
|
||||
*/
|
||||
rc = ahci_platform_get_firmware(hpriv, dev);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
hpriv->got_runtime_pm = true;
|
||||
|
|
|
@ -665,33 +665,33 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
|
|||
|
||||
/**
|
||||
* ata_build_rw_tf - Build ATA taskfile for given read/write request
|
||||
* @tf: Target ATA taskfile
|
||||
* @dev: ATA device @tf belongs to
|
||||
* @qc: Metadata associated with the taskfile to build
|
||||
* @block: Block address
|
||||
* @n_block: Number of blocks
|
||||
* @tf_flags: RW/FUA etc...
|
||||
* @tag: tag
|
||||
* @class: IO priority class
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*
|
||||
* Build ATA taskfile @tf for read/write request described by
|
||||
* @block, @n_block, @tf_flags and @tag on @dev.
|
||||
* Build ATA taskfile for the command @qc for read/write request described
|
||||
* by @block, @n_block, @tf_flags and @class.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success, -ERANGE if the request is too large for @dev,
|
||||
* -EINVAL if the request is invalid.
|
||||
*/
|
||||
int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
||||
u64 block, u32 n_block, unsigned int tf_flags,
|
||||
unsigned int tag, int class)
|
||||
int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
||||
unsigned int tf_flags, int class)
|
||||
{
|
||||
struct ata_taskfile *tf = &qc->tf;
|
||||
struct ata_device *dev = qc->dev;
|
||||
|
||||
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
|
||||
tf->flags |= tf_flags;
|
||||
|
||||
if (ata_ncq_enabled(dev) && !ata_tag_internal(tag)) {
|
||||
if (ata_ncq_enabled(dev)) {
|
||||
/* yay, NCQ */
|
||||
if (!lba_48_ok(block, n_block))
|
||||
return -ERANGE;
|
||||
|
@ -704,7 +704,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
|||
else
|
||||
tf->command = ATA_CMD_FPDMA_READ;
|
||||
|
||||
tf->nsect = tag << 3;
|
||||
tf->nsect = qc->hw_tag << 3;
|
||||
tf->hob_feature = (n_block >> 8) & 0xff;
|
||||
tf->feature = n_block & 0xff;
|
||||
|
||||
|
@ -719,7 +719,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
|||
if (tf->flags & ATA_TFLAG_FUA)
|
||||
tf->device |= 1 << 7;
|
||||
|
||||
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE &&
|
||||
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
|
||||
class == IOPRIO_CLASS_RT)
|
||||
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
|
||||
} else if (dev->flags & ATA_DFLAG_LBA) {
|
||||
|
@ -1578,8 +1578,8 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev,
|
|||
else
|
||||
ata_qc_complete(qc);
|
||||
|
||||
ata_dev_warn(dev, "qc timeout (cmd 0x%x)\n",
|
||||
command);
|
||||
ata_dev_warn(dev, "qc timeout after %u msecs (cmd 0x%x)\n",
|
||||
timeout, command);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
@ -2171,7 +2171,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
|
|||
return;
|
||||
|
||||
not_supported:
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO;
|
||||
}
|
||||
|
||||
|
@ -3021,7 +3021,8 @@ static void sata_print_link_status(struct ata_link *link)
|
|||
|
||||
if (sata_scr_read(link, SCR_STATUS, &sstatus))
|
||||
return;
|
||||
sata_scr_read(link, SCR_CONTROL, &scontrol);
|
||||
if (sata_scr_read(link, SCR_CONTROL, &scontrol))
|
||||
return;
|
||||
|
||||
if (ata_phys_link_online(link)) {
|
||||
tmp = (sstatus >> 4) & 0xf;
|
||||
|
@ -4299,7 +4300,6 @@ static void ata_dev_xfermask(struct ata_device *dev)
|
|||
static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
|
||||
{
|
||||
struct ata_taskfile tf;
|
||||
unsigned int err_mask;
|
||||
|
||||
/* set up set-features taskfile */
|
||||
ata_dev_dbg(dev, "set features - xfer mode\n");
|
||||
|
@ -4321,20 +4321,20 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
|
|||
else /* In the ancient relic department - skip all of this */
|
||||
return 0;
|
||||
|
||||
/* On some disks, this command causes spin-up, so we need longer timeout */
|
||||
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
|
||||
|
||||
return err_mask;
|
||||
/*
|
||||
* On some disks, this command causes spin-up, so we need longer
|
||||
* timeout.
|
||||
*/
|
||||
return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
|
||||
* ata_dev_set_feature - Issue SET FEATURES
|
||||
* @dev: Device to which command will be sent
|
||||
* @enable: Whether to enable or disable the feature
|
||||
* @feature: The sector count represents the feature to set
|
||||
* @subcmd: The SET FEATURES subcommand to be sent
|
||||
* @action: The sector count represents a subcommand specific action
|
||||
*
|
||||
* Issue SET FEATURES - SATA FEATURES command to device @dev
|
||||
* on port @ap with sector count
|
||||
* Issue SET FEATURES command to device @dev on port @ap with sector count
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
|
@ -4342,28 +4342,26 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
|
|||
* RETURNS:
|
||||
* 0 on success, AC_ERR_* mask otherwise.
|
||||
*/
|
||||
unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
|
||||
unsigned int ata_dev_set_feature(struct ata_device *dev, u8 subcmd, u8 action)
|
||||
{
|
||||
struct ata_taskfile tf;
|
||||
unsigned int err_mask;
|
||||
unsigned int timeout = 0;
|
||||
|
||||
/* set up set-features taskfile */
|
||||
ata_dev_dbg(dev, "set features - SATA features\n");
|
||||
ata_dev_dbg(dev, "set features\n");
|
||||
|
||||
ata_tf_init(dev, &tf);
|
||||
tf.command = ATA_CMD_SET_FEATURES;
|
||||
tf.feature = enable;
|
||||
tf.feature = subcmd;
|
||||
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
|
||||
tf.protocol = ATA_PROT_NODATA;
|
||||
tf.nsect = feature;
|
||||
tf.nsect = action;
|
||||
|
||||
if (enable == SETFEATURES_SPINUP)
|
||||
if (subcmd == SETFEATURES_SPINUP)
|
||||
timeout = ata_probe_timeout ?
|
||||
ata_probe_timeout * 1000 : SETFEATURES_SPINUP_TIMEOUT;
|
||||
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, timeout);
|
||||
|
||||
return err_mask;
|
||||
return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, timeout);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_dev_set_feature);
|
||||
|
||||
|
|
|
@ -151,6 +151,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
|
|||
#undef CMDS
|
||||
|
||||
static void __ata_port_freeze(struct ata_port *ap);
|
||||
static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||
struct ata_device **r_failed_dev);
|
||||
#ifdef CONFIG_PM
|
||||
static void ata_eh_handle_port_suspend(struct ata_port *ap);
|
||||
static void ata_eh_handle_port_resume(struct ata_port *ap);
|
||||
|
@ -1086,14 +1088,11 @@ static void __ata_port_freeze(struct ata_port *ap)
|
|||
*/
|
||||
int ata_port_freeze(struct ata_port *ap)
|
||||
{
|
||||
int nr_aborted;
|
||||
|
||||
WARN_ON(!ap->ops->error_handler);
|
||||
|
||||
__ata_port_freeze(ap);
|
||||
nr_aborted = ata_port_abort(ap);
|
||||
|
||||
return nr_aborted;
|
||||
return ata_port_abort(ap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_port_freeze);
|
||||
|
||||
|
@ -1393,7 +1392,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
|
|||
/**
|
||||
* ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
|
||||
* @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
|
||||
* @cmd: scsi command for which the sense code should be set
|
||||
*
|
||||
* Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
|
||||
* SENSE. This function is an EH helper.
|
||||
|
@ -1401,9 +1399,9 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
|
|||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*/
|
||||
static void ata_eh_request_sense(struct ata_queued_cmd *qc,
|
||||
struct scsi_cmnd *cmd)
|
||||
static void ata_eh_request_sense(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
struct ata_device *dev = qc->dev;
|
||||
struct ata_taskfile tf;
|
||||
unsigned int err_mask;
|
||||
|
@ -1541,7 +1539,6 @@ static void ata_eh_analyze_serror(struct ata_link *link)
|
|||
/**
|
||||
* ata_eh_analyze_tf - analyze taskfile of a failed qc
|
||||
* @qc: qc to analyze
|
||||
* @tf: Taskfile registers to analyze
|
||||
*
|
||||
* Analyze taskfile of @qc and further determine cause of
|
||||
* failure. This function also requests ATAPI sense data if
|
||||
|
@ -1553,9 +1550,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
|
|||
* RETURNS:
|
||||
* Determined recovery action
|
||||
*/
|
||||
static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
|
||||
const struct ata_taskfile *tf)
|
||||
static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
|
||||
{
|
||||
const struct ata_taskfile *tf = &qc->result_tf;
|
||||
unsigned int tmp, action = 0;
|
||||
u8 stat = tf->status, err = tf->error;
|
||||
|
||||
|
@ -1579,7 +1576,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
|
|||
switch (qc->dev->class) {
|
||||
case ATA_DEV_ZAC:
|
||||
if (stat & ATA_SENSE)
|
||||
ata_eh_request_sense(qc, qc->scsicmd);
|
||||
ata_eh_request_sense(qc);
|
||||
fallthrough;
|
||||
case ATA_DEV_ATA:
|
||||
if (err & ATA_ICRC)
|
||||
|
@ -1957,7 +1954,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
|||
qc->err_mask |= ehc->i.err_mask;
|
||||
|
||||
/* analyze TF */
|
||||
ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
|
||||
ehc->i.action |= ata_eh_analyze_tf(qc);
|
||||
|
||||
/* DEV errors are probably spurious in case of ATA_BUS error */
|
||||
if (qc->err_mask & AC_ERR_ATA_BUS)
|
||||
|
@ -2940,6 +2937,23 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
|
|||
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
|
||||
WARN_ON(dev->class == ATA_DEV_PMP);
|
||||
|
||||
/*
|
||||
* The link may be in a deep sleep, wake it up.
|
||||
*
|
||||
* If the link is in deep sleep, ata_phys_link_offline()
|
||||
* will return true, causing the revalidation to fail,
|
||||
* which leads to a (potentially) needless hard reset.
|
||||
*
|
||||
* ata_eh_recover() will later restore the link policy
|
||||
* to ap->target_lpm_policy after revalidation is done.
|
||||
*/
|
||||
if (link->lpm_policy > ATA_LPM_MAX_POWER) {
|
||||
rc = ata_eh_set_lpm(link, ATA_LPM_MAX_POWER,
|
||||
r_failed_dev);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
|
||||
rc = -EIO;
|
||||
goto err;
|
||||
|
|
|
@ -870,7 +870,7 @@ static ssize_t ata_ncq_prio_enable_show(struct device *device,
|
|||
if (!dev)
|
||||
rc = -ENODEV;
|
||||
else
|
||||
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE;
|
||||
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
spin_unlock_irq(ap->lock);
|
||||
|
||||
return rc ? rc : sysfs_emit(buf, "%u\n", ncq_prio_enable);
|
||||
|
@ -905,9 +905,9 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
|
|||
}
|
||||
|
||||
if (input)
|
||||
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLE;
|
||||
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
else
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(ap->lock);
|
||||
|
|
|
@ -1603,9 +1603,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
|||
qc->flags |= ATA_QCFLAG_IO;
|
||||
qc->nbytes = n_block * scmd->device->sector_size;
|
||||
|
||||
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
|
||||
qc->hw_tag, class);
|
||||
|
||||
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class);
|
||||
if (likely(rc == 0))
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -776,7 +776,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
|
|||
* @qc: Command on going
|
||||
* @bytes: number of bytes
|
||||
*
|
||||
* Transfer Transfer data from/to the ATAPI device.
|
||||
* Transfer data from/to the ATAPI device.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
|
|
|
@ -44,9 +44,8 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
|
|||
#endif
|
||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
|
||||
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
||||
u64 block, u32 n_block, unsigned int tf_flags,
|
||||
unsigned int tag, int class);
|
||||
extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
||||
unsigned int tf_flags, int class);
|
||||
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
|
||||
struct ata_device *dev);
|
||||
extern unsigned ata_exec_internal(struct ata_device *dev,
|
||||
|
@ -64,7 +63,7 @@ extern int ata_dev_configure(struct ata_device *dev);
|
|||
extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
|
||||
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
|
||||
extern unsigned int ata_dev_set_feature(struct ata_device *dev,
|
||||
u8 enable, u8 feature);
|
||||
u8 subcmd, u8 action);
|
||||
extern void ata_qc_free(struct ata_queued_cmd *qc);
|
||||
extern void ata_qc_issue(struct ata_queued_cmd *qc);
|
||||
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
|
||||
|
|
|
@ -666,8 +666,7 @@ static u8 pata_macio_bmdma_status(struct ata_port *ap)
|
|||
* a multi-block transfer.
|
||||
*
|
||||
* - The dbdma fifo hasn't yet finished flushing to
|
||||
* to system memory when the disk interrupt occurs.
|
||||
*
|
||||
* system memory when the disk interrupt occurs.
|
||||
*/
|
||||
|
||||
/* First check for errors */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause */
|
||||
/*
|
||||
* This header provides constants for most AHCI bindings.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_ATA_AHCI_H
|
||||
#define _DT_BINDINGS_ATA_AHCI_H
|
||||
|
||||
/* Host Bus Adapter generic platform capabilities */
|
||||
#define HBA_SSS (1 << 27)
|
||||
#define HBA_SMPS (1 << 28)
|
||||
|
||||
/* Host Bus Adapter port-specific platform capabilities */
|
||||
#define HBA_PORT_HPCP (1 << 18)
|
||||
#define HBA_PORT_MPSP (1 << 19)
|
||||
#define HBA_PORT_CPD (1 << 20)
|
||||
#define HBA_PORT_ESP (1 << 21)
|
||||
#define HBA_PORT_FBSCP (1 << 22)
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct clk;
|
||||
struct device;
|
||||
struct ata_port_info;
|
||||
struct ahci_host_priv;
|
||||
|
@ -21,8 +22,12 @@ struct scsi_host_template;
|
|||
|
||||
int ahci_platform_enable_phys(struct ahci_host_priv *hpriv);
|
||||
void ahci_platform_disable_phys(struct ahci_host_priv *hpriv);
|
||||
struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv,
|
||||
const char *con_id);
|
||||
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
|
||||
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
|
||||
int ahci_platform_deassert_rsts(struct ahci_host_priv *hpriv);
|
||||
int ahci_platform_assert_rsts(struct ahci_host_priv *hpriv);
|
||||
int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
|
||||
void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
|
||||
int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
|
||||
|
@ -41,6 +46,7 @@ int ahci_platform_resume_host(struct device *dev);
|
|||
int ahci_platform_suspend(struct device *dev);
|
||||
int ahci_platform_resume(struct device *dev);
|
||||
|
||||
#define AHCI_PLATFORM_GET_RESETS 0x01
|
||||
#define AHCI_PLATFORM_GET_RESETS BIT(0)
|
||||
#define AHCI_PLATFORM_RST_TRIGGER BIT(1)
|
||||
|
||||
#endif /* _AHCI_PLATFORM_H */
|
||||
|
|
|
@ -566,6 +566,18 @@ struct ata_bmdma_prd {
|
|||
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
||||
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
||||
((id)[ATA_ID_FEATURE_SUPP] & (1 << 2)))
|
||||
#define ata_id_has_devslp(id) \
|
||||
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
||||
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
||||
((id)[ATA_ID_FEATURE_SUPP] & (1 << 8)))
|
||||
#define ata_id_has_ncq_autosense(id) \
|
||||
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
||||
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
||||
((id)[ATA_ID_FEATURE_SUPP] & (1 << 7)))
|
||||
#define ata_id_has_dipm(id) \
|
||||
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
|
||||
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
|
||||
((id)[ATA_ID_FEATURE_SUPP] & (1 << 3)))
|
||||
#define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10))
|
||||
#define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11))
|
||||
#define ata_id_u32(id,n) \
|
||||
|
@ -578,9 +590,6 @@ struct ata_bmdma_prd {
|
|||
|
||||
#define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
|
||||
#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
|
||||
#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
|
||||
#define ata_id_has_ncq_autosense(id) \
|
||||
((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
|
||||
|
||||
static inline bool ata_id_has_hipm(const u16 *id)
|
||||
{
|
||||
|
@ -592,17 +601,6 @@ static inline bool ata_id_has_hipm(const u16 *id)
|
|||
return val & (1 << 9);
|
||||
}
|
||||
|
||||
static inline bool ata_id_has_dipm(const u16 *id)
|
||||
{
|
||||
u16 val = id[ATA_ID_FEATURE_SUPP];
|
||||
|
||||
if (val == 0 || val == 0xffff)
|
||||
return false;
|
||||
|
||||
return val & (1 << 3);
|
||||
}
|
||||
|
||||
|
||||
static inline bool ata_id_has_fua(const u16 *id)
|
||||
{
|
||||
if ((id[ATA_ID_CFSSE] & 0xC000) != 0x4000)
|
||||
|
@ -771,16 +769,21 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
|
|||
|
||||
static inline bool ata_id_has_sense_reporting(const u16 *id)
|
||||
{
|
||||
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
|
||||
if (!(id[ATA_ID_CFS_ENABLE_2] & BIT(15)))
|
||||
return false;
|
||||
return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
|
||||
if ((id[ATA_ID_COMMAND_SET_3] & (BIT(15) | BIT(14))) != BIT(14))
|
||||
return false;
|
||||
return id[ATA_ID_COMMAND_SET_3] & BIT(6);
|
||||
}
|
||||
|
||||
static inline bool ata_id_sense_reporting_enabled(const u16 *id)
|
||||
{
|
||||
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
|
||||
if (!ata_id_has_sense_reporting(id))
|
||||
return false;
|
||||
return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
|
||||
/* ata_id_has_sense_reporting() == true, word 86 must have bit 15 set */
|
||||
if ((id[ATA_ID_COMMAND_SET_4] & (BIT(15) | BIT(14))) != BIT(14))
|
||||
return false;
|
||||
return id[ATA_ID_COMMAND_SET_4] & BIT(6);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,7 +101,7 @@ enum {
|
|||
ATA_DFLAG_UNLOCK_HPA = (1 << 18), /* unlock HPA */
|
||||
ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */
|
||||
ATA_DFLAG_NCQ_PRIO = (1 << 20), /* device supports NCQ priority */
|
||||
ATA_DFLAG_NCQ_PRIO_ENABLE = (1 << 21), /* Priority cmds sent to dev */
|
||||
ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 21), /* Priority cmds sent to dev */
|
||||
ATA_DFLAG_INIT_MASK = (1 << 24) - 1,
|
||||
|
||||
ATA_DFLAG_DETACH = (1 << 24),
|
||||
|
|
Loading…
Reference in New Issue