* [PATCH v5 0/3] add fec support for imx6q
From: Shawn Guo @ 2011-09-23 12:12 UTC (permalink / raw)
To: linux-arm-kernel
This series adds imx6q enet support. The imx6q enet is a derivative of
imx28 enet controller. It fixes the frame endian issue found on imx28,
and adds 1 Gbps support.
Changes since v4:
* Confirmed with design team that i.MX28 Reference Manual has an error
on MII_SPEED formula. FEC uses 'ref_freq / (MII_SPEED x 2)' while
ENET-MAC uses 'ref_freq / ((MII_SPEED + 1) x 2)', so that minus one
should really apply for just FEC_QUIRK_ENET_MAC.
Changes since v3:
* The minus one on phy_speed should happen before left shift.
Changes since v2:
* Refine patch #1 to get fec_reset_phy() return void
Changes since v1:
* Fix typo pointed out by Francois Romieu
* Drop patch #3 in the v1
* Rebase on net-next tree
Thanks.
Shawn Guo (3):
net/fec: fec_reset_phy() does not need to always succeed
net/fec: fix fec1 check in fec_enet_mii_init()
net/fec: add imx6q enet support
drivers/net/ethernet/freescale/Kconfig | 9 ++--
drivers/net/ethernet/freescale/fec.c | 81 +++++++++++++++++++++++---------
2 files changed, 63 insertions(+), 27 deletions(-)
^ permalink raw reply
* [PATCH v5 1/3] net/fec: fec_reset_phy() does not need to always succeed
From: Shawn Guo @ 2011-09-23 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316779968-21390-1-git-send-email-shawn.guo@linaro.org>
FEC can work without a phy reset on some platforms, which means not
very platform necessarily have a phy-reset gpio encoded in device tree.
Even on the platforms that have the gpio, FEC can work without
resetting phy for some cases, e.g. boot loader has done that.
So it makes more sense to have the phy-reset-gpio request failure as
a debug message rather than a warning, and get fec_reset_phy() return
void since the caller does not check the return anyway.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
drivers/net/ethernet/freescale/fec.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 158b82e..9c1d059 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -1411,24 +1411,22 @@ static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static int __devinit fec_reset_phy(struct platform_device *pdev)
+static void __devinit fec_reset_phy(struct platform_device *pdev)
{
int err, phy_reset;
struct device_node *np = pdev->dev.of_node;
if (!np)
- return -ENODEV;
+ return;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset");
if (err) {
- pr_warn("FEC: failed to get gpio phy-reset: %d\n", err);
- return err;
+ pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+ return;
}
msleep(1);
gpio_set_value(phy_reset, 1);
-
- return 0;
}
#else /* CONFIG_OF */
static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
@@ -1436,13 +1434,12 @@ static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
return -ENODEV;
}
-static inline int fec_reset_phy(struct platform_device *pdev)
+static inline void fec_reset_phy(struct platform_device *pdev)
{
/*
* In case of platform probe, the reset has been done
* by machine code.
*/
- return 0;
}
#endif /* CONFIG_OF */
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 2/3] net/fec: fix fec1 check in fec_enet_mii_init()
From: Shawn Guo @ 2011-09-23 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316779968-21390-1-git-send-email-shawn.guo@linaro.org>
In function fec_enet_mii_init(), it uses non-zero pdev->id as part
of the condition to check the second fec instance (fec1). This works
before the driver supports device tree probe. But in case of device
tree probe, pdev->id is -1 which is also non-zero, so the logic becomes
broken when device tree probe gets supported.
The patch change the logic to check "pdev->id > 0" as the part of the
condition for identifying fec1.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
drivers/net/ethernet/freescale/fec.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 9c1d059..2bbe6a5 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -996,7 +996,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* mdio interface in board design, and need to be configured by
* fec0 mii_bus.
*/
- if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id) {
+ if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) {
/* fec1 uses fec0 mii_bus */
fep->mii_bus = fec0_mii_bus;
return 0;
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 3/3] net/fec: add imx6q enet support
From: Shawn Guo @ 2011-09-23 12:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316779968-21390-1-git-send-email-shawn.guo@linaro.org>
The imx6q enet is a derivative of imx28 enet controller. It fixed
the frame endian issue found on imx28, and added 1 Gbps support.
It also fixes a typo on vendor name in Kconfig.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
drivers/net/ethernet/freescale/Kconfig | 9 ++--
drivers/net/ethernet/freescale/fec.c | 66 +++++++++++++++++++++++++------
2 files changed, 57 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 4dbe41f..1cf6716 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_FREESCALE
default y
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
- IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC || \
+ ARCH_MXC || ARCH_MXS || \
(PPC_MPC52xx && PPC_BESTCOMM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
@@ -16,16 +16,15 @@ config NET_VENDOR_FREESCALE
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
- the questions about IBM devices. If you say Y, you will be asked for
- your specific card in the following questions.
+ the questions about Freescale devices. If you say Y, you will be
+ asked for your specific card in the following questions.
if NET_VENDOR_FREESCALE
config FEC
bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
- IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC)
- default IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC if ARM
+ ARCH_MXC || ARCH_MXS)
select PHYLIB
---help---
Say Y here if you want to use the built-in 10/100 Fast ethernet
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 2bbe6a5..cce78ce 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -18,7 +18,7 @@
* Bug fixes and cleanup by Philippe De Muyter (phdm at macqel.be)
* Copyright (c) 2004-2006 Macq Electronique SA.
*
- * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
*/
#include <linux/module.h>
@@ -72,6 +72,8 @@
#define FEC_QUIRK_SWAP_FRAME (1 << 1)
/* Controller uses gasket */
#define FEC_QUIRK_USE_GASKET (1 << 2)
+/* Controller has GBIT support */
+#define FEC_QUIRK_HAS_GBIT (1 << 3)
static struct platform_device_id fec_devtype[] = {
{
@@ -88,6 +90,9 @@ static struct platform_device_id fec_devtype[] = {
.name = "imx28-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
}, {
+ .name = "imx6q-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
+ }, {
/* sentinel */
}
};
@@ -97,12 +102,14 @@ enum imx_fec_type {
IMX25_FEC = 1, /* runs on i.mx25/50/53 */
IMX27_FEC, /* runs on i.mx27/35/51 */
IMX28_FEC,
+ IMX6Q_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+ { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -373,6 +380,7 @@ fec_restart(struct net_device *ndev, int duplex)
int i;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
+ u32 ecntl = 0x2; /* ETHEREN */
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
@@ -442,18 +450,23 @@ fec_restart(struct net_device *ndev, int duplex)
/* Enable flow control and length check */
rcntl |= 0x40000000 | 0x00000020;
- /* MII or RMII */
- if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+ /* RGMII, RMII or MII */
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
+ rcntl |= (1 << 6);
+ else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
rcntl |= (1 << 8);
else
rcntl &= ~(1 << 8);
- /* 10M or 100M */
- if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
- rcntl &= ~(1 << 9);
- else
- rcntl |= (1 << 9);
-
+ /* 1G, 100M or 10M */
+ if (fep->phy_dev) {
+ if (fep->phy_dev->speed == SPEED_1000)
+ ecntl |= (1 << 5);
+ else if (fep->phy_dev->speed == SPEED_100)
+ rcntl &= ~(1 << 9);
+ else
+ rcntl |= (1 << 9);
+ }
} else {
#ifdef FEC_MIIGSK_ENR
if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
@@ -478,8 +491,15 @@ fec_restart(struct net_device *ndev, int duplex)
}
writel(rcntl, fep->hwp + FEC_R_CNTRL);
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ /* enable ENET endian swap */
+ ecntl |= (1 << 8);
+ /* enable ENET store and forward mode */
+ writel(1 << 8, fep->hwp + FEC_X_WMRK);
+ }
+
/* And last, enable the transmit and receive processing */
- writel(2, fep->hwp + FEC_ECNTRL);
+ writel(ecntl, fep->hwp + FEC_ECNTRL);
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
/* Enable interrupts we wish to service */
@@ -490,6 +510,8 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
@@ -504,6 +526,10 @@ fec_stop(struct net_device *ndev)
udelay(10);
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+
+ /* We have to keep ENET enabled to have MII interrupt stay working */
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ writel(2, fep->hwp + FEC_ECNTRL);
}
@@ -918,6 +944,8 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
@@ -949,14 +977,18 @@ static int fec_enet_mii_probe(struct net_device *ndev)
snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
+ fep->phy_interface);
if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
return PTR_ERR(phy_dev);
}
/* mask with MAC supported features */
- phy_dev->supported &= PHY_BASIC_FEATURES;
+ if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+ phy_dev->supported &= PHY_GBIT_FEATURES;
+ else
+ phy_dev->supported &= PHY_BASIC_FEATURES;
+
phy_dev->advertising = phy_dev->supported;
fep->phy_dev = phy_dev;
@@ -1006,8 +1038,16 @@ static int fec_enet_mii_init(struct platform_device *pdev)
/*
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
+ *
+ * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
+ * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
+ * Reference Manual has an error on this, and gets fixed on i.MX6Q
+ * document.
*/
- fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
+ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
+ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ fep->phy_speed--;
+ fep->phy_speed <<= 1;
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
fep->mii_bus = mdiobus_alloc();
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 1/3] AM35x: voltage: Basic initialization
From: Koyamangalath, Abhilash @ 2011-09-23 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <877h50p5w0.fsf@ti.com>
hi Kevin
On Fri, Sep 23, 2011 at 4:00 AM, Hilman, Kevin wrote:
> Hi Abhilash,
>
> Abhilash K V <abhilash.kv@ti.com> writes:
>
>> This patch adds the basic initialization of voltage layer
>> for AM35x. Since AM35x doesn't support voltage scaling,
>
> I must admit to still being confused by this series.
>
> This patch says AM35x doesn't support voltage scaling, and the next
> patch adds PMIC support, and registers it with the voltage layer.
>
> However, with each voltdm->scalable flag set to false, none of the PMIC
> values will ever be used (by the current voltage layer.) Do you have
> more patches on top of this that extend the voltage layer to directly
> use the PMIC instead of using VC or VP?
>
> I'm assuming we have some more assumptions in our current voltage layer
> about the presence of VC/VP that are wrong and need to be fixed. Now
> that the big voltage layer cleanup is done, I am *very* interested in
> getting rid of any more assumptions we have in that code about how
> devices are hooked up with PMICs.
>
> Can you summarize how these devices are using (or want to use) the
> voltage layer?
[Abhilash K V] Your concerns are grave and am trying to address most,
however these are the only points I can make outright:
- AM35x has just one voltage domain, so I tried having only one entry in
voltagedomains_omap3[ ] ( and calling it "mpu_core", maybe or "mpu" or "core" ?).
Either ways, some power-domain, say mpu_pwrdm would try looking for the "mpu_iva"
volt-domain and return error, this happens for most powerdomains as their constituent
volt-domains are hard-coded (and so unavailable on am35xx). Changing the code (which
will be massive) there going against our initial premise that am35xx is still a "type of"
omap3 SoC.
- TPS65023 PMIC code was originally included as a starting point to support a omap34xx
(with SR disabled maybe) with power supplied by a TPS65023. Yes,I agree that since
this looks more of like hypothetical scenario right now and so we can do
without the addition of file pmic_tps65023.c for now as it doesn't provide any support for
scaling.
-Abhilash
>
> Thanks,
>
> Kevin
>
>> Many functions have been defined to plug into existing
>> voltage layer.
>>
>> Signed-off-by: Sanjeev Premi <premi@ti.com>
>> Signed-off-by: Abhilash K V <abhilash.kv@ti.com>
>> ---
>> arch/arm/mach-omap2/omap_opp_data.h | 1 +
>> arch/arm/mach-omap2/opp3xxx_data.c | 9 +++++++++
>> arch/arm/mach-omap2/voltagedomains3xxx_data.c | 10 ++++++++--
>> 3 files changed, 18 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h
>> index c784c12..c7cedf3 100644
>> --- a/arch/arm/mach-omap2/omap_opp_data.h
>> +++ b/arch/arm/mach-omap2/omap_opp_data.h
>> @@ -88,6 +88,7 @@ extern struct omap_volt_data omap34xx_vddmpu_volt_data[];
>> extern struct omap_volt_data omap34xx_vddcore_volt_data[];
>> extern struct omap_volt_data omap36xx_vddmpu_volt_data[];
>> extern struct omap_volt_data omap36xx_vddcore_volt_data[];
>> +extern struct omap_volt_data am35xx_vdd_volt_data[];
>>
>> extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[];
>> extern struct omap_volt_data omap44xx_vdd_iva_volt_data[];
>> diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
>> index d95f3f9..e4a5ee6 100644
>> --- a/arch/arm/mach-omap2/opp3xxx_data.c
>> +++ b/arch/arm/mach-omap2/opp3xxx_data.c
>> @@ -85,6 +85,15 @@ struct omap_volt_data omap36xx_vddcore_volt_data[] = {
>> VOLT_DATA_DEFINE(0, 0, 0, 0),
>> };
>>
>> +/* AM35x
>> + *
>> + * Fields related to SmartReflex and Voltage Processor are set to 0.
>> + */
>
> fix multi-line comment style (search for 'multi-line' in Documentation/CodingStyle)
>
>> +struct omap_volt_data am35xx_vdd_volt_data[] = {
>> + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, 0x0, 0x0, 0x0),
>> + VOLT_DATA_DEFINE(0, 0, 0, 0),
>> +};
>> +
>> /* OPP data */
>>
>> static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
>> diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
>> index 071101d..530082f 100644
>> --- a/arch/arm/mach-omap2/voltagedomains3xxx_data.c
>> +++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
>> @@ -85,7 +85,10 @@ void __init omap3xxx_voltagedomains_init(void)
>> * XXX Will depend on the process, validation, and binning
>> * for the currently-running IC
>> */
>> - if (cpu_is_omap3630()) {
>> + if (cpu_is_omap3505() || cpu_is_omap3517()) {
>> + omap3_voltdm_mpu.volt_data = am35xx_vdd_volt_data;
>> + omap3_voltdm_core.volt_data = am35xx_vdd_volt_data;
>> + } else if (cpu_is_omap3630()) {
>> omap3_voltdm_mpu.volt_data = omap36xx_vddmpu_volt_data;
>> omap3_voltdm_core.volt_data = omap36xx_vddcore_volt_data;
>> } else {
>> @@ -93,8 +96,11 @@ void __init omap3xxx_voltagedomains_init(void)
>> omap3_voltdm_core.volt_data = omap34xx_vddcore_volt_data;
>> }
>>
>> - for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++)
>> + for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++) {
>> + if (cpu_is_omap3505() || cpu_is_omap3517())
>> + voltdm->scalable = false;
>> voltdm->sys_clk.name = sys_clk_name;
>> + }
>>
>> voltdm_init(voltagedomains_omap3);
>> };
>
________________________________________
From: Hilman, Kevin
Sent: Friday, September 23, 2011 4:00 AM
To: Koyamangalath, Abhilash
Cc: linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org; tony at atomide.com; linux at arm.linux.org.uk; sameo at linux.intel.com; Shilimkar, Santosh; Premi, Sanjeev; david.woodhouse at intel.com; christian.gmeiner at gmail.com
Subject: Re: [PATCH v3 1/3] AM35x: voltage: Basic initialization
Hi Abhilash,
Abhilash K V <abhilash.kv@ti.com> writes:
> This patch adds the basic initialization of voltage layer
> for AM35x. Since AM35x doesn't support voltage scaling,
I must admit to still being confused by this series.
This patch says AM35x doesn't support voltage scaling, and the next
patch adds PMIC support, and registers it with the voltage layer.
However, with each voltdm->scalable flag set to false, none of the PMIC
values will ever be used (by the current voltage layer.) Do you have
more patches on top of this that extend the voltage layer to directly
use the PMIC instead of using VC or VP?
I'm assuming we have some more assumptions in our current voltage layer
about the presence of VC/VP that are wrong and need to be fixed. Now
that the big voltage layer cleanup is done, I am *very* interested in
getting rid of any more assumptions we have in that code about how
devices are hooked up with PMICs.
Can you summarize how these devices are using (or want to use) the
voltage layer?
Thanks,
Kevin
> Many functions have been defined to plug into existing
> voltage layer.
>
> Signed-off-by: Sanjeev Premi <premi@ti.com>
> Signed-off-by: Abhilash K V <abhilash.kv@ti.com>
> ---
> arch/arm/mach-omap2/omap_opp_data.h | 1 +
> arch/arm/mach-omap2/opp3xxx_data.c | 9 +++++++++
> arch/arm/mach-omap2/voltagedomains3xxx_data.c | 10 ++++++++--
> 3 files changed, 18 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h
> index c784c12..c7cedf3 100644
> --- a/arch/arm/mach-omap2/omap_opp_data.h
> +++ b/arch/arm/mach-omap2/omap_opp_data.h
> @@ -88,6 +88,7 @@ extern struct omap_volt_data omap34xx_vddmpu_volt_data[];
> extern struct omap_volt_data omap34xx_vddcore_volt_data[];
> extern struct omap_volt_data omap36xx_vddmpu_volt_data[];
> extern struct omap_volt_data omap36xx_vddcore_volt_data[];
> +extern struct omap_volt_data am35xx_vdd_volt_data[];
>
> extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[];
> extern struct omap_volt_data omap44xx_vdd_iva_volt_data[];
> diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
> index d95f3f9..e4a5ee6 100644
> --- a/arch/arm/mach-omap2/opp3xxx_data.c
> +++ b/arch/arm/mach-omap2/opp3xxx_data.c
> @@ -85,6 +85,15 @@ struct omap_volt_data omap36xx_vddcore_volt_data[] = {
> VOLT_DATA_DEFINE(0, 0, 0, 0),
> };
>
> +/* AM35x
> + *
> + * Fields related to SmartReflex and Voltage Processor are set to 0.
> + */
fix multi-line comment style (search for 'multi-line' in Documentation/CodingStyle)
> +struct omap_volt_data am35xx_vdd_volt_data[] = {
> + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, 0x0, 0x0, 0x0),
> + VOLT_DATA_DEFINE(0, 0, 0, 0),
> +};
> +
> /* OPP data */
>
> static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
> diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
> index 071101d..530082f 100644
> --- a/arch/arm/mach-omap2/voltagedomains3xxx_data.c
> +++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
> @@ -85,7 +85,10 @@ void __init omap3xxx_voltagedomains_init(void)
> * XXX Will depend on the process, validation, and binning
> * for the currently-running IC
> */
> - if (cpu_is_omap3630()) {
> + if (cpu_is_omap3505() || cpu_is_omap3517()) {
> + omap3_voltdm_mpu.volt_data = am35xx_vdd_volt_data;
> + omap3_voltdm_core.volt_data = am35xx_vdd_volt_data;
> + } else if (cpu_is_omap3630()) {
> omap3_voltdm_mpu.volt_data = omap36xx_vddmpu_volt_data;
> omap3_voltdm_core.volt_data = omap36xx_vddcore_volt_data;
> } else {
> @@ -93,8 +96,11 @@ void __init omap3xxx_voltagedomains_init(void)
> omap3_voltdm_core.volt_data = omap34xx_vddcore_volt_data;
> }
>
> - for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++)
> + for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++) {
> + if (cpu_is_omap3505() || cpu_is_omap3517())
> + voltdm->scalable = false;
> voltdm->sys_clk.name = sys_clk_name;
> + }
>
> voltdm_init(voltagedomains_omap3);
> };
^ permalink raw reply
* [PATCHv9 00/18] omap PRCM chain handler
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
Following set contains the version 9 of this work. This patch set contains
a number of patches tagged as 'TEMP', they are only meant for testing
purposes and to provide proof of concept. Most of the 'TEMP' patches are
related to UART runtime handling and they will be replaced by work done
by Govindraj Raja.
As this is a new set sent to linux-arm and linux-kernel lists, the basic
concept being tackled with this set is to provide a mechanism for multiple
drivers to register for PRCM interrupts. PRCM interrupt contains a SoC
depenpend number of events, which of most interesting ones are wakeup and
IO chain. These are the only supported events in the driver currently, but
it is possible to add more by tweaking omap3xxx-prm.c and omap4xxx-prm.c
files.
This driver should also be expanded later to contain much of the code
currently included within the OMAP voltage framework, which resides under
arch/arm/mach-omap2/voltage*,vc*,vp*.
Changes compared to previous version of this set:
- PRM driver is now moved under /drivers/mfd
- PRM driver split into three parts now, common, omap3 and omap4
- version of the driver to init is detected based on PRM version (patch 11)
- cleaned up the initialization logic a bit (platform device is built
separately, provide two different drivers)
- renamed PRM hwmods as prm3xxx and prm4xxx
These patches have been tested on omap3 beagle and omap4 blaze platforms.
Tested features include suspend and dynamic idle.
Tested trees are available at:
git at gitorious.org:~kristo/omap-pm/omap-pm-work.git
branches: omap3_prcm_chain and omap4_prcm_chain
-Tero
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply
* [PATCHv9 01/18] OMAP2+: hwmod: Add API to enable IO ring wakeup.
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
From: R, Govindraj <govindraj.raja@ti.com>
Add API to enable IO pad wakeup capability based on mux dynamic pad and
wake_up enable flag available from hwmod_mux initialization.
Use the wakeup_enable flag and enable wakeup capability
for the given pads. Wakeup capability will be enabled/disabled
during hwmod idle transition based on whether wakeup_flag is
set or cleared.
Map the enable/disable pad wakeup API's to hwmod_wakeup_enable/disable.
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 59 ++++++++++++++++++++++++++++++++++++++
1 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 84cc0bd..e751dd9 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2062,6 +2062,34 @@ static int __init omap_hwmod_setup_all(void)
core_initcall(omap_hwmod_setup_all);
/**
+ * omap_hwmod_set_ioring_wakeup - enable io pad wakeup flag.
+ * @oh: struct omap_hwmod *
+ * @set: bool value indicating to set or clear wakeup status.
+ *
+ * Set or Clear wakeup flag for the io_pad.
+ */
+static int omap_hwmod_set_ioring_wakeup(struct omap_hwmod *oh, bool set_wake)
+{
+ struct omap_device_pad *pad;
+ int ret = -EINVAL, j;
+
+ if (oh->mux && oh->mux->enabled) {
+ for (j = 0; j < oh->mux->nr_pads_dynamic; j++) {
+ pad = oh->mux->pads_dynamic[j];
+ if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) {
+ if (set_wake)
+ pad->idle |= OMAP_WAKEUP_EN;
+ else
+ pad->idle &= ~OMAP_WAKEUP_EN;
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
* omap_hwmod_enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
@@ -2393,6 +2421,35 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
{
return _del_initiator_dep(oh, init_oh);
}
+/**
+ * omap_hwmod_enable_ioring_wakeup - Set wakeup flag for iopad.
+ * @oh: struct omap_hwmod *
+ *
+ * Traverse through dynamic pads, if pad is enabled then
+ * set wakeup enable bit flag for the mux pin. Wakeup pad bit
+ * will be set during hwmod idle transistion.
+ * Return error if pads are not enabled or not available.
+ */
+int omap_hwmod_enable_ioring_wakeup(struct omap_hwmod *oh)
+{
+ /* Enable pad wake-up capability */
+ return omap_hwmod_set_ioring_wakeup(oh, true);
+}
+
+/**
+ * omap_hwmod_disable_ioring_wakeup - Clear wakeup flag for iopad.
+ * @oh: struct omap_hwmod *
+ *
+ * Traverse through dynamic pads, if pad is enabled then
+ * clear wakeup enable bit flag for the mux pin. Wakeup pad bit
+ * will be set during hwmod idle transistion.
+ * Return error if pads are not enabled or not available.
+ */
+int omap_hwmod_disable_ioring_wakeup(struct omap_hwmod *oh)
+{
+ /* Disable pad wakeup capability */
+ return omap_hwmod_set_ioring_wakeup(oh, false);
+}
/**
* omap_hwmod_enable_wakeup - allow device to wake up the system
@@ -2419,6 +2476,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
v = oh->_sysc_cache;
_enable_wakeup(oh, &v);
_write_sysconfig(v, oh);
+ omap_hwmod_enable_ioring_wakeup(oh);
spin_unlock_irqrestore(&oh->_lock, flags);
return 0;
@@ -2449,6 +2507,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
v = oh->_sysc_cache;
_disable_wakeup(oh, &v);
_write_sysconfig(v, oh);
+ omap_hwmod_disable_ioring_wakeup(oh);
spin_unlock_irqrestore(&oh->_lock, flags);
return 0;
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 02/18] OMAP2+: hwmod: Add API to check IO PAD wakeup status
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
From: R, Govindraj <govindraj.raja@ti.com>
Add API to determine IO-PAD wakeup event status for a given
hwmod dynamic_mux pad.
Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/mach-omap2/mux.c | 30 ++++++++++++++++++++++++++
arch/arm/mach-omap2/mux.h | 13 +++++++++++
arch/arm/mach-omap2/omap_hwmod.c | 7 ++++++
arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 +
4 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index c7fb22a..50ee806 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -351,6 +351,36 @@ err1:
return NULL;
}
+/**
+ * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup
+ * @hmux: Pads for a hwmod
+ *
+ * Gets the wakeup status of given pad from omap-hwmod.
+ * Returns true if wakeup event is set for pad else false
+ * if wakeup is not occured or pads are not avialable.
+ */
+bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
+{
+ int i;
+ unsigned int val;
+ u8 ret = false;
+
+ for (i = 0; i < hmux->nr_pads; i++) {
+ struct omap_device_pad *pad = &hmux->pads[i];
+
+ if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) {
+ val = omap_mux_read(pad->partition,
+ pad->mux->reg_offset);
+ if (val & OMAP_WAKEUP_EVENT) {
+ ret = true;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
/* Assumes the calling function takes care of locking */
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
{
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 2132308..8b2150a 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -225,8 +225,21 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads);
*/
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state);
+/**
+ * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup
+ * @hmux: Pads for a hwmod
+ *
+ * Called only from omap_hwmod.c, do not use.
+ */
+bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux);
#else
+static inline bool
+omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
+{
+ return 0;
+}
+
static inline int omap_mux_init_gpio(int gpio, int val)
{
return 0;
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e751dd9..a8b24d7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2724,3 +2724,10 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
return 0;
}
+
+int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh)
+{
+ if (oh && oh->mux)
+ return omap_hwmod_mux_get_wake_status(oh->mux);
+ return -EINVAL;
+}
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 38ac4af..9c70cc8 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -606,6 +606,7 @@ u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
+int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh);
/*
* Chip variant-specific hwmod init routines - XXX should be converted
* to use initcalls once the initial boot ordering is straightened out
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 03/18] TEMP: OMAP3xxx: hwmod data: add PRM hwmod
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This patch is temporary until Paul can provide a final version.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 56 ++++++++++++++++++++++++++++
1 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 59fdb9f..26ced4f 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -161,6 +161,7 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
};
static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_prm_hwmod;
static struct omap_hwmod omap3xxx_uart1_hwmod;
static struct omap_hwmod omap3xxx_uart2_hwmod;
static struct omap_hwmod omap3xxx_uart3_hwmod;
@@ -478,6 +479,24 @@ static struct omap_hwmod omap3xxx_l4_per_hwmod = {
.flags = HWMOD_NO_IDLEST,
};
+static struct omap_hwmod_addr_space omap3xxx_prm_addrs[] = {
+ {
+ .pa_start = 0x48306000,
+ .pa_end = 0x48306000 + SZ_8K + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ {}
+};
+
+/* L4_WKUP -> PRM interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__prm = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_prm_hwmod,
+ .clk = "wkup_l4_ick",
+ .addr = omap3xxx_prm_addrs,
+ .user = OCP_USER_MPU,
+};
+
/* Slave interfaces on the L4_WKUP interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
&omap3xxx_l4_core__l4_wkup,
@@ -493,6 +512,40 @@ static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
.flags = HWMOD_NO_IDLEST,
};
+/* Slave interfaces on the L4_WKUP interconnect */
+static struct omap_hwmod_ocp_if *omap3xxx_prm_slaves[] = {
+ &omap3xxx_l4_wkup__prm,
+};
+
+static struct omap_hwmod_class_sysconfig omap3xxx_prm_sysc = {
+ .rev_offs = 0x0804,
+ .sysc_offs = 0x0814,
+ .sysc_flags = SYSC_HAS_AUTOIDLE,
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_prm_hwmod_class = {
+ .name = "prm",
+ .sysc = &omap3xxx_prm_sysc,
+};
+
+static struct omap_hwmod_irq_info omap3xxx_prm_irqs[] = {
+ { .irq = 11 },
+ { .irq = -1 }
+};
+
+/* PRM */
+static struct omap_hwmod omap3xxx_prm_hwmod = {
+ .name = "prm3xxx",
+ .mpu_irqs = omap3xxx_prm_irqs,
+ .class = &omap3xxx_prm_hwmod_class,
+ .main_clk = "wkup_32k_fck",
+ .slaves = omap3xxx_prm_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_prm_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ .flags = HWMOD_NO_IDLEST,
+};
+
/* Master interfaces on the MPU device */
static struct omap_hwmod_ocp_if *omap3xxx_mpu_masters[] = {
&omap3xxx_mpu__l3_main,
@@ -3201,6 +3254,9 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
&omap3xxx_l4_core_hwmod,
&omap3xxx_l4_per_hwmod,
&omap3xxx_l4_wkup_hwmod,
+
+ &omap3xxx_prm_hwmod,
+
&omap3xxx_mmc1_hwmod,
&omap3xxx_mmc2_hwmod,
&omap3xxx_mmc3_hwmod,
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 04/18] TEMP: OMAP4xxx: hwmod data: add PRM hwmod
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This patch is temporary until Benoit can provide final version.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Benoit Cousson <b-cousson@ti.com>
---
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 65 ++++++++++++++++++++++++++++
1 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6201422..c09bf4d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -3990,6 +3990,68 @@ static struct omap_hwmod omap44xx_mpu_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
+ /*
+ * 'prm' class
+ * power and reset manager (part of the prcm infrastructure)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_prm_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_flags = 0,
+};
+
+static struct omap_hwmod_class omap44xx_prm_hwmod_class = {
+ .name = "prm",
+ .sysc = &omap44xx_prm_sysc,
+};
+
+/* prm */
+static struct omap_hwmod omap44xx_prm_hwmod;
+static struct omap_hwmod_irq_info omap44xx_prm_irqs[] = {
+ { .irq = 11 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_prm_resets[] = {
+ { .name = "rst_global_warm_sw", .rst_shift = 0 },
+ { .name = "rst_global_cold_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_addr_space omap44xx_prm_addrs[] = {
+ {
+ .pa_start = 0x4a306000,
+ .pa_end = 0x4a307fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> prm */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__prm = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_prm_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_prm_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* prm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_prm_slaves[] = {
+ &omap44xx_l4_wkup__prm,
+};
+
+static struct omap_hwmod omap44xx_prm_hwmod = {
+ .name = "prm4xxx",
+ .class = &omap44xx_prm_hwmod_class,
+ .mpu_irqs = omap44xx_prm_irqs,
+ .clkdm_name = "l4_wkup_clkdm",
+ .rst_lines = omap44xx_prm_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap44xx_prm_resets),
+ .slaves = omap44xx_prm_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_prm_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
/*
* 'smartreflex' class
* smartreflex module (monitor silicon performance and outputs a measure of
@@ -5448,6 +5510,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
/* mpu class */
&omap44xx_mpu_hwmod,
+ /* prm class */
+ &omap44xx_prm_hwmod,
+
/* smartreflex class */
&omap44xx_smartreflex_core_hwmod,
&omap44xx_smartreflex_iva_hwmod,
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 05/18] mfd: omap-prm: add driver skeleton
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This driver will eventually support OMAP soc PRM module features, e.g. PRCM
chain interrupts and voltage processor / controller. This patch only adds
basic skeleton for the driver that can be probed for omap3 and omap4.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/Kconfig | 7 +++++
drivers/mfd/Makefile | 2 +
drivers/mfd/omap-prm-common.c | 24 ++++++++++++++++
drivers/mfd/omap3xxx-prm.c | 60 +++++++++++++++++++++++++++++++++++++++++
drivers/mfd/omap4xxx-prm.c | 60 +++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/omap-prm.h | 24 ++++++++++++++++
6 files changed, 177 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/omap-prm-common.c
create mode 100644 drivers/mfd/omap3xxx-prm.c
create mode 100644 drivers/mfd/omap4xxx-prm.c
create mode 100644 include/linux/mfd/omap-prm.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 21574bd..1ae2571 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -770,6 +770,13 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
+config OMAP_PRM
+ bool "OMAP Power and Reset Management driver"
+ depends on (ARCH_OMAP) && PM
+ help
+ Say Y to enable support for the OMAP Power and Reset Management
+ driver.
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c580203..503d85d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -102,3 +102,5 @@ obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
+obj-$(CONFIG_OMAP_PRM) += omap-prm-common.o omap3xxx-prm.o \
+ omap4xxx-prm.o
diff --git a/drivers/mfd/omap-prm-common.c b/drivers/mfd/omap-prm-common.c
new file mode 100644
index 0000000..39b199c8
--- /dev/null
+++ b/drivers/mfd/omap-prm-common.c
@@ -0,0 +1,24 @@
+/*
+ * OMAP Power and Reset Management (PRM) driver common functionality
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Author: Tero Kristo <t-kristo@ti.com>
+ *
+ * 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 option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
+MODULE_DESCRIPTION("OMAP PRM core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/omap3xxx-prm.c b/drivers/mfd/omap3xxx-prm.c
new file mode 100644
index 0000000..177aced
--- /dev/null
+++ b/drivers/mfd/omap3xxx-prm.c
@@ -0,0 +1,60 @@
+/*
+ * OMAP Power and Reset Management (PRM) driver for OMAP3xxx
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Author: Tero Kristo <t-kristo@ti.com>
+ *
+ * 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 option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/omap-prm.h>
+
+#define DRIVER_NAME "prm3xxx"
+
+static int __devinit omap3xxx_prm_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __devexit omap3xxx_prm_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver omap3xxx_prm_driver = {
+ .probe = omap3xxx_prm_probe,
+ .remove = __devexit_p(omap3xxx_prm_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init omap3xxx_prm_init(void)
+{
+ return platform_driver_register(&omap3xxx_prm_driver);
+}
+module_init(omap3xxx_prm_init);
+
+static void __exit omap3xxx_prm_exit(void)
+{
+ platform_driver_unregister(&omap3xxx_prm_driver);
+}
+module_exit(omap3xxx_prm_exit);
+
+MODULE_ALIAS("platform:"DRIVER_NAME);
+MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
+MODULE_DESCRIPTION("OMAP3xxx PRM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/omap4xxx-prm.c b/drivers/mfd/omap4xxx-prm.c
new file mode 100644
index 0000000..9de8f3e
--- /dev/null
+++ b/drivers/mfd/omap4xxx-prm.c
@@ -0,0 +1,60 @@
+/*
+ * OMAP Power and Reset Management (PRM) driver for OMAP4xxx
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Author: Tero Kristo <t-kristo@ti.com>
+ *
+ * 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 option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/omap-prm.h>
+
+#define DRIVER_NAME "prm4xxx"
+
+static int __devinit omap4xxx_prm_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __devexit omap4xxx_prm_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver omap4xxx_prm_driver = {
+ .probe = omap4xxx_prm_probe,
+ .remove = __devexit_p(omap4xxx_prm_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init omap4xxx_prm_init(void)
+{
+ return platform_driver_register(&omap4xxx_prm_driver);
+}
+module_init(omap4xxx_prm_init);
+
+static void __exit omap4xxx_prm_exit(void)
+{
+ platform_driver_unregister(&omap4xxx_prm_driver);
+}
+module_exit(omap4xxx_prm_exit);
+
+MODULE_ALIAS("platform:"DRIVER_NAME);
+MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
+MODULE_DESCRIPTION("OMAP4xxx PRM driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/omap-prm.h b/include/linux/mfd/omap-prm.h
new file mode 100644
index 0000000..ddc814e
--- /dev/null
+++ b/include/linux/mfd/omap-prm.h
@@ -0,0 +1,28 @@
+/*
+ * OMAP Power and Reset Management (PRM) driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Author: Tero Kristo <t-kristo@ti.com>
+ *
+ * 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 option) any later version.
+ */
+
+#ifndef __LINUX_MFD_OMAP_PRM_H__
+#define __LINUX_MFD_OMAP_PRM_H__
+
+#ifdef CONFIG_OMAP_PRM
+int omap_prcm_event_to_irq(const char *name);
+#else
+static inline int omap_prcm_event_to_irq(const char *name) { return -ENOENT; }
+#endif
+
+struct omap_prm_platform_config {
+ int irq;
+ void __iomem *base;
+};
+
+#endif
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 06/18] mfd: omap-prm: added chain interrupt handler
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
Introduce a chained interrupt handler mechanism for the PRCM
interrupt, so that individual PRCM event can cleanly be handled by
handlers in separate drivers. We do this by introducing PRCM event
names, which are then matched to the particular PRCM interrupt bit
depending on the specific OMAP SoC being used.
PRCM interrupts have two priority levels, high or normal. High priority
is needed for IO event handling, so that we can be sure that IO events
are processed before other events. This reduces latency for IO event
customers and also prevents incorrect ack sequence on OMAP3.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Avinash.H.M <avinashhm@ti.com>
Cc: Cousson, Benoit <b-cousson@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/omap-prm-common.c | 239 +++++++++++++++++++++++++++++++++++++++++
drivers/mfd/omap-prm.h | 40 +++++++
drivers/mfd/omap3xxx-prm.c | 29 +++++-
drivers/mfd/omap4xxx-prm.c | 28 +++++-
4 files changed, 334 insertions(+), 2 deletions(-)
create mode 100644 drivers/mfd/omap-prm.h
diff --git a/drivers/mfd/omap-prm-common.c b/drivers/mfd/omap-prm-common.c
index 39b199c8..2886eb2 100644
--- a/drivers/mfd/omap-prm-common.c
+++ b/drivers/mfd/omap-prm-common.c
@@ -15,10 +15,249 @@
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/err.h>
+#include "omap-prm.h"
+
+#define OMAP_PRCM_MAX_NR_PENDING_REG 2
+
+struct omap_prm_device {
+ const struct omap_prcm_irq_setup *irq_setup;
+ const struct omap_prcm_irq *irqs;
+ struct irq_chip_generic **irq_chips;
+ int nr_irqs;
+ u32 *saved_mask;
+ u32 *priority_mask;
+ int base_irq;
+ int irq;
+ void __iomem *base;
+};
+
+static struct omap_prm_device prm_dev;
+
+static inline u32 prm_read_reg(int offset)
+{
+ return __raw_readl(prm_dev.base + offset);
+}
+
+static inline void prm_write_reg(u32 value, int offset)
+{
+ __raw_writel(value, prm_dev.base + offset);
+}
+
+static void prm_pending_events(unsigned long *events)
+{
+ u32 mask, st;
+ int i;
+
+ memset(events, 0, prm_dev.irq_setup->nr_regs * sizeof(unsigned long));
+
+ for (i = 0; i < prm_dev.irq_setup->nr_regs; i++) {
+ mask = prm_read_reg(prm_dev.irq_setup->mask + i * 4);
+ st = prm_read_reg(prm_dev.irq_setup->ack + i * 4);
+ events[i] = mask & st;
+ }
+}
+
+/*
+ * Move priority events from events to priority_events array
+ */
+static void prm_events_filter_priority(unsigned long *events,
+ unsigned long *priority_events)
+{
+ int i;
+
+ for (i = 0; i < prm_dev.irq_setup->nr_regs; i++) {
+ priority_events[i] = events[i] & prm_dev.priority_mask[i];
+ events[i] ^= priority_events[i];
+ }
+}
+
+/*
+ * PRCM Interrupt Handler
+ *
+ * This is a common handler for the OMAP PRCM interrupts. Pending
+ * interrupts are detected by a call to prm_pending_events and
+ * dispatched accordingly. Clearing of the wakeup events should be
+ * done by the SoC specific individual handlers.
+ */
+static void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+ unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int virtirq;
+ int nr_irqs = prm_dev.irq_setup->nr_regs * 32;
+
+ /*
+ * Loop until all pending irqs are handled, since
+ * generic_handle_irq() can cause new irqs to come
+ */
+ while (1) {
+ prm_pending_events(pending);
+
+ /* No bit set, then all IRQs are handled */
+ if (find_first_bit(pending, nr_irqs) >= nr_irqs)
+ break;
+
+ prm_events_filter_priority(pending, priority_pending);
+
+ /*
+ * Loop on all currently pending irqs so that new irqs
+ * cannot starve previously pending irqs
+ */
+
+ /* Serve priority events first */
+ for_each_set_bit(virtirq, priority_pending, nr_irqs)
+ generic_handle_irq(prm_dev.base_irq + virtirq);
+
+ /* Serve normal events next */
+ for_each_set_bit(virtirq, pending, nr_irqs)
+ generic_handle_irq(prm_dev.base_irq + virtirq);
+ }
+ if (chip->irq_ack)
+ chip->irq_ack(&desc->irq_data);
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
+ chip->irq_unmask(&desc->irq_data);
+}
+
+/*
+ * Given a PRCM event name, returns the corresponding IRQ on which the
+ * handler should be registered.
+ */
+int omap_prcm_event_to_irq(const char *name)
+{
+ int i;
+
+ for (i = 0; i < prm_dev.nr_irqs; i++)
+ if (!strcmp(prm_dev.irqs[i].name, name))
+ return prm_dev.base_irq + prm_dev.irqs[i].offset;
+
+ return -ENOENT;
+}
+
+/*
+ * Reverses memory allocated and other steps done by
+ * omap_prcm_register_chain_handler
+ */
+void omap_prcm_irq_cleanup(void)
+{
+ int i;
+
+ if (prm_dev.irq_chips) {
+ for (i = 0; i < prm_dev.irq_setup->nr_regs; i++) {
+ if (prm_dev.irq_chips[i])
+ irq_remove_generic_chip(prm_dev.irq_chips[i],
+ 0xffffffff, 0, 0);
+ prm_dev.irq_chips[i] = NULL;
+ }
+ kfree(prm_dev.irq_chips);
+ prm_dev.irq_chips = NULL;
+ }
+
+ kfree(prm_dev.saved_mask);
+ prm_dev.saved_mask = NULL;
+
+ kfree(prm_dev.priority_mask);
+ prm_dev.priority_mask = NULL;
+
+ irq_set_chained_handler(prm_dev.irq, NULL);
+
+ if (prm_dev.base_irq > 0)
+ irq_free_descs(prm_dev.base_irq,
+ prm_dev.irq_setup->nr_regs * 32);
+ prm_dev.base_irq = 0;
+}
+
+/*
+ * Initializes the prcm chain handler based on provided parameters.
+ */
+int omap_prcm_register_chain_handler(int irq, void __iomem *base,
+ const struct omap_prcm_irq_setup *irq_setup,
+ const struct omap_prcm_irq *irqs, int nr_irqs)
+{
+ int nr_regs = irq_setup->nr_regs;
+ u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
+ int offset;
+ int max_irq = 0;
+ int i;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+
+ if (nr_regs > OMAP_PRCM_MAX_NR_PENDING_REG) {
+ pr_err("PRCM: nr_regs too large\n");
+ goto err;
+ }
+
+ prm_dev.irq_setup = irq_setup;
+ prm_dev.irqs = irqs;
+ prm_dev.nr_irqs = nr_irqs;
+ prm_dev.irq = irq;
+ prm_dev.base = base;
+
+ prm_dev.irq_chips = kzalloc(sizeof(void *) * nr_regs, GFP_KERNEL);
+ prm_dev.saved_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
+ prm_dev.priority_mask = kzalloc(sizeof(u32) * nr_regs, GFP_KERNEL);
+
+ if (!prm_dev.irq_chips || !prm_dev.saved_mask ||
+ !prm_dev.priority_mask) {
+ pr_err("PRCM: kzalloc failed\n");
+ goto err;
+ }
+
+ memset(mask, 0, sizeof(mask));
+
+ for (i = 0; i < nr_irqs; i++) {
+ offset = irqs[i].offset;
+ mask[offset >> 5] |= 1 << (offset & 0x1f);
+ if (offset > max_irq)
+ max_irq = offset;
+ if (irqs[i].priority)
+ prm_dev.priority_mask[offset >> 5] |=
+ 1 << (offset & 0x1f);
+ }
+
+ irq_set_chained_handler(prm_dev.irq, prcm_irq_handler);
+
+ prm_dev.base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32, 0);
+
+ if (prm_dev.base_irq < 0) {
+ pr_err("PRCM: failed to allocate irq descs\n");
+ goto err;
+ }
+
+ for (i = 0; i <= irq_setup->nr_regs; i++) {
+ gc = irq_alloc_generic_chip("PRCM", 1,
+ prm_dev.base_irq + i * 32, base, handle_level_irq);
+
+ if (!gc) {
+ pr_err("PRCM: failed to allocate generic chip\n");
+ goto err;
+ }
+ ct = gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+
+ ct->regs.ack = irq_setup->ack + i * 4;
+ ct->regs.mask = irq_setup->mask + i * 4;
+
+ irq_setup_generic_chip(gc, mask[i], 0, IRQ_NOREQUEST, 0);
+ prm_dev.irq_chips[i] = gc;
+ }
+
+ return 0;
+
+err:
+ omap_prcm_irq_cleanup();
+ return -ENOMEM;
+}
+
MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
MODULE_DESCRIPTION("OMAP PRM core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/omap-prm.h b/drivers/mfd/omap-prm.h
new file mode 100644
index 0000000..7ffefe1
--- /dev/null
+++ b/drivers/mfd/omap-prm.h
@@ -0,0 +1,40 @@
+/*
+ * OMAP Power and Reset Management (PRM) driver common definitions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * Author: Tero Kristo <t-kristo@ti.com>
+ *
+ * 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 option) any later version.
+ */
+
+#ifndef __DRIVERS_MFD_OMAP_PRM_H__
+#define __DRIVERS_MFD_OMAP_PRM_H__
+
+struct omap_prcm_irq_setup {
+ u32 ack;
+ u32 mask;
+ int nr_regs;
+};
+
+struct omap_prcm_irq {
+ const char *name;
+ unsigned int offset;
+ bool priority;
+};
+
+#define OMAP_PRCM_IRQ(_name, _offset, _priority) { \
+ .name = _name, \
+ .offset = _offset, \
+ .priority = _priority \
+ }
+
+void omap_prcm_irq_cleanup(void);
+int omap_prcm_register_chain_handler(int irq, void __iomem *base,
+ const struct omap_prcm_irq_setup *irq_setup,
+ const struct omap_prcm_irq *irqs, int nr_irqs);
+
+#endif
diff --git a/drivers/mfd/omap3xxx-prm.c b/drivers/mfd/omap3xxx-prm.c
index 177aced..9be21ee 100644
--- a/drivers/mfd/omap3xxx-prm.c
+++ b/drivers/mfd/omap3xxx-prm.c
@@ -21,11 +21,38 @@
#include <linux/platform_device.h>
#include <linux/mfd/omap-prm.h>
+#include "omap-prm.h"
+
#define DRIVER_NAME "prm3xxx"
+#define OMAP3_PRM_IRQSTATUS_OFFSET 0x818
+#define OMAP3_PRM_IRQENABLE_OFFSET 0x81c
+
+static const struct omap_prcm_irq_setup omap3_prcm_irq_setup = {
+ .ack = OMAP3_PRM_IRQSTATUS_OFFSET,
+ .mask = OMAP3_PRM_IRQENABLE_OFFSET,
+ .nr_regs = 1,
+};
+
+static const struct omap_prcm_irq omap3_prcm_irqs[] = {
+ OMAP_PRCM_IRQ("wkup", 0, 0),
+ OMAP_PRCM_IRQ("io", 9, 1),
+};
+
static int __devinit omap3xxx_prm_probe(struct platform_device *pdev)
{
- return 0;
+ int ret = 0;
+ struct omap_prm_platform_config *pdata = pdev->dev.platform_data;
+
+ ret = omap_prcm_register_chain_handler(pdata->irq, pdata->base,
+ &omap3_prcm_irq_setup, omap3_prcm_irqs,
+ ARRAY_SIZE(omap3_prcm_irqs));
+
+ if (ret) {
+ pr_err("%s: chain handler register failed: %d\n", __func__,
+ ret);
+ }
+ return ret;
}
static int __devexit omap3xxx_prm_remove(struct platform_device *pdev)
diff --git a/drivers/mfd/omap4xxx-prm.c b/drivers/mfd/omap4xxx-prm.c
index 9de8f3e..6e134a7 100644
--- a/drivers/mfd/omap4xxx-prm.c
+++ b/drivers/mfd/omap4xxx-prm.c
@@ -21,11 +21,37 @@
#include <linux/platform_device.h>
#include <linux/mfd/omap-prm.h>
+#include "omap-prm.h"
+
#define DRIVER_NAME "prm4xxx"
+#define OMAP4_PRM_IRQSTATUS_OFFSET 0x10
+#define OMAP4_PRM_IRQENABLE_OFFSET 0x18
+
+static const struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
+ .ack = OMAP4_PRM_IRQSTATUS_OFFSET,
+ .mask = OMAP4_PRM_IRQENABLE_OFFSET,
+ .nr_regs = 2,
+};
+
+static const struct omap_prcm_irq omap4_prcm_irqs[] = {
+ OMAP_PRCM_IRQ("io", 9, 1),
+};
+
static int __devinit omap4xxx_prm_probe(struct platform_device *pdev)
{
- return 0;
+ int ret = 0;
+ struct omap_prm_platform_config *pdata = pdev->dev.platform_data;
+
+ ret = omap_prcm_register_chain_handler(pdata->irq, pdata->base,
+ &omap4_prcm_irq_setup, omap4_prcm_irqs,
+ ARRAY_SIZE(omap4_prcm_irqs));
+
+ if (ret) {
+ pr_err("%s: chain handler register failed: %d\n", __func__,
+ ret);
+ }
+ return ret;
}
static int __devexit omap4xxx_prm_remove(struct platform_device *pdev)
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 07/18] mfd: omap-prm: added suspend prepare and complete callbacks
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
These are needed because runtime PM is disabled during suspend, and
it is bad if we get interrupts from the PRCM chain handler during it.
Now, PRCM interrupt forwarding is disabled until the suspend->complete,
which makes sure that all the needed drivers are up.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/omap-prm-common.c | 34 +++++++++++++++++++++++++++++++++-
drivers/mfd/omap-prm.h | 2 ++
drivers/mfd/omap3xxx-prm.c | 1 +
drivers/mfd/omap4xxx-prm.c | 1 +
4 files changed, 37 insertions(+), 1 deletions(-)
diff --git a/drivers/mfd/omap-prm-common.c b/drivers/mfd/omap-prm-common.c
index 2886eb2..e8522fc 100644
--- a/drivers/mfd/omap-prm-common.c
+++ b/drivers/mfd/omap-prm-common.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/platform_device.h>
#include "omap-prm.h"
@@ -35,6 +36,7 @@ struct omap_prm_device {
int base_irq;
int irq;
void __iomem *base;
+ int suspended;
};
static struct omap_prm_device prm_dev;
@@ -92,12 +94,20 @@ static void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int virtirq;
int nr_irqs = prm_dev.irq_setup->nr_regs * 32;
+ int i;
+
+ if (prm_dev.suspended)
+ for (i = 0; i < prm_dev.irq_setup->nr_regs; i++) {
+ prm_dev.saved_mask[i] =
+ prm_read_reg(prm_dev.irq_setup->mask + i * 4);
+ prm_write_reg(0, prm_dev.irq_setup->mask + i * 4);
+ }
/*
* Loop until all pending irqs are handled, since
* generic_handle_irq() can cause new irqs to come
*/
- while (1) {
+ while (!prm_dev.suspended) {
prm_pending_events(pending);
/* No bit set, then all IRQs are handled */
@@ -258,6 +268,28 @@ err:
return -ENOMEM;
}
+static int omap_prm_prepare(struct device *kdev)
+{
+ prm_dev.suspended = 1;
+ return 0;
+}
+
+static void omap_prm_complete(struct device *kdev)
+{
+ int i;
+
+ prm_dev.suspended = 0;
+
+ for (i = 0; i < prm_dev.irq_setup->nr_regs; i++)
+ prm_write_reg(prm_dev.saved_mask[i],
+ prm_dev.irq_setup->mask + i * 4);
+}
+
+const struct dev_pm_ops omap_prm_pm_ops = {
+ .prepare = omap_prm_prepare,
+ .complete = omap_prm_complete,
+};
+
MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
MODULE_DESCRIPTION("OMAP PRM core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/omap-prm.h b/drivers/mfd/omap-prm.h
index 7ffefe1..c901810 100644
--- a/drivers/mfd/omap-prm.h
+++ b/drivers/mfd/omap-prm.h
@@ -32,6 +32,8 @@ struct omap_prcm_irq {
.priority = _priority \
}
+extern const struct dev_pm_ops omap_prm_pm_ops;
+
void omap_prcm_irq_cleanup(void);
int omap_prcm_register_chain_handler(int irq, void __iomem *base,
const struct omap_prcm_irq_setup *irq_setup,
diff --git a/drivers/mfd/omap3xxx-prm.c b/drivers/mfd/omap3xxx-prm.c
index 9be21ee..38b88aa 100644
--- a/drivers/mfd/omap3xxx-prm.c
+++ b/drivers/mfd/omap3xxx-prm.c
@@ -66,6 +66,7 @@ static struct platform_driver omap3xxx_prm_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
+ .pm = &omap_prm_pm_ops,
},
};
diff --git a/drivers/mfd/omap4xxx-prm.c b/drivers/mfd/omap4xxx-prm.c
index 6e134a7..92cc67d 100644
--- a/drivers/mfd/omap4xxx-prm.c
+++ b/drivers/mfd/omap4xxx-prm.c
@@ -65,6 +65,7 @@ static struct platform_driver omap4xxx_prm_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
+ .pm = &omap_prm_pm_ops,
},
};
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 08/18] OMAP2+: mux: add support for PAD wakeup interrupts
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
OMAP mux now provides a service routine to parse pending wakeup events
and to call registered ISR whenever active wakeups are detected. This
routine is called directly from PRCM interrupt handler.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/mux.c | 38 ++++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 50ee806..b27c061 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -32,6 +32,9 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/omap-prm.h>
#include <asm/system.h>
@@ -381,6 +384,33 @@ bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
return ret;
}
+/**
+ * omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod
+ *
+ * Checks a single hwmod for every wakeup capable pad to see if there is an
+ * active wakeup event. If this is the case, call the corresponding ISR.
+ */
+static int _omap_hwmod_mux_handle_irq(struct omap_hwmod *oh, void *data)
+{
+ if (!oh->mux || !oh->mux->enabled)
+ return 0;
+ if (omap_hwmod_mux_get_wake_status(oh->mux))
+ generic_handle_irq(oh->mpu_irqs[0].irq);
+ return 0;
+}
+
+/**
+ * omap_hwmod_mux_handle_irq - Process pad wakeup irqs.
+ *
+ * Calls a function for each registered omap_hwmod to check
+ * pad wakeup statuses.
+ */
+static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused)
+{
+ omap_hwmod_for_each(_omap_hwmod_mux_handle_irq, NULL);
+ return IRQ_HANDLED;
+}
+
/* Assumes the calling function takes care of locking */
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
{
@@ -745,6 +775,7 @@ static void __init omap_mux_free_names(struct omap_mux *m)
static int __init omap_mux_late_init(void)
{
struct omap_mux_partition *partition;
+ int ret;
list_for_each_entry(partition, &mux_partitions, node) {
struct omap_mux_entry *e, *tmp;
@@ -765,6 +796,13 @@ static int __init omap_mux_late_init(void)
}
}
+ ret = request_irq(omap_prcm_event_to_irq("io"),
+ omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
+ "hwmod_io", omap_mux_late_init);
+
+ if (ret)
+ printk(KERN_WARNING "Failed to setup hwmod io irq %d\n", ret);
+
omap_mux_dbg_init();
return 0;
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 09/18] omap3: pm: use prcm chain handler
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
PM interrupt handling is now done through the PRCM chain handler. The
interrupt handling logic is also split in two parts, to server IO and
WKUP events separately. This allows us to handle IO chain events in a
clean way.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/pm34xx.c | 104 +++++++++++++++---------------------------
1 files changed, 37 insertions(+), 67 deletions(-)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7255d9b..712fd15 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>
+#include <linux/mfd/omap-prm.h>
#include <trace/events/power.h>
#include <asm/suspend.h>
@@ -198,7 +199,7 @@ static void omap3_save_secure_ram_context(void)
* that any peripheral wake-up events occurring while attempting to
* clear the PM_WKST_x are detected and cleared.
*/
-static int prcm_clear_mod_irqs(s16 module, u8 regs)
+static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
{
u32 wkst, fclk, iclk, clken;
u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
@@ -210,6 +211,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
wkst = omap2_prm_read_mod_reg(module, wkst_off);
wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
+ wkst &= ~ignore_bits;
if (wkst) {
iclk = omap2_cm_read_mod_reg(module, iclk_off);
fclk = omap2_cm_read_mod_reg(module, fclk_off);
@@ -225,6 +227,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
omap2_cm_set_mod_reg_bits(clken, module, fclk_off);
omap2_prm_write_mod_reg(wkst, module, wkst_off);
wkst = omap2_prm_read_mod_reg(module, wkst_off);
+ wkst &= ~ignore_bits;
c++;
}
omap2_cm_write_mod_reg(iclk, module, iclk_off);
@@ -234,76 +237,35 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs)
return c;
}
-static int _prcm_int_handle_wakeup(void)
+static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
{
int c;
- c = prcm_clear_mod_irqs(WKUP_MOD, 1);
- c += prcm_clear_mod_irqs(CORE_MOD, 1);
- c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
- if (omap_rev() > OMAP3430_REV_ES1_0) {
- c += prcm_clear_mod_irqs(CORE_MOD, 3);
- c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
- }
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+ ~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
- return c;
+ return c ? IRQ_HANDLED : IRQ_NONE;
}
-/*
- * PRCM Interrupt Handler
- *
- * The PRM_IRQSTATUS_MPU register indicates if there are any pending
- * interrupts from the PRCM for the MPU. These bits must be cleared in
- * order to clear the PRCM interrupt. The PRCM interrupt handler is
- * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
- * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
- * register indicates that a wake-up event is pending for the MPU and
- * this bit can only be cleared if the all the wake-up events latched
- * in the various PM_WKST_x registers have been cleared. The interrupt
- * handler is implemented using a do-while loop so that if a wake-up
- * event occurred during the processing of the prcm interrupt handler
- * (setting a bit in the corresponding PM_WKST_x register and thus
- * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
- * this would be handled.
- */
-static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused)
{
- u32 irqenable_mpu, irqstatus_mpu;
- int c = 0;
-
- irqenable_mpu = omap2_prm_read_mod_reg(OCP_MOD,
- OMAP3_PRM_IRQENABLE_MPU_OFFSET);
- irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
- OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
- irqstatus_mpu &= irqenable_mpu;
-
- do {
- if (irqstatus_mpu & (OMAP3430_WKUP_ST_MASK |
- OMAP3430_IO_ST_MASK)) {
- c = _prcm_int_handle_wakeup();
-
- /*
- * Is the MPU PRCM interrupt handler racing with the
- * IVA2 PRCM interrupt handler ?
- */
- WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
- "but no wakeup sources are marked\n");
- } else {
- /* XXX we need to expand our PRCM interrupt handler */
- WARN(1, "prcm: WARNING: PRCM interrupt received, but "
- "no code to handle it (%08x)\n", irqstatus_mpu);
- }
-
- omap2_prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
- OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
-
- irqstatus_mpu = omap2_prm_read_mod_reg(OCP_MOD,
- OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
- irqstatus_mpu &= irqenable_mpu;
+ int c;
- } while (irqstatus_mpu);
+ /*
+ * Clear all except ST_IO and ST_IO_CHAIN for wkup module,
+ * these are handled in a separate handler to avoid acking
+ * IO events before parsing in mux code
+ */
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1,
+ OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK);
+ c += prcm_clear_mod_irqs(CORE_MOD, 1, 0);
+ c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1, 0);
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
+ c += prcm_clear_mod_irqs(CORE_MOD, 3, 0);
+ c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, 0);
+ }
- return IRQ_HANDLED;
+ return c ? IRQ_HANDLED : IRQ_NONE;
}
static void omap34xx_save_context(u32 *save)
@@ -876,12 +838,20 @@ static int __init omap3_pm_init(void)
* supervised mode for powerdomains */
prcm_setup_regs();
- ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
- (irq_handler_t)prcm_interrupt_handler,
- IRQF_DISABLED, "prcm", NULL);
+ ret = request_irq(omap_prcm_event_to_irq("wkup"),
+ _prcm_int_handle_wakeup, 0, "pm_wkup", NULL);
+
+ if (ret) {
+ printk(KERN_ERR "Failed to request pm_wkup irq\n");
+ goto err1;
+ }
+
+ /* IO interrupt is shared with mux code */
+ ret = request_irq(omap_prcm_event_to_irq("io"),
+ _prcm_int_handle_io, IRQF_SHARED, "pm_io", omap3_pm_init);
+
if (ret) {
- printk(KERN_ERR "request_irq failed to register for 0x%x\n",
- INT_34XX_PRCM_MPU_IRQ);
+ printk(KERN_ERR "Failed to request pm_io irq\n");
goto err1;
}
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 10/18] OMAP3: pm: do not enable PRCM MPU interrupts manually
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This is handled automatically by the PRCM chain interrupt mechanism now.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/pm34xx.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 712fd15..4bbf1cd 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -661,10 +661,6 @@ static void __init prcm_setup_regs(void)
OMAP3430_GRPSEL_GPT1_MASK |
OMAP3430_GRPSEL_GPT12_MASK,
WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
- /* For some reason IO doesn't generate wakeup event even if
- * it is selected to mpu wakeup goup */
- omap2_prm_write_mod_reg(OMAP3430_IO_EN_MASK | OMAP3430_WKUP_EN_MASK,
- OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
/* Enable PM_WKEN to support DSS LPR */
omap2_prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS_MASK,
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 11/18] omap3+: add omap prm driver initialization
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
OMAP PRM driver is initialized based on availability of PRM hwmods.
This patch will sequentially check for a list of known PRM hwmods and
will add an omap device if any is found.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/devices.c | 46 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 10adf66..d6750a4 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -419,6 +419,51 @@ static void omap_init_pmu(void)
platform_device_register(&omap_pmu_device);
}
+#ifdef CONFIG_OMAP_PRM
+
+#include <linux/mfd/omap-prm.h>
+
+static const char * const omap_prm_devnames[] = {
+ "prm3xxx",
+ "prm4xxx",
+ NULL,
+};
+
+static void omap_init_prm(void)
+{
+ struct platform_device *pdev;
+ struct omap_hwmod *oh = NULL;
+ struct omap_prm_platform_config *pdata;
+ int i = 0;
+
+ while (!oh && omap_prm_devnames[i]) {
+ oh = omap_hwmod_lookup(omap_prm_devnames[i]);
+ i++;
+ }
+
+ if (!oh) {
+ pr_info("prm hwmod not available\n");
+ return;
+ }
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+
+ if (!pdata) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ return;
+ }
+
+ pdata->irq = oh->mpu_irqs[0].irq;
+ pdata->base = omap_hwmod_get_mpu_rt_va(oh);
+
+ pdev = omap_device_build(oh->name, -1, oh, pdata,
+ sizeof(*pdata), NULL, 0, 0);
+
+ WARN(IS_ERR(pdev), "Unable to build omap device for PRM\n");
+}
+#else
+static inline void omap_init_prm(void) { }
+#endif
#if defined(CONFIG_CRYPTO_DEV_OMAP_SHAM) || defined(CONFIG_CRYPTO_DEV_OMAP_SHAM_MODULE)
@@ -687,6 +732,7 @@ static int __init omap2_init_devices(void)
omap_init_mbox();
omap_init_mcspi();
omap_init_pmu();
+ omap_init_prm();
omap_hdq_init();
omap_init_sti();
omap_init_sham();
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 12/18] TEMP: serial: added mux support
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
Just for PRCM chain handler testing purposes. This should be replaced with
a proper implementation.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/serial.c | 71 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 3d1c1d3..e08feb1 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -862,17 +862,84 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
* can call this function when they want to have default behaviour
* for serial ports (e.g initialize them all as serial ports).
*/
+
+struct serial_mux_conf {
+ char *name;
+ int omap3_mux;
+ int omap4_mux;
+};
+
+#define OMAP3_SERIAL_MUX_IN_PU (OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_IN_PD (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_IN (OMAP_PIN_INPUT | OMAP_MUX_MODE0)
+#define OMAP3_SERIAL_MUX_OUT (OMAP_PIN_OUTPUT | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_IN_PU (OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_OUT (OMAP_PIN_OUTPUT | OMAP_MUX_MODE0)
+#define OMAP4_SERIAL_MUX_IN (OMAP_PIN_INPUT | OMAP_MUX_MODE0)
+#define SERIAL_DISABLED OMAP_MUX_MODE7
+
+#define OMAP_SERIAL_NUM_PADS_PER_PORT 4
+
+static const struct serial_mux_conf serial_mux_data[] = {
+ { "uart1_cts.uart1_cts", OMAP3_SERIAL_MUX_IN, SERIAL_DISABLED, },
+ { "uart1_rts.uart1_rts", OMAP3_SERIAL_MUX_OUT, SERIAL_DISABLED, },
+ { "uart1_rx.uart1_rx", OMAP3_SERIAL_MUX_IN, SERIAL_DISABLED, },
+ { "uart1_tx.uart1_tx", OMAP3_SERIAL_MUX_OUT, SERIAL_DISABLED, },
+ { "uart2_cts.uart2_cts", OMAP3_SERIAL_MUX_IN,
+ OMAP4_SERIAL_MUX_IN_PU, },
+ { "uart2_rts.uart2_rts", OMAP3_SERIAL_MUX_OUT, OMAP4_SERIAL_MUX_OUT, },
+ { "uart2_rx.uart2_rx", OMAP3_SERIAL_MUX_IN, OMAP4_SERIAL_MUX_IN_PU, },
+ { "uart2_tx.uart2_tx", OMAP3_SERIAL_MUX_OUT, OMAP4_SERIAL_MUX_OUT },
+ { "uart3_cts_rctx.uart3_cts_rctx", OMAP3_SERIAL_MUX_IN_PD,
+ OMAP4_SERIAL_MUX_IN_PU, },
+ { "uart3_rts_sd.uart3_rts_sd", OMAP3_SERIAL_MUX_OUT,
+ OMAP4_SERIAL_MUX_OUT, },
+ { "uart3_rx_irrx.uart3_rx_irrx", OMAP3_SERIAL_MUX_IN,
+ OMAP4_SERIAL_MUX_IN, },
+ { "uart3_tx_irtx.uart3_tx_irtx", OMAP3_SERIAL_MUX_OUT,
+ OMAP4_SERIAL_MUX_OUT, },
+ { "uart4_rx.uart4_rx", SERIAL_DISABLED, OMAP4_SERIAL_MUX_IN, },
+ { "uart4_tx.uart4_tx", SERIAL_DISABLED, OMAP4_SERIAL_MUX_OUT, },
+ { NULL, SERIAL_DISABLED, SERIAL_DISABLED, },
+ { NULL, SERIAL_DISABLED, SERIAL_DISABLED, },
+};
+
void __init omap_serial_init(void)
{
struct omap_uart_state *uart;
struct omap_board_data bdata;
+ struct omap_device_pad *pads;
+ int idx;
+ int i;
+ pads = kmalloc(sizeof(struct omap_device_pad) * 4, GFP_KERNEL);
list_for_each_entry(uart, &uart_list, node) {
bdata.id = uart->num;
bdata.flags = 0;
- bdata.pads = NULL;
bdata.pads_cnt = 0;
+ bdata.pads = pads;
+
+ for (i = 0; i < OMAP_SERIAL_NUM_PADS_PER_PORT; i++) {
+ idx = bdata.id * OMAP_SERIAL_NUM_PADS_PER_PORT + i;
+ pads[i].name = serial_mux_data[idx].name;
+ pads[i].enable = 0;
+ pads[i].idle = 0;
+ pads[i].flags = 0;
+ if (cpu_is_omap34xx())
+ pads[i].enable = serial_mux_data[idx].omap3_mux;
+ if (cpu_is_omap44xx())
+ pads[i].enable = serial_mux_data[idx].omap4_mux;
+ if (pads[i].enable != SERIAL_DISABLED)
+ bdata.pads_cnt++;
+ if (pads[i].enable & OMAP_PIN_INPUT) {
+ pads[i].flags = OMAP_DEVICE_PAD_REMUX |
+ OMAP_DEVICE_PAD_WAKEUP;
+ }
+ pads[i].idle = pads[i].enable;
+ }
+ if (bdata.pads_cnt == 0)
+ bdata.pads = NULL;
omap_serial_init_port(&bdata);
-
}
+ kfree(pads);
}
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 13/18] TEMP: 4430sdp: use common serial init with mux support
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
Temporary testing related patch, not meant for integration.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 12 +-----------
1 files changed, 1 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index c7cef44..f1151e8 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -737,17 +737,7 @@ static struct omap_board_data serial4_data __initdata = {
static inline void board_serial_init(void)
{
- struct omap_board_data bdata;
- bdata.flags = 0;
- bdata.pads = NULL;
- bdata.pads_cnt = 0;
- bdata.id = 0;
- /* pass dummy data for UART1 */
- omap_serial_init_port(&bdata);
-
- omap_serial_init_port(&serial2_data);
- omap_serial_init_port(&serial3_data);
- omap_serial_init_port(&serial4_data);
+ omap_serial_init();
}
#else
#define board_mux NULL
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 14/18] TEMP: mux: added trace for io wkup event
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
Temporary patch for testing purposes, not meant for integration.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/mux.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index b27c061..642fe3f 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -376,6 +376,8 @@ bool omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux)
pad->mux->reg_offset);
if (val & OMAP_WAKEUP_EVENT) {
ret = true;
+ pr_info("wkup detected: %04x\n",
+ pad->mux->reg_offset);
break;
}
}
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 15/18] TEMP: OMAP3: pm: remove serial resume / idle calls from idle path
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This is no longer needed as it will be handled within serial driver itself.
This part should be properly handled with serial runtime support.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/mach-omap2/pm34xx.c | 19 -------------------
1 files changed, 0 insertions(+), 19 deletions(-)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 4bbf1cd..46c209d 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -341,18 +341,9 @@ void omap_sram_idle(void)
omap3_enable_io_chain();
}
- /* Block console output in case it is on one of the OMAP UARTs */
- if (!is_suspending())
- if (per_next_state < PWRDM_POWER_ON ||
- core_next_state < PWRDM_POWER_ON)
- if (!console_trylock())
- goto console_still_active;
-
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
- omap_uart_prepare_idle(2);
- omap_uart_prepare_idle(3);
omap2_gpio_prepare_for_idle(per_going_off);
if (per_next_state == PWRDM_POWER_OFF)
omap3_per_save_context();
@@ -360,8 +351,6 @@ void omap_sram_idle(void)
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
- omap_uart_prepare_idle(0);
- omap_uart_prepare_idle(1);
if (core_next_state == PWRDM_POWER_OFF) {
omap3_core_save_context();
omap3_cm_save_context();
@@ -408,8 +397,6 @@ void omap_sram_idle(void)
omap3_sram_restore_context();
omap2_sms_restore_context();
}
- omap_uart_resume_idle(0);
- omap_uart_resume_idle(1);
if (core_next_state == PWRDM_POWER_OFF)
omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
OMAP3430_GR_MOD,
@@ -423,14 +410,8 @@ void omap_sram_idle(void)
omap2_gpio_resume_after_idle();
if (per_prev_state == PWRDM_POWER_OFF)
omap3_per_restore_context();
- omap_uart_resume_idle(2);
- omap_uart_resume_idle(3);
}
- if (!is_suspending())
- console_unlock();
-
-console_still_active:
/* Disable IO-PAD and IO-CHAIN wakeup */
if (omap3_has_io_wakeup() &&
(per_next_state < PWRDM_POWER_ON ||
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 16/18] TEMP: OMAP3: serial: made serial to work properly with PRCM chain handler
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
This patch is just a temporary hack to allow serial to work properly with
the PRCM chain handler. Should be replaced with a proper implementation
by serial runtime PM support.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/mach-omap2/serial.c | 29 +++++++++--------------------
drivers/tty/serial/omap-serial.c | 8 ++++++++
2 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index e08feb1..0cc5434 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -39,6 +39,7 @@
#include <plat/dma.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
+#include <plat/prcm.h>
#include "prm2xxx_3xxx.h"
#include "pm.h"
@@ -380,6 +381,7 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart)
omap_uart_smart_idle_enable(uart, 1);
uart->can_sleep = 1;
del_timer(&uart->timer);
+ omap_uart_disable_clocks(uart);
}
static void omap_uart_idle_timer(unsigned long data)
@@ -391,36 +393,23 @@ static void omap_uart_idle_timer(unsigned long data)
void omap_uart_prepare_idle(int num)
{
- struct omap_uart_state *uart;
-
- list_for_each_entry(uart, &uart_list, node) {
- if (num == uart->num && uart->can_sleep) {
- omap_uart_disable_clocks(uart);
- return;
- }
- }
}
void omap_uart_resume_idle(int num)
{
struct omap_uart_state *uart;
+ u32 wkst;
list_for_each_entry(uart, &uart_list, node) {
if (num == uart->num && uart->can_sleep) {
- omap_uart_enable_clocks(uart);
+ omap_uart_block_sleep(uart);
- /* Check for IO pad wakeup */
- if (cpu_is_omap34xx() && uart->padconf) {
- u16 p = omap_ctrl_readw(uart->padconf);
-
- if (p & OMAP3_PADCONF_WAKEUPEVENT0)
- omap_uart_block_sleep(uart);
+ /* Check for normal UART wakeup (and clear it) */
+ if (uart->wk_st && uart->wk_mask) {
+ wkst = __raw_readl(uart->wk_st) & uart->wk_mask;
+ if (wkst)
+ __raw_writel(wkst, uart->wk_st);
}
-
- /* Check for normal UART wakeup */
- if (__raw_readl(uart->wk_st) & uart->wk_mask)
- omap_uart_block_sleep(uart);
- return;
}
}
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c37df8d..cfff8ac 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -261,6 +261,8 @@ static void serial_omap_start_tx(struct uart_port *port)
unsigned int start;
int ret = 0;
+ omap_uart_resume_idle(up->pdev->id);
+
if (!up->use_dma) {
serial_omap_enable_ier_thri(up);
return;
@@ -354,6 +356,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
unsigned int iir, lsr;
unsigned long flags;
+ omap_uart_resume_idle(up->pdev->id);
+
iir = serial_in(up, UART_IIR);
if (iir & UART_IIR_NO_INT)
return IRQ_NONE;
@@ -641,6 +645,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags = 0;
unsigned int baud, quot;
+ omap_uart_resume_idle(up->pdev->id);
+
switch (termios->c_cflag & CSIZE) {
case CS5:
cval = UART_LCR_WLEN5;
@@ -947,6 +953,8 @@ serial_omap_console_write(struct console *co, const char *s,
unsigned int ier;
int locked = 1;
+ omap_uart_resume_idle(up->pdev->id);
+
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* [PATCHv9 17/18] TEMP: OMAP: serial: remove padconf hacks
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
These are no longer needed as omap_hwmod takes care of multiplexing of pads.
Should be handled properly with serial runtime PM support patches.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/mach-omap2/serial.c | 25 +------------------------
1 files changed, 1 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 0cc5434..cdcdd83 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -73,7 +73,6 @@ struct omap_uart_state {
void __iomem *wk_st;
void __iomem *wk_en;
u32 wk_mask;
- u32 padconf;
u32 dma_enabled;
struct clk *ick;
@@ -309,13 +308,6 @@ static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
v |= uart->wk_mask;
__raw_writel(v, uart->wk_en);
}
-
- /* Ensure IOPAD wake-enables are set */
- if (cpu_is_omap34xx() && uart->padconf) {
- u16 v = omap_ctrl_readw(uart->padconf);
- v |= OMAP3_PADCONF_WAKEUPENABLE0;
- omap_ctrl_writew(v, uart->padconf);
- }
}
static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
@@ -326,13 +318,6 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
v &= ~uart->wk_mask;
__raw_writel(v, uart->wk_en);
}
-
- /* Ensure IOPAD wake-enables are cleared */
- if (cpu_is_omap34xx() && uart->padconf) {
- u16 v = omap_ctrl_readw(uart->padconf);
- v &= ~OMAP3_PADCONF_WAKEUPENABLE0;
- omap_ctrl_writew(v, uart->padconf);
- }
}
static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
@@ -478,7 +463,6 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
u32 wk_mask = 0;
- u32 padconf = 0;
/* XXX These PRM accesses do not belong here */
uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
@@ -486,23 +470,18 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
switch (uart->num) {
case 0:
wk_mask = OMAP3430_ST_UART1_MASK;
- padconf = 0x182;
break;
case 1:
wk_mask = OMAP3430_ST_UART2_MASK;
- padconf = 0x17a;
break;
case 2:
wk_mask = OMAP3430_ST_UART3_MASK;
- padconf = 0x19e;
break;
case 3:
wk_mask = OMAP3630_ST_UART4_MASK;
- padconf = 0x0d2;
break;
}
uart->wk_mask = wk_mask;
- uart->padconf = padconf;
} else if (cpu_is_omap24xx()) {
u32 wk_mask = 0;
u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
@@ -532,7 +511,6 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
uart->wk_en = NULL;
uart->wk_st = NULL;
uart->wk_mask = 0;
- uart->padconf = 0;
}
uart->irqflags |= IRQF_SHARED;
@@ -833,8 +811,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
console_unlock();
- if ((cpu_is_omap34xx() && uart->padconf) ||
- (uart->wk_en && uart->wk_mask)) {
+ if (uart->oh->mux || (uart->wk_en && uart->wk_mask)) {
device_init_wakeup(&pdev->dev, true);
DEV_CREATE_FILE(&pdev->dev, &dev_attr_sleep_timeout);
}
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ permalink raw reply related
* Identifying Primecells
From: Rob Herring @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKON4OxqqBh4xFLwiMZzsGrnoG8erQ0hMFX-_VA-EDMvdNkvQQ@mail.gmail.com>
On 09/22/2011 01:19 PM, jonsmirl at gmail.com wrote:
> I'm working on device tree support for the NXP LPC3130. To do this
> right I need to know what specific Primecells were used in the chip.
> How do I identify the primecell numbers for the devices? It is a
> 926ejs core.
>
I'm not sure I understand the question.
The primecell periph id numbers are only in the DT if they are wrong in
the h/w for some reason. The compatible property should contain the
device model number (i.e. "arm,pl011" for the uart).
Rob
^ permalink raw reply
* [PATCHv9 18/18] TEMP: OMAP device: change pr_warnings to pr_debugs
From: Tero Kristo @ 2011-09-23 12:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316781986-30642-1-git-send-email-t-kristo@ti.com>
Prevents a hang when omap_device would want to print something for
serial console device while enabling / disabling its clocks.
Should be handled properly by serial runtime PM support.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Govindraj.R <govindraj.raja@ti.com>
---
arch/arm/plat-omap/omap_device.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index d8f2299..ecec0cc 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -154,7 +154,7 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
"%d: %llu\n",
od->pm_lat_level, act_lat);
} else
- dev_warn(&od->pdev->dev,
+ dev_dbg(&od->pdev->dev,
"activate latency %d "
"higher than exptected. (%llu > %d)\n",
od->pm_lat_level, act_lat,
@@ -221,7 +221,7 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
"%d: %llu\n",
od->pm_lat_level, deact_lat);
} else
- dev_warn(&od->pdev->dev,
+ dev_dbg(&od->pdev->dev,
"deactivate latency %d "
"higher than exptected. (%llu > %d)\n",
od->pm_lat_level, deact_lat,
--
1.7.4.1
Texas Instruments Oy, Tekniikantie 12, 02150 Espoo. Y-tunnus: 0115040-6. Kotipaikka: Helsinki
^ 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