Merge tag 'ata-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Oct 2022 17:48:49 +0000 (10:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Oct 2022 17:48:49 +0000 (10:48 -0700)
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
  ...

33 files changed:
Documentation/devicetree/bindings/ata/ahci-common.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ata/ahci-platform.yaml
Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ata/brcm,sata-brcm.yaml
Documentation/devicetree/bindings/ata/sata-common.yaml
Documentation/devicetree/bindings/ata/snps,dwc-ahci-common.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml [new file with mode: 0644]
MAINTAINERS
arch/arm/mach-versatile/Kconfig
arch/arm64/Kconfig
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_da850.c
drivers/ata/ahci_dm816.c
drivers/ata/ahci_dwc.c [new file with mode: 0644]
drivers/ata/ahci_mtk.c
drivers/ata/ahci_platform.c
drivers/ata/ahci_st.c
drivers/ata/libahci.c
drivers/ata/libahci_platform.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-sata.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_macio.c
include/dt-bindings/ata/ahci.h [new file with mode: 0644]
include/linux/ahci_platform.h
include/linux/ata.h
include/linux/libata.h

diff --git a/Documentation/devicetree/bindings/ata/ahci-common.yaml b/Documentation/devicetree/bindings/ata/ahci-common.yaml
new file mode 100644 (file)
index 0000000..94d72ae
--- /dev/null
@@ -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
+
+...
index c146ab8..7dc2a2e 100644 (file)
@@ -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
-
-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
+    $ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port
 
     anyOf:
       - required: [ phys ]
       - required: [ target-supply ]
 
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
 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 = <&reg_sata0>;
+
+            hba-port-cap = <(HBA_PORT_FBSCP | HBA_PORT_ESP)>;
         };
 
         sata1: sata-port@1 {
             reg = <1>;
+
             phys = <&sata_phy 1>;
             target-supply = <&reg_sata1>;
+
+            hba-port-cap = <(HBA_PORT_HPCP | HBA_PORT_MPSP | HBA_PORT_FBSCP)>;
         };
     };
diff --git a/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml b/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
new file mode 100644 (file)
index 0000000..9b7ca47
--- /dev/null
@@ -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>;
+      };
+    };
+...
index 235a93a..fa8ebc8 100644 (file)
@@ -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:
index 7ac77b1..58c9342 100644 (file)
@@ -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.
 
 ...
diff --git a/Documentation/devicetree/bindings/ata/snps,dwc-ahci-common.yaml b/Documentation/devicetree/bindings/ata/snps,dwc-ahci-common.yaml
new file mode 100644 (file)
index 0000000..c145791
--- /dev/null
@@ -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 ]
+
+...
diff --git a/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml b/Documentation/devicetree/bindings/ata/snps,dwc-ahci.yaml
new file mode 100644 (file)
index 0000000..5afa4b5
--- /dev/null
@@ -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>;
+      };
+    };
+
+...
index 700aa00..f610d8b 100644 (file)
@@ -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
index 2ef2261..b1519b4 100644 (file)
@@ -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
index 0e48d1e..fb8463c 100644 (file)
@@ -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
index 1c9f4fb..36833a8 100644 (file)
@@ -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
index b8aebfb..3462336 100644 (file)
@@ -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
index c1eca72..639de2d 100644 (file)
@@ -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)
index ad11a4c..da7ee8b 100644 (file)
@@ -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)
index 052c28e..dc8a019 100644 (file)
@@ -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);
-
-               hpriv->clks[0] = clk;
-       }
-
-       /*
-        * 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;
+       if (hpriv->n_clks < 2) {
+               hpriv->clks = devm_kcalloc(dev, 2, sizeof(*hpriv->clks), GFP_KERNEL);
+               if (!hpriv->clks)
+                       return -ENOMEM;
+
+               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;
        }
 
-       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;
index 8a92112..d26efcd 100644 (file)
@@ -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;
diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
new file mode 100644 (file)
index 0000000..8fb6686
--- /dev/null
@@ -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");
index 1f6c85f..c056378 100644 (file)
@@ -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;
 }
 
index 28a8de5..8f5572a 100644 (file)
@@ -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 */ }
index 7526653..5a2cac6 100644 (file)
@@ -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) {
index cf8c7fd..954386a 100644 (file)
@@ -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.
+        */
+
+       /*
+        * 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.
         */
-       hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
-       hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+       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)
index 32495ae..ddf17e2 100644 (file)
@@ -94,31 +94,41 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
 EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);
 
 /**
- * ahci_platform_enable_clks - Enable platform clocks
+ * ahci_platform_find_clk - Find platform clock
  * @hpriv: host private area to store config values
+ * @con_id: clock connection ID
  *
- * 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 returns a pointer to the clock descriptor of the clock with
+ * the passed ID.
  *
  * RETURNS:
- * 0 on success otherwise a negative error code
+ * Pointer to the clock descriptor on success otherwise NULL
  */
-int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+struct clk *ahci_platform_find_clk(struct ahci_host_priv *hpriv, const char *con_id)
 {
-       int c, rc;
+       int i;
 
-       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
-               rc = clk_prepare_enable(hpriv->clks[c]);
-               if (rc)
-                       goto disable_unprepare_clk;
+       for (i = 0; i < hpriv->n_clks; i++) {
+               if (!strcmp(hpriv->clks[i].id, con_id))
+                       return hpriv->clks[i].clk;
        }
-       return 0;
 
-disable_unprepare_clk:
-       while (--c >= 0)
-               clk_disable_unprepare(hpriv->clks[c]);
-       return rc;
+       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 for the AHCI device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+       return clk_bulk_prepare_enable(hpriv->n_clks, hpriv->clks);
 }
 EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
 
@@ -126,20 +136,55 @@ 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++) {
+       /*
+        * 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 (rc > 0) {
+               /* Got clocks in bulk */
+               hpriv->n_clks = rc;
+       } else {
                /*
-                * 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).
+                * No clock bulk found: fallback to manually getting
+                * the optional clock.
                 */
-               if (i == 0)
-                       clk = clk_get(dev, NULL);
-               else
-                       clk = of_clk_get(dev->of_node, i);
-
-               if (IS_ERR(clk)) {
-                       rc = PTR_ERR(clk);
-                       if (rc == -EPROBE_DEFER)
-                               goto err_out;
-                       break;
+               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;
index c9a9aa6..d3ce5c3 100644 (file)
@@ -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);
 
index 7c128c8..08e11bc 100644 (file)
@@ -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;
index 13b9d0f..b6806d4 100644 (file)
@@ -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);
index ff9602a..e2ebb0b 100644 (file)
@@ -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;
 
index b1666ad..7916e36 100644 (file)
@@ -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.
index 98bc864..2c5c827 100644 (file)
@@ -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);
index bfea2be..9ccaac9 100644 (file)
@@ -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 */
diff --git a/include/dt-bindings/ata/ahci.h b/include/dt-bindings/ata/ahci.h
new file mode 100644 (file)
index 0000000..77997b3
--- /dev/null
@@ -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
index 49e5383..17fa262 100644 (file)
@@ -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 */
index 21292b5..e3050e1 100644 (file)
@@ -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;
+       if ((id[ATA_ID_COMMAND_SET_3] & (BIT(15) | BIT(14))) != BIT(14))
                return false;
-       return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
+       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;
+       /* 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] & (1 << 6);
+       return id[ATA_ID_COMMAND_SET_4] & BIT(6);
 }
 
 /**
index 20765d1..fe99017 100644 (file)
@@ -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),