* [PATCH v4 1/3] net/fec: fec_reset_phy() does not need to always succeed
From: Shawn Guo @ 2011-09-22 5:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316668218-10194-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>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
---
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 v4 2/3] net/fec: fix fec1 check in fec_enet_mii_init()
From: Shawn Guo @ 2011-09-22 5:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316668218-10194-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>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
---
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 v4 3/3] net/fec: add imx6q enet support
From: Shawn Guo @ 2011-09-22 5:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316668218-10194-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 | 64 +++++++++++++++++++++++++------
2 files changed, 55 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..6a6a83d 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,10 @@
#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)
+/* Controller's phy_speed bit field need to minus one */
+#define FEC_QUIRK_PHY_SPEED_MINUS_ONE (1 << 4)
static struct platform_device_id fec_devtype[] = {
{
@@ -88,6 +92,10 @@ 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 |
+ FEC_QUIRK_PHY_SPEED_MINUS_ONE,
+ }, {
/* sentinel */
}
};
@@ -97,12 +105,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 +383,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 +453,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 +494,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 +513,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 +529,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 +947,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 +980,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;
@@ -1007,7 +1042,10 @@ static int fec_enet_mii_init(struct platform_device *pdev)
/*
* Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
*/
- 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_PHY_SPEED_MINUS_ONE)
+ 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] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Jassi Brar @ 2011-09-22 5:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGsJ_4zURv1_zJ0rwZawa8VSOw0kT9U4-cCCj2Q4-BhV1pdTHA@mail.gmail.com>
On Thu, Sep 22, 2011 at 5:38 AM, Barry Song <21cnbao@gmail.com> wrote:
> 2011/9/21 Jassi Brar <jassisinghbrar@gmail.com>:
>> On Fri, Sep 16, 2011 at 3:13 PM, Barry Song <Baohua.Song@csr.com> wrote:
>>> dma_async_device_register will re-init chan_id and chancnt,
>>> so whatever chan_id and chancnt are set in drivers, they will
>>> be re-written by dma_async_device_register.
>>>
>>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>>> Cc: Viresh Kumar <viresh.kumar@st.com>
>>> Cc: Vinod Koul <vinod.koul@intel.com>
>>> Cc: Piotr Ziecik <kosmo@semihalf.com>
>>> Cc: Yong Wang <yong.y.wang@intel.com>
>>> Cc: Jaswinder Singh <jassi.brar@samsung.com>
>>> Cc: Pelagicore AB <info@pelagicore.com>
>>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>>> ---
>>> ?drivers/dma/at_hdmac.c ? ? ?| ? ?5 ++---
>>> ?drivers/dma/dw_dmac.c ? ? ? | ? ?5 ++---
>>> ?drivers/dma/intel_mid_dma.c | ? ?2 --
>>> ?drivers/dma/mpc512x_dma.c ? | ? ?1 -
>>> ?drivers/dma/pch_dma.c ? ? ? | ? ?2 --
>>> ?drivers/dma/pl330.c ? ? ? ? | ? ?2 --
>>> ?drivers/dma/timb_dma.c ? ? ?| ? ?3 +--
>>
>> Apparently ....
>>
>> drivers/dma/ppc4xx/adma.c
>> drivers/dma/ipu/ipu_idmac.c
>> ? ? ? still write to chan_id.
>>
>> drivers/dma/amba-pl08x.c
>> drivers/dma/fsldma.c
>> drivers/dma/ioat/dma_v2.c
>> drivers/dma/ioat/dma.c
>> drivers/dma/mpc512x_dma.c
>> drivers/dma/shdma.c
>> ? ? ? still write to chancnt
>>
My question was if you really intended to convert only some of
the drivers and not others?
>> Most of them are simply a matter of removal, but some seem
>> like really depending upon setting them(?)
>>
>> Anyways, even after you modify those as well, chan_id and chancnt
>> are rendered overstaying guests in dmaengine core. Because chan_id
>> of each channel would be _precisely_ the order in which the
>> _dmac-driver_ added the channel to the 'channels' list.
>>
>> So if their values are _always_ gonna be just contiguously incrementing
>> why need variables for that in the dmaengine api?
>> Dmac drivers could use local variables for that.
>>
>> OTOH, why not chan_id be left solely for use by dmac drivers read by the
>> dmaengine only to create sysfs entries ?
>
> actually i don't like the way dmaengine core handles chan_id. in my
> opinion, every dmac only needs to tell dmaengine core the chan_base.
> then dmaengine core set the id in a global scale.
>
> for example, if you have two dmac in system:
> dmac0 chan_base 0
> dmac1 chan_base 16
> then core will have chan 0~31 by chan_id from 0 to 31 but not
> dmac0chan0~15, dmac1chan0~15.
But note the numbering is still decided by the dmac driver - directly
or indirectly.
That is, if the dmac driver reorder registering of dmac or adding
channels to the 'channels' list, the assigned chan_id's would change.
So why not rather get rid of chan_id assignment from dmaengine
and do explicitly in dmac drivers ?
Which I already submitted a patch for https://lkml.org/lkml/2011/7/21/1
> client drivers can request a specific chan_id just like it can request a gpio.
No dear. That's not gonna fly if we are to have common client drivers
across SoCs.
> now dmac drivers and dmaengine core have repeated chan_id and chancnt,
> anyway, it is a problem that should be fixed at first.
Correct, chan_id assignment should be completely either in dmaengine
or in dmac drivers. But this patch does neither.
^ permalink raw reply
* [PATCH v16 07/12] OMAP: dmtimer: add timeout to low-level routines
From: DebBarma, Tarun Kanti @ 2011-09-22 5:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922010046.GS2937@atomide.com>
> Let's leave out these changes for now, they make the
> omap2_gp_timer_set_next_event used for system timer interrupts
> huge if you take a look at it with objdump.
>
> Later on we might want to split the posted bit check into a separate
> inline function, and then you can implement this for the device
> driver where things are more likely to go wrong with more complicated
> use scenarios.
Alright.
--
Tarun
>
> Regards,
>
> Tony
>
>
^ permalink raw reply
* [PATCH 8/8] OMAP4: Fix the emif and dmm virtual mapping
From: Shilimkar, Santosh @ 2011-09-22 5:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87zkhx3iqo.fsf@ti.com>
On Wed, Sep 21, 2011 at 11:01 PM, Kevin Hilman <khilman@ti.com> wrote:
> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
>
>> On Tuesday 20 September 2011 08:31 PM, Santosh Shilimkar wrote:
>>> On Friday 16 September 2011 11:26 PM, Kevin Hilman wrote:
>>>> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
>>>>
>>
>> [...]
>>
>>>
>>>>> ?#define OMAP44XX_EMIF2_SIZE ? ? ? SZ_1M
>>>>>
>>>>> ?#define OMAP44XX_DMM_PHYS OMAP44XX_DMM_BASE
>>>>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 0x4e000000 --> 0xfd300000 */
>>>>> -#define OMAP44XX_DMM_VIRT (OMAP44XX_DMM_PHYS + OMAP4_L3_PER_IO_OFFSET)
>>>>> +#define OMAP44XX_DMM_VIRT (OMAP44XX_EMIF2_VIRT + SZ_1M)
>>>>
>>>> and '+ OMAP44XX_EMIF2_SIZE' here.
>>>>
>>> Will add OMAP44XX_EMIF_SIZE since 2 EMIFs instaces are and
>>> suppose to be identical.Almost missed this email in other traffic.
>>
>> OPPs. It was already there. Dumb of me not using it. Below
>> is the update what I will do.
>>
>> diff --git a/arch/arm/plat-omap/include/plat/io.h
>> b/arch/arm/plat-omap/include/plat/io.h
>> index d72ec85..db36292 100644
>> --- a/arch/arm/plat-omap/include/plat/io.h
>> +++ b/arch/arm/plat-omap/include/plat/io.h
>> @@ -228,13 +228,13 @@
>>
>> ?#define OMAP44XX_EMIF2_PHYS ?OMAP44XX_EMIF2_BASE
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 0x4d000000 --> 0xfd200000 */
>> -#define OMAP44XX_EMIF2_VIRT ?(OMAP44XX_EMIF2_PHYS + OMAP4_L3_PER_IO_OFFSET)
>> ?#define OMAP44XX_EMIF2_SIZE ?SZ_1M
>> +#define OMAP44XX_EMIF2_VIRT ?(OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF2_SIZE)
>
> This doesn't look right either.
>
> This #define is for the *start* of EMIF2 virtual address space, so
> assuming the start address of EMIF2 is immediatly after EMIF1, it should
> be EMIF1_VIRT + EMIF1_SIZE (not EMIF2_SIZE.)
>
>> ?#define OMAP44XX_DMM_PHYS ? ?OMAP44XX_DMM_BASE
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 0x4e000000 --> 0xfd300000 */
>> -#define OMAP44XX_DMM_VIRT ? ?(OMAP44XX_DMM_PHYS + OMAP4_L3_PER_IO_OFFSET)
>> ?#define OMAP44XX_DMM_SIZE ? ?SZ_1M
>> +#define OMAP44XX_DMM_VIRT ? ?(OMAP44XX_EMIF2_VIRT + OMAP44XX_DMM_SIZE)
>
> And here, assuming DMM range is immediately after EMIF2, this should be
> EMIF2_VIRT + EMFI2_SIZE)
>
I agree.
Regards
Santosh
^ permalink raw reply
* [PATCH v3 0/2] Add TVOUT support for SMDKV310
From: Hatim Ali @ 2011-09-22 5:54 UTC (permalink / raw)
To: linux-arm-kernel
This is v3 of the TVOUT patch set for SMDKV310.
v1 is available at below link.
(http://www.spinics.net/lists/arm-kernel/msg138054.html)
Patch 1 has been modified according to the comments received from
Tomasz Stanislawski and Sylwester Nawrocki.
Patch 2 is a resend.
NOTE: This patch set has a dependency on "Setup consistent dma size at boot
time" by Tushar Behera.
(http://www.spinics.net/lists/linux-samsung-soc/msg06627.html)
Hatim Ali (2):
ARM: EXYNOS4: Add TVOUT support for SMDKV310
s5p-tv: Add PM_RUNTIME dependency
arch/arm/mach-exynos4/Kconfig | 2 ++
arch/arm/mach-exynos4/mach-smdkv310.c | 18 ++++++++++++++++++
drivers/media/video/s5p-tv/Kconfig | 2 +-
3 files changed, 21 insertions(+), 1 deletions(-)
--
1.7.2.3
^ permalink raw reply
* [PATCH v3 1/2] ARM: EXYNOS4: Add TVOUT support for SMDKV310
From: Hatim Ali @ 2011-09-22 5:54 UTC (permalink / raw)
To: linux-arm-kernel
Add support for TVOUT on SMDKV310 board.
Signed-off-by: Hatim Ali <hatim.rv@samsung.com>
---
Changes since v2:
Incorporated review comments by Tomasz Stanislawski & Sylwester Nawrocki.
- Used gpio_request_one to request for gpio line.
- Added WARN_ON to check gpio_request is successful.
Changes since v1:
Incorporated changes as suggested by Tomasz Stanislawski
- Added GPIO settings for hot-plug detection.
- Added setting hdmi and mixer's parent for TV power domain.
arch/arm/mach-exynos4/Kconfig | 2 ++
arch/arm/mach-exynos4/mach-smdkv310.c | 18 ++++++++++++++++++
2 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index 690bf6f..2857ab0 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -139,7 +139,9 @@ config MACH_SMDKV310
select S3C_DEV_RTC
select S3C_DEV_WDT
select S3C_DEV_I2C1
+ select S5P_DEV_I2C_HDMIPHY
select S5P_DEV_MFC
+ select S5P_DEV_TV
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c
index 5f62b2b..fa3f9d7 100644
--- a/arch/arm/mach-exynos4/mach-smdkv310.c
+++ b/arch/arm/mach-exynos4/mach-smdkv310.c
@@ -173,6 +173,7 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
&s3c_device_i2c1,
+ &s5p_device_i2c_hdmiphy,
&s3c_device_rtc,
&s3c_device_wdt,
&exynos4_device_ac97,
@@ -194,6 +195,8 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&samsung_asoc_idma,
&smdkv310_smsc911x,
&exynos4_device_ahci,
+ &s5p_device_hdmi,
+ &s5p_device_mixer,
};
static void __init smdkv310_smsc911x_init(void)
@@ -230,6 +233,18 @@ static struct platform_pwm_backlight_data smdkv310_bl_data = {
.pwm_period_ns = 1000,
};
+static void s5p_tv_setup(void)
+{
+ /* direct HPD to HDMI chip */
+ WARN_ON(gpio_request_one(EXYNOS4_GPX3(7),GPIOF_IN, "hpd-plug"));
+ s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE);
+
+ /* setup dependencies between TV devices */
+ s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev;
+ s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;
+}
+
static void __init smdkv310_map_io(void)
{
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -254,6 +269,9 @@ static void __init smdkv310_machine_init(void)
s3c_sdhci2_set_platdata(&smdkv310_hsmmc2_pdata);
s3c_sdhci3_set_platdata(&smdkv310_hsmmc3_pdata);
+ s5p_tv_setup();
+ s5p_i2c_hdmiphy_set_platdata(NULL);
+
samsung_keypad_set_platdata(&smdkv310_keypad_data);
samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data);
--
1.7.2.3
^ permalink raw reply related
* [RESEND PATCH 2/2] s5p-tv: Add PM_RUNTIME dependency
From: Hatim Ali @ 2011-09-22 5:54 UTC (permalink / raw)
To: linux-arm-kernel
The TVOUT driver requires PM_RUNTIME support for proper clock
enabling.
Signed-off-by: Hatim Ali <hatim.rv@samsung.com>
---
drivers/media/video/s5p-tv/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
index 9c37dee..f2a0977 100644
--- a/drivers/media/video/s5p-tv/Kconfig
+++ b/drivers/media/video/s5p-tv/Kconfig
@@ -8,7 +8,7 @@
config VIDEO_SAMSUNG_S5P_TV
bool "Samsung TV driver for S5P platform (experimental)"
- depends on PLAT_S5P
+ depends on PLAT_S5P && PM_RUNTIME
depends on EXPERIMENTAL
default n
---help---
--
1.7.2.3
^ permalink raw reply related
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Barry Song @ 2011-09-22 5:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY3T7JmcLXY-6GYHqF+3SiVK5N0xGzqsE8pv8A+S10hWQw@mail.gmail.com>
2011/9/22 Jassi Brar <jassisinghbrar@gmail.com>:
> On Thu, Sep 22, 2011 at 5:38 AM, Barry Song <21cnbao@gmail.com> wrote:
>> 2011/9/21 Jassi Brar <jassisinghbrar@gmail.com>:
>>> On Fri, Sep 16, 2011 at 3:13 PM, Barry Song <Baohua.Song@csr.com> wrote:
>>>> dma_async_device_register will re-init chan_id and chancnt,
>>>> so whatever chan_id and chancnt are set in drivers, they will
>>>> be re-written by dma_async_device_register.
>>>>
>>>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>>>> Cc: Viresh Kumar <viresh.kumar@st.com>
>>>> Cc: Vinod Koul <vinod.koul@intel.com>
>>>> Cc: Piotr Ziecik <kosmo@semihalf.com>
>>>> Cc: Yong Wang <yong.y.wang@intel.com>
>>>> Cc: Jaswinder Singh <jassi.brar@samsung.com>
>>>> Cc: Pelagicore AB <info@pelagicore.com>
>>>> Signed-off-by: Barry Song <Baohua.Song@csr.com>
>>>> ---
>>>> ?drivers/dma/at_hdmac.c ? ? ?| ? ?5 ++---
>>>> ?drivers/dma/dw_dmac.c ? ? ? | ? ?5 ++---
>>>> ?drivers/dma/intel_mid_dma.c | ? ?2 --
>>>> ?drivers/dma/mpc512x_dma.c ? | ? ?1 -
>>>> ?drivers/dma/pch_dma.c ? ? ? | ? ?2 --
>>>> ?drivers/dma/pl330.c ? ? ? ? | ? ?2 --
>>>> ?drivers/dma/timb_dma.c ? ? ?| ? ?3 +--
>>>
>>> Apparently ....
>>>
>>> drivers/dma/ppc4xx/adma.c
>>> drivers/dma/ipu/ipu_idmac.c
>>> ? ? ? still write to chan_id.
>>>
>>> drivers/dma/amba-pl08x.c
>>> drivers/dma/fsldma.c
>>> drivers/dma/ioat/dma_v2.c
>>> drivers/dma/ioat/dma.c
>>> drivers/dma/mpc512x_dma.c
>>> drivers/dma/shdma.c
>>> ? ? ? still write to chancnt
>>>
> My question was if you really intended to convert only some of
> the drivers and not others?
i intended to convert all. but i lost some....
>
>>> Most of them are simply a matter of removal, but some seem
>>> like really depending upon setting them(?)
>>>
>>> Anyways, even after you modify those as well, chan_id and chancnt
>>> are rendered overstaying guests in dmaengine core. Because chan_id
>>> of each channel would be _precisely_ the order in which the
>>> _dmac-driver_ added the channel to the 'channels' list.
>>>
>>> So if their values are _always_ gonna be just contiguously incrementing
>>> why need variables for that in the dmaengine api?
>>> Dmac drivers could use local variables for that.
>>>
>>> OTOH, why not chan_id be left solely for use by dmac drivers read by the
>>> dmaengine only to create sysfs entries ?
>>
>> actually i don't like the way dmaengine core handles chan_id. in my
>> opinion, every dmac only needs to tell dmaengine core the chan_base.
>> then dmaengine core set the id in a global scale.
>>
>> for example, if you have two dmac in system:
>> dmac0 chan_base 0
>> dmac1 chan_base 16
>> then core will have chan 0~31 by chan_id from 0 to 31 but not
>> dmac0chan0~15, dmac1chan0~15.
> But note the numbering is still decided by the dmac driver - directly
> or indirectly.
> That is, if the dmac driver reorder registering of dmac or adding
> channels to the 'channels' list, the assigned chan_id's would change.
> So why not rather get rid of chan_id assignment from dmaengine
> and do explicitly in dmac drivers ?
> Which I already submitted a patch for https://lkml.org/lkml/2011/7/21/1
i don't agree chan_id is just a property of dmac. i think chan_id is
also a property core wants.
why could not dmac driver decide the chan_id in dmaengine core? i
think that is just what dmac driver wants.dmac just tells the base,
core re-number them one by one.
if dmac can't decide the ID directly or indirectly, this will be
random. how could client driver request the channel it wants?
>
>> client drivers can request a specific chan_id just like it can request a gpio.
> No dear. That's not gonna fly if we are to have common client drivers
> across SoCs.
>
>> now dmac drivers and dmaengine core have repeated chan_id and chancnt,
>> anyway, it is a problem that should be fixed at first.
> Correct, chan_id assignment should be completely either in dmaengine
> or in dmac drivers. But this patch does neither.
>
i like the way gpiolib handles ID more.
-barry
^ permalink raw reply
* [PATCH v16 05/12] OMAP: dmtimer: switch-over to platform device driver
From: DebBarma, Tarun Kanti @ 2011-09-22 5:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922010055.GT2937@atomide.com>
[...]
>>
>> ? ? ? /* Ack possibly pending interrupt */
>
> I've left out this is_omap2 change as it really does not improve anything.
> Instead it just makes __omap_dm_timer_stop inline function more complex.
Agreed.
>
> I've also folded in the spinlock fixes in patch 10 into this patch.
Ok, thanks.
--
Tarun
>
> Updated patch below.
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:20 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: switch-over to platform device driver
>
> Register timer devices by going through hwmod database using
> hwmod API. The driver probes each of the registered devices.
> Functionality which are already performed by hwmod framework
> are removed from timer code. New set of timers present on
> OMAP4 are now supported.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Acked-by: Cousson, Benoit <b-cousson@ti.com>
> [tony at atomide.com: folded in spinlock changes, left out is_omap2]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index b2829ee..9c2f588 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -478,3 +478,23 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
>
> ? ? ? ?return ret;
> ?}
> +
> +/**
> + * omap2_dm_timer_init - top level regular device initialization
> + *
> + * Uses dedicated hwmod api to parse through hwmod database for
> + * given class name and then build and register the timer device.
> + */
> +static int __init omap2_dm_timer_init(void)
> +{
> + ? ? ? int ret;
> +
> + ? ? ? ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
> + ? ? ? if (unlikely(ret)) {
> + ? ? ? ? ? ? ? pr_err("%s: device registration failed.\n", __func__);
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +arch_initcall(omap2_dm_timer_init);
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index 92d5aff..6019208 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -36,120 +36,22 @@
> ?*/
>
> ?#include <linux/io.h>
> -#include <linux/module.h>
> ?#include <linux/slab.h>
> -#include <mach/hardware.h>
> -#include <plat/dmtimer.h>
> -#include <mach/irqs.h>
> -
> -static int dm_timer_count;
> -
> -#ifdef CONFIG_ARCH_OMAP2
> -static struct omap_dm_timer omap2_dm_timers[] = {
> - ? ? ? { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
> - ? ? ? { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
> - ? ? ? { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
> - ? ? ? { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
> - ? ? ? { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
> - ? ? ? { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
> - ? ? ? { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
> - ? ? ? { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
> - ? ? ? { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> - ? ? ? { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
> -};
> -
> -static const char *omap2_dm_source_names[] __initdata = {
> - ? ? ? "sys_ck",
> - ? ? ? "func_32k_ck",
> - ? ? ? "alt_ck",
> - ? ? ? NULL
> -};
> -
> -static struct clk *omap2_dm_source_clocks[3];
> -static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
> -
> -#else
> -#define omap2_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap2_dm_timer_count ? ? ? ? ? 0
> -#define omap2_dm_source_names ? ? ? ? ?NULL
> -#define omap2_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP2 */
> -
> -#ifdef CONFIG_ARCH_OMAP3
> -static struct omap_dm_timer omap3_dm_timers[] = {
> - ? ? ? { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
> - ? ? ? { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
> - ? ? ? { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
> - ? ? ? { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
> - ? ? ? { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
> - ? ? ? { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
> - ? ? ? { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
> - ? ? ? { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
> - ? ? ? { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
> - ? ? ? { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
> -};
> -
> -static const char *omap3_dm_source_names[] __initdata = {
> - ? ? ? "sys_ck",
> - ? ? ? "omap_32k_fck",
> - ? ? ? NULL
> -};
> -
> -static struct clk *omap3_dm_source_clocks[2];
> -static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
> -
> -#else
> -#define omap3_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap3_dm_timer_count ? ? ? ? ? 0
> -#define omap3_dm_source_names ? ? ? ? ?NULL
> -#define omap3_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP3 */
> -
> -#ifdef CONFIG_ARCH_OMAP4
> -static struct omap_dm_timer omap4_dm_timers[] = {
> - ? ? ? { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
> - ? ? ? { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
> - ? ? ? { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
> - ? ? ? { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
> - ? ? ? { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
> - ? ? ? { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 },
> - ? ? ? { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
> - ? ? ? { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
> - ? ? ? { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
> - ? ? ? { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
> - ? ? ? { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
> - ? ? ? { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
> -};
> -static const char *omap4_dm_source_names[] __initdata = {
> - ? ? ? "sys_clkin_ck",
> - ? ? ? "sys_32k_ck",
> - ? ? ? NULL
> -};
> -static struct clk *omap4_dm_source_clocks[2];
> -static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers);
> +#include <linux/err.h>
>
> -#else
> -#define omap4_dm_timers ? ? ? ? ? ? ? ? ? ? ? ?NULL
> -#define omap4_dm_timer_count ? ? ? ? ? 0
> -#define omap4_dm_source_names ? ? ? ? ?NULL
> -#define omap4_dm_source_clocks ? ? ? ? NULL
> -#endif /* CONFIG_ARCH_OMAP4 */
> -
> -static struct omap_dm_timer *dm_timers;
> -static const char **dm_source_names;
> -static struct clk **dm_source_clocks;
> +#include <plat/dmtimer.h>
>
> -static spinlock_t dm_timer_lock;
> ?static LIST_HEAD(omap_timer_list);
> +static DEFINE_SPINLOCK(dm_timer_lock);
>
> -/*
> - * Reads timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode write pending bit must be
> - * checked. Otherwise a read of a non completed write will produce an error.
> +/**
> + * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
> + * @timer: ? ? ?timer pointer over which read operation to perform
> + * @reg: ? ? ? ?lowest byte holds the register offset
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode write
> + * pending bit must be checked. Otherwise a read of a non completed write
> + * will produce an error.
> ?*/
> ?static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ?{
> @@ -157,11 +59,15 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ? ? ? ?return __omap_dm_timer_read(timer, reg, timer->posted);
> ?}
>
> -/*
> - * Writes timer registers in posted and non-posted mode. The posted mode bit
> - * is encoded in reg. Note that in posted mode the write pending bit must be
> - * checked. Otherwise a write on a register which has a pending write will be
> - * lost.
> +/**
> + * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
> + * @timer: ? ? ?timer pointer over which write operation is to perform
> + * @reg: ? ? ? ?lowest byte holds the register offset
> + * @value: ? ? ?data to write into the register
> + *
> + * The posted mode bit is encoded in reg. Note that in posted mode the write
> + * pending bit must be checked. Otherwise a write on a register which has a
> + * pending write will be lost.
> ?*/
> ?static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 value)
> @@ -189,53 +95,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
> ?static void omap_dm_timer_reset(struct omap_dm_timer *timer)
> ?{
> - ? ? ? int autoidle = 0, wakeup = 0;
> -
> - ? ? ? if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
> + ? ? ? if (timer->pdev->id != 1) {
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
> ? ? ? ? ? ? ? ?omap_dm_timer_wait_for_reset(timer);
> ? ? ? ?}
> - ? ? ? omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> -
> - ? ? ? /* Enable autoidle on OMAP2+ */
> - ? ? ? if (cpu_class_is_omap2())
> - ? ? ? ? ? ? ? autoidle = 1;
> -
> - ? ? ? /*
> - ? ? ? ?* Enable wake-up on OMAP2 CPUs.
> - ? ? ? ?*/
> - ? ? ? if (cpu_class_is_omap2())
> - ? ? ? ? ? ? ? wakeup = 1;
>
> - ? ? ? __omap_dm_timer_reset(timer, autoidle, wakeup);
> + ? ? ? __omap_dm_timer_reset(timer, 0, 0);
> ? ? ? ?timer->posted = 1;
> ?}
>
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer)
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer)
> ?{
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> + ? ? ? int ret;
> +
> + ? ? ? timer->fclk = clk_get(&timer->pdev->dev, "fck");
> + ? ? ? if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
> + ? ? ? ? ? ? ? timer->fclk = NULL;
> + ? ? ? ? ? ? ? dev_err(&timer->pdev->dev, ": No fclk handle.\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_enable(timer);
> - ? ? ? omap_dm_timer_reset(timer);
> +
> + ? ? ? if (pdata->needs_manual_reset)
> + ? ? ? ? ? ? ? omap_dm_timer_reset(timer);
> +
> + ? ? ? ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
> +
> + ? ? ? timer->posted = 1;
> + ? ? ? return ret;
> ?}
>
> ?struct omap_dm_timer *omap_dm_timer_request(void)
> ?{
> - ? ? ? struct omap_dm_timer *timer = NULL;
> + ? ? ? struct omap_dm_timer *timer = NULL, *t;
> ? ? ? ?unsigned long flags;
> - ? ? ? int i;
> + ? ? ? int ret = 0;
>
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? if (dm_timers[i].reserved)
> + ? ? ? list_for_each_entry(t, &omap_timer_list, node) {
> + ? ? ? ? ? ? ? if (t->reserved)
> ? ? ? ? ? ? ? ? ? ? ? ?continue;
>
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> + ? ? ? ? ? ? ? timer = t;
> ? ? ? ? ? ? ? ?timer->reserved = 1;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
> +
> + ? ? ? if (timer) {
> + ? ? ? ? ? ? ? ret = omap_dm_timer_prepare(timer);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 0;
> + ? ? ? ? ? ? ? ? ? ? ? timer = NULL;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> ? ? ? ?spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> - ? ? ? if (timer != NULL)
> - ? ? ? ? ? ? ? omap_dm_timer_prepare(timer);
> + ? ? ? if (!timer)
> + ? ? ? ? ? ? ? pr_debug("%s: timer request failed!\n", __func__);
>
> ? ? ? ?return timer;
> ?}
> @@ -243,23 +161,30 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request);
>
> ?struct omap_dm_timer *omap_dm_timer_request_specific(int id)
> ?{
> - ? ? ? struct omap_dm_timer *timer;
> + ? ? ? struct omap_dm_timer *timer = NULL, *t;
> ? ? ? ?unsigned long flags;
> + ? ? ? int ret = 0;
>
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> - ? ? ? if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
> - ? ? ? ? ? ? ? spin_unlock_irqrestore(&dm_timer_lock, flags);
> - ? ? ? ? ? ? ? printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
> - ? ? ? ? ? ? ? ? ? ? ?__FILE__, __LINE__, __func__, id);
> - ? ? ? ? ? ? ? dump_stack();
> - ? ? ? ? ? ? ? return NULL;
> + ? ? ? list_for_each_entry(t, &omap_timer_list, node) {
> + ? ? ? ? ? ? ? if (t->pdev->id == id && !t->reserved) {
> + ? ? ? ? ? ? ? ? ? ? ? timer = t;
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 1;
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? }
> ? ? ? ?}
>
> - ? ? ? timer = &dm_timers[id-1];
> - ? ? ? timer->reserved = 1;
> + ? ? ? if (timer) {
> + ? ? ? ? ? ? ? ret = omap_dm_timer_prepare(timer);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 0;
> + ? ? ? ? ? ? ? ? ? ? ? timer = NULL;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> ? ? ? ?spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> - ? ? ? omap_dm_timer_prepare(timer);
> + ? ? ? if (!timer)
> + ? ? ? ? ? ? ? pr_debug("%s: timer%d request failed!\n", __func__, id);
>
> ? ? ? ?return timer;
> ?}
> @@ -267,9 +192,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
> ?void omap_dm_timer_free(struct omap_dm_timer *timer)
> ?{
> - ? ? ? omap_dm_timer_enable(timer);
> - ? ? ? omap_dm_timer_reset(timer);
> ? ? ? ?omap_dm_timer_disable(timer);
> + ? ? ? clk_put(timer->fclk);
>
> ? ? ? ?WARN_ON(!timer->reserved);
> ? ? ? ?timer->reserved = 0;
> @@ -278,15 +202,15 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_free);
>
> ?void omap_dm_timer_enable(struct omap_dm_timer *timer)
> ?{
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> +
> ? ? ? ?if (timer->enabled)
> ? ? ? ? ? ? ? ?return;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? if (cpu_class_is_omap2()) {
> + ? ? ? if (!pdata->needs_manual_reset) {
> ? ? ? ? ? ? ? ?clk_enable(timer->fclk);
> ? ? ? ? ? ? ? ?clk_enable(timer->iclk);
> ? ? ? ?}
> -#endif
>
> ? ? ? ?timer->enabled = 1;
> ?}
> @@ -294,15 +218,15 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
>
> ?void omap_dm_timer_disable(struct omap_dm_timer *timer)
> ?{
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> +
> ? ? ? ?if (!timer->enabled)
> ? ? ? ? ? ? ? ?return;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? if (cpu_class_is_omap2()) {
> + ? ? ? if (!pdata->needs_manual_reset) {
> ? ? ? ? ? ? ? ?clk_disable(timer->iclk);
> ? ? ? ? ? ? ? ?clk_disable(timer->fclk);
> ? ? ? ?}
> -#endif
>
> ? ? ? ?timer->enabled = 0;
> ?}
> @@ -322,24 +246,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
> ?*/
> ?__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
> ?{
> - ? ? ? int i;
> + ? ? ? int i = 0;
> + ? ? ? struct omap_dm_timer *timer = NULL;
> + ? ? ? unsigned long flags;
>
> ? ? ? ?/* If ARMXOR cannot be idled this function call is unnecessary */
> ? ? ? ?if (!(inputmask & (1 << 1)))
> ? ? ? ? ? ? ? ?return inputmask;
>
> ? ? ? ?/* If any active timer is using ARMXOR return modified mask */
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> + ? ? ? spin_lock_irqsave(&dm_timer_lock, flags);
> + ? ? ? list_for_each_entry(timer, &omap_timer_list, node) {
> ? ? ? ? ? ? ? ?u32 l;
>
> - ? ? ? ? ? ? ? l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
> + ? ? ? ? ? ? ? l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ? ? ? ? ?if (l & OMAP_TIMER_CTRL_ST) {
> ? ? ? ? ? ? ? ? ? ? ? ?if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?inputmask &= ~(1 << 1);
> ? ? ? ? ? ? ? ? ? ? ? ?else
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?inputmask &= ~(1 << 2);
> ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? i++;
> ? ? ? ?}
> + ? ? ? spin_unlock_irqrestore(&dm_timer_lock, flags);
>
> ? ? ? ?return inputmask;
> ?}
> @@ -384,10 +313,10 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
> ?void omap_dm_timer_stop(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?unsigned long rate = 0;
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? rate = clk_get_rate(timer->fclk);
> -#endif
> + ? ? ? if (!pdata->needs_manual_reset)
> + ? ? ? ? ? ? ? rate = clk_get_rate(timer->fclk);
>
> ? ? ? ?__omap_dm_timer_stop(timer, timer->posted, rate);
> ?}
> @@ -395,15 +324,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>
> ?int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
> ?{
> + ? ? ? int ret;
> + ? ? ? struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
> +
> ? ? ? ?if (source < 0 || source >= 3)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? return __omap_dm_timer_set_source(timer->fclk,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dm_source_clocks[source]);
> -#else
> - ? ? ? return 0;
> -#endif
> + ? ? ? omap_dm_timer_disable(timer);
> + ? ? ? ret = pdata->set_timer_src(timer->pdev, source);
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? return ret;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
>
> @@ -526,13 +457,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
> ?int omap_dm_timers_active(void)
> ?{
> - ? ? ? int i;
> -
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? struct omap_dm_timer *timer;
> -
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> + ? ? ? struct omap_dm_timer *timer;
>
> + ? ? ? list_for_each_entry(timer, &omap_timer_list, node) {
> ? ? ? ? ? ? ? ?if (!timer->enabled)
> ? ? ? ? ? ? ? ? ? ? ? ?continue;
>
> @@ -602,7 +529,6 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ?timer->id = pdev->id;
> ? ? ? ?timer->irq = irq->start;
> ? ? ? ?timer->pdev = pdev;
> - ? ? ? __omap_dm_timer_init_regs(timer);
>
> ? ? ? ?/* add the timer element to the list */
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> @@ -675,73 +601,3 @@ MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
> ?MODULE_LICENSE("GPL");
> ?MODULE_ALIAS("platform:" DRIVER_NAME);
> ?MODULE_AUTHOR("Texas Instruments Inc");
> -
> -static int __init omap_dm_timer_init(void)
> -{
> - ? ? ? struct omap_dm_timer *timer;
> - ? ? ? int i, map_size = SZ_8K; ? ? ? ?/* Module 4KB + L4 4KB except on omap1 */
> -
> - ? ? ? if (!cpu_class_is_omap2())
> - ? ? ? ? ? ? ? return -ENODEV;
> -
> - ? ? ? spin_lock_init(&dm_timer_lock);
> -
> - ? ? ? if (cpu_is_omap24xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap2_dm_timers;
> - ? ? ? ? ? ? ? dm_timer_count = omap2_dm_timer_count;
> - ? ? ? ? ? ? ? dm_source_names = omap2_dm_source_names;
> - ? ? ? ? ? ? ? dm_source_clocks = omap2_dm_source_clocks;
> - ? ? ? } else if (cpu_is_omap34xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap3_dm_timers;
> - ? ? ? ? ? ? ? dm_timer_count = omap3_dm_timer_count;
> - ? ? ? ? ? ? ? dm_source_names = omap3_dm_source_names;
> - ? ? ? ? ? ? ? dm_source_clocks = omap3_dm_source_clocks;
> - ? ? ? } else if (cpu_is_omap44xx()) {
> - ? ? ? ? ? ? ? dm_timers = omap4_dm_timers;
> - ? ? ? ? ? ? ? dm_timer_count = omap4_dm_timer_count;
> - ? ? ? ? ? ? ? dm_source_names = omap4_dm_source_names;
> - ? ? ? ? ? ? ? dm_source_clocks = omap4_dm_source_clocks;
> -
> - ? ? ? ? ? ? ? pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
> - ? ? ? ? ? ? ? return -ENODEV;
> - ? ? ? }
> -
> - ? ? ? if (cpu_class_is_omap2())
> - ? ? ? ? ? ? ? for (i = 0; dm_source_names[i] != NULL; i++)
> - ? ? ? ? ? ? ? ? ? ? ? dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);
> -
> - ? ? ? if (cpu_is_omap243x())
> - ? ? ? ? ? ? ? dm_timers[0].phys_base = 0x49018000;
> -
> - ? ? ? for (i = 0; i < dm_timer_count; i++) {
> - ? ? ? ? ? ? ? timer = &dm_timers[i];
> -
> - ? ? ? ? ? ? ? /* Static mapping, never released */
> - ? ? ? ? ? ? ? timer->io_base = ioremap(timer->phys_base, map_size);
> - ? ? ? ? ? ? ? BUG_ON(!timer->io_base);
> -
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> - ? ? ? ? ? ? ? if (cpu_class_is_omap2()) {
> - ? ? ? ? ? ? ? ? ? ? ? char clk_name[16];
> - ? ? ? ? ? ? ? ? ? ? ? sprintf(clk_name, "gpt%d_ick", i + 1);
> - ? ? ? ? ? ? ? ? ? ? ? timer->iclk = clk_get(NULL, clk_name);
> - ? ? ? ? ? ? ? ? ? ? ? sprintf(clk_name, "gpt%d_fck", i + 1);
> - ? ? ? ? ? ? ? ? ? ? ? timer->fclk = clk_get(NULL, clk_name);
> - ? ? ? ? ? ? ? }
> -
> - ? ? ? ? ? ? ? /* One or two timers may be set up early for sys_timer */
> - ? ? ? ? ? ? ? if (sys_timer_reserved & (1 ?<< i)) {
> - ? ? ? ? ? ? ? ? ? ? ? timer->reserved = 1;
> - ? ? ? ? ? ? ? ? ? ? ? timer->posted = 1;
> - ? ? ? ? ? ? ? ? ? ? ? continue;
> - ? ? ? ? ? ? ? }
> -#endif
> - ? ? ? ? ? ? ? omap_dm_timer_enable(timer);
> - ? ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
> - ? ? ? ? ? ? ? omap_dm_timer_disable(timer);
> - ? ? ? }
> -
> - ? ? ? return 0;
> -}
> -
> -arch_initcall(omap_dm_timer_init);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 98f186e..2ac7538 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -231,9 +231,8 @@ struct omap_dm_timer {
> ? ? ? ?unsigned long phys_base;
> ? ? ? ?int id;
> ? ? ? ?int irq;
> -#ifdef CONFIG_ARCH_OMAP2PLUS
> ? ? ? ?struct clk *iclk, *fclk;
> -#endif
> +
> ? ? ? ?void __iomem ? ?*io_base;
> ? ? ? ?void __iomem ? ?*sys_stat; ? ? ?/* TISTAT timer status */
> ? ? ? ?void __iomem ? ?*irq_stat; ? ? ?/* TISR/IRQSTATUS interrupt status */
> @@ -251,7 +250,7 @@ struct omap_dm_timer {
> ?};
>
> ?extern u32 sys_timer_reserved;
> -void omap_dm_timer_prepare(struct omap_dm_timer *timer);
> +int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
> ?static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int posted)
>
^ permalink raw reply
* [PATCH v16 01/12] OMAP2+: dmtimer: add device names to flck nodes
From: DebBarma, Tarun Kanti @ 2011-09-22 5:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922010031.GR2937@atomide.com>
On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> Add device name to OMAP2 dmtimer fclk nodes so that the fclk nodes can be
>> retrieved by doing a clk_get with the corresponding device pointers or
>> device names.
>>
>> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com
>
> I've fixed the missing bracket in the email address ? ? ^^^
Thanks.
--
Tarun
>
> Tony
>
^ permalink raw reply
* [PATCH v16 10/12] OMAP: dmtimer: extend spinlock in request functions
From: DebBarma, Tarun Kanti @ 2011-09-22 6:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922004243.GL2937@atomide.com>
On Thu, Sep 22, 2011 at 6:12 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> The request functions now verify the success of omap_dm_timer_prepare() call
>> after a timer is acquired. If *_prepare() fails then we have to release the
>> timer. In order to avoid race condition during this time, include *_prepare()
>> within lock.
>
> This I've folded into patch 5.
That should be fine.
--
Tarun
>
> Tony
>
^ permalink raw reply
* [PATCH v16 08/12] OMAP: dmtimer: do remaining initialization in probe
From: DebBarma, Tarun Kanti @ 2011-09-22 6:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922010005.GO2937@atomide.com>
On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> @@ -514,10 +514,23 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>> ? ? ? timer->irq = irq->start;
>> ? ? ? timer->pdev = pdev;
>>
>> - ? ? /* Skip pm_runtime_enable for OMAP1 */
>> - ? ? if (!pdata->needs_manual_reset) {
>> - ? ? ? ? ? ? pm_runtime_enable(&pdev->dev);
>> - ? ? ? ? ? ? pm_runtime_irq_safe(&pdev->dev);
>> +/*
>> + * sys_timer_reserved is not defined for OMAP1.
>> + * Use the macro to avoid compilation error on OMAP1.
>> + */
>> +#if defined(CONFIG_ARCH_OMAP2PLUS)
>> + ? ? pm_runtime_enable(&pdev->dev);
>> + ? ? pm_runtime_irq_safe(&pdev->dev);
>> + ? ? /* Mark clocksource and clockevent timers as reserved */
>> + ? ? if ((sys_timer_reserved >> (pdev->id - 1)) & 0x1)
>> + ? ? ? ? ? ? timer->reserved = 1;
>> +#endif
>> +
>> + ? ? if (!timer->reserved) {
>> + ? ? ? ? ? ? pm_runtime_get_sync(&pdev->dev);
>> + ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
>> + ? ? ? ? ? ? timer->tidr = __raw_readl(timer->io_base);
>> + ? ? ? ? ? ? pm_runtime_put(&pdev->dev);
>> ? ? ? }
>>
>> ? ? ? /* add the timer element to the list */
>
> This all should not be necessary. We can pass the reserved flag
> in pdata. Let's replace this one with the patch below.
Yes, this is much better organized.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tony Lindgren <tony@atomide.com>
> Date: Wed, 21 Sep 2011 16:38:51 -0700
> Subject: [PATCH] ARM: OMAP: dmtimer: skip reserved timers
>
> Pass the reserved flag in pdata and use it. We can
> now make sys_timer_reserved static to mach-omap2/timer.c.
>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index 9c2f588..f1e3ec1 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -69,7 +69,7 @@
> ?/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
> ?#define MAX_GPTIMER_ID ? ? ? ? 12
>
> -u32 sys_timer_reserved;
> +static u32 sys_timer_reserved;
>
> ?/* Clockevent code */
>
> @@ -463,6 +463,10 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
> ? ? ? ?pdata->set_timer_src = omap2_dm_timer_set_src;
> ? ? ? ?pdata->timer_ip_version = oh->class->rev;
>
> + ? ? ? /* Mark clocksource and clockevent timers as reserved */
> + ? ? ? if ((sys_timer_reserved >> (id - 1)) & 0x1)
> + ? ? ? ? ? ? ? pdata->reserved = 1;
> +
> ? ? ? ?od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
> ? ? ? ? ? ? ? ? ? ? ? ?omap2_dmtimer_latency,
> ? ? ? ? ? ? ? ? ? ? ? ?ARRAY_SIZE(omap2_dmtimer_latency),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index ac904c2..c8df3c3 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -509,6 +509,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
>
> ? ? ? ?timer->id = pdev->id;
> ? ? ? ?timer->irq = irq->start;
> + ? ? ? timer->reserved = pdata->reserved;
> ? ? ? ?timer->pdev = pdev;
>
> ? ? ? ?/* Skip pm_runtime_enable for OMAP1 */
> @@ -517,6 +518,12 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?pm_runtime_irq_safe(&pdev->dev);
> ? ? ? ?}
>
> + ? ? ? if (!timer->reserved) {
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&pdev->dev);
> + ? ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
> + ? ? ? ? ? ? ? pm_runtime_put(&pdev->dev);
> + ? ? ? }
> +
> ? ? ? ?/* add the timer element to the list */
> ? ? ? ?spin_lock_irqsave(&dm_timer_lock, flags);
> ? ? ? ?list_add_tail(&timer->node, &omap_timer_list);
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 4e3a326..29764c3 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -77,6 +77,7 @@ struct dmtimer_platform_data {
> ? ? ? ?int (*set_timer_src)(struct platform_device *pdev, int source);
> ? ? ? ?int timer_ip_version;
> ? ? ? ?u32 needs_manual_reset:1;
> + ? ? ? bool reserved;
> ?};
>
> ?struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -248,7 +249,6 @@ struct omap_dm_timer {
> ? ? ? ?struct list_head node;
> ?};
>
> -extern u32 sys_timer_reserved;
> ?int omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
> ?static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
>
^ permalink raw reply
* [PATCH v16 09/12] OMAP: dmtimer: low-power mode support
From: DebBarma, Tarun Kanti @ 2011-09-22 6:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922010015.GP2937@atomide.com>
On Thu, Sep 22, 2011 at 6:30 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> Clock is enabled only when timer is started and disabled when the the timer
>> is stopped. Therefore before accessing registers in functions clock is enabled
>> and then disabled back at the end of access. Context save is done dynamically
>> whenever the registers are modified. Context restore is called when context is
>> lost.
>
> I've updated this to use revision instead of tidr. Updated patch below.
Ok.
--
Tarun
>
> Regards,
>
> Tony
>
>
> From: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Date: Tue, 20 Sep 2011 17:00:24 +0530
> Subject: [PATCH] ARM: OMAP: dmtimer: low-power mode support
>
> Clock is enabled only when timer is started and disabled when the the timer
> is stopped. Therefore before accessing registers in functions clock is enabled
> and then disabled back at the end of access. Context save is done dynamically
> whenever the registers are modified. Context restore is called when context is
> lost.
>
> Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com>
> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> [tony at atomide.com: updated to use revision instead of tidr]
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index f1e3ec1..1140e98 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -44,6 +44,9 @@
> ?#include <plat/common.h>
> ?#include <plat/omap_hwmod.h>
> ?#include <plat/omap_device.h>
> +#include <plat/omap-pm.h>
> +
> +#include "powerdomain.h"
>
> ?/* Parent clocks, eventually these will come from the clock framework */
>
> @@ -433,6 +436,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
> ? ? ? ?struct dmtimer_platform_data *pdata;
> ? ? ? ?struct omap_device *od;
> ? ? ? ?struct omap_timer_capability_dev_attr *timer_dev_attr;
> + ? ? ? struct powerdomain *pwrdm;
>
> ? ? ? ?pr_debug("%s: %s\n", __func__, oh->name);
>
> @@ -467,6 +471,11 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
> ? ? ? ?if ((sys_timer_reserved >> (id - 1)) & 0x1)
> ? ? ? ? ? ? ? ?pdata->reserved = 1;
>
> + ? ? ? pwrdm = omap_hwmod_get_pwrdm(oh);
> + ? ? ? pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
> +#ifdef CONFIG_PM
> + ? ? ? pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
> +#endif
> ? ? ? ?od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
> ? ? ? ? ? ? ? ? ? ? ? ?omap2_dmtimer_latency,
> ? ? ? ? ? ? ? ? ? ? ? ?ARRAY_SIZE(omap2_dmtimer_latency),
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index c8df3c3..43eb750 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -77,6 +77,29 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ?__omap_dm_timer_write(timer, reg, value, timer->posted);
> ?}
>
> +static void omap_timer_restore_context(struct omap_dm_timer *timer)
> +{
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tiocp_cfg);
> + ? ? ? if (timer->revision > 1)
> + ? ? ? ? ? ? ? __raw_writel(timer->context.tistat, timer->sys_stat);
> +
> + ? ? ? __raw_writel(timer->context.tisr, timer->irq_stat);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.twer);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tcrr);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tldr);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tmar);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tsicr);
> + ? ? ? __raw_writel(timer->context.tier, timer->irq_ena);
> + ? ? ? omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timer->context.tclr);
> +}
> +
> ?static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?int c;
> @@ -96,12 +119,14 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
>
> ?static void omap_dm_timer_reset(struct omap_dm_timer *timer)
> ?{
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?if (timer->pdev->id != 1) {
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
> ? ? ? ? ? ? ? ?omap_dm_timer_wait_for_reset(timer);
> ? ? ? ?}
>
> ? ? ? ?__omap_dm_timer_reset(timer, 0, 0);
> + ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?timer->posted = 1;
> ?}
>
> @@ -117,8 +142,6 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
>
> - ? ? ? omap_dm_timer_enable(timer);
> -
> ? ? ? ?if (pdata->needs_manual_reset)
> ? ? ? ? ? ? ? ?omap_dm_timer_reset(timer);
>
> @@ -193,7 +216,6 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
>
> ?void omap_dm_timer_free(struct omap_dm_timer *timer)
> ?{
> - ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?clk_put(timer->fclk);
>
> ? ? ? ?WARN_ON(!timer->reserved);
> @@ -275,6 +297,11 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
>
> ?void omap_dm_timer_trigger(struct omap_dm_timer *timer)
> ?{
> + ? ? ? if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
> + ? ? ? ? ? ? ? pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
> + ? ? ? ? ? ? ? return;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
> @@ -283,11 +310,23 @@ void omap_dm_timer_start(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? if (timer->loses_context) {
> + ? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
> + ? ? ? ? ? ? ? if (ctx_loss_cnt_after != timer->ctx_loss_count)
> + ? ? ? ? ? ? ? ? ? ? ? omap_timer_restore_context(timer);
> + ? ? ? }
> +
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (!(l & OMAP_TIMER_CTRL_ST)) {
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_ST;
> ? ? ? ? ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> ? ? ? ?}
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_start);
>
> @@ -311,9 +350,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
> ? ? ? ?if (source < 0 || source >= 3)
> ? ? ? ? ? ? ? ?return -EINVAL;
>
> - ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?ret = pdata->set_timer_src(timer->pdev, source);
> - ? ? ? omap_dm_timer_enable(timer);
>
> ? ? ? ?return ret;
> ?}
> @@ -324,6 +361,7 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (autoreload)
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_AR;
> @@ -333,6 +371,10 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
>
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tldr = load;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
>
> @@ -342,6 +384,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> +
> + ? ? ? if (timer->loses_context) {
> + ? ? ? ? ? ? ? u32 ctx_loss_cnt_after =
> + ? ? ? ? ? ? ? ? ? ? ? timer->get_context_loss_count(&timer->pdev->dev);
> + ? ? ? ? ? ? ? if (ctx_loss_cnt_after != timer->ctx_loss_count)
> + ? ? ? ? ? ? ? ? ? ? ? omap_timer_restore_context(timer);
> + ? ? ? }
> +
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (autoreload) {
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_AR;
> @@ -352,6 +403,11 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
> ? ? ? ?l |= OMAP_TIMER_CTRL_ST;
>
> ? ? ? ?__omap_dm_timer_load_start(timer, l, load, timer->posted);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tldr = load;
> + ? ? ? timer->context.tcrr = load;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
>
> @@ -360,6 +416,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?if (enable)
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_CE;
> @@ -367,6 +424,11 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
> ? ? ? ? ? ? ? ?l &= ~OMAP_TIMER_CTRL_CE;
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? timer->context.tmar = match;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
>
> @@ -375,6 +437,7 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
> ? ? ? ? ? ? ? OMAP_TIMER_CTRL_PT | (0x03 << 10));
> @@ -384,6 +447,10 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
> ? ? ? ? ? ? ? ?l |= OMAP_TIMER_CTRL_PT;
> ? ? ? ?l |= trigger << 10;
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
>
> @@ -391,6 +458,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
> ?{
> ? ? ? ?u32 l;
>
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
> ? ? ? ?l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
> ? ? ? ?if (prescaler >= 0x00 && prescaler <= 0x07) {
> @@ -398,13 +466,23 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
> ? ? ? ? ? ? ? ?l |= prescaler << 2;
> ? ? ? ?}
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tclr = l;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
>
> ?void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value)
> ?{
> + ? ? ? omap_dm_timer_enable(timer);
> ? ? ? ?__omap_dm_timer_int_enable(timer, value);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tier = value;
> + ? ? ? timer->context.twer = value;
> + ? ? ? omap_dm_timer_disable(timer);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
>
> @@ -412,6 +490,11 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?unsigned int l;
>
> + ? ? ? if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
> + ? ? ? ? ? ? ? pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> +
> ? ? ? ?l = __raw_readl(timer->irq_stat);
>
> ? ? ? ?return l;
> @@ -421,18 +504,33 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
> ?void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
> ?{
> ? ? ? ?__omap_dm_timer_write_status(timer, value);
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tisr = value;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
>
> ?unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
> ?{
> + ? ? ? if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
> + ? ? ? ? ? ? ? pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> +
> ? ? ? ?return __omap_dm_timer_read_counter(timer, timer->posted);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
>
> ?void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
> ?{
> + ? ? ? if (unlikely(pm_runtime_suspended(&timer->pdev->dev))) {
> + ? ? ? ? ? ? ? pr_err("%s: timer%d not enabled.\n", __func__, timer->id);
> + ? ? ? ? ? ? ? return;
> + ? ? ? }
> +
> ? ? ? ?omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
> +
> + ? ? ? /* Save the context */
> + ? ? ? timer->context.tcrr = value;
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
>
> @@ -511,6 +609,8 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
> ? ? ? ?timer->irq = irq->start;
> ? ? ? ?timer->reserved = pdata->reserved;
> ? ? ? ?timer->pdev = pdev;
> + ? ? ? timer->loses_context = pdata->loses_context;
> + ? ? ? timer->get_context_loss_count = pdata->get_context_loss_count;
>
> ? ? ? ?/* Skip pm_runtime_enable for OMAP1 */
> ? ? ? ?if (!pdata->needs_manual_reset) {
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index 29764c3..9519d87 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -73,11 +73,38 @@ struct omap_timer_capability_dev_attr {
> ?struct omap_dm_timer;
> ?struct clk;
>
> +struct timer_regs {
> + ? ? ? u32 tidr;
> + ? ? ? u32 tiocp_cfg;
> + ? ? ? u32 tistat;
> + ? ? ? u32 tisr;
> + ? ? ? u32 tier;
> + ? ? ? u32 twer;
> + ? ? ? u32 tclr;
> + ? ? ? u32 tcrr;
> + ? ? ? u32 tldr;
> + ? ? ? u32 ttrg;
> + ? ? ? u32 twps;
> + ? ? ? u32 tmar;
> + ? ? ? u32 tcar1;
> + ? ? ? u32 tsicr;
> + ? ? ? u32 tcar2;
> + ? ? ? u32 tpir;
> + ? ? ? u32 tnir;
> + ? ? ? u32 tcvr;
> + ? ? ? u32 tocr;
> + ? ? ? u32 towr;
> +};
> +
> ?struct dmtimer_platform_data {
> ? ? ? ?int (*set_timer_src)(struct platform_device *pdev, int source);
> ? ? ? ?int timer_ip_version;
> ? ? ? ?u32 needs_manual_reset:1;
> ? ? ? ?bool reserved;
> +
> + ? ? ? bool loses_context;
> +
> + ? ? ? u32 (*get_context_loss_count)(struct device *dev);
> ?};
>
> ?struct omap_dm_timer *omap_dm_timer_request(void);
> @@ -245,8 +272,14 @@ struct omap_dm_timer {
> ? ? ? ?unsigned long rate;
> ? ? ? ?unsigned reserved:1;
> ? ? ? ?unsigned posted:1;
> + ? ? ? struct timer_regs context;
> + ? ? ? bool loses_context;
> + ? ? ? int ctx_loss_count;
> + ? ? ? int revision;
> ? ? ? ?struct platform_device *pdev;
> ? ? ? ?struct list_head node;
> +
> + ? ? ? u32 (*get_context_loss_count)(struct device *dev);
> ?};
>
> ?int omap_dm_timer_prepare(struct omap_dm_timer *timer);
> @@ -278,6 +311,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
> ? ? ? ?/* Assume v1 ip if bits [31:16] are zero */
> ? ? ? ?tidr = __raw_readl(timer->io_base);
> ? ? ? ?if (!(tidr >> 16)) {
> + ? ? ? ? ? ? ? timer->revision = 1;
> ? ? ? ? ? ? ? ?timer->sys_stat = timer->io_base +
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_V1_SYS_STAT_OFFSET;
> ? ? ? ? ? ? ? ?timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
> @@ -286,6 +320,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
> ? ? ? ? ? ? ? ?timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
> ? ? ? ? ? ? ? ?timer->func_base = timer->io_base;
> ? ? ? ?} else {
> + ? ? ? ? ? ? ? timer->revision = 2;
> ? ? ? ? ? ? ? ?timer->sys_stat = 0;
> ? ? ? ? ? ? ? ?timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
> ? ? ? ? ? ? ? ?timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
>
^ permalink raw reply
* [PATCH v16 00/12] OMAP: dmtimer: adaptation to platform_driver
From: DebBarma, Tarun Kanti @ 2011-09-22 6:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922005930.GN2937@atomide.com>
On Thu, Sep 22, 2011 at 6:29 AM, Tony Lindgren <tony@atomide.com> wrote:
> Hi Tarun,
>
> * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110920 03:57]:
>> Adaptation of dmtimer code to platform driver using omap_device and
>> omap_hwmod abstraction. It also include pm-runtime and off-mode support.
>
> I've applied these into dmtimer branch with some changes to simplify
> things further. I've also merged it into linux-omap master branch
> for further testing.
>
> I'll reply to your patches with the changes I've done. Care give the
> dmtimer branch a try and see if I've missed something?
Sure, I will go through the changes and do testing on it.
--
Tarun
>
> Regards,
>
> Tony
>
^ permalink raw reply
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Jassi Brar @ 2011-09-22 6:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY3T7JmcLXY-6GYHqF+3SiVK5N0xGzqsE8pv8A+S10hWQw@mail.gmail.com>
On Thu, Sep 22, 2011 at 11:11 AM, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>
>> client drivers can request a specific chan_id just like it can request a gpio.
> No dear. That's not gonna fly if we are to have common client drivers
> across SoCs.
>
Btw, I meant you can't simply have clients specify a channel number and
get the channel in a portable manner. Clients need to specify the capabilities
they need of the channel.
^ permalink raw reply
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Barry Song @ 2011-09-22 6:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY3mCHwWx-8gQG75107eWQBT1kPDu59vi9vHU+OQFXq_kg@mail.gmail.com>
2011/9/22 Jassi Brar <jassisinghbrar@gmail.com>:
> On Thu, Sep 22, 2011 at 11:11 AM, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>>
>>> client drivers can request a specific chan_id just like it can request a gpio.
>> No dear. That's not gonna fly if we are to have common client drivers
>> across SoCs.
>>
> Btw, I meant you can't simply have clients specify a channel number and
> get the channel in a portable manner. Clients need to specify the capabilities
> they need of the channel.
if the dmac is flexible in design, what you said is right. but the
problem is that there are some chips which actually fix one channel to
one peripheral.
-barry
^ permalink raw reply
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Jassi Brar @ 2011-09-22 6:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGsJ_4x-SxYLyuyR9nQ530DhmfYN-Bqc2DOSyAVhM=h3zxCvMw@mail.gmail.com>
On Thu, Sep 22, 2011 at 12:01 PM, Barry Song <21cnbao@gmail.com> wrote:
> 2011/9/22 Jassi Brar <jassisinghbrar@gmail.com>:
>> On Thu, Sep 22, 2011 at 11:11 AM, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>>>
>>>> client drivers can request a specific chan_id just like it can request a gpio.
>>> No dear. That's not gonna fly if we are to have common client drivers
>>> across SoCs.
>>>
>> Btw, I meant you can't simply have clients specify a channel number and
>> get the channel in a portable manner. Clients need to specify the capabilities
>> they need of the channel.
>
> if the dmac is flexible in design, what you said is right. but the
> problem is that there are some chips which actually fix one channel to
> one peripheral.
Nevertheless it is better to assume the dmac's req-signals could be hacked
to re-route at even runtime.
Also it won't work for client drivers that run the same controller on different
SoC with a different dmac.
^ permalink raw reply
* [PATCH] dmaengine: delete redundant chan_id and chancnt initialization in dma drivers
From: Barry Song @ 2011-09-22 6:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABb+yY3ufFhD6Gf-OqYPpa2k--c8z52fFn6VDEpmc_NgWC04XQ@mail.gmail.com>
2011/9/22 Jassi Brar <jassisinghbrar@gmail.com>:
> On Thu, Sep 22, 2011 at 12:01 PM, Barry Song <21cnbao@gmail.com> wrote:
>> 2011/9/22 Jassi Brar <jassisinghbrar@gmail.com>:
>>> On Thu, Sep 22, 2011 at 11:11 AM, Jassi Brar <jassisinghbrar@gmail.com> wrote:
>>>>
>>>>> client drivers can request a specific chan_id just like it can request a gpio.
>>>> No dear. That's not gonna fly if we are to have common client drivers
>>>> across SoCs.
>>>>
>>> Btw, I meant you can't simply have clients specify a channel number and
>>> get the channel in a portable manner. Clients need to specify the capabilities
>>> they need of the channel.
>>
>> if the dmac is flexible in design, what you said is right. but the
>> problem is that there are some chips which actually fix one channel to
>> one peripheral.
> Nevertheless it is better to assume the dmac's req-signals could be hacked
> to re-route at even runtime.
> Also it won't work for client drivers that run the same controller on different
> SoC with a different dmac.
>
you mean there is a mapping table in dmac driver. otherwise, there
will always require some changes in client drivers.
-barry
^ permalink raw reply
* [PATCH] arm: Add unwinding annotations for 64bit division functions
From: Jon Medhurst (Tixy) @ 2011-09-22 7:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110921115553.GF17169@n2100.arm.linux.org.uk>
On Wed, 2011-09-21 at 12:55 +0100, Russell King - ARM Linux wrote:
> Instructions such as VFP, kprobes tracing, etc are expected fault
> locations, and those are fairly well controlled where they can be placed.
> With things like ftrace, it certainly is the case that the unwinder can
> theoretically be called from almost anywhere in a function.
Actually, kprobes can be places on any instruction in the kernel that
isn't in the section .kprobes.text.
I also strongly suspect that stack unwinding won't happen correctly
across the boundary between the kprobes handling code and the function
which was probed - there's an awful lot of stack jiggery pokery going on
there.
--
Tixy
^ permalink raw reply
* parallel load of modules on an ARM multicore
From: George G. Davis @ 2011-09-22 7:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <274124B9C6907D4B8CE985903EAA19E9185A92923E@SI-MBX06.de.bosch.com>
Hello,
On Mon, Jun 20, 2011 at 03:43:27PM +0200, EXTERNAL Waechtler Peter (Fa. TCP, CM-AI/PJ-CF31) wrote:
> Hi,
>
> I'm getting unexpected results from loading several modules - some
> of them in parallel - on an ARM11 MPcore system.
>
> The system does not use "single sequential" modprobe commands - instead it
> starts several shells doing insmod sequences like this:
>
> shell A:
> insmod a
> insmod ab
> insmod abc
>
> shell B:
> insmod b
> insmod bc
> insmod bcd
>
> shell C:
> insmod c
> insmod cd
> insmod cde
>
> This is done to crash^H^H^H^H^Hboot faster ;)
>
> While one insmod operation is protected via the module_mutex - I'm wondering
> what happens with the instruction cache invalidation.
> AFAICT the flush_icache_range only invalidates the ICache on the running cpu.
> The module_mutex is unlocked after _loading_ the module, do_mod_ctors() and
> do_one_initcall() are called without that lock - can they run on a different cpu?
> It's an preemptible system (SMP PREEMPT armv6l).
In case anyone missed the subtlety, this report was for an ARM11 MPCore system
with CONFIG_PREEMPT enabled. I've also been looking into this and various other
memory corruption issues on ARM11 MPCore with CONFIG_PREEMPT enabled and have
come to the conclusion that CONFIG_PREEMPT is broken on ARM11 MPCore.
I added the following instrumentation in 3.1.0-rc4ish to watch for
process migration in a few places of interest:
diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
index 22de005..e36d682 100644
--- a/arch/arm/include/asm/pgalloc.h
+++ b/arch/arm/include/asm/pgalloc.h
@@ -62,11 +62,18 @@ static inline pte_t *
pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
{
pte_t *pte;
+ int cpu = raw_smp_processor_id();
pte = (pte_t *)__get_free_page(PGALLOC_GFP);
if (pte)
clean_pte_table(pte);
+// WARN_ON(cpu != raw_smp_processor_id());
+ if (cpu != raw_smp_processor_id())
+ printk(KERN_EMERG "%s:%d: cpu was %d but is now %d, memory corruption is possible\n",
+ __func__, __LINE__, cpu, raw_smp_processor_id());
+
+
return pte;
}
@@ -74,6 +81,7 @@ static inline pgtable_t
pte_alloc_one(struct mm_struct *mm, unsigned long addr)
{
struct page *pte;
+ int cpu = raw_smp_processor_id();
#ifdef CONFIG_HIGHPTE
pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0);
@@ -86,6 +94,11 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
pgtable_page_ctor(pte);
}
+// WARN_ON(cpu != raw_smp_processor_id());
+ if (cpu != raw_smp_processor_id())
+ printk(KERN_EMERG "%s:%d: cpu was %d but is now %d, memory corruption is possible\n",
+ __func__, __LINE__, cpu, raw_smp_processor_id());
+
return pte;
}
@@ -108,9 +121,14 @@ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
unsigned long prot)
{
unsigned long pmdval = (pte + PTE_HWTABLE_OFF) | prot;
+ int cpu = raw_smp_processor_id();
pmdp[0] = __pmd(pmdval);
pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
flush_pmd_entry(pmdp);
+// WARN_ON(cpu != raw_smp_processor_id());
+ if (cpu != raw_smp_processor_id())
+ printk(KERN_EMERG "%s:%d: cpu was %d but is now %d, memory corruption is possible\n",
+ __func__, __LINE__, cpu, raw_smp_processor_id());
}
/*
diff --git a/kernel/module.c b/kernel/module.c
index e0ddcec..6a43af8 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2807,6 +2807,7 @@ static struct module *load_module(void __user *umod,
struct load_info info = { NULL, };
struct module *mod;
long err;
+ int cpu = raw_smp_processor_id();
DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
umod, len, uargs);
@@ -2852,6 +2853,9 @@ static struct module *load_module(void __user *umod,
if (err < 0)
goto free_modinfo;
+ if (cpu != raw_smp_processor_id())
+ printk(KERN_EMERG "%s:%d: cpu was %d but is now %d, memory corruption is possible\n",
+ __func__, __LINE__, cpu, raw_smp_processor_id());
flush_module_icache(mod);
/* Now copy in args */
Now with sufficient system stress, I get the following recurring problems
(it's a 3-core system : ):
load_module:2858: cpu was 0 but is now 1, memory corruption is possible
load_module:2858: cpu was 0 but is now 2, memory corruption is possible
load_module:2858: cpu was 1 but is now 0, memory corruption is possible
load_module:2858: cpu was 1 but is now 2, memory corruption is possible
load_module:2858: cpu was 2 but is now 0, memory corruption is possible
load_module:2858: cpu was 2 but is now 1, memory corruption is possible
pte_alloc_one:100: cpu was 0 but is now 1, memory corruption is possible
pte_alloc_one:100: cpu was 0 but is now 2, memory corruption is possible
pte_alloc_one:100: cpu was 1 but is now 0, memory corruption is possible
pte_alloc_one:100: cpu was 1 but is now 2, memory corruption is possible
pte_alloc_one:100: cpu was 2 but is now 0, memory corruption is possible
pte_alloc_one:100: cpu was 2 but is now 1, memory corruption is possible
pte_alloc_one_kernel:74: cpu was 2 but is now 1, memory corruption is possible
With sufficient stress and extended run time, the system will eventually
hang or oops with non-sensical oops traces - machine state does not
make sense relative to the code excuting@the time of the oops.
The interesting point here is that each of the above contain critical
sections in which ARM11 MPCore memory is inconsistent, i.e. cache on
CPU A contains modified entries but then migration occurs and the
cache is flushed on CPU B yet those cache ops called in the above
cases do not implement ARM11 MPCore RWFO workarounds. Furthermore,
the current ARM11 MPCore RWFO workarounds for DMA et al are unsafe
as well for the CONFIG_PREEMPT case because, again, process migration
can occur during DMA cache maintance operations in between RWFO and
cache op instructions resulting in memory inconsistencies for the
DMA case - a very narrow but real window.
So what's the recommendation, don't use CONFIG_PREEMPT on ARM11 MPCore?
Are there any known fixes for CONFIG_PREEMPT on ARM11 MPCore if it
is indeed broken as it appears?
Thanks in advance for comments.
--
Regards,
George
>
> Wouldn't it be required to flush the icache on _all_ cpus?
> It might be highly dependable from the cache organization, but isn't it possible
> that the cpu that didn't load the module, is scheduled to run a function from it
> with a "stale" instruction cache line???
>
> I sometimes see oopses where I wonder how such a state could be reached.
> The code and register state seem not to fit - looks like an interrupt does not
> restore all registers properly :)
>
> Also an Oops happens when loading module abc, and still the module list is
> reported empty in the Oops despite the fact that "abc" depends on "a". Hmh.
>
>
> Best regards
>
> Peter
>
> <snip kernel/module.c:SYSCALL_DEFINE3(init_module>
> [..]
> /* Only one module load at a time, please */
> if (mutex_lock_interruptible(&module_mutex) != 0)
> return -EINTR;
>
> /* Do all the hard work */
> mod = load_module(umod, len, uargs);
> if (IS_ERR(mod)) {
> mutex_unlock(&module_mutex);
> return PTR_ERR(mod);
> }
>
> /* Drop lock so they can recurse */
> mutex_unlock(&module_mutex);
>
> blocking_notifier_call_chain(&module_notify_list,
> MODULE_STATE_COMING, mod);
>
> do_mod_ctors(mod);
> /* Start the module */
> if (mod->init != NULL)
> ret = do_one_initcall(mod->init);
> </snip>
>
> <snip kernel/module.c:load_module>
> [..]
> old_fs = get_fs();
> set_fs(KERNEL_DS);
>
> /*
> * Flush the instruction cache, since we've played with text.
> * Do it before processing of module parameters, so the module
> * can provide parameter accessor functions of its own.
> */
> if (mod->module_init)
> flush_icache_range((unsigned long)mod->module_init,
> (unsigned long)mod->module_init
> + mod->init_size);
> flush_icache_range((unsigned long)mod->module_core,
> (unsigned long)mod->module_core + mod->core_size);
>
> set_fs(old_fs);
>
> </snip>
>
> arch/arm/mm/cache-v6.S:
>
> ENTRY(v6_flush_kern_cache_all)
> mov r0, #0
> #ifdef HARVARD_CACHE
> mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate
> #ifndef CONFIG_ARM_ERRATA_411920
> mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
> #else
> b v6_icache_inval_all
> #endif
> #else
> mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate
> #endif
> mov pc, lr
>
>
>
>
>
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 2/2] at91: add Atmel ISI and ov2640 support on sam9m10/sam9g45 board.
From: Guennadi Liakhovetski @ 2011-09-22 7:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316664661-11383-2-git-send-email-josh.wu@atmel.com>
On Thu, 22 Sep 2011, Josh Wu wrote:
> This patch
> 1. add ISI_MCK parent setting code when add ISI device.
> 2. add ov2640 support on board file.
> 3. define isi_mck clock in sam9g45 chip file.
>
> Signed-off-by: Josh Wu <josh.wu@atmel.com>
> ---
> arch/arm/mach-at91/at91sam9g45.c | 3 +
> arch/arm/mach-at91/at91sam9g45_devices.c | 105 +++++++++++++++++++++++++++++-
> arch/arm/mach-at91/board-sam9m10g45ek.c | 85 ++++++++++++++++++++++++-
> arch/arm/mach-at91/include/mach/board.h | 3 +-
Personally, I think, it would be better to separate this into two patches
at least: one for at91 core and one for the specific board, but that's up
to arch maintainers to decide.
You also want to patch arch/arm/mach-at91/at91sam9263_devices.c, don't
you?
> 4 files changed, 193 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
> index e04c5fb..5e23d6d 100644
> --- a/arch/arm/mach-at91/at91sam9g45.c
> +++ b/arch/arm/mach-at91/at91sam9g45.c
> @@ -201,6 +201,7 @@ static struct clk *periph_clocks[] __initdata = {
> // irq0
> };
>
> +static struct clk pck1;
Hm, it really doesn't need any initialisation, not even for the .type
field? .type=0 doesn't seem to be valid.
> static struct clk_lookup periph_clocks_lookups[] = {
> /* One additional fake clock for ohci */
> CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
> @@ -215,6 +216,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
> CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
> CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
> CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
> + /* ISI_MCK, which is provided by programmable clock(PCK1) */
> + CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", &pck1),
> };
>
> static struct clk_lookup usart_clocks_lookups[] = {
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index 600bffb..82eeac8 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -16,7 +16,7 @@
> #include <linux/platform_device.h>
> #include <linux/i2c-gpio.h>
> #include <linux/atmel-mci.h>
> -
> +#include <linux/clk.h>
> #include <linux/fb.h>
> #include <video/atmel_lcdc.h>
>
> @@ -28,6 +28,8 @@
> #include <mach/at_hdmac.h>
> #include <mach/atmel-mci.h>
>
> +#include <media/atmel-isi.h>
> +
> #include "generic.h"
>
>
> @@ -863,6 +865,107 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data)
> void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
> #endif
>
> +/* --------------------------------------------------------------------
> + * Image Sensor Interface
> + * -------------------------------------------------------------------- */
> +#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
> +static u64 isi_dmamask = DMA_BIT_MASK(32);
> +static struct isi_platform_data isi_data;
> +
> +struct resource isi_resources[] = {
> + [0] = {
> + .start = AT91SAM9G45_BASE_ISI,
> + .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + .start = AT91SAM9G45_ID_ISI,
> + .end = AT91SAM9G45_ID_ISI,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device at91sam9g45_isi_device = {
> + .name = "atmel_isi",
> + .id = 0,
> + .dev = {
> + .dma_mask = &isi_dmamask,
> + .coherent_dma_mask = DMA_BIT_MASK(32),
> + .platform_data = &isi_data,
> + },
> + .resource = isi_resources,
> + .num_resources = ARRAY_SIZE(isi_resources),
> +};
> +
> +static int __init isi_set_clk_parent(void)
> +{
> + struct clk *pck1;
> + struct clk *plla;
> + int ret;
> +
> + /* ISI_MCK is supplied by PCK1 - set parent for it. */
> + pck1 = clk_get(NULL, "pck1");
> + if (IS_ERR(pck1)) {
> + printk(KERN_ERR "Failed to get PCK1\n");
> + ret = PTR_ERR(pck1);
> + goto err;
> + }
> +
> + plla = clk_get(NULL, "plla");
> + if (IS_ERR(plla)) {
> + printk(KERN_ERR "Failed to get PLLA\n");
> + ret = PTR_ERR(plla);
> + goto err_pck1;
> + }
> + ret = clk_set_parent(pck1, plla);
> + clk_put(plla);
> + if (ret != 0) {
> + printk(KERN_ERR "Failed to set PCK1 parent\n");
> + goto err_pck1;
> + }
> + return ret;
> +
> +err_pck1:
> + clk_put(pck1);
> +err:
> + return ret;
> +}
> +
> +void __init at91_add_device_isi(struct isi_platform_data * data)
> +{
> + if (!data)
> + return;
> + isi_data = *data;
> +
> + at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */
> + at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */
> + at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */
> + at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */
> + at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */
> + at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */
> + at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */
> + at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */
> + at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */
> + at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */
> + at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */
> + at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */
> + at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */
> + at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */
> + at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */
> + at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */
> +
> + platform_device_register(&at91sam9g45_isi_device);
> +
> + if (isi_set_clk_parent())
> + printk(KERN_ERR "Fail to set parent for ISI_MCK.\n");
> +
> + return;
> +}
> +#else
> +static int __init isi_set_clk_parent(void) { }
> +void __init at91_add_device_isi(struct isi_platform_data * data) { }
> +#endif
> +
>
> /* --------------------------------------------------------------------
> * LCD Controller
> diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
> index ad234cc..d5293fb 100644
> --- a/arch/arm/mach-at91/board-sam9m10g45ek.c
> +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
> @@ -23,11 +23,13 @@
> #include <linux/gpio_keys.h>
> #include <linux/input.h>
> #include <linux/leds.h>
> -#include <linux/clk.h>
> #include <linux/atmel-mci.h>
> +#include <linux/delay.h>
>
> #include <mach/hardware.h>
> #include <video/atmel_lcdc.h>
> +#include <media/soc_camera.h>
> +#include <media/atmel-isi.h>
>
> #include <asm/setup.h>
> #include <asm/mach-types.h>
> @@ -185,6 +187,83 @@ static void __init ek_add_device_nand(void)
> at91_add_device_nand(&ek_nand_data);
> }
>
> +/*
> + * ISI
> + */
> +#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
> +static struct isi_platform_data __initdata isi_data = {
> + .frate = ISI_CFG1_FRATE_CAPTURE_ALL,
> + .has_emb_sync = 0,
> + .emb_crc_sync = 0,
> + .hsync_act_low = 0,
> + .vsync_act_low = 0,
> + .pclk_act_falling = 0,
You don't need all the "= 0" assignments above - all uninitialised fields
will be = 0. Also, if you have started aligning assignments, as in .frate
and .has_emb_sync, would be better to align all of them.
> + /* to use codec and preview path simultaneously */
> + .isi_full_mode = 1,
> + .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
> + /* ISI_MCK is provided by PCK1 */
> + .isi_mck_hz = 25000000,
> +};
> +
> +#else
> +static struct isi_platform_data __initdata isi_data;
Hmm, that doesn't help a lot, does it? Either do not allocate isi_data if
ISI is not selected in .config, or just remove the "#if" completely.
> +#endif
> +
> +/*
> + * soc-camera OV2640
> + */
> +#if defined(CONFIG_SOC_CAMERA_OV2640)
... || defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
> +static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
> +{
> + /* ISI board for ek using default 8-bits connection */
> + return SOCAM_DATAWIDTH_8;
> +}
> +
> +static int i2c_camera_power(struct device *dev, int on)
> +{
> + /* enable or disable the camera */
> + pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
> + at91_set_gpio_output(AT91_PIN_PD13, on ? 0 : 1);
maybe just
at91_set_gpio_output(AT91_PIN_PD13, !on);
> +
> + if (!on)
> + goto out;
> +
> + /* If enabled, give a reset impulse */
> + at91_set_gpio_output(AT91_PIN_PD12, 0);
> + msleep(20);
> + at91_set_gpio_output(AT91_PIN_PD12, 1);
> + msleep(100);
> +
> +out:
> + return 0;
> +}
> +
> +static struct i2c_board_info i2c_camera = {
> + I2C_BOARD_INFO("ov2640", 0x30),
> +};
> +
> +static struct soc_camera_link iclink_ov2640 = {
> + .bus_id = 0,
> + .board_info = &i2c_camera,
> + .i2c_adapter_id = 0,
> + .power = i2c_camera_power,
> + .query_bus_param = isi_camera_query_bus_param,
You could as well make this alignment look better.
> +};
> +
> +static struct platform_device isi_ov2640 = {
> + .name = "soc-camera-pdrv",
> + .id = 0,
> + .dev = {
> + .platform_data = &iclink_ov2640,
> + },
> +};
> +
> +static struct platform_device *devices[] __initdata = {
> + &isi_ov2640,
> +};
> +#else
> +static struct platform_device *devices[] __initdata = {};
> +#endif
>
> /*
> * LCD Controller
> @@ -400,6 +479,10 @@ static void __init ek_board_init(void)
> ek_add_device_nand();
> /* I2C */
> at91_add_device_i2c(0, NULL, 0);
> + /* ISI */
> + platform_add_devices(devices, ARRAY_SIZE(devices));
"devices" is a generic name, but you make it depend on
CONFIG_SOC_CAMERA_OV2640. Why don't you do
static struct platform_device *devices[] __initdata = {
#if defined(CONFIG_SOC_CAMERA_OV2640) || defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
&isi_ov2640,
#endif
};
and move
+ platform_add_devices(devices, ARRAY_SIZE(devices));
out of the /* ISI */ section to a more generic location?
> + at91_add_device_isi(&isi_data);
> +
> /* LCD Controller */
> at91_add_device_lcdc(&ek_lcdc_data);
> /* Touch Screen */
> diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
> index ed544a0..276d63a 100644
> --- a/arch/arm/mach-at91/include/mach/board.h
> +++ b/arch/arm/mach-at91/include/mach/board.h
> @@ -183,7 +183,8 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
> extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
>
> /* ISI */
> -extern void __init at91_add_device_isi(void);
> +struct isi_platform_data;
> +extern void __init at91_add_device_isi(struct isi_platform_data *data);
>
> /* Touchscreen Controller */
> struct at91_tsadcc_data {
> --
> 1.6.3.3
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* [PATCH v5 09/15] OMAP2+: UART: Add runtime pm support for omap-serial driver
From: Ming Lei @ 2011-09-22 7:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316607206-21669-7-git-send-email-govindraj.raja@ti.com>
Hi,
On Wed, Sep 21, 2011 at 8:13 PM, Govindraj.R <govindraj.raja@ti.com> wrote:
> Adapts omap-serial driver to use pm_runtime API's.
> ? ? ? ?console_unlock();
>
> - ? ? ? if ((cpu_is_omap34xx() && bdata->pads) ||
> - ? ? ? ? ? ? ? (pdata->wk_en && pdata->wk_mask))
> + ? ? ? if ((cpu_is_omap34xx() && bdata->pads))
> ? ? ? ? ? ? ? ?device_init_wakeup(&pdev->dev, true);
Just a bit curious, why doesn't the code enable wakeup at default
on omap4, which will disable runtime pm of serial port on omap4.
I have tested your patches on omap4 panda(enable wakeup at
default manually), runtime pm of serial port 2 can work well and
remote wakeup too.
>
> ? ? ? ?kfree(pdata);
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index 74822b3..8ef81ce 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -62,6 +62,9 @@ struct omap_uart_port_info {
> ? ? ? ?upf_t ? ? ? ? ? ? ? ? ? flags; ? ? ? ? ?/* UPF_* flags */
>
> ? ? ? ?u32 ? ? ? ? ? ? ? ? ? ? errata;
> +
> + ? ? ? void (*enable_wakeup)(struct platform_device *, bool);
> + ? ? ? u32 (*get_context_loss_count)(struct device *);
> ?};
>
> ?struct uart_omap_dma {
> @@ -113,6 +116,8 @@ struct uart_omap_port {
> ? ? ? ?unsigned char ? ? ? ? ? msr_saved_flags;
> ? ? ? ?char ? ? ? ? ? ? ? ? ? ?name[20];
> ? ? ? ?unsigned long ? ? ? ? ? port_activity;
> + ? ? ? u32 ? ? ? ? ? ? ? ? ? ? context_loss_cnt;
> + ? ? ? u8 ? ? ? ? ? ? ? ? ? ? ?wakeups_enabled;
> ?};
>
> ?#endif /* __OMAP_SERIAL_H__ */
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 9a0eac2..43c33da 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -37,11 +37,14 @@
> ?#include <linux/clk.h>
> ?#include <linux/serial_core.h>
> ?#include <linux/irq.h>
> +#include <linux/pm_runtime.h>
>
> ?#include <plat/dma.h>
> ?#include <plat/dmtimer.h>
> ?#include <plat/omap-serial.h>
>
> +#define OMAP_UART_AUTOSUSPEND_DELAY -1
> +
> ?static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
>
> ?/* Forward declaration of functions */
> @@ -102,6 +105,8 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up)
> ? ? ? ? ? ? ? ?omap_free_dma(up->uart_dma.rx_dma_channel);
> ? ? ? ? ? ? ? ?up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
> ? ? ? ? ? ? ? ?up->uart_dma.rx_dma_used = false;
> + ? ? ? ? ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? ? ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ?}
> ?}
>
> @@ -110,8 +115,11 @@ static void serial_omap_enable_ms(struct uart_port *port)
> ? ? ? ?struct uart_omap_port *up = (struct uart_omap_port *)port;
>
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
> +
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?up->ier |= UART_IER_MSI;
> ? ? ? ?serial_out(up, UART_IER, up->ier);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ?}
>
> ?static void serial_omap_stop_tx(struct uart_port *port)
> @@ -129,23 +137,32 @@ static void serial_omap_stop_tx(struct uart_port *port)
> ? ? ? ? ? ? ? ?omap_stop_dma(up->uart_dma.tx_dma_channel);
> ? ? ? ? ? ? ? ?omap_free_dma(up->uart_dma.tx_dma_channel);
> ? ? ? ? ? ? ? ?up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
> + ? ? ? ? ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? ? ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ?}
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?if (up->ier & UART_IER_THRI) {
> ? ? ? ? ? ? ? ?up->ier &= ~UART_IER_THRI;
> ? ? ? ? ? ? ? ?serial_out(up, UART_IER, up->ier);
> ? ? ? ?}
> +
> + ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ?}
>
> ?static void serial_omap_stop_rx(struct uart_port *port)
> ?{
> ? ? ? ?struct uart_omap_port *up = (struct uart_omap_port *)port;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?if (up->use_dma)
> ? ? ? ? ? ? ? ?serial_omap_stop_rxdma(up);
> ? ? ? ?up->ier &= ~UART_IER_RLSI;
> ? ? ? ?up->port.read_status_mask &= ~UART_LSR_DR;
> ? ? ? ?serial_out(up, UART_IER, up->ier);
> + ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ?}
>
> ?static inline void receive_chars(struct uart_omap_port *up, int *status)
> @@ -262,7 +279,10 @@ static void serial_omap_start_tx(struct uart_port *port)
> ? ? ? ?int ret = 0;
>
> ? ? ? ?if (!up->use_dma) {
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ? ? ? ? ?serial_omap_enable_ier_thri(up);
> + ? ? ? ? ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? ? ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ? ? ? ? ?return;
> ? ? ? ?}
>
> @@ -272,6 +292,7 @@ static void serial_omap_start_tx(struct uart_port *port)
> ? ? ? ?xmit = &up->port.state->xmit;
>
> ? ? ? ?if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ? ? ? ? ?ret = omap_request_dma(up->uart_dma.uart_dma_tx,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"UART Tx DMA",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(void *)uart_tx_dma_callback, up,
> @@ -354,9 +375,13 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
> ? ? ? ?unsigned int iir, lsr;
> ? ? ? ?unsigned long flags;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?iir = serial_in(up, UART_IIR);
> - ? ? ? if (iir & UART_IIR_NO_INT)
> + ? ? ? if (iir & UART_IIR_NO_INT) {
> + ? ? ? ? ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? ? ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ? ? ? ? ?return IRQ_NONE;
> + ? ? ? }
>
> ? ? ? ?spin_lock_irqsave(&up->port.lock, flags);
> ? ? ? ?lsr = serial_in(up, UART_LSR);
> @@ -378,6 +403,9 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
> ? ? ? ? ? ? ? ?transmit_chars(up);
>
> ? ? ? ?spin_unlock_irqrestore(&up->port.lock, flags);
> + ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> +
> ? ? ? ?up->port_activity = jiffies;
> ? ? ? ?return IRQ_HANDLED;
> ?}
> @@ -388,11 +416,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
> ? ? ? ?unsigned long flags = 0;
> ? ? ? ?unsigned int ret = 0;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
> ? ? ? ?spin_lock_irqsave(&up->port.lock, flags);
> ? ? ? ?ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
> ? ? ? ?spin_unlock_irqrestore(&up->port.lock, flags);
> -
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ? ? ? ?return ret;
> ?}
>
> @@ -402,7 +431,10 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
> ? ? ? ?unsigned char status;
> ? ? ? ?unsigned int ret = 0;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?status = check_modem_status(up);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> +
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
>
> ? ? ? ?if (status & UART_MSR_DCD)
> @@ -433,9 +465,11 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
> ? ? ? ?if (mctrl & TIOCM_LOOP)
> ? ? ? ? ? ? ? ?mcr |= UART_MCR_LOOP;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?up->mcr = serial_in(up, UART_MCR);
> ? ? ? ?up->mcr |= mcr;
> ? ? ? ?serial_out(up, UART_MCR, up->mcr);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ?}
>
> ?static void serial_omap_break_ctl(struct uart_port *port, int break_state)
> @@ -444,6 +478,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
> ? ? ? ?unsigned long flags = 0;
>
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?spin_lock_irqsave(&up->port.lock, flags);
> ? ? ? ?if (break_state == -1)
> ? ? ? ? ? ? ? ?up->lcr |= UART_LCR_SBC;
> @@ -451,6 +486,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
> ? ? ? ? ? ? ? ?up->lcr &= ~UART_LCR_SBC;
> ? ? ? ?serial_out(up, UART_LCR, up->lcr);
> ? ? ? ?spin_unlock_irqrestore(&up->port.lock, flags);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ?}
>
> ?static int serial_omap_startup(struct uart_port *port)
> @@ -469,6 +505,7 @@ static int serial_omap_startup(struct uart_port *port)
>
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?/*
> ? ? ? ? * Clear the FIFO buffers and disable them.
> ? ? ? ? * (they will be reenabled in set_termios())
> @@ -524,6 +561,8 @@ static int serial_omap_startup(struct uart_port *port)
> ? ? ? ?/* Enable module level wake up */
> ? ? ? ?serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
>
> + ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ?up->port_activity = jiffies;
> ? ? ? ?return 0;
> ?}
> @@ -534,6 +573,8 @@ static void serial_omap_shutdown(struct uart_port *port)
> ? ? ? ?unsigned long flags = 0;
>
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
> +
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?/*
> ? ? ? ? * Disable interrupts from this port
> ? ? ? ? */
> @@ -567,6 +608,7 @@ static void serial_omap_shutdown(struct uart_port *port)
> ? ? ? ? ? ? ? ? ? ? ? ?up->uart_dma.rx_buf_dma_phys);
> ? ? ? ? ? ? ? ?up->uart_dma.rx_buf = NULL;
> ? ? ? ?}
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ? ? ? ?free_irq(up->port.irq, up);
> ?}
>
> @@ -682,6 +724,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
> ? ? ? ? * Ok, we're now changing the port state. Do it with
> ? ? ? ? * interrupts disabled.
> ? ? ? ? */
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?spin_lock_irqsave(&up->port.lock, flags);
>
> ? ? ? ?/*
> @@ -814,6 +857,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
> ? ? ? ?serial_omap_configure_xonxoff(up, termios);
>
> ? ? ? ?spin_unlock_irqrestore(&up->port.lock, flags);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
> ?}
>
> @@ -825,6 +869,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
> ? ? ? ?unsigned char efr;
>
> ? ? ? ?dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
> +
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
> ? ? ? ?efr = serial_in(up, UART_EFR);
> ? ? ? ?serial_out(up, UART_EFR, efr | UART_EFR_ECB);
> @@ -834,6 +880,7 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
> ? ? ? ?serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
> ? ? ? ?serial_out(up, UART_EFR, efr);
> ? ? ? ?serial_out(up, UART_LCR, 0);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ?}
>
> ?static void serial_omap_release_port(struct uart_port *port)
> @@ -911,19 +958,26 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
> ?static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
> ?{
> ? ? ? ?struct uart_omap_port *up = (struct uart_omap_port *)port;
> +
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ?wait_for_xmitr(up);
> ? ? ? ?serial_out(up, UART_TX, ch);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> ?}
>
> ?static int serial_omap_poll_get_char(struct uart_port *port)
> ?{
> ? ? ? ?struct uart_omap_port *up = (struct uart_omap_port *)port;
> - ? ? ? unsigned int status = serial_in(up, UART_LSR);
> + ? ? ? unsigned int status;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> + ? ? ? status = serial_in(up, UART_LSR);
> ? ? ? ?if (!(status & UART_LSR_DR))
> ? ? ? ? ? ? ? ?return NO_POLL_CHAR;
>
> - ? ? ? return serial_in(up, UART_RX);
> + ? ? ? status = serial_in(up, UART_RX);
> + ? ? ? pm_runtime_put(&up->pdev->dev);
> + ? ? ? return status;
> ?}
>
> ?#endif /* CONFIG_CONSOLE_POLL */
> @@ -951,6 +1005,8 @@ serial_omap_console_write(struct console *co, const char *s,
> ? ? ? ?unsigned int ier;
> ? ? ? ?int locked = 1;
>
> + ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> +
> ? ? ? ?local_irq_save(flags);
> ? ? ? ?if (up->port.sysrq)
> ? ? ? ? ? ? ? ?locked = 0;
> @@ -983,6 +1039,8 @@ serial_omap_console_write(struct console *co, const char *s,
> ? ? ? ?if (up->msr_saved_flags)
> ? ? ? ? ? ? ? ?check_modem_status(up);
>
> + ? ? ? pm_runtime_mark_last_busy(&up->pdev->dev);
> + ? ? ? pm_runtime_put_autosuspend(&up->pdev->dev);
> ? ? ? ?if (locked)
> ? ? ? ? ? ? ? ?spin_unlock(&up->port.lock);
> ? ? ? ?local_irq_restore(flags);
> @@ -1065,19 +1123,18 @@ static struct uart_driver serial_omap_reg = {
> ? ? ? ?.cons ? ? ? ? ? = OMAP_CONSOLE,
> ?};
>
> -static int
> -serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
> +static int serial_omap_suspend(struct device *dev)
> ?{
> - ? ? ? struct uart_omap_port *up = platform_get_drvdata(pdev);
> + ? ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
>
> ? ? ? ?if (up)
> ? ? ? ? ? ? ? ?uart_suspend_port(&serial_omap_reg, &up->port);
> ? ? ? ?return 0;
> ?}
>
> -static int serial_omap_resume(struct platform_device *dev)
> +static int serial_omap_resume(struct device *dev)
> ?{
> - ? ? ? struct uart_omap_port *up = platform_get_drvdata(dev);
> + ? ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
>
> ? ? ? ?if (up)
> ? ? ? ? ? ? ? ?uart_resume_port(&serial_omap_reg, &up->port);
> @@ -1140,6 +1197,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)
> ? ? ? ?int ret = 0;
>
> ? ? ? ?if (up->uart_dma.rx_dma_channel == -1) {
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&up->pdev->dev);
> ? ? ? ? ? ? ? ?ret = omap_request_dma(up->uart_dma.uart_dma_rx,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"UART Rx DMA",
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(void *)uart_rx_dma_callback, up,
> @@ -1305,6 +1363,16 @@ static int serial_omap_probe(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
> ? ? ? ?}
>
> + ? ? ? pm_runtime_use_autosuspend(&pdev->dev);
> + ? ? ? pm_runtime_set_autosuspend_delay(&pdev->dev,
> + ? ? ? ? ? ? ? ? ? ? ? OMAP_UART_AUTOSUSPEND_DELAY);
> +
> + ? ? ? pm_runtime_irq_safe(&pdev->dev);
> + ? ? ? if (device_may_wakeup(&pdev->dev)) {
> + ? ? ? ? ? ? ? pm_runtime_enable(&pdev->dev);
> + ? ? ? ? ? ? ? pm_runtime_get_sync(&pdev->dev);
> + ? ? ? }
> +
> ? ? ? ?ui[pdev->id] = up;
> ? ? ? ?serial_omap_add_console_port(up);
>
> @@ -1312,6 +1380,7 @@ static int serial_omap_probe(struct platform_device *pdev)
> ? ? ? ?if (ret != 0)
> ? ? ? ? ? ? ? ?goto do_release_region;
>
> + ? ? ? pm_runtime_put(&pdev->dev);
> ? ? ? ?platform_set_drvdata(pdev, up);
> ? ? ? ?return 0;
> ?err:
> @@ -1326,22 +1395,96 @@ static int serial_omap_remove(struct platform_device *dev)
> ?{
> ? ? ? ?struct uart_omap_port *up = platform_get_drvdata(dev);
>
> - ? ? ? platform_set_drvdata(dev, NULL);
> ? ? ? ?if (up) {
> + ? ? ? ? ? ? ? pm_runtime_disable(&up->pdev->dev);
> ? ? ? ? ? ? ? ?uart_remove_one_port(&serial_omap_reg, &up->port);
> ? ? ? ? ? ? ? ?kfree(up);
> ? ? ? ?}
> +
> + ? ? ? platform_set_drvdata(dev, NULL);
> + ? ? ? return 0;
> +}
> +
> +static void serial_omap_restore_context(struct uart_omap_port *up)
> +{
> + ? ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
> + ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
> + ? ? ? serial_out(up, UART_EFR, UART_EFR_ECB);
> + ? ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
> + ? ? ? serial_out(up, UART_IER, 0x0);
> + ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
> + ? ? ? serial_out(up, UART_DLL, up->dll);
> + ? ? ? serial_out(up, UART_DLM, up->dlh);
> + ? ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */
> + ? ? ? serial_out(up, UART_IER, up->ier);
> + ? ? ? serial_out(up, UART_FCR, up->fcr);
> + ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
> + ? ? ? serial_out(up, UART_MCR, up->mcr);
> + ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
> + ? ? ? serial_out(up, UART_EFR, up->efr);
> + ? ? ? serial_out(up, UART_LCR, up->lcr);
> + ? ? ? /* UART 16x mode */
> + ? ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1);
> +}
> +
> +static int serial_omap_runtime_suspend(struct device *dev)
> +{
> + ? ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
> + ? ? ? struct omap_uart_port_info *pdata = dev->platform_data;
> +
> + ? ? ? if (!up)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? if (!pdata->enable_wakeup || !pdata->get_context_loss_count)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? if (pdata->get_context_loss_count)
> + ? ? ? ? ? ? ? up->context_loss_cnt = pdata->get_context_loss_count(dev);
> +
> + ? ? ? if (device_may_wakeup(dev)) {
> + ? ? ? ? ? ? ? if (!up->wakeups_enabled) {
> + ? ? ? ? ? ? ? ? ? ? ? pdata->enable_wakeup(up->pdev, true);
> + ? ? ? ? ? ? ? ? ? ? ? up->wakeups_enabled = true;
> + ? ? ? ? ? ? ? }
> + ? ? ? } else {
> + ? ? ? ? ? ? ? if (up->wakeups_enabled) {
> + ? ? ? ? ? ? ? ? ? ? ? pdata->enable_wakeup(up->pdev, false);
> + ? ? ? ? ? ? ? ? ? ? ? up->wakeups_enabled = false;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static int serial_omap_runtime_resume(struct device *dev)
> +{
> + ? ? ? struct uart_omap_port *up = dev_get_drvdata(dev);
> + ? ? ? struct omap_uart_port_info *pdata = dev->platform_data;
> +
> + ? ? ? if (up) {
> + ? ? ? ? ? ? ? if (pdata->get_context_loss_count) {
> + ? ? ? ? ? ? ? ? ? ? ? u32 loss_cnt = pdata->get_context_loss_count(dev);
> +
> + ? ? ? ? ? ? ? ? ? ? ? if (up->context_loss_cnt != loss_cnt)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? serial_omap_restore_context(up);
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> ? ? ? ?return 0;
> ?}
>
> +static const struct dev_pm_ops serial_omap_dev_pm_ops = {
> + ? ? ? SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)
> + ? ? ? SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? serial_omap_runtime_resume, NULL)
> +};
> +
> ?static struct platform_driver serial_omap_driver = {
> ? ? ? ?.probe ? ? ? ? ?= serial_omap_probe,
> ? ? ? ?.remove ? ? ? ? = serial_omap_remove,
> -
> - ? ? ? .suspend ? ? ? ?= serial_omap_suspend,
> - ? ? ? .resume ? ? ? ? = serial_omap_resume,
> ? ? ? ?.driver ? ? ? ? = {
> ? ? ? ? ? ? ? ?.name ? = DRIVER_NAME,
> + ? ? ? ? ? ? ? .pm ? ? = &serial_omap_dev_pm_ops,
> ? ? ? ?},
> ?};
>
> --
> 1.7.4.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
thanks,
--
Ming Lei
^ permalink raw reply
* [PATCH v5 09/15] OMAP2+: UART: Add runtime pm support for omap-serial driver
From: Govindraj @ 2011-09-22 7:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACVXFVMpvF5foA1asLYE5WbvHQ3b_eXaBpiMT7Q1h0KHDGLSCg@mail.gmail.com>
On Thu, Sep 22, 2011 at 1:18 PM, Ming Lei <tom.leiming@gmail.com> wrote:
> Hi,
>
> On Wed, Sep 21, 2011 at 8:13 PM, Govindraj.R <govindraj.raja@ti.com> wrote:
>> Adapts omap-serial driver to use pm_runtime API's.
>
>> ? ? ? ?console_unlock();
>>
>> - ? ? ? if ((cpu_is_omap34xx() && bdata->pads) ||
>> - ? ? ? ? ? ? ? (pdata->wk_en && pdata->wk_mask))
>> + ? ? ? if ((cpu_is_omap34xx() && bdata->pads))
>> ? ? ? ? ? ? ? ?device_init_wakeup(&pdev->dev, true);
>
> Just a bit curious, why doesn't the code enable wakeup at default
> on omap4, which will disable runtime pm of serial port on omap4.
>
yes sure will add for omap4.
> I have tested your patches on omap4 panda(enable wakeup at
> default manually), runtime pm of serial port 2 can work well and
> remote wakeup too.
>
Thanks, for testing.
--
Govindraj.R
^ permalink raw reply
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