2548 lines
76 KiB
Diff
2548 lines
76 KiB
Diff
commit 15d6fcb8b18bcd251139f2f557067411f4c9500a
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Mar 1 20:26:20 2014 +0100
|
|
|
|
ARM: sunxi: dt: Add sunxi-common-regulators include file
|
|
|
|
Most sunxi boards with a sata connector also have a gpio controlled connector
|
|
for sata target power and almost all sunxi boards have a gpio controlled vbus
|
|
for usb1 and usb2.
|
|
|
|
This commit adds an include file for the regulators representing these
|
|
supplies, avoiding the need to copy and paste the regulator code to allmost
|
|
all sunxi board dts files.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 25ff22a532f1124397ece327e675aabfef4fa7b4)
|
|
|
|
commit cef54381f3fe3b9968dc0944eda347b734ec0aeb
|
|
Author: Emilio López <emilio@elopez.com.ar>
|
|
Date: Wed Mar 19 15:19:32 2014 -0300
|
|
|
|
clk: sunxi: fix some calculations
|
|
|
|
Some divisor calculations were misrounded, causing higher than requested
|
|
rates on some clocks. Fix them up using DIV_ROUND_UP, and replace one
|
|
homebrew instance of it as well with the right macro.
|
|
|
|
Reported-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
Signed-off-by: Mike Turquette <mturquette@linaro.org>
|
|
(cherry picked from commit 2226013972da1ec0a2aeb13a684180bb2b50e0f3)
|
|
|
|
commit f1096cc726d521c62a36ef4cfd7d31845d2a3f01
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:47 2014 +0800
|
|
|
|
clk: sunxi: Add Allwinner A20/A31 GMAC clock unit
|
|
|
|
The Allwinner A20/A31 clock module controls the transmit clock source
|
|
and interface type of the GMAC ethernet controller. Model this as
|
|
a single clock for GMAC drivers to use.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
(cherry picked from commit e4c6d6c11bee5ff11feb837a0a76103b3eba252f)
|
|
|
|
Conflicts:
|
|
Documentation/devicetree/bindings/clock/sunxi.txt
|
|
|
|
commit 5732a8aedf1e58bf154942d35d6675beead2cc58
|
|
Author: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Date: Wed Feb 5 14:05:03 2014 +0100
|
|
|
|
clk: sunxi: Add support for PLL6 on the A31
|
|
|
|
The A31 has a slightly different PLL6 clock. Add support for this new clock in
|
|
our driver.
|
|
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
(cherry picked from commit 92ef67c53ad92487c3c8de75e7940384c2edd793)
|
|
|
|
commit e50895e6c5f5a0677f6a65ccea8934897604c7da
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 3 09:51:40 2014 +0800
|
|
|
|
clk: sunxi: get divs parent clock name from parent factor clock
|
|
|
|
Divs clocks consist of a parent factor clock with multiple outputs,
|
|
and seperate clocks for each output. Get the name of the parent
|
|
clock from the parent factor clock, instead of the DT node name.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Acked-by: Mike Turquette <mturquette@linaro.org>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
(cherry picked from commit 97e36b3ce3106988b82e1ca53b1d1c872bde855a)
|
|
|
|
commit 1daa0121a7be5f38adcdfbb6e6bf42d9d6df5737
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 3 09:51:39 2014 +0800
|
|
|
|
clk: sunxi: add names for pll5, pll6 parent clocks to factors_data
|
|
|
|
Some factor clocks, such as the parent clock of pll5 and pll6, have
|
|
multiple output names. Add the corresponding names to factors_data
|
|
tied to compatible string.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Acked-by: Mike Turquette <mturquette@linaro.org>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
(cherry picked from commit 667f542db542fddc62d1299b17451d7cae84f6e1)
|
|
|
|
commit 66d96749ad78255d0903f67497fdfe5bd2161bf3
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 3 09:51:37 2014 +0800
|
|
|
|
clk: sunxi: add clock-output-names dt property support
|
|
|
|
sunxi clock drivers use dt node name as clock name, but clock
|
|
nodes should be named clk@X, so the names would be the same.
|
|
Let the drivers read clock names from dt clock-output-names
|
|
property.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Acked-by: Mike Turquette <mturquette@linaro.org>
|
|
Signed-off-by: Emilio López <emilio@elopez.com.ar>
|
|
(cherry picked from commit f64111ebaf6776558f0e60d0ea8c7a9c579b9436)
|
|
|
|
commit ba9d3543becbab5cb2582e81c4ee15afc19f720c
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Mar 1 20:26:22 2014 +0100
|
|
|
|
ARM: sun7i: dt: Add ahci / sata support
|
|
|
|
This patch adds sunxi sata support to A20 boards that have such a connector.
|
|
Some boards also feature a regulator via a GPIO and support for this is also
|
|
added.
|
|
|
|
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 902febf9ea856dc9a9376bcdc70dfaa9b3ad5a74)
|
|
|
|
Conflicts:
|
|
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
|
|
arch/arm/boot/dts/sun7i-a20.dtsi
|
|
|
|
commit 089eb5838989a6f0cab56cb259637d8ff145f3bc
|
|
Author: Oliver Schinagl <oliver@schinagl.nl>
|
|
Date: Sat Mar 1 20:26:21 2014 +0100
|
|
|
|
ARM: sun4i: dt: Add ahci / sata support
|
|
|
|
This patch adds sunxi sata support to A10 boards that have such a connector.
|
|
Some boards also feature a regulator via a GPIO and support for this is also
|
|
added.
|
|
|
|
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 248bd1e228eb9cc7ff9577d45b5d1b6d52c43cd9)
|
|
|
|
Conflicts:
|
|
arch/arm/boot/dts/sun4i-a10.dtsi
|
|
|
|
commit 7a25c91712808d75e7e504487bb94620f12ce0b8
|
|
Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
Date: Tue Feb 18 14:04:44 2014 +0000
|
|
|
|
ARM: sun7i: add arch timer node
|
|
|
|
The Allwinner A20 SoC is built around a pair of Cortex-A7 cores,
|
|
which have the usual generic timers. Report this in the DT.
|
|
|
|
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 7902763e4a4d04a96406447f935a8f676e73e0ce)
|
|
|
|
commit 7ffc006a340f7f2dcd4949462e3aa7b22f59ef62
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:54 2014 +0800
|
|
|
|
ARM: dts: sun7i: Add ethernet alias for GMAC
|
|
|
|
All Allwinner A20 boards we support can only use either EMAC or GMAC,
|
|
as they share the same pins. As we have switched all supported to
|
|
GMAC, we should alias GMAC (the active controller) as ethernet0,
|
|
so u-boot will insert the MAC address for the correct controller.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 18428f7782920171fbcf0ccedcf6a146e7cc2e6f)
|
|
|
|
commit 5ccc8c209394c5217cf1e4195997d9f936f5bd63
|
|
Author: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Date: Thu Jan 2 22:05:04 2014 +0100
|
|
|
|
ARM: sun7i: Add missing serial aliases
|
|
|
|
Some UART aliases have been defined, but not all of them. Add the remaining
|
|
ones to be consistent and to ease the parsing of the DT by the bootloaders.
|
|
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 4566b4beafe4582488907b84cb04e6c0efba384a)
|
|
|
|
commit ee1689f3993061de7757eab84e95c70f497c6886
|
|
Author: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Date: Thu Jan 2 22:05:04 2014 +0100
|
|
|
|
ARM: sun6i: Add missing serial aliases
|
|
|
|
Some UART aliases have been defined, but not all of them. Add the remaining
|
|
ones to be consistent and to ease the parsing of the DT by the bootloaders.
|
|
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 54428d4025c2ce1f26bd6f677edaa7170a974787)
|
|
|
|
commit d8183f5ad12bd23962b89063387899abdc717648
|
|
Author: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Date: Thu Jan 2 22:05:04 2014 +0100
|
|
|
|
ARM: sun5i: a10s: Add missing serial aliases
|
|
|
|
Some UART aliases have been defined, but not all of them. Add the remaining
|
|
ones to be consistent and to ease the parsing of the DT by the bootloaders.
|
|
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 4dd4065f80ccd09e336388e7ff8e3a4a1dcf8e83)
|
|
|
|
commit 5dc99b5e04e8048d550634ea56bf699e02c147f1
|
|
Author: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
Date: Thu Jan 2 22:05:04 2014 +0100
|
|
|
|
ARM: sun4i: a10: Add missing serial aliases
|
|
|
|
Some UART aliases have been defined, but not all of them. Add the remaining
|
|
ones to be consistent and to ease the parsing of the DT by the bootloaders.
|
|
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 143b13d6e603abb0dc374cf31ec22f5dd28500eb)
|
|
|
|
commit c67f298a228e6614a5394f831d17ad5f8a29d186
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:53 2014 +0800
|
|
|
|
ARM: dts: sun7i: a20-olinuxino-micro: Enable GMAC instead of EMAC
|
|
|
|
GMAC has better performance and fewer hardware issues.
|
|
Use the GMAC in MII mode for ethernet instead of the EMAC.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 7164318297f7f2567d4ca44a5e4affc910b1b979)
|
|
|
|
commit 08f1be55ac881ca708f0d21d4ab5244cc99dc3ed
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:52 2014 +0800
|
|
|
|
ARM: dts: sun7i: cubieboard2: Enable GMAC instead of EMAC
|
|
|
|
GMAC has better performance and fewer hardware issues.
|
|
Use the GMAC in MII mode for ethernet instead of the EMAC.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 5e71892f01d07a68bab0529f64cb8cd06bf94fd4)
|
|
|
|
commit fb227cb85a9fb05925b7d2dbfc91ee0469523c05
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:51 2014 +0800
|
|
|
|
ARM: dts: sun7i: cubietruck: Enable the GMAC
|
|
|
|
The CubieTruck uses the GMAC with an RGMII phy.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 67073d97672d03cc29ba252235e31c7e54ea9b62)
|
|
|
|
commit 7dc7a78b507297af1ced79170c4b5f9a3b559c76
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:50 2014 +0800
|
|
|
|
ARM: dts: sun7i: Add pin muxing options for the GMAC
|
|
|
|
The A20 has EMAC and GMAC muxed on the same pins.
|
|
Add pin sets with gmac function for MII and RGMII mode to the DTSI.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit 129ccbcd6fc704f3a0df892240f3aeb463d461f5)
|
|
|
|
commit e7609b19b3f95a7415acb249b5ede9ae5b74caa0
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:49 2014 +0800
|
|
|
|
ARM: dts: sun7i: Add GMAC controller node to sun7i DTSI
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit c40b8d5858f6396b11d7f859a76bef9b82a65743)
|
|
|
|
commit 9fd91d26fb223ca444d7232aae39bc402f7c0c67
|
|
Author: Chen-Yu Tsai <wens@csie.org>
|
|
Date: Mon Feb 10 18:35:48 2014 +0800
|
|
|
|
ARM: dts: sun7i: Add GMAC clock node to sun7i DTSI
|
|
|
|
The GMAC uses 1 of 2 sources for its transmit clock, depending on the
|
|
PHY interface mode. Add both sources as dummy clocks, and as parents
|
|
to the GMAC clock node.
|
|
|
|
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
|
|
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
(cherry picked from commit daed5a8163dcc9ff63e4fde8f7e8ce885ba4c34b)
|
|
|
|
commit 732a0e04187ae4e216b9b3f2add1e8af1491b9f2
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sun Feb 23 12:52:41 2014 +0100
|
|
|
|
ahci_sunxi: Use msleep instead of mdelay
|
|
|
|
ahci_sunxi_phy_init is called from the probe and resume code paths, and
|
|
sleeping is safe in both, so use msleep instead of mdelay.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit d2ec147a76d0e051db19d378cac3ee7721877717)
|
|
|
|
commit e47a4a22ce18b11ae8108cb66579bdbf27a3c6b6
|
|
Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
|
Date: Mon Mar 17 14:08:12 2014 +0100
|
|
|
|
ata: ahci_sunxi: fix code formatting
|
|
|
|
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
Acked-by: Hans de Goede <hdegoede@redhat.com>
|
|
(cherry picked from commit cdf457a4fe30980f7c15a894af2f954f85cd71d2)
|
|
|
|
commit 55f1e3fa16e761e5d9f69bfd45fbf94f74182356
|
|
Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
|
Date: Mon Mar 17 14:06:57 2014 +0100
|
|
|
|
ata: ahci_sunxi: make ahci_sunxi_resume() static
|
|
|
|
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
Acked-by: Hans de Goede <hdegoede@redhat.com>
|
|
(cherry picked from commit 1bf9d885658cbee1bc8e4324d0e27b02b1540d58)
|
|
|
|
commit 98e351d4a64434059defa66fb463c42cc3b91ae5
|
|
Author: Roger Quadros <rogerq@ti.com>
|
|
Date: Sat Feb 22 16:53:40 2014 +0100
|
|
|
|
ata: ahci_platform: Manage SATA PHY
|
|
|
|
Some platforms have a PHY hooked up to the SATA controller. The PHY
|
|
needs to be initialized and powered up for SATA to work. We do that
|
|
using the PHY framework.
|
|
|
|
tj: Minor comment formatting updates.
|
|
|
|
CC: Balaji T K <balajitk@ti.com>
|
|
Signed-off-by: Roger Quadros <rogerq@ti.com>
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo<tj@kernel.org>
|
|
(cherry picked from commit 21b5faeec229d4f70a7f60a7b0b065c98198f491)
|
|
|
|
commit b86357997ea09c7201e532809fb8a4a3ac809280
|
|
Author: Olliver Schinagl <oliver@schinagl.nl>
|
|
Date: Sat Feb 22 16:53:36 2014 +0100
|
|
|
|
ARM: sunxi: Add support for Allwinner SUNXi SoCs sata to ahci_platform
|
|
|
|
This patch adds support for the ahci sata controler found on Allwinner A10
|
|
and A20 SoCs to the ahci_platform driver.
|
|
|
|
Orignally written by Olliver Schinagl using the approach of having a platform
|
|
device which probe method creates a new child platform device which gets
|
|
driven by ahci_platform.c, as done by ahci_imx.c .
|
|
|
|
Refactored by Hans de Goede to add most of the non sunxi specific functionality
|
|
to ahci_platform.c and use a platform_data pointer from of_device_id for the
|
|
sunxi specific bits.
|
|
|
|
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit c5754b5220f01e8722799d35c04a76e82c62d7d8)
|
|
|
|
commit 510b793cdc550ff40fdd51cb59ad081e89217a86
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:35 2014 +0100
|
|
|
|
ahci-platform: "Library-ise" suspend / resume functionality
|
|
|
|
Split suspend / resume code into host suspend / resume functionality and
|
|
resource enable / disabling phases, and export the new suspend_ / resume_host
|
|
functions.
|
|
|
|
tj: Minor comment formatting updates.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 648cb6fd83b97f0f772db783a280af300fa9f2bc)
|
|
|
|
commit f86ef8cec39c7bfc27f128ae1325ba51892bff0f
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:34 2014 +0100
|
|
|
|
ahci-platform: "Library-ise" ahci_probe functionality
|
|
|
|
ahci_probe consists of 3 steps:
|
|
1) Get resources (get mmio, clks, regulator)
|
|
2) Enable resources, handled by ahci_platform_enable_resouces
|
|
3) The more or less standard ahci-host controller init sequence
|
|
|
|
This commit refactors step 1 and 3 into separate functions, so the platform
|
|
drivers for AHCI implementations which need a specific order in step 2,
|
|
and / or need to do some custom register poking at some time, can re-use
|
|
ahci-platform.c code without needing to copy and paste it.
|
|
|
|
Note that ahci_platform_init_host's prototype takes the 3 non function
|
|
members of ahci_platform_data as arguments, the idea is that drivers using
|
|
the new exported utility functions will not use ahci_platform_data at all,
|
|
and hopefully in the future ahci_platform_data can go away entirely.
|
|
|
|
tj: Minor comment formatting updates.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 23b07d4cb3c0c850055cf968af44019b8da185fb)
|
|
|
|
commit d2892d30b6752365f821ba67d0352125ec683d39
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:33 2014 +0100
|
|
|
|
ahci-platform: Add enable_ / disable_resources helper functions
|
|
|
|
tj: Minor comment formatting updates.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 96a01ba52c60fdd74dd6e8cf06645d06515b1396)
|
|
|
|
commit 7114f980aefb057ab24921130e14d92ac76e44c3
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:32 2014 +0100
|
|
|
|
ahci-platform: Add support for an optional regulator for sata-target power
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 4b3e603a298db26c6c37e8b08adcce24d014df13)
|
|
|
|
commit 0e457adc70a512a892727895a4758fadd3d567ee
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:31 2014 +0100
|
|
|
|
ahci-platform: Add support for devices with more then 1 clock
|
|
|
|
The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
|
|
imx AHCI controller needs 3 clocks to be enabled.
|
|
|
|
tj: Minor comment formatting updates.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 156c5887948cd191417f18026aab9ce26e5a95da)
|
|
|
|
commit 3535037fafc980139b3c6ae31b58455660600195
|
|
Author: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Sat Feb 22 16:53:30 2014 +0100
|
|
|
|
libahci: Allow drivers to override start_engine
|
|
|
|
Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
|
|
special register to be poked before starting the DMA engine.
|
|
|
|
This register gets reset on an ahci_stop_engine call, so there is no other
|
|
place then ahci_start_engine where this poking can be done.
|
|
|
|
This commit allows drivers to override ahci_start_engine behavior for use by
|
|
the Allwinner AHCI driver (and potentially other drivers in the future).
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
(cherry picked from commit 039ece38da45f5e6a94be3aa7611cf3634bc2461)
|
|
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
|
|
index 89de156..499bfed 100644
|
|
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
|
|
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
|
|
@@ -4,17 +4,28 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
|
|
Each SATA controller should have its own node.
|
|
|
|
Required properties:
|
|
-- compatible : compatible list, contains "snps,spear-ahci"
|
|
+- compatible : compatible list, one of "snps,spear-ahci",
|
|
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
|
|
+ "allwinner,sun4i-a10-ahci"
|
|
- interrupts : <interrupt mapping for SATA IRQ>
|
|
- reg : <registers mapping>
|
|
|
|
Optional properties:
|
|
- dma-coherent : Present if dma operations are coherent
|
|
+- clocks : a list of phandle + clock specifier pairs
|
|
+- target-supply : regulator for SATA target power
|
|
|
|
-Example:
|
|
+Examples:
|
|
sata@ffe08000 {
|
|
compatible = "snps,spear-ahci";
|
|
reg = <0xffe08000 0x1000>;
|
|
interrupts = <115>;
|
|
-
|
|
};
|
|
+
|
|
+ ahci: sata@01c18000 {
|
|
+ compatible = "allwinner,sun4i-a10-ahci";
|
|
+ reg = <0x01c18000 0x1000>;
|
|
+ interrupts = <56>;
|
|
+ clocks = <&pll6 0>, <&ahb_gates 25>;
|
|
+ target-supply = <®_ahci_5v>;
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
|
|
index c2cb762..5865acd 100644
|
|
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
|
|
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
|
|
@@ -11,6 +11,7 @@ Required properties:
|
|
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
|
|
"allwinner,sun4i-pll5-clk" - for the PLL5 clock
|
|
"allwinner,sun4i-pll6-clk" - for the PLL6 clock
|
|
+ "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
|
|
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
|
|
"allwinner,sun4i-axi-clk" - for the AXI clock
|
|
"allwinner,sun4i-axi-gates-clk" - for the AXI gates
|
|
@@ -37,6 +38,7 @@ Required properties:
|
|
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
|
|
"allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
|
|
"allwinner,sun7i-a20-out-clk" - for the external output clocks
|
|
+ "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
|
|
|
|
Required properties for all clocks:
|
|
- reg : shall be the control register address for the clock.
|
|
@@ -49,6 +51,9 @@ Required properties for all clocks:
|
|
Additionally, "allwinner,*-gates-clk" clocks require:
|
|
- clock-output-names : the corresponding gate names that the clock controls
|
|
|
|
+For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
|
|
+dummy clocks at 25 MHz and 125 MHz, respectively. See example.
|
|
+
|
|
Clock consumers should specify the desired clocks they use with a
|
|
"clocks" phandle cell. Consumers that are using a gated clock should
|
|
provide an additional ID in their clock property. This ID is the
|
|
@@ -76,3 +81,29 @@ cpu: cpu@01c20054 {
|
|
reg = <0x01c20054 0x4>;
|
|
clocks = <&osc32k>, <&osc24M>, <&pll1>;
|
|
};
|
|
+
|
|
+mii_phy_tx_clk: clk@2 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <25000000>;
|
|
+ clock-output-names = "mii_phy_tx";
|
|
+};
|
|
+
|
|
+gmac_int_tx_clk: clk@3 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <125000000>;
|
|
+ clock-output-names = "gmac_int_tx";
|
|
+};
|
|
+
|
|
+gmac_clk: clk@01c20164 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "allwinner,sun7i-a20-gmac-clk";
|
|
+ reg = <0x01c20164 0x4>;
|
|
+ /*
|
|
+ * The first clock must be fixed at 25MHz;
|
|
+ * the second clock must be fixed at 125MHz
|
|
+ */
|
|
+ clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
|
|
+ clock-output-names = "gmac";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
|
|
index d4b081d..027a0ed 100644
|
|
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
|
|
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
|
|
@@ -35,6 +35,10 @@
|
|
};
|
|
};
|
|
|
|
+ ahci: sata@01c18000 {
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
pinctrl@01c20800 {
|
|
emac_power_pin_a1000: emac_power_pin@0 {
|
|
allwinner,pins = "PH15";
|
|
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
|
|
index b139ee6..20407ac 100644
|
|
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
|
|
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
|
|
@@ -12,6 +12,7 @@
|
|
|
|
/dts-v1/;
|
|
/include/ "sun4i-a10.dtsi"
|
|
+/include/ "sunxi-common-regulators.dtsi"
|
|
|
|
/ {
|
|
model = "Cubietech Cubieboard";
|
|
@@ -33,6 +34,11 @@
|
|
};
|
|
};
|
|
|
|
+ ahci: sata@01c18000 {
|
|
+ target-supply = <®_ahci_5v>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
pinctrl@01c20800 {
|
|
led_pins_cubieboard: led_pins@0 {
|
|
allwinner,pins = "PH20", "PH21";
|
|
@@ -77,4 +83,8 @@
|
|
linux,default-trigger = "heartbeat";
|
|
};
|
|
};
|
|
+
|
|
+ reg_ahci_5v: ahci-5v {
|
|
+ status = "okay";
|
|
+ };
|
|
};
|
|
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
|
|
index d4d2763..796e59b 100644
|
|
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
|
|
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
|
|
@@ -19,6 +19,12 @@
|
|
ethernet0 = &emac;
|
|
serial0 = &uart0;
|
|
serial1 = &uart1;
|
|
+ serial2 = &uart2;
|
|
+ serial3 = &uart3;
|
|
+ serial4 = &uart4;
|
|
+ serial5 = &uart5;
|
|
+ serial6 = &uart6;
|
|
+ serial7 = &uart7;
|
|
};
|
|
|
|
cpus {
|
|
@@ -330,6 +336,14 @@
|
|
#size-cells = <0>;
|
|
};
|
|
|
|
+ ahci: sata@01c18000 {
|
|
+ compatible = "allwinner,sun4i-a10-ahci";
|
|
+ reg = <0x01c18000 0x1000>;
|
|
+ interrupts = <56>;
|
|
+ clocks = <&pll6 0>, <&ahb_gates 25>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
intc: interrupt-controller@01c20400 {
|
|
compatible = "allwinner,sun4i-ic";
|
|
reg = <0x01c20400 0x400>;
|
|
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
|
|
index 79fd412..848baaa 100644
|
|
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
|
|
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
|
|
@@ -18,6 +18,10 @@
|
|
|
|
aliases {
|
|
ethernet0 = &emac;
|
|
+ serial0 = &uart0;
|
|
+ serial1 = &uart1;
|
|
+ serial2 = &uart2;
|
|
+ serial3 = &uart3;
|
|
};
|
|
|
|
cpus {
|
|
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
|
|
index 5256ad9..092bf97 100644
|
|
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
|
|
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
|
|
@@ -16,6 +16,16 @@
|
|
/ {
|
|
interrupt-parent = <&gic>;
|
|
|
|
+ aliases {
|
|
+ serial0 = &uart0;
|
|
+ serial1 = &uart1;
|
|
+ serial2 = &uart2;
|
|
+ serial3 = &uart3;
|
|
+ serial4 = &uart4;
|
|
+ serial5 = &uart5;
|
|
+ };
|
|
+
|
|
+
|
|
cpus {
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
|
|
index 5c51cb8..4bed115 100644
|
|
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
|
|
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
|
|
@@ -13,25 +13,16 @@
|
|
|
|
/dts-v1/;
|
|
/include/ "sun7i-a20.dtsi"
|
|
+/include/ "sunxi-common-regulators.dtsi"
|
|
|
|
/ {
|
|
model = "Cubietech Cubieboard2";
|
|
compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
|
|
|
|
soc@01c00000 {
|
|
- emac: ethernet@01c0b000 {
|
|
- pinctrl-names = "default";
|
|
- pinctrl-0 = <&emac_pins_a>;
|
|
- phy = <&phy1>;
|
|
- status = "okay";
|
|
- };
|
|
-
|
|
- mdio@01c0b080 {
|
|
+ ahci: sata@01c18000 {
|
|
+ target-supply = <®_ahci_5v>;
|
|
status = "okay";
|
|
-
|
|
- phy1: ethernet-phy@1 {
|
|
- reg = <1>;
|
|
- };
|
|
};
|
|
|
|
pinctrl@01c20800 {
|
|
@@ -60,6 +51,18 @@
|
|
pinctrl-0 = <&i2c1_pins_a>;
|
|
status = "okay";
|
|
};
|
|
+
|
|
+ gmac: ethernet@01c50000 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac_pins_mii_a>;
|
|
+ phy = <&phy1>;
|
|
+ phy-mode = "mii";
|
|
+ status = "okay";
|
|
+
|
|
+ phy1: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
leds {
|
|
@@ -77,4 +80,8 @@
|
|
gpios = <&pio 7 20 0>;
|
|
};
|
|
};
|
|
+
|
|
+ reg_ahci_5v: ahci-5v {
|
|
+ status = "okay";
|
|
+ };
|
|
};
|
|
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
|
|
index f9dcb61..ef5fed8 100644
|
|
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
|
|
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
|
|
@@ -13,13 +13,26 @@
|
|
|
|
/dts-v1/;
|
|
/include/ "sun7i-a20.dtsi"
|
|
+/include/ "sunxi-common-regulators.dtsi"
|
|
|
|
/ {
|
|
model = "Cubietech Cubietruck";
|
|
compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
|
|
|
|
soc@01c00000 {
|
|
+ ahci: sata@01c18000 {
|
|
+ target-supply = <®_ahci_5v>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
pinctrl@01c20800 {
|
|
+ ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
|
|
+ allwinner,pins = "PH12";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <0>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
+
|
|
led_pins_cubietruck: led_pins@0 {
|
|
allwinner,pins = "PH7", "PH11", "PH20", "PH21";
|
|
allwinner,function = "gpio_out";
|
|
@@ -51,6 +64,18 @@
|
|
pinctrl-0 = <&i2c2_pins_a>;
|
|
status = "okay";
|
|
};
|
|
+
|
|
+ gmac: ethernet@01c50000 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
|
|
+ phy = <&phy1>;
|
|
+ phy-mode = "rgmii";
|
|
+ status = "okay";
|
|
+
|
|
+ phy1: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
leds {
|
|
@@ -78,4 +103,10 @@
|
|
gpios = <&pio 7 7 0>;
|
|
};
|
|
};
|
|
+
|
|
+ reg_ahci_5v: ahci-5v {
|
|
+ pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
|
|
+ gpio = <&pio 7 12 0>;
|
|
+ status = "okay";
|
|
+ };
|
|
};
|
|
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
|
|
index ead3013..9b104ad 100644
|
|
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
|
|
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
|
|
@@ -13,25 +13,16 @@
|
|
|
|
/dts-v1/;
|
|
/include/ "sun7i-a20.dtsi"
|
|
+/include/ "sunxi-common-regulators.dtsi"
|
|
|
|
/ {
|
|
model = "Olimex A20-Olinuxino Micro";
|
|
compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
|
|
|
|
soc@01c00000 {
|
|
- emac: ethernet@01c0b000 {
|
|
- pinctrl-names = "default";
|
|
- pinctrl-0 = <&emac_pins_a>;
|
|
- phy = <&phy1>;
|
|
- status = "okay";
|
|
- };
|
|
-
|
|
- mdio@01c0b080 {
|
|
+ ahci: sata@01c18000 {
|
|
+ target-supply = <®_ahci_5v>;
|
|
status = "okay";
|
|
-
|
|
- phy1: ethernet-phy@1 {
|
|
- reg = <1>;
|
|
- };
|
|
};
|
|
|
|
pinctrl@01c20800 {
|
|
@@ -78,6 +69,18 @@
|
|
pinctrl-0 = <&i2c2_pins_a>;
|
|
status = "okay";
|
|
};
|
|
+
|
|
+ gmac: ethernet@01c50000 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac_pins_mii_a>;
|
|
+ phy = <&phy1>;
|
|
+ phy-mode = "mii";
|
|
+ status = "okay";
|
|
+
|
|
+ phy1: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
leds {
|
|
@@ -91,4 +94,8 @@
|
|
default-state = "on";
|
|
};
|
|
};
|
|
+
|
|
+ reg_ahci_5v: ahci-5v {
|
|
+ status = "okay";
|
|
+ };
|
|
};
|
|
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
|
|
index 6f25cf5..c16ef91 100644
|
|
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
|
|
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
|
|
@@ -17,7 +17,15 @@
|
|
interrupt-parent = <&gic>;
|
|
|
|
aliases {
|
|
- ethernet0 = &emac;
|
|
+ ethernet0 = &gmac;
|
|
+ serial0 = &uart0;
|
|
+ serial1 = &uart1;
|
|
+ serial2 = &uart2;
|
|
+ serial3 = &uart3;
|
|
+ serial4 = &uart4;
|
|
+ serial5 = &uart5;
|
|
+ serial6 = &uart6;
|
|
+ serial7 = &uart7;
|
|
};
|
|
|
|
cpus {
|
|
@@ -41,6 +49,14 @@
|
|
reg = <0x40000000 0x80000000>;
|
|
};
|
|
|
|
+ timer {
|
|
+ compatible = "arm,armv7-timer";
|
|
+ interrupts = <1 13 0xf08>,
|
|
+ <1 14 0xf08>,
|
|
+ <1 11 0xf08>,
|
|
+ <1 10 0xf08>;
|
|
+ };
|
|
+
|
|
clocks {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
@@ -305,6 +321,34 @@
|
|
};
|
|
|
|
/*
|
|
+ * The following two are dummy clocks, placeholders used in the gmac_tx
|
|
+ * clock. The gmac driver will choose one parent depending on the PHY
|
|
+ * interface mode, using clk_set_rate auto-reparenting.
|
|
+ * The actual TX clock rate is not controlled by the gmac_tx clock.
|
|
+ */
|
|
+ mii_phy_tx_clk: clk@2 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <25000000>;
|
|
+ clock-output-names = "mii_phy_tx";
|
|
+ };
|
|
+
|
|
+ gmac_int_tx_clk: clk@3 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <125000000>;
|
|
+ clock-output-names = "gmac_int_tx";
|
|
+ };
|
|
+
|
|
+ gmac_tx_clk: clk@01c20164 {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "allwinner,sun7i-a20-gmac-clk";
|
|
+ reg = <0x01c20164 0x4>;
|
|
+ clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
|
|
+ clock-output-names = "gmac_tx";
|
|
+ };
|
|
+
|
|
+ /*
|
|
* Dummy clock used by output clocks
|
|
*/
|
|
osc24M_32k: clk@1 {
|
|
@@ -355,6 +399,14 @@
|
|
#size-cells = <0>;
|
|
};
|
|
|
|
+ ahci: sata@01c18000 {
|
|
+ compatible = "allwinner,sun4i-a10-ahci";
|
|
+ reg = <0x01c18000 0x1000>;
|
|
+ interrupts = <0 56 4>;
|
|
+ clocks = <&pll6 0>, <&ahb_gates 25>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
pio: pinctrl@01c20800 {
|
|
compatible = "allwinner,sun7i-a20-pinctrl";
|
|
reg = <0x01c20800 0x400>;
|
|
@@ -432,6 +484,32 @@
|
|
allwinner,drive = <0>;
|
|
allwinner,pull = <0>;
|
|
};
|
|
+
|
|
+ gmac_pins_mii_a: gmac_mii@0 {
|
|
+ allwinner,pins = "PA0", "PA1", "PA2",
|
|
+ "PA3", "PA4", "PA5", "PA6",
|
|
+ "PA7", "PA8", "PA9", "PA10",
|
|
+ "PA11", "PA12", "PA13", "PA14",
|
|
+ "PA15", "PA16";
|
|
+ allwinner,function = "gmac";
|
|
+ allwinner,drive = <0>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
+
|
|
+ gmac_pins_rgmii_a: gmac_rgmii@0 {
|
|
+ allwinner,pins = "PA0", "PA1", "PA2",
|
|
+ "PA3", "PA4", "PA5", "PA6",
|
|
+ "PA7", "PA8", "PA10",
|
|
+ "PA11", "PA12", "PA13",
|
|
+ "PA15", "PA16";
|
|
+ allwinner,function = "gmac";
|
|
+ /*
|
|
+ * data lines in RGMII mode use DDR mode
|
|
+ * and need a higher signal drive strength
|
|
+ */
|
|
+ allwinner,drive = <3>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
};
|
|
|
|
timer@01c20c00 {
|
|
@@ -593,6 +671,21 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
+ gmac: ethernet@01c50000 {
|
|
+ compatible = "allwinner,sun7i-a20-gmac";
|
|
+ reg = <0x01c50000 0x10000>;
|
|
+ interrupts = <0 85 4>;
|
|
+ interrupt-names = "macirq";
|
|
+ clocks = <&ahb_gates 49>, <&gmac_tx_clk>;
|
|
+ clock-names = "stmmaceth", "allwinner_gmac_tx";
|
|
+ snps,pbl = <2>;
|
|
+ snps,fixed-burst;
|
|
+ snps,force_sf_dma_mode;
|
|
+ status = "disabled";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ };
|
|
+
|
|
hstimer@01c60000 {
|
|
compatible = "allwinner,sun7i-a20-hstimer";
|
|
reg = <0x01c60000 0x1000>;
|
|
diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
|
|
new file mode 100644
|
|
index 0000000..18eeac0
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
|
|
@@ -0,0 +1,75 @@
|
|
+/*
|
|
+ * sunxi boards common regulator (ahci target power supply, usb-vbus) code
|
|
+ *
|
|
+ * Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
|
|
+ *
|
|
+ * The code contained herein is licensed under the GNU General Public
|
|
+ * License. You may obtain a copy of the GNU General Public License
|
|
+ * Version 2 or later at the following locations:
|
|
+ *
|
|
+ * http://www.opensource.org/licenses/gpl-license.html
|
|
+ * http://www.gnu.org/copyleft/gpl.html
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ soc@01c00000 {
|
|
+ pio: pinctrl@01c20800 {
|
|
+ ahci_pwr_pin_a: ahci_pwr_pin@0 {
|
|
+ allwinner,pins = "PB8";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <0>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
+
|
|
+ usb1_vbus_pin_a: usb1_vbus_pin@0 {
|
|
+ allwinner,pins = "PH6";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <0>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
+
|
|
+ usb2_vbus_pin_a: usb2_vbus_pin@0 {
|
|
+ allwinner,pins = "PH3";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <0>;
|
|
+ allwinner,pull = <0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ reg_ahci_5v: ahci-5v {
|
|
+ compatible = "regulator-fixed";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&ahci_pwr_pin_a>;
|
|
+ regulator-name = "ahci-5v";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ enable-active-high;
|
|
+ gpio = <&pio 1 8 0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ reg_usb1_vbus: usb1-vbus {
|
|
+ compatible = "regulator-fixed";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&usb1_vbus_pin_a>;
|
|
+ regulator-name = "usb1-vbus";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ enable-active-high;
|
|
+ gpio = <&pio 7 6 0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ reg_usb2_vbus: usb2-vbus {
|
|
+ compatible = "regulator-fixed";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&usb2_vbus_pin_a>;
|
|
+ regulator-name = "usb2-vbus";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ enable-active-high;
|
|
+ gpio = <&pio 7 3 0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+};
|
|
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
|
|
index 868429a..10a9c25 100644
|
|
--- a/drivers/ata/Kconfig
|
|
+++ b/drivers/ata/Kconfig
|
|
@@ -106,6 +106,15 @@ config AHCI_IMX
|
|
|
|
If unsure, say N.
|
|
|
|
+config AHCI_SUNXI
|
|
+ tristate "Allwinner sunxi AHCI SATA support"
|
|
+ depends on ARCH_SUNXI && SATA_AHCI_PLATFORM
|
|
+ help
|
|
+ This option enables support for the Allwinner sunxi SoC's
|
|
+ onboard AHCI SATA.
|
|
+
|
|
+ If unsure, say N.
|
|
+
|
|
config SATA_FSL
|
|
tristate "Freescale 3.0Gbps SATA support"
|
|
depends on FSL_SOC
|
|
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
|
|
index 46518c6..246050b 100644
|
|
--- a/drivers/ata/Makefile
|
|
+++ b/drivers/ata/Makefile
|
|
@@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
|
|
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
|
|
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
|
|
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
|
|
+obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o
|
|
|
|
# SFF w/ custom DMA
|
|
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
|
|
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
|
|
index c81d809..8bfc477 100644
|
|
--- a/drivers/ata/ahci.c
|
|
+++ b/drivers/ata/ahci.c
|
|
@@ -578,6 +578,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
|
|
unsigned long deadline)
|
|
{
|
|
struct ata_port *ap = link->ap;
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
bool online;
|
|
int rc;
|
|
|
|
@@ -588,7 +589,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
|
|
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
|
|
deadline, &online, NULL);
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
|
|
|
|
@@ -603,6 +604,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
|
|
{
|
|
struct ata_port *ap = link->ap;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
|
struct ata_taskfile tf;
|
|
bool online;
|
|
@@ -618,7 +620,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
|
|
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
|
|
deadline, &online, NULL);
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
/* The pseudo configuration device on SIMG4726 attached to
|
|
* ASUS P5W-DH Deluxe doesn't send signature FIS after
|
|
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
|
|
index 2289efd..3ab7ac9 100644
|
|
--- a/drivers/ata/ahci.h
|
|
+++ b/drivers/ata/ahci.h
|
|
@@ -37,6 +37,8 @@
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/libata.h>
|
|
+#include <linux/phy/phy.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
|
|
/* Enclosure Management Control */
|
|
#define EM_CTRL_MSG_TYPE 0x000f0000
|
|
@@ -51,6 +53,7 @@
|
|
|
|
enum {
|
|
AHCI_MAX_PORTS = 32,
|
|
+ AHCI_MAX_CLKS = 3,
|
|
AHCI_MAX_SG = 168, /* hardware max is 64K */
|
|
AHCI_DMA_BOUNDARY = 0xffffffff,
|
|
AHCI_MAX_CMDS = 32,
|
|
@@ -321,8 +324,16 @@ struct ahci_host_priv {
|
|
u32 em_loc; /* enclosure management location */
|
|
u32 em_buf_sz; /* EM buffer size in byte */
|
|
u32 em_msg_type; /* EM message type */
|
|
- struct clk *clk; /* Only for platforms supporting clk */
|
|
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
|
|
+ struct regulator *target_pwr; /* Optional */
|
|
+ struct phy *phy; /* If platform uses phy */
|
|
void *plat_data; /* Other platform data */
|
|
+ /*
|
|
+ * Optional ahci_start_engine override, if not set this gets set to the
|
|
+ * default ahci_start_engine during ahci_save_initial_config, this can
|
|
+ * be overridden anytime before the host is activated.
|
|
+ */
|
|
+ void (*start_engine)(struct ata_port *ap);
|
|
};
|
|
|
|
extern int ahci_ignore_sss;
|
|
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
|
|
index 4b231ba..ecacd4d 100644
|
|
--- a/drivers/ata/ahci_platform.c
|
|
+++ b/drivers/ata/ahci_platform.c
|
|
@@ -23,6 +23,7 @@
|
|
#include <linux/platform_device.h>
|
|
#include <linux/libata.h>
|
|
#include <linux/ahci_platform.h>
|
|
+#include <linux/phy/phy.h>
|
|
#include "ahci.h"
|
|
|
|
static void ahci_host_stop(struct ata_host *host);
|
|
@@ -87,78 +88,275 @@ static struct scsi_host_template ahci_platform_sht = {
|
|
AHCI_SHT("ahci_platform"),
|
|
};
|
|
|
|
-static int ahci_probe(struct platform_device *pdev)
|
|
+/**
|
|
+ * 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.
|
|
+ *
|
|
+ * 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;
|
|
+}
|
|
+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).
|
|
+ */
|
|
+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]);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
|
|
+
|
|
+/**
|
|
+ * ahci_platform_enable_resources - Enable platform resources
|
|
+ * @hpriv: host private area to store config values
|
|
+ *
|
|
+ * This function enables all ahci_platform managed resources in the
|
|
+ * following order:
|
|
+ * 1) Regulator
|
|
+ * 2) Clocks (through ahci_platform_enable_clks)
|
|
+ * 3) Phy
|
|
+ *
|
|
+ * If resource enabling fails at any point the previous enabled resources
|
|
+ * are disabled in reverse order.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
|
|
{
|
|
- struct device *dev = &pdev->dev;
|
|
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
|
|
- const struct platform_device_id *id = platform_get_device_id(pdev);
|
|
- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
|
|
- const struct ata_port_info *ppi[] = { &pi, NULL };
|
|
- struct ahci_host_priv *hpriv;
|
|
- struct ata_host *host;
|
|
- struct resource *mem;
|
|
- int irq;
|
|
- int n_ports;
|
|
- int i;
|
|
int rc;
|
|
|
|
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
- if (!mem) {
|
|
- dev_err(dev, "no mmio space\n");
|
|
- return -EINVAL;
|
|
+ if (hpriv->target_pwr) {
|
|
+ rc = regulator_enable(hpriv->target_pwr);
|
|
+ if (rc)
|
|
+ return rc;
|
|
}
|
|
|
|
- irq = platform_get_irq(pdev, 0);
|
|
- if (irq <= 0) {
|
|
- dev_err(dev, "no irq\n");
|
|
- return -EINVAL;
|
|
+ rc = ahci_platform_enable_clks(hpriv);
|
|
+ if (rc)
|
|
+ goto disable_regulator;
|
|
+
|
|
+ if (hpriv->phy) {
|
|
+ rc = phy_init(hpriv->phy);
|
|
+ if (rc)
|
|
+ goto disable_clks;
|
|
+
|
|
+ rc = phy_power_on(hpriv->phy);
|
|
+ if (rc) {
|
|
+ phy_exit(hpriv->phy);
|
|
+ goto disable_clks;
|
|
+ }
|
|
}
|
|
|
|
- if (pdata && pdata->ata_port_info)
|
|
- pi = *pdata->ata_port_info;
|
|
+ return 0;
|
|
|
|
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
|
|
- if (!hpriv) {
|
|
- dev_err(dev, "can't alloc ahci_host_priv\n");
|
|
- return -ENOMEM;
|
|
+disable_clks:
|
|
+ ahci_platform_disable_clks(hpriv);
|
|
+
|
|
+disable_regulator:
|
|
+ if (hpriv->target_pwr)
|
|
+ regulator_disable(hpriv->target_pwr);
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
|
|
+
|
|
+/**
|
|
+ * ahci_platform_disable_resources - Disable platform resources
|
|
+ * @hpriv: host private area to store config values
|
|
+ *
|
|
+ * This function disables all ahci_platform managed resources in the
|
|
+ * following order:
|
|
+ * 1) Phy
|
|
+ * 2) Clocks (through ahci_platform_disable_clks)
|
|
+ * 3) Regulator
|
|
+ */
|
|
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
|
|
+{
|
|
+ if (hpriv->phy) {
|
|
+ phy_power_off(hpriv->phy);
|
|
+ phy_exit(hpriv->phy);
|
|
}
|
|
|
|
- hpriv->flags |= (unsigned long)pi.private_data;
|
|
+ ahci_platform_disable_clks(hpriv);
|
|
|
|
- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
|
|
+ if (hpriv->target_pwr)
|
|
+ regulator_disable(hpriv->target_pwr);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
|
|
+
|
|
+static void ahci_platform_put_resources(struct device *dev, void *res)
|
|
+{
|
|
+ struct ahci_host_priv *hpriv = res;
|
|
+ int c;
|
|
+
|
|
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
|
|
+ clk_put(hpriv->clks[c]);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * ahci_platform_get_resources - Get platform resources
|
|
+ * @pdev: platform device to get resources for
|
|
+ *
|
|
+ * This function allocates an ahci_host_priv struct, and gets the following
|
|
+ * resources, storing a reference to them inside the returned struct:
|
|
+ *
|
|
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
|
|
+ * 2) regulator for controlling the targets power (optional)
|
|
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
|
|
+ * or for non devicetree enabled platforms a single clock
|
|
+ * 4) phy (optional)
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
|
|
+ */
|
|
+struct ahci_host_priv *ahci_platform_get_resources(
|
|
+ struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct ahci_host_priv *hpriv;
|
|
+ struct clk *clk;
|
|
+ int i, rc = -ENOMEM;
|
|
+
|
|
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
|
|
+ GFP_KERNEL);
|
|
+ if (!hpriv)
|
|
+ goto err_out;
|
|
+
|
|
+ devres_add(dev, hpriv);
|
|
+
|
|
+ hpriv->mmio = devm_ioremap_resource(dev,
|
|
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
|
|
if (!hpriv->mmio) {
|
|
- dev_err(dev, "can't map %pR\n", mem);
|
|
- return -ENOMEM;
|
|
+ dev_err(dev, "no mmio space\n");
|
|
+ goto err_out;
|
|
}
|
|
|
|
- hpriv->clk = clk_get(dev, NULL);
|
|
- if (IS_ERR(hpriv->clk)) {
|
|
- dev_err(dev, "can't get clock\n");
|
|
- } else {
|
|
- rc = clk_prepare_enable(hpriv->clk);
|
|
- if (rc) {
|
|
- dev_err(dev, "clock prepare enable failed");
|
|
- goto free_clk;
|
|
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
|
|
+ if (IS_ERR(hpriv->target_pwr)) {
|
|
+ rc = PTR_ERR(hpriv->target_pwr);
|
|
+ if (rc == -EPROBE_DEFER)
|
|
+ goto err_out;
|
|
+ hpriv->target_pwr = NULL;
|
|
+ }
|
|
+
|
|
+ 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);
|
|
+
|
|
+ if (IS_ERR(clk)) {
|
|
+ rc = PTR_ERR(clk);
|
|
+ if (rc == -EPROBE_DEFER)
|
|
+ goto err_out;
|
|
+ break;
|
|
}
|
|
+ hpriv->clks[i] = clk;
|
|
}
|
|
|
|
- /*
|
|
- * Some platforms might need to prepare for mmio region access,
|
|
- * which could be done in the following init call. So, the mmio
|
|
- * region shouldn't be accessed before init (if provided) has
|
|
- * returned successfully.
|
|
- */
|
|
- if (pdata && pdata->init) {
|
|
- rc = pdata->init(dev, hpriv->mmio);
|
|
- if (rc)
|
|
- goto disable_unprepare_clk;
|
|
+ hpriv->phy = devm_phy_get(dev, "sata-phy");
|
|
+ if (IS_ERR(hpriv->phy)) {
|
|
+ rc = PTR_ERR(hpriv->phy);
|
|
+ switch (rc) {
|
|
+ case -ENODEV:
|
|
+ case -ENOSYS:
|
|
+ /* continue normally */
|
|
+ hpriv->phy = NULL;
|
|
+ break;
|
|
+
|
|
+ case -EPROBE_DEFER:
|
|
+ goto err_out;
|
|
+
|
|
+ default:
|
|
+ dev_err(dev, "couldn't get sata-phy\n");
|
|
+ goto err_out;
|
|
+ }
|
|
}
|
|
|
|
- ahci_save_initial_config(dev, hpriv,
|
|
- pdata ? pdata->force_port_map : 0,
|
|
- pdata ? pdata->mask_port_map : 0);
|
|
+ devres_remove_group(dev, NULL);
|
|
+ return hpriv;
|
|
+
|
|
+err_out:
|
|
+ devres_release_group(dev, NULL);
|
|
+ return ERR_PTR(rc);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
|
|
+
|
|
+/**
|
|
+ * ahci_platform_init_host - Bring up an ahci-platform host
|
|
+ * @pdev: platform device pointer for the host
|
|
+ * @hpriv: ahci-host private data for the host
|
|
+ * @pi_template: template for the ata_port_info to use
|
|
+ * @force_port_map: param passed to ahci_save_initial_config
|
|
+ * @mask_port_map: param passed to ahci_save_initial_config
|
|
+ *
|
|
+ * This function does all the usual steps needed to bring up an
|
|
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
|
|
+ * must be initialized / enabled before calling this.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_init_host(struct platform_device *pdev,
|
|
+ struct ahci_host_priv *hpriv,
|
|
+ const struct ata_port_info *pi_template,
|
|
+ unsigned int force_port_map,
|
|
+ unsigned int mask_port_map)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct ata_port_info pi = *pi_template;
|
|
+ const struct ata_port_info *ppi[] = { &pi, NULL };
|
|
+ struct ata_host *host;
|
|
+ int i, irq, n_ports, rc;
|
|
+
|
|
+ irq = platform_get_irq(pdev, 0);
|
|
+ if (irq <= 0) {
|
|
+ dev_err(dev, "no irq\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
/* prepare host */
|
|
+ hpriv->flags |= (unsigned long)pi.private_data;
|
|
+
|
|
+ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
|
|
+
|
|
if (hpriv->cap & HOST_CAP_NCQ)
|
|
pi.flags |= ATA_FLAG_NCQ;
|
|
|
|
@@ -175,10 +373,8 @@ static int ahci_probe(struct platform_device *pdev)
|
|
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
|
|
|
|
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
|
|
- if (!host) {
|
|
- rc = -ENOMEM;
|
|
- goto pdata_exit;
|
|
- }
|
|
+ if (!host)
|
|
+ return -ENOMEM;
|
|
|
|
host->private_data = hpriv;
|
|
|
|
@@ -193,7 +389,8 @@ static int ahci_probe(struct platform_device *pdev)
|
|
for (i = 0; i < host->n_ports; i++) {
|
|
struct ata_port *ap = host->ports[i];
|
|
|
|
- ata_port_desc(ap, "mmio %pR", mem);
|
|
+ ata_port_desc(ap, "mmio %pR",
|
|
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
|
|
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
|
|
|
|
/* set enclosure management message type */
|
|
@@ -207,13 +404,53 @@ static int ahci_probe(struct platform_device *pdev)
|
|
|
|
rc = ahci_reset_controller(host);
|
|
if (rc)
|
|
- goto pdata_exit;
|
|
+ return rc;
|
|
|
|
ahci_init_controller(host);
|
|
ahci_print_info(host, "platform");
|
|
|
|
- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
|
|
- &ahci_platform_sht);
|
|
+ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
|
|
+ &ahci_platform_sht);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
|
|
+
|
|
+static int ahci_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
|
|
+ const struct platform_device_id *id = platform_get_device_id(pdev);
|
|
+ const struct ata_port_info *pi_template;
|
|
+ struct ahci_host_priv *hpriv;
|
|
+ int rc;
|
|
+
|
|
+ hpriv = ahci_platform_get_resources(pdev);
|
|
+ if (IS_ERR(hpriv))
|
|
+ return PTR_ERR(hpriv);
|
|
+
|
|
+ rc = ahci_platform_enable_resources(hpriv);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ /*
|
|
+ * Some platforms might need to prepare for mmio region access,
|
|
+ * which could be done in the following init call. So, the mmio
|
|
+ * region shouldn't be accessed before init (if provided) has
|
|
+ * returned successfully.
|
|
+ */
|
|
+ if (pdata && pdata->init) {
|
|
+ rc = pdata->init(dev, hpriv->mmio);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
+ }
|
|
+
|
|
+ if (pdata && pdata->ata_port_info)
|
|
+ pi_template = pdata->ata_port_info;
|
|
+ else
|
|
+ pi_template = &ahci_port_info[id ? id->driver_data : 0];
|
|
+
|
|
+ rc = ahci_platform_init_host(pdev, hpriv, pi_template,
|
|
+ pdata ? pdata->force_port_map : 0,
|
|
+ pdata ? pdata->mask_port_map : 0);
|
|
if (rc)
|
|
goto pdata_exit;
|
|
|
|
@@ -221,12 +458,8 @@ static int ahci_probe(struct platform_device *pdev)
|
|
pdata_exit:
|
|
if (pdata && pdata->exit)
|
|
pdata->exit(dev);
|
|
-disable_unprepare_clk:
|
|
- if (!IS_ERR(hpriv->clk))
|
|
- clk_disable_unprepare(hpriv->clk);
|
|
-free_clk:
|
|
- if (!IS_ERR(hpriv->clk))
|
|
- clk_put(hpriv->clk);
|
|
+disable_resources:
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
return rc;
|
|
}
|
|
|
|
@@ -239,21 +472,27 @@ static void ahci_host_stop(struct ata_host *host)
|
|
if (pdata && pdata->exit)
|
|
pdata->exit(dev);
|
|
|
|
- if (!IS_ERR(hpriv->clk)) {
|
|
- clk_disable_unprepare(hpriv->clk);
|
|
- clk_put(hpriv->clk);
|
|
- }
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
}
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
-static int ahci_suspend(struct device *dev)
|
|
+/**
|
|
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
|
|
+ * @dev: device pointer for the host
|
|
+ *
|
|
+ * This function does all the usual steps needed to suspend an
|
|
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
|
|
+ * must be disabled after calling this.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_suspend_host(struct device *dev)
|
|
{
|
|
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
|
|
struct ata_host *host = dev_get_drvdata(dev);
|
|
struct ahci_host_priv *hpriv = host->private_data;
|
|
void __iomem *mmio = hpriv->mmio;
|
|
u32 ctl;
|
|
- int rc;
|
|
|
|
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
|
|
dev_err(dev, "firmware update required for suspend/resume\n");
|
|
@@ -270,61 +509,113 @@ static int ahci_suspend(struct device *dev)
|
|
writel(ctl, mmio + HOST_CTL);
|
|
readl(mmio + HOST_CTL); /* flush */
|
|
|
|
- rc = ata_host_suspend(host, PMSG_SUSPEND);
|
|
+ return ata_host_suspend(host, PMSG_SUSPEND);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
|
|
+
|
|
+/**
|
|
+ * ahci_platform_resume_host - Resume an ahci-platform host
|
|
+ * @dev: device pointer for the host
|
|
+ *
|
|
+ * This function does all the usual steps needed to resume an ahci-platform
|
|
+ * host, note any necessary resources (ie clks, phy, etc.) must be
|
|
+ * initialized / enabled before calling this.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_resume_host(struct device *dev)
|
|
+{
|
|
+ struct ata_host *host = dev_get_drvdata(dev);
|
|
+ int rc;
|
|
+
|
|
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
|
|
+ rc = ahci_reset_controller(host);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ ahci_init_controller(host);
|
|
+ }
|
|
+
|
|
+ ata_host_resume(host);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
|
|
+
|
|
+/**
|
|
+ * ahci_platform_suspend - Suspend an ahci-platform device
|
|
+ * @dev: the platform device to suspend
|
|
+ *
|
|
+ * This function suspends the host associated with the device, followed by
|
|
+ * disabling all the resources of the device.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_suspend(struct device *dev)
|
|
+{
|
|
+ struct ahci_platform_data *pdata = dev_get_platdata(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;
|
|
|
|
if (pdata && pdata->suspend)
|
|
return pdata->suspend(dev);
|
|
|
|
- if (!IS_ERR(hpriv->clk))
|
|
- clk_disable_unprepare(hpriv->clk);
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
|
|
return 0;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
|
|
|
|
-static int ahci_resume(struct device *dev)
|
|
+/**
|
|
+ * ahci_platform_resume - Resume an ahci-platform device
|
|
+ * @dev: the platform device to resume
|
|
+ *
|
|
+ * This function enables all the resources of the device followed by
|
|
+ * resuming the host associated with the device.
|
|
+ *
|
|
+ * RETURNS:
|
|
+ * 0 on success otherwise a negative error code
|
|
+ */
|
|
+int ahci_platform_resume(struct device *dev)
|
|
{
|
|
struct ahci_platform_data *pdata = dev_get_platdata(dev);
|
|
struct ata_host *host = dev_get_drvdata(dev);
|
|
struct ahci_host_priv *hpriv = host->private_data;
|
|
int rc;
|
|
|
|
- if (!IS_ERR(hpriv->clk)) {
|
|
- rc = clk_prepare_enable(hpriv->clk);
|
|
- if (rc) {
|
|
- dev_err(dev, "clock prepare enable failed");
|
|
- return rc;
|
|
- }
|
|
- }
|
|
+ rc = ahci_platform_enable_resources(hpriv);
|
|
+ if (rc)
|
|
+ return rc;
|
|
|
|
if (pdata && pdata->resume) {
|
|
rc = pdata->resume(dev);
|
|
if (rc)
|
|
- goto disable_unprepare_clk;
|
|
- }
|
|
-
|
|
- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
|
|
- rc = ahci_reset_controller(host);
|
|
- if (rc)
|
|
- goto disable_unprepare_clk;
|
|
-
|
|
- ahci_init_controller(host);
|
|
+ goto disable_resources;
|
|
}
|
|
|
|
- ata_host_resume(host);
|
|
+ rc = ahci_platform_resume_host(dev);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
|
|
return 0;
|
|
|
|
-disable_unprepare_clk:
|
|
- if (!IS_ERR(hpriv->clk))
|
|
- clk_disable_unprepare(hpriv->clk);
|
|
+disable_resources:
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
|
|
return rc;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
|
|
#endif
|
|
|
|
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
|
|
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
|
|
+ ahci_platform_resume);
|
|
|
|
static const struct of_device_id ahci_of_match[] = {
|
|
{ .compatible = "snps,spear-ahci", },
|
|
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
|
|
new file mode 100644
|
|
index 0000000..42d3f64
|
|
--- /dev/null
|
|
+++ b/drivers/ata/ahci_sunxi.c
|
|
@@ -0,0 +1,249 @@
|
|
+/*
|
|
+ * Allwinner sunxi AHCI SATA platform driver
|
|
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
|
|
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
|
|
+ *
|
|
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
|
|
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
|
|
+ * Daniel Wang <danielwang@allwinnertech.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms and conditions of the GNU General Public License,
|
|
+ * version 2, as published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ * more details.
|
|
+ */
|
|
+
|
|
+#include <linux/ahci_platform.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include "ahci.h"
|
|
+
|
|
+#define AHCI_BISTAFR 0x00a0
|
|
+#define AHCI_BISTCR 0x00a4
|
|
+#define AHCI_BISTFCTR 0x00a8
|
|
+#define AHCI_BISTSR 0x00ac
|
|
+#define AHCI_BISTDECR 0x00b0
|
|
+#define AHCI_DIAGNR0 0x00b4
|
|
+#define AHCI_DIAGNR1 0x00b8
|
|
+#define AHCI_OOBR 0x00bc
|
|
+#define AHCI_PHYCS0R 0x00c0
|
|
+#define AHCI_PHYCS1R 0x00c4
|
|
+#define AHCI_PHYCS2R 0x00c8
|
|
+#define AHCI_TIMER1MS 0x00e0
|
|
+#define AHCI_GPARAM1R 0x00e8
|
|
+#define AHCI_GPARAM2R 0x00ec
|
|
+#define AHCI_PPARAMR 0x00f0
|
|
+#define AHCI_TESTR 0x00f4
|
|
+#define AHCI_VERSIONR 0x00f8
|
|
+#define AHCI_IDR 0x00fc
|
|
+#define AHCI_RWCR 0x00fc
|
|
+#define AHCI_P0DMACR 0x0170
|
|
+#define AHCI_P0PHYCR 0x0178
|
|
+#define AHCI_P0PHYSR 0x017c
|
|
+
|
|
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
|
|
+{
|
|
+ u32 reg_val;
|
|
+
|
|
+ reg_val = readl(reg);
|
|
+ reg_val &= ~(clr_val);
|
|
+ writel(reg_val, reg);
|
|
+}
|
|
+
|
|
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
|
|
+{
|
|
+ u32 reg_val;
|
|
+
|
|
+ reg_val = readl(reg);
|
|
+ reg_val |= set_val;
|
|
+ writel(reg_val, reg);
|
|
+}
|
|
+
|
|
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
|
|
+{
|
|
+ u32 reg_val;
|
|
+
|
|
+ reg_val = readl(reg);
|
|
+ reg_val &= ~(clr_val);
|
|
+ reg_val |= set_val;
|
|
+ writel(reg_val, reg);
|
|
+}
|
|
+
|
|
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
|
|
+{
|
|
+ return (readl(reg) >> shift) & mask;
|
|
+}
|
|
+
|
|
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
|
|
+{
|
|
+ u32 reg_val;
|
|
+ int timeout;
|
|
+
|
|
+ /* This magic is from the original code */
|
|
+ writel(0, reg_base + AHCI_RWCR);
|
|
+ msleep(5);
|
|
+
|
|
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
|
|
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
|
|
+ (0x7 << 24),
|
|
+ (0x5 << 24) | BIT(23) | BIT(18));
|
|
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
|
|
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
|
|
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
|
|
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
|
|
+ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
|
|
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
|
|
+ (0x7 << 20), (0x3 << 20));
|
|
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
|
|
+ (0x1f << 5), (0x19 << 5));
|
|
+ msleep(5);
|
|
+
|
|
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
|
|
+
|
|
+ timeout = 250; /* Power up takes aprox 50 us */
|
|
+ do {
|
|
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
|
|
+ if (reg_val == 0x02)
|
|
+ break;
|
|
+
|
|
+ if (--timeout == 0) {
|
|
+ dev_err(dev, "PHY power up failed.\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+ udelay(1);
|
|
+ } while (1);
|
|
+
|
|
+ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
|
|
+
|
|
+ timeout = 100; /* Calibration takes aprox 10 us */
|
|
+ do {
|
|
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
|
|
+ if (reg_val == 0x00)
|
|
+ break;
|
|
+
|
|
+ if (--timeout == 0) {
|
|
+ dev_err(dev, "PHY calibration failed.\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+ udelay(1);
|
|
+ } while (1);
|
|
+
|
|
+ msleep(15);
|
|
+
|
|
+ writel(0x7, reg_base + AHCI_RWCR);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ahci_sunxi_start_engine(struct ata_port *ap)
|
|
+{
|
|
+ void __iomem *port_mmio = ahci_port_base(ap);
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
+
|
|
+ /* Setup DMA before DMA start */
|
|
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
|
|
+
|
|
+ /* Start DMA */
|
|
+ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
|
|
+}
|
|
+
|
|
+static const struct ata_port_info ahci_sunxi_port_info = {
|
|
+ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
|
|
+ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
|
|
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
|
|
+ .pio_mask = ATA_PIO4,
|
|
+ .udma_mask = ATA_UDMA6,
|
|
+ .port_ops = &ahci_platform_ops,
|
|
+};
|
|
+
|
|
+static int ahci_sunxi_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct ahci_host_priv *hpriv;
|
|
+ int rc;
|
|
+
|
|
+ hpriv = ahci_platform_get_resources(pdev);
|
|
+ if (IS_ERR(hpriv))
|
|
+ return PTR_ERR(hpriv);
|
|
+
|
|
+ hpriv->start_engine = ahci_sunxi_start_engine;
|
|
+
|
|
+ rc = ahci_platform_enable_resources(hpriv);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
+
|
|
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+disable_resources:
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+static int ahci_sunxi_resume(struct device *dev)
|
|
+{
|
|
+ struct ata_host *host = dev_get_drvdata(dev);
|
|
+ struct ahci_host_priv *hpriv = host->private_data;
|
|
+ int rc;
|
|
+
|
|
+ rc = ahci_platform_enable_resources(hpriv);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
+
|
|
+ rc = ahci_platform_resume_host(dev);
|
|
+ if (rc)
|
|
+ goto disable_resources;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+disable_resources:
|
|
+ ahci_platform_disable_resources(hpriv);
|
|
+ return rc;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
|
|
+ ahci_sunxi_resume);
|
|
+
|
|
+static const struct of_device_id ahci_sunxi_of_match[] = {
|
|
+ { .compatible = "allwinner,sun4i-a10-ahci", },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
|
|
+
|
|
+static struct platform_driver ahci_sunxi_driver = {
|
|
+ .probe = ahci_sunxi_probe,
|
|
+ .remove = ata_platform_remove_one,
|
|
+ .driver = {
|
|
+ .name = "ahci-sunxi",
|
|
+ .owner = THIS_MODULE,
|
|
+ .of_match_table = ahci_sunxi_of_match,
|
|
+ .pm = &ahci_sunxi_pm_ops,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(ahci_sunxi_driver);
|
|
+
|
|
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
|
|
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
|
|
index 36605ab..f839bb3 100644
|
|
--- a/drivers/ata/libahci.c
|
|
+++ b/drivers/ata/libahci.c
|
|
@@ -394,6 +394,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
|
|
*
|
|
* If inconsistent, config values are fixed up by this function.
|
|
*
|
|
+ * If it is not set already this function sets hpriv->start_engine to
|
|
+ * ahci_start_engine.
|
|
+ *
|
|
* LOCKING:
|
|
* None.
|
|
*/
|
|
@@ -500,6 +503,9 @@ void ahci_save_initial_config(struct device *dev,
|
|
hpriv->cap = cap;
|
|
hpriv->cap2 = cap2;
|
|
hpriv->port_map = port_map;
|
|
+
|
|
+ if (!hpriv->start_engine)
|
|
+ hpriv->start_engine = ahci_start_engine;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
|
|
|
|
@@ -766,7 +772,7 @@ static void ahci_start_port(struct ata_port *ap)
|
|
|
|
/* enable DMA */
|
|
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
/* turn on LEDs */
|
|
if (ap->flags & ATA_FLAG_EM) {
|
|
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
|
|
|
|
/* restart engine */
|
|
out_restart:
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ahci_kick_engine);
|
|
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
|
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
|
|
struct ata_port *ap = link->ap;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
|
struct ata_taskfile tf;
|
|
bool online;
|
|
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
|
rc = sata_link_hardreset(link, timing, deadline, &online,
|
|
ahci_check_ready);
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
if (online)
|
|
*class = ahci_dev_classify(ap);
|
|
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
|
|
|
|
void ahci_error_handler(struct ata_port *ap)
|
|
{
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
+
|
|
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
|
|
/* restart engine */
|
|
ahci_stop_engine(ap);
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
}
|
|
|
|
sata_pmp_error_handler(ap);
|
|
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
|
|
|
|
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
|
|
{
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
void __iomem *port_mmio = ahci_port_base(ap);
|
|
struct ata_device *dev = ap->link.device;
|
|
u32 devslp, dm, dito, mdat, deto;
|
|
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
|
|
PORT_DEVSLP_ADSE);
|
|
writel(devslp, port_mmio + PORT_DEVSLP);
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
/* enable device sleep feature for the drive */
|
|
err_mask = ata_dev_set_feature(dev,
|
|
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
|
|
|
|
static void ahci_enable_fbs(struct ata_port *ap)
|
|
{
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
void __iomem *port_mmio = ahci_port_base(ap);
|
|
u32 fbs;
|
|
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
|
|
} else
|
|
dev_err(ap->host->dev, "Failed to enable FBS\n");
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
}
|
|
|
|
static void ahci_disable_fbs(struct ata_port *ap)
|
|
{
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
void __iomem *port_mmio = ahci_port_base(ap);
|
|
u32 fbs;
|
|
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
|
|
pp->fbs_enabled = false;
|
|
}
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
}
|
|
|
|
static void ahci_pmp_attach(struct ata_port *ap)
|
|
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
|
|
index 870b11e..b3b18d1 100644
|
|
--- a/drivers/ata/sata_highbank.c
|
|
+++ b/drivers/ata/sata_highbank.c
|
|
@@ -403,6 +403,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
|
|
static const unsigned long timing[] = { 5, 100, 500};
|
|
struct ata_port *ap = link->ap;
|
|
struct ahci_port_priv *pp = ap->private_data;
|
|
+ struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
|
struct ata_taskfile tf;
|
|
bool online;
|
|
@@ -431,7 +432,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
|
|
break;
|
|
} while (!online && retry--);
|
|
|
|
- ahci_start_engine(ap);
|
|
+ hpriv->start_engine(ap);
|
|
|
|
if (online)
|
|
*class = ahci_dev_classify(ap);
|
|
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
|
|
index abb6c5a..a4b5025 100644
|
|
--- a/drivers/clk/sunxi/clk-sunxi.c
|
|
+++ b/drivers/clk/sunxi/clk-sunxi.c
|
|
@@ -51,6 +51,8 @@ static void __init sun4i_osc_clk_setup(struct device_node *node)
|
|
if (!gate)
|
|
goto err_free_fixed;
|
|
|
|
+ of_property_read_string(node, "clock-output-names", &clk_name);
|
|
+
|
|
/* set up gate and fixed rate properties */
|
|
gate->reg = of_iomap(node, 0);
|
|
gate->bit_idx = SUNXI_OSC24M_GATE;
|
|
@@ -249,7 +251,38 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
|
|
*n = DIV_ROUND_UP(div, (*k+1));
|
|
}
|
|
|
|
+/**
|
|
+ * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
|
|
+ * PLL6 rate is calculated as follows
|
|
+ * rate = parent_rate * n * (k + 1) / 2
|
|
+ * parent_rate is always 24Mhz
|
|
+ */
|
|
+
|
|
+static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
|
|
+ u8 *n, u8 *k, u8 *m, u8 *p)
|
|
+{
|
|
+ u8 div;
|
|
+
|
|
+ /*
|
|
+ * We always have 24MHz / 2, so we can just say that our
|
|
+ * parent clock is 12MHz.
|
|
+ */
|
|
+ parent_rate = parent_rate / 2;
|
|
+
|
|
+ /* Normalize value to a parent_rate multiple (24M / 2) */
|
|
+ div = *freq / parent_rate;
|
|
+ *freq = parent_rate * div;
|
|
|
|
+ /* we were called to round the frequency, we can now return */
|
|
+ if (n == NULL)
|
|
+ return;
|
|
+
|
|
+ *k = div / 32;
|
|
+ if (*k > 3)
|
|
+ *k = 3;
|
|
+
|
|
+ *n = DIV_ROUND_UP(div, (*k+1));
|
|
+}
|
|
|
|
/**
|
|
* sun4i_get_apb1_factors() - calculates m, p factors for APB1
|
|
@@ -265,7 +298,7 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,
|
|
if (parent_rate < *freq)
|
|
*freq = parent_rate;
|
|
|
|
- parent_rate = (parent_rate + (*freq - 1)) / *freq;
|
|
+ parent_rate = DIV_ROUND_UP(parent_rate, *freq);
|
|
|
|
/* Invalid rate! */
|
|
if (parent_rate > 32)
|
|
@@ -310,7 +343,7 @@ static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,
|
|
if (*freq > parent_rate)
|
|
*freq = parent_rate;
|
|
|
|
- div = parent_rate / *freq;
|
|
+ div = DIV_ROUND_UP(parent_rate, *freq);
|
|
|
|
if (div < 16)
|
|
calcp = 0;
|
|
@@ -351,7 +384,7 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
|
|
if (*freq > parent_rate)
|
|
*freq = parent_rate;
|
|
|
|
- div = parent_rate / *freq;
|
|
+ div = DIV_ROUND_UP(parent_rate, *freq);
|
|
|
|
if (div < 32)
|
|
calcp = 0;
|
|
@@ -377,6 +410,102 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
|
|
|
|
|
|
/**
|
|
+ * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
|
|
+ *
|
|
+ * This clock looks something like this
|
|
+ * ________________________
|
|
+ * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
|
|
+ * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
|
|
+ * Ext. 125MHz RGMII TX clk >--|__divider__/ |
|
|
+ * |________________________|
|
|
+ *
|
|
+ * The external 125 MHz reference is optional, i.e. GMAC can use its
|
|
+ * internal TX clock just fine. The A31 GMAC clock module does not have
|
|
+ * the divider controls for the external reference.
|
|
+ *
|
|
+ * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
|
|
+ * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
|
|
+ * select the appropriate source and gate/ungate the output to the PHY.
|
|
+ *
|
|
+ * Only the GMAC should use this clock. Altering the clock so that it doesn't
|
|
+ * match the GMAC's operation parameters will result in the GMAC not being
|
|
+ * able to send traffic out. The GMAC driver should set the clock rate and
|
|
+ * enable/disable this clock to configure the required state. The clock
|
|
+ * driver then responds by auto-reparenting the clock.
|
|
+ */
|
|
+
|
|
+#define SUN7I_A20_GMAC_GPIT 2
|
|
+#define SUN7I_A20_GMAC_MASK 0x3
|
|
+#define SUN7I_A20_GMAC_PARENTS 2
|
|
+
|
|
+static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ struct clk_mux *mux;
|
|
+ struct clk_gate *gate;
|
|
+ const char *clk_name = node->name;
|
|
+ const char *parents[SUN7I_A20_GMAC_PARENTS];
|
|
+ void *reg;
|
|
+
|
|
+ if (of_property_read_string(node, "clock-output-names", &clk_name))
|
|
+ return;
|
|
+
|
|
+ /* allocate mux and gate clock structs */
|
|
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
|
|
+ if (!mux)
|
|
+ return;
|
|
+
|
|
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
|
|
+ if (!gate)
|
|
+ goto free_mux;
|
|
+
|
|
+ /* gmac clock requires exactly 2 parents */
|
|
+ parents[0] = of_clk_get_parent_name(node, 0);
|
|
+ parents[1] = of_clk_get_parent_name(node, 1);
|
|
+ if (!parents[0] || !parents[1])
|
|
+ goto free_gate;
|
|
+
|
|
+ reg = of_iomap(node, 0);
|
|
+ if (!reg)
|
|
+ goto free_gate;
|
|
+
|
|
+ /* set up gate and fixed rate properties */
|
|
+ gate->reg = reg;
|
|
+ gate->bit_idx = SUN7I_A20_GMAC_GPIT;
|
|
+ gate->lock = &clk_lock;
|
|
+ mux->reg = reg;
|
|
+ mux->mask = SUN7I_A20_GMAC_MASK;
|
|
+ mux->flags = CLK_MUX_INDEX_BIT;
|
|
+ mux->lock = &clk_lock;
|
|
+
|
|
+ clk = clk_register_composite(NULL, clk_name,
|
|
+ parents, SUN7I_A20_GMAC_PARENTS,
|
|
+ &mux->hw, &clk_mux_ops,
|
|
+ NULL, NULL,
|
|
+ &gate->hw, &clk_gate_ops,
|
|
+ 0);
|
|
+
|
|
+ if (IS_ERR(clk))
|
|
+ goto iounmap_reg;
|
|
+
|
|
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
|
+ clk_register_clkdev(clk, clk_name, NULL);
|
|
+
|
|
+ return;
|
|
+
|
|
+iounmap_reg:
|
|
+ iounmap(reg);
|
|
+free_gate:
|
|
+ kfree(gate);
|
|
+free_mux:
|
|
+ kfree(mux);
|
|
+}
|
|
+CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
|
|
+ sun7i_a20_gmac_clk_setup);
|
|
+
|
|
+
|
|
+
|
|
+/**
|
|
* sunxi_factors_clk_setup() - Setup function for factor clocks
|
|
*/
|
|
|
|
@@ -387,6 +516,7 @@ struct factors_data {
|
|
int mux;
|
|
struct clk_factors_config *table;
|
|
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
|
|
+ const char *name;
|
|
};
|
|
|
|
static struct clk_factors_config sun4i_pll1_config = {
|
|
@@ -416,6 +546,13 @@ static struct clk_factors_config sun4i_pll5_config = {
|
|
.kwidth = 2,
|
|
};
|
|
|
|
+static struct clk_factors_config sun6i_a31_pll6_config = {
|
|
+ .nshift = 8,
|
|
+ .nwidth = 5,
|
|
+ .kshift = 4,
|
|
+ .kwidth = 2,
|
|
+};
|
|
+
|
|
static struct clk_factors_config sun4i_apb1_config = {
|
|
.mshift = 0,
|
|
.mwidth = 5,
|
|
@@ -455,6 +592,20 @@ static const struct factors_data sun4i_pll5_data __initconst = {
|
|
.enable = 31,
|
|
.table = &sun4i_pll5_config,
|
|
.getter = sun4i_get_pll5_factors,
|
|
+ .name = "pll5",
|
|
+};
|
|
+
|
|
+static const struct factors_data sun4i_pll6_data __initconst = {
|
|
+ .enable = 31,
|
|
+ .table = &sun4i_pll5_config,
|
|
+ .getter = sun4i_get_pll5_factors,
|
|
+ .name = "pll6",
|
|
+};
|
|
+
|
|
+static const struct factors_data sun6i_a31_pll6_data __initconst = {
|
|
+ .enable = 31,
|
|
+ .table = &sun6i_a31_pll6_config,
|
|
+ .getter = sun6i_a31_get_pll6_factors,
|
|
};
|
|
|
|
static const struct factors_data sun4i_apb1_data __initconst = {
|
|
@@ -497,14 +648,14 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
|
|
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
|
|
i++;
|
|
|
|
- /* Nodes should be providing the name via clock-output-names
|
|
- * but originally our dts didn't, and so we used node->name.
|
|
- * The new, better nodes look like clk@deadbeef, so we pull the
|
|
- * name just in this case */
|
|
- if (!strcmp("clk", clk_name)) {
|
|
- of_property_read_string_index(node, "clock-output-names",
|
|
- 0, &clk_name);
|
|
- }
|
|
+ /*
|
|
+ * some factor clocks, such as pll5 and pll6, may have multiple
|
|
+ * outputs, and have their name designated in factors_data
|
|
+ */
|
|
+ if (data->name)
|
|
+ clk_name = data->name;
|
|
+ else
|
|
+ of_property_read_string(node, "clock-output-names", &clk_name);
|
|
|
|
factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
|
|
if (!factors)
|
|
@@ -601,6 +752,8 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
|
|
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
|
|
i++;
|
|
|
|
+ of_property_read_string(node, "clock-output-names", &clk_name);
|
|
+
|
|
clk = clk_register_mux(NULL, clk_name, parents, i,
|
|
CLK_SET_RATE_NO_REPARENT, reg,
|
|
data->shift, SUNXI_MUX_GATE_WIDTH,
|
|
@@ -660,6 +813,8 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
|
|
|
|
clk_parent = of_clk_get_parent_name(node, 0);
|
|
|
|
+ of_property_read_string(node, "clock-output-names", &clk_name);
|
|
+
|
|
clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
|
|
reg, data->shift, data->width,
|
|
data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
|
|
@@ -832,7 +987,7 @@ static const struct divs_data pll5_divs_data __initconst = {
|
|
};
|
|
|
|
static const struct divs_data pll6_divs_data __initconst = {
|
|
- .factors = &sun4i_pll5_data,
|
|
+ .factors = &sun4i_pll6_data,
|
|
.div = {
|
|
{ .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
|
|
{ .fixed = 2 }, /* P, other */
|
|
@@ -854,7 +1009,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
|
|
struct divs_data *data)
|
|
{
|
|
struct clk_onecell_data *clk_data;
|
|
- const char *parent = node->name;
|
|
+ const char *parent;
|
|
const char *clk_name;
|
|
struct clk **clks, *pclk;
|
|
struct clk_hw *gate_hw, *rate_hw;
|
|
@@ -868,6 +1023,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
|
|
|
|
/* Set up factor clock that we will be dividing */
|
|
pclk = sunxi_factors_clk_setup(node, data->factors);
|
|
+ parent = __clk_get_name(pclk);
|
|
|
|
reg = of_iomap(node, 0);
|
|
|
|
@@ -972,6 +1128,7 @@ free_clkdata:
|
|
static const struct of_device_id clk_factors_match[] __initconst = {
|
|
{.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
|
|
{.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
|
|
+ {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
|
|
{.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
|
|
{.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
|
|
{.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
|
|
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
|
|
index 73a2500..542f268 100644
|
|
--- a/include/linux/ahci_platform.h
|
|
+++ b/include/linux/ahci_platform.h
|
|
@@ -19,7 +19,15 @@
|
|
|
|
struct device;
|
|
struct ata_port_info;
|
|
+struct ahci_host_priv;
|
|
+struct platform_device;
|
|
|
|
+/*
|
|
+ * Note ahci_platform_data is deprecated, it is only kept around for use
|
|
+ * by the old da850 and spear13xx ahci code.
|
|
+ * New drivers should instead declare their own platform_driver struct, and
|
|
+ * use ahci_platform* functions in their own probe, suspend and resume methods.
|
|
+ */
|
|
struct ahci_platform_data {
|
|
int (*init)(struct device *dev, void __iomem *addr);
|
|
void (*exit)(struct device *dev);
|
|
@@ -30,4 +38,21 @@ struct ahci_platform_data {
|
|
unsigned int mask_port_map;
|
|
};
|
|
|
|
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
|
|
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
|
|
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
|
|
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
|
|
+struct ahci_host_priv *ahci_platform_get_resources(
|
|
+ struct platform_device *pdev);
|
|
+int ahci_platform_init_host(struct platform_device *pdev,
|
|
+ struct ahci_host_priv *hpriv,
|
|
+ const struct ata_port_info *pi_template,
|
|
+ unsigned int force_port_map,
|
|
+ unsigned int mask_port_map);
|
|
+
|
|
+int ahci_platform_suspend_host(struct device *dev);
|
|
+int ahci_platform_resume_host(struct device *dev);
|
|
+int ahci_platform_suspend(struct device *dev);
|
|
+int ahci_platform_resume(struct device *dev);
|
|
+
|
|
#endif /* _AHCI_PLATFORM_H */
|