* [PATCH v6 00/18] ahci: library-ise ahci_platform, add sunxi driver and cleanup imx driver
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
Hi all,
Here is v6 of my patchset for adding ahci-sunxi support. This has been
tested with Allwinner A10, Allwinner A20 and Freeware imx6x SoCs, including
suspend / resume. Note that since my last revision the ahci_imx driver has
also grown imx53 sata support, it would be good if some-one could test that
with this series.
History:
v1, by Olliver Schinagl:
This was 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 .
v2, by Hans de Goede:
Stand-alone platform driver based on Olliver's work
v3, by Hans de Goede:
patch-series, with 4 different parts
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) New ahci-sunxi code only populating ahci_platform_data, passed to
ahci_platform.c to of_device_id matching.
c) Refactor ahci-imx code to work the same as the new ahci-sunxi code, this
is the reason why v3 is an RFC, I'm waiting for the wandboard I ordered to
arrive so that I can actually test this.
d) dts bindings for the sunxi ahci parts
v4, by Hans de Goede:
patch-series, with 5 different parts:
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) Turn parts of ahci_platform.c into a library for use by other drivers
c) New ahci-sunxi driver using the ahci_platform.c library functionality
d) Refactor ahci-imx code to work the same as the new ahci-sunxi code
e) dts bindings for the sunxi ahci parts
v5:
v4 + the following changes:
1) fsl,imx6q driver is now tested
2) fixed suspend / resume on fsl,imx6q
3) Modifed devicetree node naming to match dt spec
4) Reworked the busy waiting code in the sunxi-phy handling as suggested by
Russell King
v6:
v5 rebased on top of 3.14-rc3 + the following changes
1) Added Roger Quadros' generic phy support series
2) Added a "ARM: sun4i: dt: Remove grouping + simple-bus for regulators" dts
patch
Tejun, can you please add patches 1-15 to your ata tree for 3.15 ?
Maxime, can you please add patch 16-18 to your dts tree for 3.15 ?
Thanks & Regards,
Hans
^ permalink raw reply
* [PATCH v6 01/18] libahci: Allow drivers to override start_engine
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
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-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci.c | 6 ++++--
drivers/ata/ahci.h | 3 ++-
drivers/ata/libahci.c | 27 ++++++++++++++++++---------
drivers/ata/sata_highbank.c | 3 ++-
4 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index dc2756f..eda68b4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -564,6 +564,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;
@@ -574,7 +575,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);
@@ -589,6 +590,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;
@@ -604,7 +606,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..2c04211 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -323,6 +323,8 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
};
extern int ahci_ignore_sss;
@@ -357,7 +359,6 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int (*check_ready)(struct ata_link *link));
int ahci_stop_engine(struct ata_port *ap);
-void ahci_start_engine(struct ata_port *ap);
int ahci_check_ready(struct ata_link *link);
int ahci_kick_engine(struct ata_port *ap);
int ahci_port_resume(struct ata_port *ap);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 36605ab..c550b5c 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -69,6 +69,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static void ahci_start_engine(struct ata_port *ap);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int ahci_port_start(struct ata_port *ap);
@@ -500,6 +501,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);
@@ -565,7 +569,7 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return -EINVAL;
}
-void ahci_start_engine(struct ata_port *ap)
+static void ahci_start_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
@@ -576,7 +580,6 @@ void ahci_start_engine(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
}
-EXPORT_SYMBOL_GPL(ahci_start_engine);
int ahci_stop_engine(struct ata_port *ap)
{
@@ -766,7 +769,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 +1237,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 +1429,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 +1447,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 +2011,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 +2037,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 +2101,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 +2113,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 +2142,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 +2175,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);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 02/18] libahci: Move ahci_host_priv declaration to include/linux/ahci.h
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
With the ahci-platform.c changes later in this patch-set, some
arch/arm/mach-foo/*.c sata drivers need access to ahci_host_priv, so move
its declaration outside of drivers/ata.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci.h | 20 +-------------------
include/linux/ahci.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 19 deletions(-)
create mode 100644 include/linux/ahci.h
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2c04211..0f80129 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -35,7 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
-#include <linux/clk.h>
+#include <linux/ahci.h>
#include <linux/libata.h>
/* Enclosure Management Control */
@@ -309,24 +309,6 @@ struct ahci_port_priv {
char *irq_desc; /* desc in /proc/interrupts */
};
-struct ahci_host_priv {
- void __iomem * mmio; /* bus-independent mem map */
- unsigned int flags; /* AHCI_HFLAG_* */
- u32 cap; /* cap to use */
- u32 cap2; /* cap2 to use */
- u32 port_map; /* port map to use */
- u32 saved_cap; /* saved initial cap */
- u32 saved_cap2; /* saved initial cap2 */
- u32 saved_port_map; /* saved initial port_map */
- 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 */
- void *plat_data; /* Other platform data */
- /* Optional ahci_start_engine override */
- void (*start_engine)(struct ata_port *ap);
-};
-
extern int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[];
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
new file mode 100644
index 0000000..3499d44
--- /dev/null
+++ b/include/linux/ahci.h
@@ -0,0 +1,46 @@
+/*
+ * ahci.h - Common AHCI SATA definitions and declarations
+ *
+ * Maintained by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
+ * Please ALWAYS copy linux-ide-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef __LINUX_AHCI_H__
+#define __LINUX_AHCI_H__
+
+#include <linux/clk.h>
+
+struct ata_port;
+
+struct ahci_host_priv {
+ void __iomem *mmio; /* bus-independent mem map */
+ unsigned int flags; /* AHCI_HFLAG_* */
+ u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
+ u32 saved_port_map; /* saved initial port_map */
+ 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; /* Optional */
+ void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
+};
+
+#endif
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 03/18] ahci-platform: Pass ahci_host_priv ptr to ahci_platform_data init method
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Some ahci_platform_data->init methods need access to the ahci_host_priv data.
When calling ahci_platform_data->init the ata_host has not been allocated yet,
so access to ahci_host_priv through the dev argument is not possible.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/arm/mach-davinci/devices-da8xx.c | 5 +++--
arch/arm/mach-spear/spear1340.c | 2 +-
drivers/ata/ahci_imx.c | 12 ++++++------
drivers/ata/ahci_platform.c | 2 +-
include/linux/ahci_platform.h | 3 ++-
5 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 0486cdf..c4e97da 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/dma-contiguous.h>
#include <linux/serial_8250.h>
+#include <linux/ahci.h>
#include <linux/ahci_platform.h>
#include <linux/clk.h>
#include <linux/reboot.h>
@@ -1061,7 +1062,7 @@ static unsigned long da850_sata_xtal[] = {
KHZ_TO_HZ(60000),
};
-static int da850_sata_init(struct device *dev, void __iomem *addr)
+static int da850_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int i, ret;
unsigned int val;
@@ -1096,7 +1097,7 @@ static int da850_sata_init(struct device *dev, void __iomem *addr)
SATA_PHY_TXSWING(3) |
SATA_PHY_ENPLL(1);
- __raw_writel(val, addr + SATA_P0PHYCR_REG);
+ __raw_writel(val, hpriv->mmio + SATA_P0PHYCR_REG);
return 0;
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
index 3fb6834..9e2f3ac 100644
--- a/arch/arm/mach-spear/spear1340.c
+++ b/arch/arm/mach-spear/spear1340.c
@@ -77,7 +77,7 @@
SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
/* SATA device registration */
-static int sata_miphy_init(struct device *dev, void __iomem *addr)
+static int sata_miphy_init(struct device *dev, struct ahci_host_priv *hpriv)
{
writel(SPEAR1340_SATA_CFG_VAL, SPEAR1340_PCIE_SATA_CFG);
writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK,
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index dd4d6f7..ebfd1d6 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -168,7 +168,7 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx_sata_init(struct device *dev, void __iomem *mmio)
+static int imx_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int ret = 0;
unsigned int reg_val;
@@ -185,19 +185,19 @@ static int imx_sata_init(struct device *dev, void __iomem *mmio)
* Implement the port0.
* Get the ahb clock rate, and configure the TIMER1MS register.
*/
- reg_val = readl(mmio + HOST_CAP);
+ reg_val = readl(hpriv->mmio + HOST_CAP);
if (!(reg_val & HOST_CAP_SSS)) {
reg_val |= HOST_CAP_SSS;
- writel(reg_val, mmio + HOST_CAP);
+ writel(reg_val, hpriv->mmio + HOST_CAP);
}
- reg_val = readl(mmio + HOST_PORTS_IMPL);
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
if (!(reg_val & 0x1)) {
reg_val |= 0x1;
- writel(reg_val, mmio + HOST_PORTS_IMPL);
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, mmio + HOST_TIMER1MS);
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
return 0;
}
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4b231ba..434ab89 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -149,7 +149,7 @@ static int ahci_probe(struct platform_device *pdev)
* returned successfully.
*/
if (pdata && pdata->init) {
- rc = pdata->init(dev, hpriv->mmio);
+ rc = pdata->init(dev, hpriv);
if (rc)
goto disable_unprepare_clk;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 73a2500..737fe38 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -19,9 +19,10 @@
struct device;
struct ata_port_info;
+struct ahci_host_priv;
struct ahci_platform_data {
- int (*init)(struct device *dev, void __iomem *addr);
+ int (*init)(struct device *dev, struct ahci_host_priv *hpriv);
void (*exit)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 04/18] ahci-platform: Add support for devices with more then 1 clock
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
imx AHCI controller needs 3 clocks to be enabled.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 97 +++++++++++++++-------
include/linux/ahci.h | 4 +-
include/linux/ahci_platform.h | 3 +
4 files changed, 73 insertions(+), 32 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de156..3ced07d 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -10,6 +10,7 @@ Required properties:
Optional properties:
- dma-coherent : Present if dma operations are coherent
+- clocks : a list of phandle + clock specifier pairs
Example:
sata@ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 434ab89..aaa0c08 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -87,6 +87,44 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT("ahci_platform"),
};
+
+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);
+
+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);
+
+
+static void ahci_put_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -97,10 +135,8 @@ static int ahci_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
struct ata_host *host;
struct resource *mem;
- int irq;
- int n_ports;
- int i;
- int rc;
+ struct clk *clk;
+ int i, irq, max_clk, n_ports, rc;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -131,17 +167,26 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
- 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;
+ max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
+ for (i = 0; i < max_clk; i++) {
+ if (i == 0)
+ clk = clk_get(dev, NULL); /* For old platform init */
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto free_clk;
+ break;
}
+ hpriv->clks[i] = clk;
}
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+ goto free_clk;
+
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@@ -222,11 +267,9 @@ pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
free_clk:
- if (!IS_ERR(hpriv->clk))
- clk_put(hpriv->clk);
+ ahci_put_clks(hpriv);
return rc;
}
@@ -239,10 +282,8 @@ 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_disable_clks(hpriv);
+ ahci_put_clks(hpriv);
}
#ifdef CONFIG_PM_SLEEP
@@ -277,8 +318,7 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return 0;
}
@@ -290,13 +330,9 @@ static int ahci_resume(struct device *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_enable_clks(dev, hpriv);
+ if (rc)
+ return rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -317,8 +353,7 @@ static int ahci_resume(struct device *dev)
return 0;
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 3499d44..19970b0 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -23,6 +23,8 @@
#include <linux/clk.h>
+#define AHCI_MAX_CLKS 3
+
struct ata_port;
struct ahci_host_priv {
@@ -37,7 +39,7 @@ 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; /* Optional */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 737fe38..0071d0b 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -31,4 +31,7 @@ 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);
+
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 05/18] ahci-platform: Add support for an optional regulator for sata-target power
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 35 ++++++++++++++++++++--
include/linux/ahci.h | 2 ++
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 3ced07d..1ac807f 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -11,6 +11,7 @@ Required properties:
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:
sata@ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index aaa0c08..2f319e9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -167,6 +167,13 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ if (PTR_ERR(hpriv->target_pwr) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ hpriv->target_pwr = NULL;
+ }
+
max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
for (i = 0; i < max_clk; i++) {
if (i == 0)
@@ -183,9 +190,15 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ goto free_clk;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- goto free_clk;
+ goto disable_regulator;
/*
* Some platforms might need to prepare for mmio region access,
@@ -268,6 +281,9 @@ pdata_exit:
pdata->exit(dev);
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
free_clk:
ahci_put_clks(hpriv);
return rc;
@@ -284,6 +300,9 @@ static void ahci_host_stop(struct ata_host *host)
ahci_disable_clks(hpriv);
ahci_put_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
#ifdef CONFIG_PM_SLEEP
@@ -320,6 +339,9 @@ static int ahci_suspend(struct device *dev)
ahci_disable_clks(hpriv);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return 0;
}
@@ -330,9 +352,15 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- return rc;
+ goto disable_regulator;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -354,6 +382,9 @@ static int ahci_resume(struct device *dev)
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 19970b0..ac69cdc 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -22,6 +22,7 @@
#define __LINUX_AHCI_H__
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#define AHCI_MAX_CLKS 3
@@ -40,6 +41,7 @@ struct ahci_host_priv {
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 06/18] ahci-platform: Add enable_ / disable_resources helper functions
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_platform.c | 83 ++++++++++++++++++++++++-------------------
include/linux/ahci_platform.h | 2 ++
2 files changed, 48 insertions(+), 37 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 2f319e9..1cce7a2 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -117,6 +117,39 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+ int rc;
+
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
+ return 0;
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+
static void ahci_put_clks(struct ahci_host_priv *hpriv)
{
int c;
@@ -190,15 +223,9 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
- if (hpriv->target_pwr) {
- rc = regulator_enable(hpriv->target_pwr);
- if (rc)
- goto free_clk;
- }
-
- rc = ahci_enable_clks(dev, hpriv);
+ rc = ahci_platform_enable_resources(hpriv);
if (rc)
- goto disable_regulator;
+ goto free_clk;
/*
* Some platforms might need to prepare for mmio region access,
@@ -209,7 +236,7 @@ static int ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
}
ahci_save_initial_config(dev, hpriv,
@@ -279,11 +306,8 @@ static int ahci_probe(struct platform_device *pdev)
pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
-disable_unprepare_clk:
- ahci_disable_clks(hpriv);
-disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
free_clk:
ahci_put_clks(hpriv);
return rc;
@@ -298,11 +322,8 @@ static void ahci_host_stop(struct ata_host *host)
if (pdata && pdata->exit)
pdata->exit(dev);
- ahci_disable_clks(hpriv);
+ ahci_platform_disable_resources(hpriv);
ahci_put_clks(hpriv);
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
}
#ifdef CONFIG_PM_SLEEP
@@ -337,10 +358,7 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
- ahci_disable_clks(hpriv);
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_resources(hpriv);
return 0;
}
@@ -352,26 +370,20 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
- if (hpriv->target_pwr) {
- rc = regulator_enable(hpriv->target_pwr);
- if (rc)
- return rc;
- }
-
- rc = ahci_enable_clks(dev, hpriv);
+ rc = ahci_platform_enable_resources(hpriv);
if (rc)
- goto disable_regulator;
+ return rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
}
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
ahci_init_controller(host);
}
@@ -380,11 +392,8 @@ static int ahci_resume(struct device *dev)
return 0;
-disable_unprepare_clk:
- ahci_disable_clks(hpriv);
-disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
return rc;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 0071d0b..5e5f85e 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -33,5 +33,7 @@ struct ahci_platform_data {
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);
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 07/18] ahci-platform: "Library-ise" ahci_probe functionality
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
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.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_platform.c | 158 ++++++++++++++++++++++++------------------
include/linux/ahci_platform.h | 14 ++++
2 files changed, 106 insertions(+), 66 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 1cce7a2..b260ebe 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -150,60 +150,31 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
-static void ahci_put_clks(struct ahci_host_priv *hpriv)
-{
- int c;
-
- for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
- clk_put(hpriv->clks[c]);
-}
-
-static int ahci_probe(struct platform_device *pdev)
+struct ahci_host_priv *ahci_platform_get_resources(
+ 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);
- 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;
struct clk *clk;
- int i, irq, max_clk, n_ports, rc;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(dev, "no mmio space\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev, "no irq\n");
- return -EINVAL;
- }
-
- if (pdata && pdata->ata_port_info)
- pi = *pdata->ata_port_info;
+ int i, max_clk, rc;
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
dev_err(dev, "can't alloc ahci_host_priv\n");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- hpriv->flags |= (unsigned long)pi.private_data;
-
- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
+ 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");
+ return ERR_PTR(-EINVAL);
}
hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
if (IS_ERR(hpriv->target_pwr)) {
if (PTR_ERR(hpriv->target_pwr) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ return ERR_PTR(-EPROBE_DEFER);
hpriv->target_pwr = NULL;
}
@@ -223,27 +194,48 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
- rc = ahci_platform_enable_resources(hpriv);
- if (rc)
- goto free_clk;
+ return hpriv;
- /*
- * 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);
- if (rc)
- goto disable_resources;
- }
+free_clk:
+ while (--i >= 0)
+ clk_put(hpriv->clks[i]);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+void ahci_platform_put_resources(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_put_resources);
+
+
+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;
- ahci_save_initial_config(dev, hpriv,
- pdata ? pdata->force_port_map : 0,
- pdata ? pdata->mask_port_map : 0);
+ 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;
@@ -260,10 +252,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;
@@ -278,7 +268,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 */
@@ -292,13 +283,48 @@ 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);
+ 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)
+ goto put_resources;
+
+ /*
+ * 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);
+ if (rc)
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv,
+ &ahci_port_info[id ? id->driver_data : 0],
+ pdata ? pdata->force_port_map : 0,
+ pdata ? pdata->mask_port_map : 0);
if (rc)
goto pdata_exit;
@@ -308,8 +334,8 @@ pdata_exit:
pdata->exit(dev);
disable_resources:
ahci_platform_disable_resources(hpriv);
-free_clk:
- ahci_put_clks(hpriv);
+put_resources:
+ ahci_platform_put_resources(hpriv);
return rc;
}
@@ -323,7 +349,7 @@ static void ahci_host_stop(struct ata_host *host)
pdata->exit(dev);
ahci_platform_disable_resources(hpriv);
- ahci_put_clks(hpriv);
+ ahci_platform_put_resources(hpriv);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 5e5f85e..1dc7602 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -20,7 +20,13 @@
struct device;
struct ata_port_info;
struct ahci_host_priv;
+struct platform_device;
+/*
+ * Note ahci_platform_data is deprecated. New drivers which need to override
+ * any of these, should instead declare there 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, struct ahci_host_priv *hpriv);
void (*exit)(struct device *dev);
@@ -35,5 +41,13 @@ 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);
+void ahci_platform_put_resources(struct ahci_host_priv *hpriv);
+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);
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 08/18] ahci-platform: "Library-ise" suspend / resume functionality
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Split suspend / resume code into host suspend / resume functionality and
resource enable / disabling phases, and export the new suspend_ / resume_host
functions.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_platform.c | 55 +++++++++++++++++++++++++++++++------------
include/linux/ahci_platform.h | 5 ++++
2 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index b260ebe..ba93930 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -353,14 +353,12 @@ static void ahci_host_stop(struct ata_host *host)
}
#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
+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");
@@ -377,7 +375,37 @@ 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);
+
+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);
+
+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;
@@ -388,8 +416,9 @@ static int ahci_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
-static int ahci_resume(struct device *dev)
+int ahci_platform_resume(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
@@ -406,15 +435,9 @@ static int ahci_resume(struct device *dev)
goto disable_resources;
}
- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
- if (rc)
- goto disable_resources;
-
- ahci_init_controller(host);
- }
-
- ata_host_resume(host);
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
return 0;
@@ -423,9 +446,11 @@ disable_resources:
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/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 1dc7602..7c683c7 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -50,4 +50,9 @@ int ahci_platform_init_host(struct platform_device *pdev,
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 */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 09/18] ARM: sunxi: Add support for Allwinner SUNXi SoCs sata to ahci_platform
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Olliver Schinagl <oliver-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
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-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/ata/ahci-platform.txt | 15 +-
drivers/ata/Kconfig | 9 +
drivers/ata/Makefile | 1 +
drivers/ata/ahci_sunxi.c | 251 +++++++++++++++++++++
4 files changed, 273 insertions(+), 3 deletions(-)
create mode 100644 drivers/ata/ahci_sunxi.c
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 1ac807f..499bfed 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,7 +4,9 @@ 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>
@@ -13,10 +15,17 @@ Optional properties:
- 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/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e73772..cc67cc0 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_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644
index 0000000..568a211
--- /dev/null
+++ b/drivers/ata/ahci_sunxi.c
@@ -0,0 +1,251 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
+ * Copyright 2014 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * 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-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org>
+ *
+ * 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);
+ mdelay(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));
+ mdelay(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);
+
+ mdelay(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)
+ goto put_resources;
+
+ 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);
+put_resources:
+ ahci_platform_put_resources(hpriv);
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+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-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>");
+MODULE_LICENSE("GPL");
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 10/18] ahci-imx: Port to library-ised ahci_platform
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
This avoids the ugliness of creating a nested platform device from probe.
While moving it around anyways, move the mk6q phy init code from probe
to imx_sata_enable, as the phy needs to be re-initialized on resume too,
otherwise the drive won't be recognized after resume.
Tested on a wandboard i.mx6 quad.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/ata/ahci-platform.txt | 9 +-
drivers/ata/ahci_imx.c | 338 ++++++++-------------
2 files changed, 141 insertions(+), 206 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 499bfed..d86e854 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -5,8 +5,9 @@ Each SATA controller should have its own node.
Required properties:
- compatible : compatible list, one of "snps,spear-ahci",
- "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
- "allwinner,sun4i-a10-ahci"
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+ "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci" or
+ "fsl,imx6q-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
@@ -15,6 +16,10 @@ Optional properties:
- clocks : a list of phandle + clock specifier pairs
- target-supply : regulator for SATA target power
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks : must contain the sata, sata_ref and ahb clocks
+- clock-names : must contain "ahb" for the ahb clock
+
Examples:
sata@ffe08000 {
compatible = "snps,spear-ahci";
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index ebfd1d6..7d51ee2 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -42,13 +42,7 @@ enum ahci_imx_type {
struct imx_ahci_priv {
struct platform_device *ahci_pdev;
enum ahci_imx_type type;
-
- /* i.MX53 clock */
- struct clk *sata_gate_clk;
- /* Common clock */
- struct clk *sata_ref_clk;
struct clk *ahb_clk;
-
struct regmap *gpr;
bool no_device;
bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret;
- if (imxpriv->type == AHCI_IMX53) {
- ret = clk_prepare_enable(imxpriv->sata_gate_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
- ret);
+ if (imxpriv->no_device)
+ return 0;
+
+ if (hpriv->target_pwr) {
+ ret = regulator_enable(hpriv->target_pwr);
+ if (ret)
return ret;
- }
}
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
- ret);
- goto clk_err;
- }
+ ret = ahci_platform_enable_clks(hpriv);
+ if (ret < 0)
+ goto disable_regulator;
if (imxpriv->type == AHCI_IMX6Q) {
+ /*
+ * set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07ffffff, and the other one write for setting
+ * the mpll_clk_en.
+ */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+ IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+ IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+ IMX6Q_GPR13_SATA_TX_LVL_MASK |
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+ IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+ IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+ IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+ IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
return 0;
-clk_err:
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return ret;
}
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ if (imxpriv->no_device)
+ return;
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
struct ata_host *host = dev_get_drvdata(ap->dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
ahci_error_handler(ap);
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
- imx_sata_clock_disable(ap->dev);
+ imx_sata_disable(hpriv);
imxpriv->no_device = true;
}
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct ata_host *host = dev_get_drvdata(ap->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret = -EIO;
if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
}
static struct ata_port_operations ahci_imx_ops = {
- .inherits = &ahci_platform_ops,
+ .inherits = &ahci_ops,
+ .host_stop = ahci_imx_host_stop,
.error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
};
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
-{
- int ret = 0;
- unsigned int reg_val;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- ret = imx_sata_clock_enable(dev);
- if (ret < 0)
- return ret;
-
- /*
- * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
- * and IP vendor specific register HOST_TIMER1MS.
- * Configure CAP_SSS (support stagered spin up).
- * Implement the port0.
- * Get the ahb clock rate, and configure the TIMER1MS register.
- */
- reg_val = readl(hpriv->mmio + HOST_CAP);
- if (!(reg_val & HOST_CAP_SSS)) {
- reg_val |= HOST_CAP_SSS;
- writel(reg_val, hpriv->mmio + HOST_CAP);
- }
- reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
- if (!(reg_val & 0x1)) {
- reg_val |= 0x1;
- writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
- }
-
- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
-
- return 0;
-}
-
-static void imx_sata_exit(struct device *dev)
-{
- imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- /*
- * If no_device is set, The CLKs had been gated off in the
- * initialization so don't do it again here.
- */
- if (!imxpriv->no_device)
- imx_sata_clock_disable(dev);
-
- return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
- int ret = 0;
-
- if (!imxpriv->no_device)
- ret = imx_sata_clock_enable(dev);
-
- return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
- .init = imx_sata_init,
- .exit = imx_sata_exit,
- .ata_port_info = &ahci_imx_port_info,
- .suspend = imx_ahci_suspend,
- .resume = imx_ahci_resume,
-
-};
-
static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,129 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct resource *mem, *irq, res[2];
const struct of_device_id *of_id;
- enum ahci_imx_type type;
- const struct ahci_platform_data *pdata = NULL;
+ struct ahci_host_priv *hpriv;
struct imx_ahci_priv *imxpriv;
- struct device *ahci_dev;
- struct platform_device *ahci_pdev;
+ unsigned int reg_val;
int ret;
of_id = of_match_device(imx_ahci_of_match, dev);
if (!of_id)
return -EINVAL;
- type = (enum ahci_imx_type)of_id->data;
- pdata = &imx_sata_pdata;
-
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- if (!imxpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
+ if (!imxpriv)
return -ENOMEM;
- }
-
- ahci_pdev = platform_device_alloc("ahci", -1);
- if (!ahci_pdev)
- return -ENODEV;
-
- ahci_dev = &ahci_pdev->dev;
- ahci_dev->parent = dev;
imxpriv->no_device = false;
imxpriv->first_time = true;
- imxpriv->type = type;
-
+ imxpriv->type = (enum ahci_imx_type)of_id->data;
imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
if (IS_ERR(imxpriv->ahb_clk)) {
dev_err(dev, "can't get ahb clock.\n");
- ret = PTR_ERR(imxpriv->ahb_clk);
- goto err_out;
+ return PTR_ERR(imxpriv->ahb_clk);
}
- if (type == AHCI_IMX53) {
- imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
- if (IS_ERR(imxpriv->sata_gate_clk)) {
- dev_err(dev, "can't get sata_gate clock.\n");
- ret = PTR_ERR(imxpriv->sata_gate_clk);
- goto err_out;
+ if (imxpriv->type == AHCI_IMX6Q) {
+ imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+ "fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev,
+ "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ return PTR_ERR(imxpriv->gpr);
}
}
- imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
- if (IS_ERR(imxpriv->sata_ref_clk)) {
- dev_err(dev, "can't get sata_ref clock.\n");
- ret = PTR_ERR(imxpriv->sata_ref_clk);
- goto err_out;
- }
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
- imxpriv->ahci_pdev = ahci_pdev;
- platform_set_drvdata(pdev, imxpriv);
+ hpriv->plat_data = imxpriv;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!mem || !irq) {
- dev_err(dev, "no mmio/irq resource\n");
- ret = -ENOMEM;
- goto err_out;
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ goto put_resources;
+
+ /*
+ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+ * and IP vendor specific register HOST_TIMER1MS.
+ * Configure CAP_SSS (support stagered spin up).
+ * Implement the port0.
+ * Get the ahb clock rate, and configure the TIMER1MS register.
+ */
+ reg_val = readl(hpriv->mmio + HOST_CAP);
+ if (!(reg_val & HOST_CAP_SSS)) {
+ reg_val |= HOST_CAP_SSS;
+ writel(reg_val, hpriv->mmio + HOST_CAP);
+ }
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+ if (!(reg_val & 0x1)) {
+ reg_val |= 0x1;
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- res[0] = *mem;
- res[1] = *irq;
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
- ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
- ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
- ahci_dev->of_node = dev->of_node;
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+ if (ret)
+ goto disable;
- if (type == AHCI_IMX6Q) {
- imxpriv->gpr = syscon_regmap_lookup_by_compatible(
- "fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- dev_err(dev,
- "failed to find fsl,imx6q-iomux-gpr regmap\n");
- ret = PTR_ERR(imxpriv->gpr);
- goto err_out;
- }
+ return 0;
- /*
- * Set PHY Paremeters, two steps to configure the GPR13,
- * one write for rest of parameters, mask of first write
- * is 0x07fffffe, and the other one write for setting
- * the mpll_clk_en happens in imx_sata_clock_enable().
- */
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
- IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
- IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
- IMX6Q_GPR13_SATA_SPD_MODE_MASK |
- IMX6Q_GPR13_SATA_MPLL_SS_EN |
- IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
- IMX6Q_GPR13_SATA_TX_BOOST_MASK |
- IMX6Q_GPR13_SATA_TX_LVL_MASK |
- IMX6Q_GPR13_SATA_MPLL_CLK_EN |
- IMX6Q_GPR13_SATA_TX_EDGE_RATE,
- IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
- IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- IMX6Q_GPR13_SATA_MPLL_SS_EN |
- IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
- IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
- IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- }
+disable:
+ imx_sata_disable(hpriv);
+put_resources:
+ ahci_platform_put_resources(hpriv);
+ return ret;
+}
- ret = platform_device_add_resources(ahci_pdev, res, 2);
- if (ret)
- goto err_out;
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
- if (ret)
- goto err_out;
+ imx_sata_disable(hpriv);
+ ahci_platform_put_resources(hpriv);
+}
+
+static int imx_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- ret = platform_device_add(ahci_pdev);
- if (ret) {
-err_out:
- platform_device_put(ahci_pdev);
+ ret = ahci_platform_suspend_host(dev);
+ if (ret)
return ret;
- }
+
+ imx_sata_disable(hpriv);
return 0;
}
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
- struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- platform_device_unregister(ahci_pdev);
- return 0;
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
+
+ return ahci_platform_resume_host(dev);
}
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
+
static struct platform_driver imx_ahci_driver = {
.probe = imx_ahci_probe,
- .remove = imx_ahci_remove,
+ .remove = ata_platform_remove_one,
.driver = {
.name = "ahci-imx",
.owner = THIS_MODULE,
.of_match_table = imx_ahci_of_match,
+ .pm = &ahci_imx_pm_ops,
},
};
module_platform_driver(imx_ahci_driver);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 11/18] ata: ahci_platform: Add DT compatible for Synopsis DWC AHCI controller
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Add compatible string "snps,dwc-ahci", which should be used
for Synopsis Designware SATA cores. e.g. on TI OMAP5 and DRA7 platforms.
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_platform.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index ba93930..962ec25 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -456,6 +456,7 @@ static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", },
{ .compatible = "snps,exynos5440-ahci", },
{ .compatible = "ibm,476gtr-ahci", },
+ { .compatible = "snps,dwc-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 12/18] ata: ahci_platform: Update DT compatible list
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
The ahci_platform driver supports "snps,dwc-ahci".
Add this to the DT binding information.
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
Documentation/devicetree/bindings/ata/ahci-platform.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index d86e854..48b285f 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -6,8 +6,8 @@ Each SATA controller should have its own node.
Required properties:
- compatible : compatible list, one of "snps,spear-ahci",
"snps,exynos5440-ahci", "ibm,476gtr-ahci",
- "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci" or
- "fsl,imx6q-ahci"
+ "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
+ "fsl,imx6q-ahci" or "snps,dwc-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 13/18] ata: ahci_platform: Manage SATA PHY
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Balaji T K, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
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.
CC: Balaji T K <balajitk-l0cyMroinI0@public.gmane.org>
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/Kconfig | 1 +
drivers/ata/ahci_platform.c | 40 ++++++++++++++++++++++++++++++++++++++++
include/linux/ahci.h | 2 ++
3 files changed, 43 insertions(+)
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index cc67cc0..96176f4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -91,6 +91,7 @@ config SATA_AHCI
config SATA_AHCI_PLATFORM
tristate "Platform AHCI SATA support"
+ depends on GENERIC_PHY || !GENERIC_PHY
help
This option enables support for Platform AHCI Serial ATA
controllers.
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 962ec25..073931a 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);
@@ -131,8 +132,23 @@ int ahci_platform_enable_resources(struct ahci_host_priv *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;
+ }
+ }
+
return 0;
+disable_clks:
+ ahci_platform_disable_clks(hpriv);
+
disable_regulator:
if (hpriv->target_pwr)
regulator_disable(hpriv->target_pwr);
@@ -142,6 +158,11 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
{
+ if (hpriv->phy) {
+ phy_power_off(hpriv->phy);
+ phy_exit(hpriv->phy);
+ }
+
ahci_platform_disable_clks(hpriv);
if (hpriv->target_pwr)
@@ -194,6 +215,25 @@ struct ahci_host_priv *ahci_platform_get_resources(
hpriv->clks[i] = 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 free_clk;
+
+ default:
+ dev_err(dev, "couldn't get sata-phy\n");
+ goto free_clk;
+ }
+ }
+
return hpriv;
free_clk:
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index ac69cdc..8fbe3d7 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -23,6 +23,7 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
+#include <linux/phy/phy.h>
#define AHCI_MAX_CLKS 3
@@ -42,6 +43,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
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 */
void (*start_engine)(struct ata_port *ap);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 14/18] ata: ahci_platform: Add 'struct device' argument to ahci_platform_put_resources()
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
There is no easy way to access 'struct device' from 'struct ahci_host_priv'
so add an explicit argument for 'struct device'. We will need it
to call Runtime PM APIs.
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_imx.c | 5 +++--
drivers/ata/ahci_platform.c | 7 ++++---
drivers/ata/ahci_sunxi.c | 2 +-
include/linux/ahci_platform.h | 3 ++-
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 7d51ee2..5cdaf0b 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -276,16 +276,17 @@ static int imx_ahci_probe(struct platform_device *pdev)
disable:
imx_sata_disable(hpriv);
put_resources:
- ahci_platform_put_resources(hpriv);
+ ahci_platform_put_resources(dev, hpriv);
return ret;
}
static void ahci_imx_host_stop(struct ata_host *host)
{
+ struct device *dev = host->dev;
struct ahci_host_priv *hpriv = host->private_data;
imx_sata_disable(hpriv);
- ahci_platform_put_resources(hpriv);
+ ahci_platform_put_resources(dev, hpriv);
}
static int imx_ahci_suspend(struct device *dev)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 073931a..f8ef780 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -243,7 +243,8 @@ free_clk:
}
EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
-void ahci_platform_put_resources(struct ahci_host_priv *hpriv)
+void ahci_platform_put_resources(struct device *dev,
+ struct ahci_host_priv *hpriv)
{
int c;
@@ -375,7 +376,7 @@ pdata_exit:
disable_resources:
ahci_platform_disable_resources(hpriv);
put_resources:
- ahci_platform_put_resources(hpriv);
+ ahci_platform_put_resources(dev, hpriv);
return rc;
}
@@ -389,7 +390,7 @@ static void ahci_host_stop(struct ata_host *host)
pdata->exit(dev);
ahci_platform_disable_resources(hpriv);
- ahci_platform_put_resources(hpriv);
+ ahci_platform_put_resources(dev, hpriv);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index 568a211..219d77f 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -194,7 +194,7 @@ static int ahci_sunxi_probe(struct platform_device *pdev)
disable_resources:
ahci_platform_disable_resources(hpriv);
put_resources:
- ahci_platform_put_resources(hpriv);
+ ahci_platform_put_resources(dev, hpriv);
return rc;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 7c683c7..719678c 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -43,7 +43,8 @@ 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);
-void ahci_platform_put_resources(struct ahci_host_priv *hpriv);
+void ahci_platform_put_resources(struct device *dev,
+ struct ahci_host_priv *hpriv);
int ahci_platform_init_host(struct platform_device *pdev,
struct ahci_host_priv *hpriv,
const struct ata_port_info *pi_template,
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 15/18] ata: ahci_platform: runtime resume the device before use
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Balaji T K, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
On OMAP platforms the device needs to be runtime resumed before
it can be accessed. The OMAP HWMOD framework takes care of
enabling the module and its resources based on the
device's runtime PM state.
In this patch we runtime resume during .probe() and runtime suspend
during .remove() (i.e. ahci_host_stop()).
We also update the runtime PM state during .resume().
CC: Balaji T K <balajitk-l0cyMroinI0@public.gmane.org>
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/ata/ahci_platform.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index f8ef780..bb2e7ab 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -24,6 +24,7 @@
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
#include "ahci.h"
static void ahci_host_stop(struct ata_host *host);
@@ -234,6 +235,9 @@ struct ahci_host_priv *ahci_platform_get_resources(
}
}
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
return hpriv;
free_clk:
@@ -248,6 +252,9 @@ void ahci_platform_put_resources(struct device *dev,
{
int c;
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
clk_put(hpriv->clks[c]);
}
@@ -480,6 +487,11 @@ int ahci_platform_resume(struct device *dev)
if (rc)
goto disable_resources;
+ /* We resumed so update PM runtime state */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
return 0;
disable_resources:
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 16/18] ARM: sun4i: dt: Remove grouping + simple-bus compatible for regulators
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
According to Documentation/devicetree/bindings/regulator/regulator.txt
regulator nodes should not be placed under 'simple-bus'.
Mark Rutland also explains about it at:
http://www.spinics.net/lists/linux-usb/msg101497.html
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/sun4i-a10-a1000.dts | 22 +++++++++-------------
arch/arm/boot/dts/sun4i-a10-hackberry.dts | 18 +++++++-----------
2 files changed, 16 insertions(+), 24 deletions(-)
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index d4b081d..cbd2e13 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -80,18 +80,14 @@
};
};
- regulators {
- compatible = "simple-bus";
-
- reg_emac_3v3: emac-3v3 {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&emac_power_pin_a1000>;
- regulator-name = "emac-3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- enable-active-high;
- gpio = <&pio 7 15 0>;
- };
+ reg_emac_3v3: emac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_power_pin_a1000>;
+ regulator-name = "emac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 15 0>;
};
};
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index 3a1595f..6692d336 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -54,16 +54,12 @@
};
};
- regulators {
- compatible = "simple-bus";
-
- reg_emac_3v3: emac-3v3 {
- compatible = "regulator-fixed";
- regulator-name = "emac-3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- enable-active-high;
- gpio = <&pio 7 19 0>;
- };
+ reg_emac_3v3: emac-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "emac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 19 0>;
};
};
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 17/18] ARM: sun4i: dt: Add ahci / sata support
From: Hans de Goede @ 2014-02-19 12:01 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Oliver Schinagl <oliver-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
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-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/sun4i-a10-a1000.dts | 4 ++++
arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 6 +++++
arch/arm/boot/dts/sun4i-a10.dtsi | 8 +++++++
arch/arm/boot/dts/sunxi-ahci-reg.dtsi | 36 ++++++++++++++++++++++++++++++
4 files changed, 54 insertions(+)
create mode 100644 arch/arm/boot/dts/sunxi-ahci-reg.dtsi
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index cbd2e13..d6ec839 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..6df237d8 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-ahci-reg.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";
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 336dbec..454077a 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -338,6 +338,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/sunxi-ahci-reg.dtsi b/arch/arm/boot/dts/sunxi-ahci-reg.dtsi
new file mode 100644
index 0000000..7072af1
--- /dev/null
+++ b/arch/arm/boot/dts/sunxi-ahci-reg.dtsi
@@ -0,0 +1,36 @@
+/*
+ * sunxi boards sata target power supply common code
+ *
+ * Copyright 2014 - Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ *
+ * 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>;
+ };
+ };
+ };
+
+ 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>;
+ };
+};
--
1.8.5.3
^ permalink raw reply related
* [PATCH v6 18/18] ARM: sun7i: dt: Add ahci / sata support
From: Hans de Goede @ 2014-02-19 12:02 UTC (permalink / raw)
To: Tejun Heo, Maxime Ripard
Cc: Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede
In-Reply-To: <1392811320-3132-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
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-dxLnbx3+1qmEVqv0pETR8A@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 6 ++++++
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 18 ++++++++++++++++++
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 6 ++++++
arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
4 files changed, 38 insertions(+)
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 7bf4935..07823c2 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -13,12 +13,18 @@
/dts-v1/;
/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Cubietech Cubieboard2";
compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
soc@01c00000 {
+ ahci: sata@01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl@01c20800 {
led_pins_cubieboard2: led_pins@0 {
allwinner,pins = "PH20", "PH21";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 025ce52..403bd2e 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-ahci-reg.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";
@@ -90,4 +103,9 @@
gpios = <&pio 7 7 0>;
};
};
+
+ reg_ahci_5v: ahci-5v {
+ pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
+ gpio = <&pio 7 12 0>;
+ };
};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index b02a796..d5c6799 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -13,12 +13,18 @@
/dts-v1/;
/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Olimex A20-Olinuxino Micro";
compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
soc@01c00000 {
+ ahci: sata@01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl@01c20800 {
led_pins_olinuxino: led_pins@0 {
allwinner,pins = "PH2";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index daaafd0..3385994 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -392,6 +392,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>;
--
1.8.5.3
^ permalink raw reply related
* Re: [PATCH v2] ARM/dts: hdmi-codec: panda/es dt entries
From: Peter Ujfalusi @ 2014-02-19 12:13 UTC (permalink / raw)
To: Paolo Pisati
Cc: Paolo Pisati, bcousson, tony, devicetree, linux-omap,
Valkeinen, Tomi, Sarha, Jyri
In-Reply-To: <20140219105434.GA5738@luxor.wired.org>
On 02/19/2014 12:54 PM, Paolo Pisati wrote:
> On Wed, Feb 19, 2014 at 10:15:24AM +0200, Peter Ujfalusi wrote:
>>> diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
>>> index 88c6a05..f4aeaa1 100644
>>> --- a/arch/arm/boot/dts/omap4-panda-common.dtsi
>>> +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
>>> @@ -36,9 +36,15 @@
>>> };
>>> };
>>>
>>> + hdmi_audio: hdmi_audio@0 {
>>> + compatible = "linux,hdmi-audio";
>>> + status = "okay";
>>> + };
>>> +
>>> sound: sound {
>>> compatible = "ti,abe-twl6040";
>>> ti,model = "PandaBoard";
>>> + ti,audio-codec = <&hdmi_audio>;
>>
>> I don't think this is going to work. The omap-abe-twl6040 machine driver only
>> handles mcpdm and dmic right know.
>> 'ti,audio-codec' is not even supported and it is kind of misleading naming in
>> this context since twl6040 is also a codec, so why only the dummy-hdmi codec
>> deserves to be called as codec.
>
> i see what you mean: i thought that hdmi_audio to actually work had to be
> referenced inside the sound node (hence my inclusion there) but i was wrong and
> it had nothing to do with twl6040,
> would this one be ok for you?
>
> diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
> index 88c6a05..b6dd458 100644
> --- a/arch/arm/boot/dts/omap4-panda-common.dtsi
> +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
> @@ -36,6 +36,11 @@
> };
> };
>
> + hdmi_audio: hdmi_audio@0 {
> + compatible = "linux,hdmi-audio";
> + status = "okay";
> + };
> +
> sound: sound {
> compatible = "ti,abe-twl6040";
> ti,model = "PandaBoard";
>
>
>> Furthermore: we have the omap-hdmi-card machine driver to handle the HDMI
>> audio. It lacks DT support AFAIK but should not be a big deal to add the bindings.
>> To get the hdmi audio working you also need to have phandle for the omap-hdmi
>> DAI, the codec alone is not enough.
>>
>
> you mean sound/soc/omap/omap-hdmi-card.c? that's exactly what i'm trying to fix.
>
> With the above patch, plus:
>
> -CONFIG_DISPLAY_CONNECTOR_HDMI=m
> +CONFIG_DISPLAY_CONNECTOR_HDMI=y
> CONFIG_DISPLAY_ENCODER_TFP410=m
> -CONFIG_DISPLAY_ENCODER_TPD12S015=m
> +CONFIG_DISPLAY_ENCODER_TPD12S015=y
>
> to make the omap-hdmi-audio-dai attach (sound/soc/omap/omap-hdmi.c)
> and something like this (that is not upstreamable as i understand
> but is an unfortunate fallout from the board removal[*]):
>
> --- a/arch/arm/mach-omap2/devices.c
> +++ b/arch/arm/mach-omap2/devices.c
> @@ -335,6 +335,11 @@ static struct platform_device omap_hdmi_audio = {
> .id = -1,
> };
>
> +static struct platform_device hdmi_audio_codec = {
> + .name = "hdmi-audio-codec",
> + .id = -1,
> +};
> +
> static void __init omap_init_hdmi_audio(void)
> {
> struct omap_hwmod *oh;
> @@ -349,6 +354,7 @@ static void __init omap_init_hdmi_audio(void)
> "Can't build omap_device for omap-hdmi-audio-dai.\n");
>
> platform_device_register(&omap_hdmi_audio);
> + platform_device_register(&hdmi_audio_codec);
> }
> #else
> static inline void omap_init_hdmi_audio(void) {}
>
> i finally get my OMAPHDMI device back:
>
> flag@panda:~$ cat /proc/asound/cards
> 0 [OMAPHDMI ]: OMAPHDMI - OMAPHDMI
> OMAPHDMI
> 1 [PandaBoardES ]: PandaBoardES - PandaBoardES
> PandaBoardES
>
Yeah, the OMAP4 hdmi audio got hit by the move to DT hard. In legacy boot we
did created the needed devices for us to use but we still lack the DT support
for the HDMI audio (along with the DSS AFAIK).
The stack we have at the moment going to change for sure. I need to sync up
with Tomi and Jyri regarding to this but right now there's no clean (ie
upstreamable ) way to enable HDMI audio.
--
Péter
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v7 4/8] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
From: Hans de Goede @ 2014-02-19 12:14 UTC (permalink / raw)
To: Maxime Ripard
Cc: David Lanzendörfer, devicetree-u79uwXL29TY76Z2rM5mHXA,
Ulf Hansson, Laurent Pinchart, Mike Turquette, Simon Baatz,
Emilio López, linux-mmc-u79uwXL29TY76Z2rM5mHXA, Chris Ball,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, H Hartley Sweeten,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Tejun Heo,
Guennadi Liakhovetski,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20140219094615.GT3142@lukather>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
On 02/19/2014 10:46 AM, Maxime Ripard wrote:
> Hi Hans,
>
> On Tue, Feb 18, 2014 at 09:49:21PM +0100, Hans de Goede wrote:
>> Hi,
>>
>> On 02/18/2014 04:37 PM, Maxime Ripard wrote:
>>
>> <snip>
>>
>>>> + + for (i = 0; i < data->sg_len; i++) { + pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN | + SDXC_IDMAC_DES0_DIC; + + if (data->sg[i].length == max_len) + pdes[i].buf_size = 0; /* 0 == max_len */ + else + pdes[i].buf_size = data->sg[i].length; + + pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]); + pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1]; + } + + pdes[0].config |= SDXC_IDMAC_DES0_FD; + pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD; + + wmb(); /* Ensure idma_des hit main mem before we start the idmac */
>>>
>>> wmb ensure the proper ordering of the instructions, not flushing the caches like what your comment implies.
>>
>> Since I put that comment there, allow me to explain. A modern ARM cpu core has 2 or more units handling stores. One for regular memory stores, and one for io-mem stores. Regular mem stores can be re-ordered, io stores cannot. Normally there is no "syncing" between the 2 store units. Cache flushing is not an issue here since the memory holding the descriptors for the idma controller is allocated cache coherent, which on arm means it is not cached.
>>
>> What is an issue here is the io-store starting the idmac hitting the io-mem before the descriptors hit the main-mem, the wmb() ensures this does not happen.
>
> To expand a bit, my point was not that it was functionnally wrong. Since you put a barrier in there, and that it resides in a cache coherent section, we're fine.
>
> My point was that the comment itself was misleading.
Well as explained above, the purpose of the wmb is to ensure that
the descriptors hit main memory, before the following writel (in the
caller of this function) starts the controller. So I don't see exactly
how the comment is wrong.
If you've a better wording for the comment, suggestions are welcome.
<snip>
>>>> +static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host) +{ + struct mmc_command *cmd = smc_host->mrq->cmd; + struct mmc_data *data = smc_host->mrq->data; + + /* For some cmds timeout is normal with sd/mmc cards */ + if ((smc_host->int_sum & SDXC_INTERRUPT_ERROR_BIT) == SDXC_RESP_TIMEOUT && + (cmd->opcode == SD_IO_SEND_OP_COND || cmd->opcode == SD_IO_RW_DIRECT)) + return; + + dev_err(mmc_dev(smc_host->mmc),
>>>
>>> I'd rather put it at a debug loglevel.
>>
>> Erm, this only happens if something is seriously wrong.
>
> Still. Something would be seriously wrong in the MMC driver/controller. You don't want to bloat the whole kernel logs with the dump of your registers just because the MMC is failing. This is of no interest to anyone but someone that would actually try to debug what's wrong.
This is not a complete register dump, this writes a single line to the
kernel log saying that an io error happened, and printing the error flags
set in the status register. We cannot be much shorter then this without
simply not notifying the user that an io error has happened, and not
notifying the user is wrong IMHO.
>
>>>> + /* Make sure the controller is in a sane state before enabling irqs */ + ret = sunxi_mmc_init_host(host->mmc); + if (ret) + return ret; + + host->irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0, + "sunxi-mmc", host); + if (ret == 0) + disable_irq(host->irq);
>>>
>>> The disable_irq is useless here. Just exit.
>>
>> No it is not note the ret == 0, this is not an error handling path!
>
> Doh... Right. My bad.
>
>> This is done under an if because we want to do the sunxi_mmc_exit_host regardless of the request_irq succeeding or not.
>>
>>>
>>>> + + /* And put it back in reset */ + sunxi_mmc_exit_host(host);
>>>
>>> Hu? If it's in reset, how can it generate some IRQs?
>>
>> Yes, that is why we do the whole dance of init controller, get irq, disable irq, drop it back in reset (until the mmc subsys does a power on of the mmc card / sdio dev).
>>
>> Sometime the controller asserts the irq in reset for some reason, so without the dance as soon as we do the devm_request_irq we get an irq, and worse, not only do we get an irq, we cannot clear it since writing to the interrupt status register does not work when the controller is in reset, so we get stuck re-entering the irq handler.
>
> Hmmm, I see. It probably deserves some commenting here too then.
This call is the mirror of the sunxi_mmc_init_host a few lines higher, which
has this comment:
/* Make sure the controller is in a sane state before enabling irqs */
Which attempts to explain why we do the init controller, claim irq,
disable irq, put controller back in reset sequence. Again suggestions
for a better comment are welcome.
<snip>
>>>> + ret = mmc_add_host(mmc); + + if (ret) + goto error_free_dma; + + dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq); + platform_set_drvdata(pdev, mmc);
>>>
>>> This should be before the registration. Otherwise, you're racy.
>>
>> Nope, we only need this to get the data on sunxi_mmc_remove, everywhere else the data is found through the mmc-host struct.
>
> Still, if anyone makes a following patch using the platform_device for some reason, we will have a race condition, without any way to notice it.
>
> Plus, you're doing all the other bits of initialization of your structures much earlier, why not be consistent and having all of them at the same place?
Most platform drivers I've worked on do platform_set_drvdata as late as possible,
so that the drvdata does not get set and never cleared in error paths.
This is just following that pattern.
Regards,
Hans
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iEYEARECAAYFAlMEoDYACgkQF3VEtJrzE/uAggCdGpdcz1Nli6JREPcUcGww7wXk
r4QAoIZfwy2e5GkHjQvrdpz0aT62x9/W
=y0wO
-----END PGP SIGNATURE-----
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/groups/opt_out.
^ permalink raw reply
* Re: [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Roger Quadros @ 2014-02-19 12:37 UTC (permalink / raw)
To: Kishon Vijay Abraham I, Heikki Krogerus, Felipe Balbi
Cc: george.cherian-l0cyMroinI0, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <52FB42DE.4090203-l0cyMroinI0@public.gmane.org>
Hi,
On 02/12/2014 11:46 AM, Kishon Vijay Abraham I wrote:
> On Wednesday 29 January 2014 08:17 PM, Heikki Krogerus wrote:
>> Hi,
>>
>> On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
>>> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
>>>> On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
>>>> For the controller drivers the PHYs are just a resource like any
>>>> other. The controller drivers can't have any responsibility of
>>>> them. They should not care if PHY drivers are available for them or
>>>> not, or even if the PHY framework is available or not.
>>>
>>> huh? If memory isn't available you don't continue probing, right ? If
>>> your IORESOURCE_MEM is missing, you also don't continue probing, if your
>>> IRQ line is missing, you bail too. Those are also nothing but resources
>>> to the driver, what you're asking here is to treat PHY as a _different_
>>> resource; which might be fine, but we need to make sure we don't
>>> continue probing when a PHY is missing in a platform that certainly
>>> needs a PHY.
>>
>> Yes, true. In my head I was comparing the PHY only to resources like
>> gpios, clocks, dma channels, etc. that are often optional to the
>> drivers.
>>
>>>>>>> But I really want to see the argument against using no-op. As far as I
>>>>>>> could see, everybody needs a PHY driver one way or another, some
>>>>>>> platforms just haven't sent any PHY driver upstream and have their own
>>>>>>> hacked up solution to avoid using the PHY layer.
>>>>>>
>>>>>> Not true in our case. Platforms using Intel's SoCs and chip sets may
>>>>>> or may not have controllable USB PHY. Quite often they don't. The
>>>>>> Baytrails have usually ULPI PHY for USB2, but that does not mean they
>>>>>> provide any vendor specific functions or any need for a driver in any
>>>>>> case.
>>>>>
>>>>> that's different from what I heard.
>>>>
>>>> I don't know where you got that impression, but it's not true. The
>>>> Baytrail SoCs for example don't have internal USB PHYs, which means
>>>> the manufacturers using it can select what they want. So we have
>>>> boards where PHY driver(s) is needed and boards where it isn't.
>>>
>>> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
>>> You have an external PIPE3 interface ? That's quite an achievement,
>>> kudos to your HW designers. Getting timing closure on PIPE3 is a
>>> difficult task.
>>
>> No, only the USB2 PHY is external. I'm giving you wrong information,
>> I'm sorry about that. Need to concentrate on what I'm writing.
>>
>> <snip>
>>
>>>> This is really good to get. We have some projects where we are dealing
>>>> with more embedded environments, like IVI, where the kernel should be
>>>> stripped of everything useless. Since the PHYs are autonomous, we
>>>> should be able to disable the PHY libraries/frameworks.
>>>
>>> hmmm, in that case it's a lot easier to treat. We can use
>>> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
>>> something like that.
>>>
>>> The difficult is really reliably supporting e.g. OMAP5 (which won't work
>>> without a PHY) and your BayTrail with autonomous PHYs. What can we use
>>> as an indication ?
>>
>> OMAP has it's own glue driver, so shouldn't it depend on the PHY
>> layer?
>
> right, but the PHY is connected to the dwc3 core and not to the glue.
>>
>>> I mean, I need to know that a particular platform depends on a PHY
>>> driver before I decide to return -EPROBE_DEFER or just assume the PHY
>>> isn't needed ;-)
>>
>> I don't think dwc3 (core) should care about that. The PHY layer needs
>> to tell us that. If the PHY driver that the platform depends is not
>> available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
>> returning -EPROBE_DEFER.
>
> I don't think the PHY layer can 'reliably' tell if PHY driver is available or
> not. Consider when the phy_provider_register fails, there is no way to know if
> PHY driver is available or not. There are a few cases where PHY layer returns
> -EPROBE_DEFER but none of them can tell for sure that PHY driver is either
> available and failed or not available at all. It would be best for us to leave
> that to the platforms if we want to be sure if the platform needs a PHY or not.
>
Just to summarize this thread on what we need
1) dwc3 core shouldn't worry about platform specific stuff i.e. PHY needed or not.
It should be as generic as possible.
2) dwc3 core should continue probe even if PHY layer is not enabled, as not all platforms need it.
3) dwc3 core should continue probe if PHY device is not available. (-ENODEV?)
4) dwc3 core should error out on any error condition if PHY device is available and caused some error,
e.g. init error.
5) dwc3 core should return EPROBE_DEFER if PHY device is available but device driver is not yet loaded.
6) platform glue should do the necessary sanity checks for availability of all resources like PHY device, PHY layer, etc, before populating the dwc3 device. e.g. in OMAP5 case we could check if both usb2 and usb3 PHY
nodes are available in the DT and PHY layer is enabled, from dwc3-omap.c? In J6 case we could check that at least usb2 phy node is there for the High-Speed only controller, and so on.
Let us first agree on the requirements and then we can think about implementation.
cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 3/6] drivers: of: implement reserved-memory handling for dma
From: Marek Szyprowski @ 2014-02-19 12:39 UTC (permalink / raw)
To: Grant Likely, linux-kernel, linux-arm-kernel, linaro-mm-sig,
devicetree, linux-doc
Cc: Kyungmin Park, Benjamin Herrenschmidt, Arnd Bergmann,
Michal Nazarewicz, Tomasz Figa, Sascha Hauer, Laura Abbott,
Rob Herring, Olof Johansson, Pawel Moll, Mark Rutland,
Stephen Warren, Ian Campbell, Tomasz Figa, Kumar Gala,
Nishanth Peethambaran, Marc, Josh Cartwright
In-Reply-To: <20140218165815.C7661C40517@trevor.secretlab.ca>
Hello,
On 2014-02-18 17:58, Grant Likely wrote:
> On Tue, 18 Feb 2014 14:37:58 +0100, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> > From: Josh Cartwright <joshc@codeaurora.org>
> >
> > Add support for handling 'shared-dma-pool' reserved-memory nodes using
> > dma exclusive driver (dma_alloc_coherent()).
> >
> > Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > ---
> > drivers/of/Kconfig | 7 ++++
> > drivers/of/Makefile | 1 +
> > drivers/of/of_reserved_mem_dma.c | 65 ++++++++++++++++++++++++++++++++++++++
>
> I don't see any reason to have this separate from of_reserved_mem.c
Some architectures don't have support for dma_declare_coherent_memory()
(CONFIG_HAVE_GENERIC_DMA_COHERENT), good examples are arc, c6x, metag
and extensa.
This code will not work for them.
> > 3 files changed, 73 insertions(+)
> > create mode 100644 drivers/of/of_reserved_mem_dma.c
> >
> > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> > index f25931dfc6db..7f00b801bcd2 100644
> > --- a/drivers/of/Kconfig
> > +++ b/drivers/of/Kconfig
> > @@ -80,4 +80,11 @@ config OF_RESERVED_MEM
> > help
> > Helpers to allow for reservation of memory regions
> >
> > +config OF_RESERVED_MEM_DMA
> > + depends on OF_RESERVED_MEM
> > + depends on HAVE_GENERIC_DMA_COHERENT
> > + def_bool y
> > + help
> > + Helpers for reserving memory regions for DMA use
> > +
> > endmenu # OF
> > diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> > index ed9660adad77..6142227ca854 100644
> > --- a/drivers/of/Makefile
> > +++ b/drivers/of/Makefile
> > @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_PCI) += of_pci.o
> > obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> > obj-$(CONFIG_OF_MTD) += of_mtd.o
> > obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
> > +obj-$(CONFIG_OF_RESERVED_MEM_DMA) += of_reserved_mem_dma.o
> > diff --git a/drivers/of/of_reserved_mem_dma.c b/drivers/of/of_reserved_mem_dma.c
> > new file mode 100644
> > index 000000000000..a3e596d1091d
> > --- /dev/null
> > +++ b/drivers/of/of_reserved_mem_dma.c
> > @@ -0,0 +1,65 @@
> > +/*
> > + * Device tree based initialization code for DMA reserved regions.
> > + *
> > + * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
> > + * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
> > + * http://www.samsung.com
> > + * Author: Marek Szyprowski <m.szyprowski@samsung.com>
> > + * Author: Josh Cartwright <joshc@codeaurora.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License as
> > + * published by the Free Software Foundation; either version 2 of the
> > + * License or (at your optional) any later version of the license.
> > + */
> > +#include <linux/memblock.h>
> > +#include <linux/err.h>
> > +#include <linux/of.h>
> > +#include <linux/of_fdt.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/mm.h>
> > +#include <linux/sizes.h>
> > +#include <linux/mm_types.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/of_reserved_mem.h>
> > +
> > +static void rmem_dma_device_init(struct reserved_mem *rmem,
> > + struct device *dev,
> > + struct of_phandle_args *args)
> > +{
> > + dma_declare_coherent_memory(dev, rmem->base, rmem->base,
> > + rmem->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
> > +}
> > +
> > +static void rmem_dma_device_release(struct reserved_mem *rmem,
> > + struct device *dev)
> > +{
> > + dma_release_declared_memory(dev);
> > +}
> > +
> > +static const struct reserved_mem_ops rmem_dma_ops = {
> > + .device_init = rmem_dma_device_init,
> > + .device_release = rmem_dma_device_release,
> > +};
> > +
> > +static int __init rmem_dma_setup(struct reserved_mem *rmem,
> > + unsigned long node,
> > + const char *uname)
> > +{
> > + int err;
> > +
> > + if (of_get_flat_dt_prop(node, "reusable", NULL))
> > + return -EINVAL;
> > +
> > + err = memblock_remove(rmem->base, rmem->size);
>
> Isn't the memblock_remove() now handled by the core code? Or am I
> mis-reading it?
I forgot to remove it...
> > + if (err == 0) {
> > + rmem->ops = &rmem_dma_ops;
> > + pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
> > + &rmem->base, (unsigned long)rmem->size / SZ_1M);
> > + } else {
> > + pr_err("Reserved memory: unable to setup '%s' memory region for DMA.\n",
> > + uname);
> > + }
> > + return err;
> > +}
> > +RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
> > --
> > 1.7.9.5
> >
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* [PATCH][v3] powerpc/fsl: Add/update miscellaneous missing binding
From: Harninder Rai @ 2014-02-19 12:41 UTC (permalink / raw)
To: scottwood-KZfg59tc24xl57MIdRCFDg,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ, Harninder Rai
Missing bindings were found on running checkpatch.pl on bsc9132
device tree. This patch add/update the following
- Add bindings for L2 cache controller
- Add bindings for memory controller
- Update bindings for USB controller
Signed-off-by: Harninder Rai <harninder.rai-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
* Changes in v3:
Incorporated Scott's comments
- Move cache-line-size property under required properties
- Update compatible for mem-ctrl to reflect "fsl,qoriq-memory-controller"
- One minor
* Changes since base version:
Incorporated Scott's comments
- Rename l2cc.txt to l2cache.txt
- Add information about ePAPR compliance
- Add missing "cache" in compatible
- Miscellaneous minors
.../devicetree/bindings/powerpc/fsl/l2cache.txt | 23 +++++++++++++++++
.../devicetree/bindings/powerpc/fsl/mem-ctrlr.txt | 27 ++++++++++++++++++++
Documentation/devicetree/bindings/usb/fsl-usb.txt | 4 ++-
3 files changed, 53 insertions(+), 1 deletions(-)
create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
new file mode 100644
index 0000000..c41b218
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
@@ -0,0 +1,23 @@
+Freescale L2 Cache Controller
+
+L2 cache is present in Freescale's QorIQ and QorIQ Qonverge platforms.
+The cache bindings explained below are ePAPR compliant
+
+Required Properties:
+
+- compatible : Should include "fsl,chip-l2-cache-controller" and "cache"
+ where chip is the processor (bsc9132, npc8572 etc.)
+- reg : Address and size of L2 cache controller registers
+- cache-size : Size of the entire L2 cache
+- interrupts : Error interrupt of L2 controller
+- cache-line-size : Size of L2 cache lines
+
+Example:
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,bsc9132-l2-cache-controller", "cache";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2,256K
+ interrupts = <16 2 1 0>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
new file mode 100644
index 0000000..f87856f
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
@@ -0,0 +1,27 @@
+Freescale DDR memory controller
+
+Properties:
+
+- compatible : Should include "fsl,chip-memory-controller" where
+ chip is the processor (bsc9132, mpc8572 etc.), or
+ "fsl,qoriq-memory-controller".
+- reg : Address and size of DDR controller registers
+- interrupts : Error interrupt of DDR controller
+
+Example 1:
+
+ memory-controller@2000 {
+ compatible = "fsl,bsc9132-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupts = <16 2 1 8>;
+ };
+
+
+Example 2:
+
+ ddr1: memory-controller@8000 {
+ compatible = "fsl,qoriq-memory-controller-v4.7",
+ "fsl,qoriq-memory-controller";
+ reg = <0x8000 0x1000>;
+ interrupts = <16 2 1 23>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/fsl-usb.txt b/Documentation/devicetree/bindings/usb/fsl-usb.txt
index bd5723f..4779c02 100644
--- a/Documentation/devicetree/bindings/usb/fsl-usb.txt
+++ b/Documentation/devicetree/bindings/usb/fsl-usb.txt
@@ -8,7 +8,9 @@ and additions :
Required properties :
- compatible : Should be "fsl-usb2-mph" for multi port host USB
controllers, or "fsl-usb2-dr" for dual role USB controllers
- or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
+ or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121.
+ Wherever applicable, the IP version of the USB controller should
+ also be mentioned (for eg. fsl-usb2-dr-v2.2 for bsc9132).
- phy_type : For multi port host USB controllers, should be one of
"ulpi", or "serial". For dual role USB controllers, should be
one of "ulpi", "utmi", "utmi_wide", or "serial".
--
1.7.6.GIT
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v3 2/4] of: reimplement the matching method for __of_match_node()
From: Grant Likely @ 2014-02-19 12:48 UTC (permalink / raw)
To: devicetree, linux-kernel; +Cc: Kevin Hao, Rob Herring, Sebastian Hesselbarth
In-Reply-To: <1392797745-7561-1-git-send-email-haokexin@gmail.com>
On Wed, 19 Feb 2014 16:15:45 +0800, Kevin Hao <haokexin@gmail.com> wrote:
> In the current implementation of __of_match_node(), it will compare
> each given match entry against all the node's compatible strings
> with of_device_is_compatible().
>
> To achieve multiple compatible strings per node with ordering from
> specific to generic, this requires given matches to be ordered from
> specific to generic. For most of the drivers this is not true and
> also an alphabetical ordering is more sane there.
>
> Therefore, we define a following priority order for the match, and
> then scan all the entries to find the best match.
> 1. specific compatible && type && name
> 2. specific compatible && type
> 3. specific compatible && name
> 4. specific compatible
> 5. general compatible && type && name
> 6. general compatible && type
> 7. general compatible && name
> 8. general compatible
> 9. type && name
> 10. type
> 11. name
>
> This is based on some pseudo-codes provided by Grant Likely.
>
> Signed-off-by: Kevin Hao <haokexin@gmail.com>
> [grant.likely: Changed multiplier to 4 which makes more sense]
> Signed-off-by: Grant Likely <grant.likely@linaro.org>
> ---
> v3: Also need to bail out when there does have a compatible member in match
> entry, but it doesn't match with the device node's compatible.
>
> v2: Fix the bug such as we get the same score for the following two match
> entries:
> name2 { }
>
> struct of_device_id matches[] = {
> {.name = "name2", },
> {.name = "name2", .type = "type1", },
> {}
> };
>
> drivers/of/base.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 77 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index ba195fbce4c6..8f79f006d86f 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -342,21 +342,28 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
> }
> EXPORT_SYMBOL(of_get_cpu_node);
>
> -/** Checks if the given "compat" string matches one of the strings in
> - * the device's "compatible" property
> +/*
> + * Compare with the __of_device_is_compatible, this will return a score for the
> + * matching strings. The smaller value indicates the match for the more specific
> + * compatible string.
> */
> -static int __of_device_is_compatible(const struct device_node *device,
> - const char *compat)
> +static int __of_device_is_compatible_score(const struct device_node *device,
> + const char *compat, int *pscore)
> {
> const char* cp;
> int cplen, l;
> + int score = 0;
>
> cp = __of_get_property(device, "compatible", &cplen);
> if (cp == NULL)
> return 0;
> while (cplen > 0) {
> - if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
> + score++;
> + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
> + if (pscore)
> + *pscore = score;
> return 1;
> + }
> l = strlen(cp) + 1;
> cp += l;
> cplen -= l;
> @@ -368,6 +375,15 @@ static int __of_device_is_compatible(const struct device_node *device,
> /** Checks if the given "compat" string matches one of the strings in
> * the device's "compatible" property
> */
> +static int __of_device_is_compatible(const struct device_node *device,
> + const char *compat)
> +{
> + return __of_device_is_compatible_score(device, compat, NULL);
> +}
> +
> +/** Checks if the given "compat" string matches one of the strings in
> + * the device's "compatible" property
> + */
> int of_device_is_compatible(const struct device_node *device,
> const char *compat)
> {
> @@ -734,25 +750,55 @@ static
> const struct of_device_id *__of_match_node(const struct of_device_id *matches,
> const struct device_node *node)
> {
> + const struct of_device_id *best_match = NULL;
> + int best_score = 0;
> +
> if (!matches)
> return NULL;
>
> while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
> - int match = 1;
> - if (matches->name[0])
> - match &= node->name
> - && !strcmp(matches->name, node->name);
> - if (matches->type[0])
> - match &= node->type
> - && !strcmp(matches->type, node->type);
> - if (matches->compatible[0])
> - match &= __of_device_is_compatible(node,
> - matches->compatible);
> - if (match)
> - return matches;
> + int score = 0;
> +
> + /*
> + * Matching compatible is better than matching type and name,
> + * and the specific compatible is better than the general.
> + */
> + if (matches->compatible[0]) {
> + if (__of_device_is_compatible_score(node,
> + matches->compatible, &score))
> + score = INT_MAX - 4 * score;
> + else
> + score = INT_MIN;
> + }
> +
> + /*
> + * Matching type is better than matching name, but matching
> + * both is even better than that.
> + */
> + if (matches->type[0]) {
> + if (node->type && !strcmp(matches->type, node->type))
> + score += 2;
> + else
> + score = INT_MIN;
> + }
> +
> + /* Matching name is a bit better than not */
> + if (matches->name[0]) {
> + if (node->name && !strcmp(matches->name, node->name))
> + score++;
> + else
> + score = INT_MIN;
> + }
All that mucking about with setting the score to INT_MIN is pretty ugly.
I've reworked the patch to 'continue;' whenever one of the above matches
fail. That completely eliminates any possibility of accepting an entry
that has a failed match. Here's my diff. I'll merge this change into the
patch before committing. All of the test cases still pass with my
rework.
---
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8f79f006d86f..fcb65d27d071 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -756,7 +756,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
if (!matches)
return NULL;
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
int score = 0;
/*
@@ -764,11 +764,10 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* and the specific compatible is better than the general.
*/
if (matches->compatible[0]) {
- if (__of_device_is_compatible_score(node,
+ if (!__of_device_is_compatible_score(node,
matches->compatible, &score))
- score = INT_MAX - 4 * score;
- else
- score = INT_MIN;
+ continue;
+ score = INT_MAX - 4 * score;
}
/*
@@ -776,26 +775,22 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* both is even better than that.
*/
if (matches->type[0]) {
- if (node->type && !strcmp(matches->type, node->type))
- score += 2;
- else
- score = INT_MIN;
+ if (!node->type || strcmp(matches->type, node->type))
+ continue;
+ score += 2;
}
/* Matching name is a bit better than not */
if (matches->name[0]) {
- if (node->name && !strcmp(matches->name, node->name))
- score++;
- else
- score = INT_MIN;
+ if (!node->name || strcmp(matches->name, node->name))
+ continue;
+ score++;
}
if (score > best_score) {
best_match = matches;
best_score = score;
}
-
- matches++;
}
return best_match;
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox