diff mbox

[v2,2/2] powerpc/mpic: add global timer support

Message ID 1344578081-8095-1-git-send-email-Dongsheng.wang@freescale.com (mailing list archive)
State Superseded
Delegated to: Kumar Gala
Headers show

Commit Message

Dongsheng Wang Aug. 10, 2012, 5:54 a.m. UTC
From: Wang Dongsheng <Dongsheng.Wang@freescale.com>

The MPIC global timer is a hardware timer inside the Freescale PIC comply
to Open-PIC standard. When the timer is timeout of the specified interval,
the hardware timer generates an interrupt. The driver currently is only
tested on fsl chip, but it can potentially support other global timers
complying to Open-PIC standard.
The two independent groups of global timer on fsl chip, group A and group B,
are identical in their functionality, except that they appear at different
locations within the PIC register map. The hardware timer can be cascaded to
create timers larger than the default 31-bit global timers. Timer cascade
fields allow configuration of up to two 63-bit timers. But These two groups
of timers cannot be cascaded together.
It can be used as a wakeup source for low power modes. It also could be used
as periodical timer for protocols, drivers and etc.

Signed-off-by: Wang Dongsheng <Dongsheng.Wang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 arch/powerpc/include/asm/mpic_timer.h |   15 +
 arch/powerpc/platforms/Kconfig        |    5 +
 arch/powerpc/sysdev/Makefile          |    1 +
 arch/powerpc/sysdev/mpic_timer.c      |  525 +++++++++++++++++++++++++++++++++
 4 files changed, 546 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/mpic_timer.h
 create mode 100644 arch/powerpc/sysdev/mpic_timer.c

Comments

Scott Wood Aug. 10, 2012, 7:40 p.m. UTC | #1
On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> +static const struct of_device_id mpic_timer_ids[] = {
> +	{ .compatible = "open-pic,global-timer", },
> +	{ .compatible = "fsl,global-timer", },
> +	{},
> +};
> +
> +static int __init mpic_timer_init(void)
> +{
> +	struct device_node *np = NULL;
> +
> +	for_each_node_by_type(np, "open-pic")
> +		if (of_match_node(mpic_timer_ids, np))
> +			group_init(np);
> +
> +	if (list_empty(&group_list))
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +arch_initcall(mpic_timer_init);
> 

Where do you distinguish an FSL timer from an openpic timer?  I thought
openpic timers didn't support cascading.

Oh, and don't probe by device_type.

-Scott
Gala Kumar-B11780 Aug. 10, 2012, 8:24 p.m. UTC | #2
On Aug 10, 2012, at 2:40 PM, Scott Wood wrote:

> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
>> +static const struct of_device_id mpic_timer_ids[] = {
>> +	{ .compatible = "open-pic,global-timer", },
>> +	{ .compatible = "fsl,global-timer", },
>> +	{},
>> +};
>> +
>> +static int __init mpic_timer_init(void)
>> +{
>> +	struct device_node *np = NULL;
>> +
>> +	for_each_node_by_type(np, "open-pic")
>> +		if (of_match_node(mpic_timer_ids, np))
>> +			group_init(np);
>> +
>> +	if (list_empty(&group_list))
>> +		return -ENODEV;
>> +
>> +	return 0;
>> +}
>> +arch_initcall(mpic_timer_init);
>> 
> 
> Where do you distinguish an FSL timer from an openpic timer?  I thought
> openpic timers didn't support cascading.

in group_init()

+	if (of_device_is_compatible(np, "fsl,global-timer"))
+		priv->flags |= FSL_GLOBAL_TIMER;
+

- k
Scott Wood Aug. 10, 2012, 8:37 p.m. UTC | #3
On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> +static int group_get_freq(struct group_priv *priv)
> +{
> +	if (priv->flags & FSL_GLOBAL_TIMER) {
> +		ccbfreq = fsl_get_sys_freq();
> +		priv->timerfreq = ccbfreq;
> +	} else {
> +		priv->timerfreq = in_be32(priv->group_tfrr);
> +	}

FSL MPICs have TFRR too.  I'm not sure that the lack of fsl,mpic is a
good indication that TFRR is being set (e.g. we have old device trees
for FSL chips with U-Boot that are labelled as ordinary openpics).

> +
> +	if (priv->timerfreq <= 0)
> +		return -EINVAL;
> +
> +	return 0;
> +}

timerfreq is unsigned.  It can never be < 0.

> +
> +static int group_init_regmap(struct device_node *np, struct group_priv *priv)
> +{
> +	priv->group_tfrr = of_iomap(np, 0);
> +	if (!priv->group_tfrr) {
> +		pr_err("%s: cannot ioremap tfrr address.\n",
> +				np->full_name);
> +		return -EINVAL;
> +	}
> +
> +	priv->regs = of_iomap(np, 1);
> +	if (!priv->regs) {
> +		pr_err("%s: cannot ioremap timer register address.\n",
> +				np->full_name);
> +		return -EINVAL;
> +	}
> +
> +	if (!(priv->flags & FSL_GLOBAL_TIMER))
> +		return 0;
> +
> +	priv->group_tcr = of_iomap(np, 2);
> +	if (!priv->group_tcr) {
> +		pr_err("%s: cannot ioremap tcr address.\n", np->full_name);
> +		return -EINVAL;
> +	}

This is not compatible with existing mpic timer nodes.

> +	p = of_get_property(np, "available-ranges", &len);
> +	if (p && len % (2 * sizeof(u32)) != 0) {
> +		pr_err("%s: malformed fsl,available-ranges property.\n",
> +				np->full_name);
> +		return -EINVAL;
> +	}

You need to support fsl,available-ranges since that's in an accepted
binding and people could have partitioned setups already using it.

You also have a mismatch between the property you check and the error
string.

-Scott
Tabi Timur-B04825 Aug. 11, 2012, 1:10 p.m. UTC | #4
On Fri, Aug 10, 2012 at 12:54 AM,  <Dongsheng.wang@freescale.com> wrote:
> From: Wang Dongsheng <Dongsheng.Wang@freescale.com>

> +EXPORT_SYMBOL_GPL(mpic_request_timer);

Make these EXPORT_SYMBOL.  No need for a GPL restriction.
Wang Dongsheng-B40534 Aug. 13, 2012, 5:53 a.m. UTC | #5
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Saturday, August 11, 2012 3:40 AM
> To: Wang Dongsheng-B40534
> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> > +static const struct of_device_id mpic_timer_ids[] = {
> > +	{ .compatible = "open-pic,global-timer", },
> > +	{ .compatible = "fsl,global-timer", },
> > +	{},
> > +};
> > +
> > +static int __init mpic_timer_init(void) {
> > +	struct device_node *np = NULL;
> > +
> > +	for_each_node_by_type(np, "open-pic")
> > +		if (of_match_node(mpic_timer_ids, np))
> > +			group_init(np);
> > +
> > +	if (list_empty(&group_list))
> > +		return -ENODEV;
> > +
> > +	return 0;
> > +}
> > +arch_initcall(mpic_timer_init);
> 
> Oh, and don't probe by device_type.
> 
[Wang Dongsheng] fine. for_each_node_by_name.

> -Scott
Li Yang-R58472 Aug. 13, 2012, 6:17 a.m. UTC | #6
> -----Original Message-----
> From: Wang Dongsheng-B40534
> Sent: Monday, August 13, 2012 1:54 PM
> To: Wood Scott-B07421
> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: RE: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> 
> 
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Saturday, August 11, 2012 3:40 AM
> > To: Wang Dongsheng-B40534
> > Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
> > dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> > Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >
> > On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> > > +static const struct of_device_id mpic_timer_ids[] = {
> > > +	{ .compatible = "open-pic,global-timer", },
> > > +	{ .compatible = "fsl,global-timer", },
> > > +	{},
> > > +};
> > > +
> > > +static int __init mpic_timer_init(void) {
> > > +	struct device_node *np = NULL;
> > > +
> > > +	for_each_node_by_type(np, "open-pic")
> > > +		if (of_match_node(mpic_timer_ids, np))
> > > +			group_init(np);
> > > +
> > > +	if (list_empty(&group_list))
> > > +		return -ENODEV;
> > > +
> > > +	return 0;
> > > +}
> > > +arch_initcall(mpic_timer_init);
> >
> > Oh, and don't probe by device_type.

Actually it does match the compatible.  The device_type is just to speed up the search.  I don't think it's a problem unless the device type is not mandatory any more for defined types.

- Leo
Wang Dongsheng-B40534 Aug. 13, 2012, 6:18 a.m. UTC | #7
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Saturday, August 11, 2012 4:38 AM
> To: Wang Dongsheng-B40534
> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> > +static int group_get_freq(struct group_priv *priv) {
> > +	if (priv->flags & FSL_GLOBAL_TIMER) {
> > +		ccbfreq = fsl_get_sys_freq();
> > +		priv->timerfreq = ccbfreq;
> > +	} else {
> > +		priv->timerfreq = in_be32(priv->group_tfrr);
> > +	}
> 
> FSL MPICs have TFRR too.  I'm not sure that the lack of fsl,mpic is a
> good indication that TFRR is being set (e.g. we have old device trees for
> FSL chips with U-Boot that are labelled as ordinary openpics).
> 
[Wang Dongsheng] yes, we have. But we do not used it. The TFRR register value
is zero. 

> > +
> > +	if (priv->timerfreq <= 0)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> 
> timerfreq is unsigned.  It can never be < 0.
> 
[Wang Dongsheng] Yeah. Thanks.
> > +
> > +static int group_init_regmap(struct device_node *np, struct
> > +group_priv *priv) {
> > +	priv->group_tfrr = of_iomap(np, 0);
> > +	if (!priv->group_tfrr) {
> > +		pr_err("%s: cannot ioremap tfrr address.\n",
> > +				np->full_name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	priv->regs = of_iomap(np, 1);
> > +	if (!priv->regs) {
> > +		pr_err("%s: cannot ioremap timer register address.\n",
> > +				np->full_name);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (!(priv->flags & FSL_GLOBAL_TIMER))
> > +		return 0;
> > +
> > +	priv->group_tcr = of_iomap(np, 2);
> > +	if (!priv->group_tcr) {
> > +		pr_err("%s: cannot ioremap tcr address.\n", np->full_name);
> > +		return -EINVAL;
> > +	}
> 
> This is not compatible with existing mpic timer nodes.
> 
[Wang Dongsheng] Yeah, next patch to support that.

> > +	p = of_get_property(np, "available-ranges", &len);
> > +	if (p && len % (2 * sizeof(u32)) != 0) {
> > +		pr_err("%s: malformed fsl,available-ranges property.\n",
> > +				np->full_name);
> > +		return -EINVAL;
> > +	}
> 
> You need to support fsl,available-ranges since that's in an accepted
> binding and people could have partitioned setups already using it.
> 
[Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group)
in each group only four timer. This is unified. So i use a generic name.
I think there is not compatible with existing mpic timer nodes.

	p = of_get_property(np, "available-ranges", &len);
	if (!p)
		p = of_get_property(np, "fsl,available-ranges", &len);

	if (p && len % (2 * sizeof(u32)) != 0) {
		pr_err("%s: malformed fsl,available-ranges property.\n",
				np->full_name);
		return -EINVAL;
	}

> You also have a mismatch between the property you check and the error
> string.
> 
[Wang Dongsheng] Yeah. :-(.

> -Scott
Wang Dongsheng-B40534 Aug. 13, 2012, 6:20 a.m. UTC | #8
> -----Original Message-----
> From: Tabi Timur-B04825
> Sent: Saturday, August 11, 2012 9:10 PM
> To: Wang Dongsheng-B40534
> Cc: benh@kernel.crashing.org; paulus@samba.org; Wood Scott-B07421; Gala
> Kumar-B11780; linuxppc-dev@lists.ozlabs.org
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On Fri, Aug 10, 2012 at 12:54 AM,  <Dongsheng.wang@freescale.com> wrote:
> > From: Wang Dongsheng <Dongsheng.Wang@freescale.com>
> 
> > +EXPORT_SYMBOL_GPL(mpic_request_timer);
> 
> Make these EXPORT_SYMBOL.  No need for a GPL restriction.
> 
[Wang Dongsheng] Why?
> --
> Timur Tabi
> Linux kernel developer at Freescale
Wang Dongsheng-B40534 Aug. 13, 2012, 6:25 a.m. UTC | #9
> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-
> bounces+b40534=freescale.com@lists.ozlabs.org] On Behalf Of Wang
> Dongsheng-B40534
> Sent: Monday, August 13, 2012 2:21 PM
> To: Tabi Timur-B04825
> Cc: Gala Kumar-B11780; paulus@samba.org; linuxppc-dev@lists.ozlabs.org;
> Wood Scott-B07421
> Subject: RE: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> 
> 
> > -----Original Message-----
> > From: Tabi Timur-B04825
> > Sent: Saturday, August 11, 2012 9:10 PM
> > To: Wang Dongsheng-B40534
> > Cc: benh@kernel.crashing.org; paulus@samba.org; Wood Scott-B07421;
> > Gala Kumar-B11780; linuxppc-dev@lists.ozlabs.org
> > Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >
> > On Fri, Aug 10, 2012 at 12:54 AM,  <Dongsheng.wang@freescale.com> wrote:
> > > From: Wang Dongsheng <Dongsheng.Wang@freescale.com>
> >
> > > +EXPORT_SYMBOL_GPL(mpic_request_timer);
> >
> > Make these EXPORT_SYMBOL.  No need for a GPL restriction.
> >
> [Wang Dongsheng] Why?
[Wang Dongsheng] Sorry, I just see the mail. Thanks.

> > --
> > Timur Tabi
> > Linux kernel developer at Freescale
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
Scott Wood Aug. 13, 2012, 4:49 p.m. UTC | #10
On 08/13/2012 12:53 AM, Wang Dongsheng-B40534 wrote:
> 
> 
>> -----Original Message-----
>> From: Wood Scott-B07421
>> Sent: Saturday, August 11, 2012 3:40 AM
>> To: Wang Dongsheng-B40534
>> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
>> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>
>> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
>>> +static const struct of_device_id mpic_timer_ids[] = {
>>> +	{ .compatible = "open-pic,global-timer", },
>>> +	{ .compatible = "fsl,global-timer", },
>>> +	{},
>>> +};
>>> +
>>> +static int __init mpic_timer_init(void) {
>>> +	struct device_node *np = NULL;
>>> +
>>> +	for_each_node_by_type(np, "open-pic")
>>> +		if (of_match_node(mpic_timer_ids, np))
>>> +			group_init(np);
>>> +
>>> +	if (list_empty(&group_list))
>>> +		return -ENODEV;
>>> +
>>> +	return 0;
>>> +}
>>> +arch_initcall(mpic_timer_init);
>>
>> Oh, and don't probe by device_type.
>>
> [Wang Dongsheng] fine. for_each_node_by_name.

No.  Probe by compatible only.

-Scott
Scott Wood Aug. 13, 2012, 4:50 p.m. UTC | #11
On 08/13/2012 01:17 AM, Li Yang-R58472 wrote:
> 
> 
>> -----Original Message-----
>> From: Wang Dongsheng-B40534
>> Sent: Monday, August 13, 2012 1:54 PM
>> To: Wood Scott-B07421
>> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
>> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>> Subject: RE: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>
>>
>>
>>> -----Original Message-----
>>> From: Wood Scott-B07421
>>> Sent: Saturday, August 11, 2012 3:40 AM
>>> To: Wang Dongsheng-B40534
>>> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
>>> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>>
>>> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
>>>> +static const struct of_device_id mpic_timer_ids[] = {
>>>> +	{ .compatible = "open-pic,global-timer", },
>>>> +	{ .compatible = "fsl,global-timer", },
>>>> +	{},
>>>> +};
>>>> +
>>>> +static int __init mpic_timer_init(void) {
>>>> +	struct device_node *np = NULL;
>>>> +
>>>> +	for_each_node_by_type(np, "open-pic")
>>>> +		if (of_match_node(mpic_timer_ids, np))
>>>> +			group_init(np);
>>>> +
>>>> +	if (list_empty(&group_list))
>>>> +		return -ENODEV;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +arch_initcall(mpic_timer_init);
>>>
>>> Oh, and don't probe by device_type.
> 
> Actually it does match the compatible.  The device_type is just to
> speed up the search.  I don't think it's a problem unless the device
> type is not mandatory any more for defined types.

Doesn't matter (and I doubt it provides any significant speed up
compared to a search by compatible, and in any case this is not
performance critical).  device_type is deprecated outside certain
specific legacy uses.  Get rid of it.

-Scott
Scott Wood Aug. 13, 2012, 5:36 p.m. UTC | #12
On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
>>> +	p = of_get_property(np, "available-ranges", &len);
>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
>>> +				np->full_name);
>>> +		return -EINVAL;
>>> +	}
>>
>> You need to support fsl,available-ranges since that's in an accepted
>> binding and people could have partitioned setups already using it.
>>
> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group)
> in each group only four timer. This is unified. So i use a generic name.
> I think there is not compatible with existing mpic timer nodes.

We need to be compatible with existing trees, so you'd need to check for
both -- but I think any further discussion of the details is premature
until we decide whether this is worthwhile to begin with (both the
support of non-FSL timers, and the creation of a new device tree binding
which will not be implemented by many of the machines that have non-FSL
openpic because they run real Open Firmware).

-Scott
Wang Dongsheng-B40534 Aug. 14, 2012, 2 a.m. UTC | #13
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Tuesday, August 14, 2012 1:37 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
> >>> +	p = of_get_property(np, "available-ranges", &len);
> >>> +	if (p && len % (2 * sizeof(u32)) != 0) {
> >>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
> >>> +				np->full_name);
> >>> +		return -EINVAL;
> >>> +	}
> >>
> >> You need to support fsl,available-ranges since that's in an accepted
> >> binding and people could have partitioned setups already using it.
> >>
> > [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group) in
> > each group only four timer. This is unified. So i use a generic name.
> > I think there is not compatible with existing mpic timer nodes.
> 
> We need to be compatible with existing trees, so you'd need to check for
> both -- but I think any further discussion of the details is premature
> until we decide whether this is worthwhile to begin with (both the
> support of non-FSL timers, and the creation of a new device tree binding
> which will not be implemented by many of the machines that have non-FSL
> openpic because they run real Open Firmware).
> 
[Wang Dongsheng] 
	p = of_get_property(np, "available-ranges", &len);
	if (!p)
		p = of_get_property(np, "fsl,available-ranges", &len);
	
	this code be compatible with existing trees.
	
> -Scott
Scott Wood Aug. 14, 2012, 2:05 a.m. UTC | #14
On 08/13/2012 09:00 PM, Wang Dongsheng-B40534 wrote:
> 
> 
>> -----Original Message-----
>> From: Wood Scott-B07421
>> Sent: Tuesday, August 14, 2012 1:37 AM
>> To: Wang Dongsheng-B40534
>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>
>> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
>>>>> +	p = of_get_property(np, "available-ranges", &len);
>>>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
>>>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
>>>>> +				np->full_name);
>>>>> +		return -EINVAL;
>>>>> +	}
>>>>
>>>> You need to support fsl,available-ranges since that's in an accepted
>>>> binding and people could have partitioned setups already using it.
>>>>
>>> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group) in
>>> each group only four timer. This is unified. So i use a generic name.
>>> I think there is not compatible with existing mpic timer nodes.
>>
>> We need to be compatible with existing trees, so you'd need to check for
>> both -- but I think any further discussion of the details is premature
>> until we decide whether this is worthwhile to begin with (both the
>> support of non-FSL timers, and the creation of a new device tree binding
>> which will not be implemented by many of the machines that have non-FSL
>> openpic because they run real Open Firmware).
>>
> [Wang Dongsheng] 
> 	p = of_get_property(np, "available-ranges", &len);
> 	if (!p)
> 		p = of_get_property(np, "fsl,available-ranges", &len);
> 	
> 	this code be compatible with existing trees.

Yes, that's what I meant by checking both.

I still think we need to discuss why we're doing this first.  What
specific machines are going to have these new openpic timer nodes?

-Scott
Wang Dongsheng-B40534 Aug. 14, 2012, 2:06 a.m. UTC | #15
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Tuesday, August 14, 2012 12:49 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/13/2012 12:53 AM, Wang Dongsheng-B40534 wrote:
> >
> >
> >> -----Original Message-----
> >> From: Wood Scott-B07421
> >> Sent: Saturday, August 11, 2012 3:40 AM
> >> To: Wang Dongsheng-B40534
> >> Cc: benh@kernel.crashing.org; paulus@samba.org; linuxppc-
> >> dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> >> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >>
> >> On 08/10/2012 12:54 AM, Dongsheng.wang@freescale.com wrote:
> >>> +static const struct of_device_id mpic_timer_ids[] = {
> >>> +	{ .compatible = "open-pic,global-timer", },
> >>> +	{ .compatible = "fsl,global-timer", },
> >>> +	{},
> >>> +};
> >>> +
> >>> +static int __init mpic_timer_init(void) {
> >>> +	struct device_node *np = NULL;
> >>> +
> >>> +	for_each_node_by_type(np, "open-pic")
> >>> +		if (of_match_node(mpic_timer_ids, np))
> >>> +			group_init(np);
> >>> +
> >>> +	if (list_empty(&group_list))
> >>> +		return -ENODEV;
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +arch_initcall(mpic_timer_init);
> >>
> >> Oh, and don't probe by device_type.
> >>
> > [Wang Dongsheng] fine. for_each_node_by_name.
> 
> No.  Probe by compatible only.
> 
[Wang Dongsheng] I looked devicetree's API. 

	for_each_matching_node(np, mpic_timer_ids) looks better. Thanks.
                        

> -Scott
Wang Dongsheng-B40534 Aug. 14, 2012, 2:15 a.m. UTC | #16
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Tuesday, August 14, 2012 10:05 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/13/2012 09:00 PM, Wang Dongsheng-B40534 wrote:
> >
> >
> >> -----Original Message-----
> >> From: Wood Scott-B07421
> >> Sent: Tuesday, August 14, 2012 1:37 AM
> >> To: Wang Dongsheng-B40534
> >> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> >> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> >> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >>
> >> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
> >>>>> +	p = of_get_property(np, "available-ranges", &len);
> >>>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
> >>>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
> >>>>> +				np->full_name);
> >>>>> +		return -EINVAL;
> >>>>> +	}
> >>>>
> >>>> You need to support fsl,available-ranges since that's in an
> >>>> accepted binding and people could have partitioned setups already
> using it.
> >>>>
> >>> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group) in
> >>> each group only four timer. This is unified. So i use a generic name.
> >>> I think there is not compatible with existing mpic timer nodes.
> >>
> >> We need to be compatible with existing trees, so you'd need to check
> >> for both -- but I think any further discussion of the details is
> >> premature until we decide whether this is worthwhile to begin with
> >> (both the support of non-FSL timers, and the creation of a new device
> >> tree binding which will not be implemented by many of the machines
> >> that have non-FSL openpic because they run real Open Firmware).
> >>
> > [Wang Dongsheng]
> > 	p = of_get_property(np, "available-ranges", &len);
> > 	if (!p)
> > 		p = of_get_property(np, "fsl,available-ranges", &len);
> >
> > 	this code be compatible with existing trees.
> 
> Yes, that's what I meant by checking both.
> 
> I still think we need to discuss why we're doing this first.  What
> specific machines are going to have these new openpic timer nodes?
> 
[Wang Dongsheng] It's support to power management awakening. At present, 
the power management more and more important. This way is important to wake
up machine. At least need support power management of machine still needs
such a driver.

> -Scott
Scott Wood Aug. 14, 2012, 2:18 a.m. UTC | #17
On 08/13/2012 09:15 PM, Wang Dongsheng-B40534 wrote:
> 
> 
>> -----Original Message-----
>> From: Wood Scott-B07421
>> Sent: Tuesday, August 14, 2012 10:05 AM
>> To: Wang Dongsheng-B40534
>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>
>> On 08/13/2012 09:00 PM, Wang Dongsheng-B40534 wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Wood Scott-B07421
>>>> Sent: Tuesday, August 14, 2012 1:37 AM
>>>> To: Wang Dongsheng-B40534
>>>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>>>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>>>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>>>
>>>> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
>>>>>>> +	p = of_get_property(np, "available-ranges", &len);
>>>>>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
>>>>>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
>>>>>>> +				np->full_name);
>>>>>>> +		return -EINVAL;
>>>>>>> +	}
>>>>>>
>>>>>> You need to support fsl,available-ranges since that's in an
>>>>>> accepted binding and people could have partitioned setups already
>> using it.
>>>>>>
>>>>> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group) in
>>>>> each group only four timer. This is unified. So i use a generic name.
>>>>> I think there is not compatible with existing mpic timer nodes.
>>>>
>>>> We need to be compatible with existing trees, so you'd need to check
>>>> for both -- but I think any further discussion of the details is
>>>> premature until we decide whether this is worthwhile to begin with
>>>> (both the support of non-FSL timers, and the creation of a new device
>>>> tree binding which will not be implemented by many of the machines
>>>> that have non-FSL openpic because they run real Open Firmware).
>>>>
>>> [Wang Dongsheng]
>>> 	p = of_get_property(np, "available-ranges", &len);
>>> 	if (!p)
>>> 		p = of_get_property(np, "fsl,available-ranges", &len);
>>>
>>> 	this code be compatible with existing trees.
>>
>> Yes, that's what I meant by checking both.
>>
>> I still think we need to discuss why we're doing this first.  What
>> specific machines are going to have these new openpic timer nodes?
>>
> [Wang Dongsheng] It's support to power management awakening. At present, 
> the power management more and more important. This way is important to wake
> up machine. At least need support power management of machine still needs
> such a driver.

I mean specifically for the non-Freescale openpic nodes.

-Scott
Wang Dongsheng-B40534 Aug. 14, 2012, 2:32 a.m. UTC | #18
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Tuesday, August 14, 2012 10:19 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> 
> On 08/13/2012 09:15 PM, Wang Dongsheng-B40534 wrote:
> >
> >
> >> -----Original Message-----
> >> From: Wood Scott-B07421
> >> Sent: Tuesday, August 14, 2012 10:05 AM
> >> To: Wang Dongsheng-B40534
> >> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> >> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> >> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >>
> >> On 08/13/2012 09:00 PM, Wang Dongsheng-B40534 wrote:
> >>>
> >>>
> >>>> -----Original Message-----
> >>>> From: Wood Scott-B07421
> >>>> Sent: Tuesday, August 14, 2012 1:37 AM
> >>>> To: Wang Dongsheng-B40534
> >>>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
> >>>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
> >>>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
> >>>>
> >>>> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
> >>>>>>> +	p = of_get_property(np, "available-ranges", &len);
> >>>>>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
> >>>>>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
> >>>>>>> +				np->full_name);
> >>>>>>> +		return -EINVAL;
> >>>>>>> +	}
> >>>>>>
> >>>>>> You need to support fsl,available-ranges since that's in an
> >>>>>> accepted binding and people could have partitioned setups already
> >> using it.
> >>>>>>
> >>>>> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group)
> >>>>> in each group only four timer. This is unified. So i use a generic
> name.
> >>>>> I think there is not compatible with existing mpic timer nodes.
> >>>>
> >>>> We need to be compatible with existing trees, so you'd need to
> >>>> check for both -- but I think any further discussion of the details
> >>>> is premature until we decide whether this is worthwhile to begin
> >>>> with (both the support of non-FSL timers, and the creation of a new
> >>>> device tree binding which will not be implemented by many of the
> >>>> machines that have non-FSL openpic because they run real Open
> Firmware).
> >>>>
> >>> [Wang Dongsheng]
> >>> 	p = of_get_property(np, "available-ranges", &len);
> >>> 	if (!p)
> >>> 		p = of_get_property(np, "fsl,available-ranges", &len);
> >>>
> >>> 	this code be compatible with existing trees.
> >>
> >> Yes, that's what I meant by checking both.
> >>
> >> I still think we need to discuss why we're doing this first.  What
> >> specific machines are going to have these new openpic timer nodes?
> >>
> > [Wang Dongsheng] It's support to power management awakening. At
> > present, the power management more and more important. This way is
> > important to wake up machine. At least need support power management
> > of machine still needs such a driver.
> 
> I mean specifically for the non-Freescale openpic nodes.
> 
[Wang Dongsheng] I think non-Freescale chips can also use this function
to wake up the machine. And There is also an important feature, It can 
periodically generate an interrupt. For example, the network periodically
check the hardware device(link status).
> -Scott
Scott Wood Aug. 14, 2012, 9:20 p.m. UTC | #19
On 08/13/2012 09:32 PM, Wang Dongsheng-B40534 wrote:
> 
> 
>> -----Original Message-----
>> From: Wood Scott-B07421
>> Sent: Tuesday, August 14, 2012 10:19 AM
>> To: Wang Dongsheng-B40534
>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>
>> On 08/13/2012 09:15 PM, Wang Dongsheng-B40534 wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Wood Scott-B07421
>>>> Sent: Tuesday, August 14, 2012 10:05 AM
>>>> To: Wang Dongsheng-B40534
>>>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>>>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>>>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>>>
>>>> On 08/13/2012 09:00 PM, Wang Dongsheng-B40534 wrote:
>>>>>
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: Wood Scott-B07421
>>>>>> Sent: Tuesday, August 14, 2012 1:37 AM
>>>>>> To: Wang Dongsheng-B40534
>>>>>> Cc: Wood Scott-B07421; benh@kernel.crashing.org; paulus@samba.org;
>>>>>> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Li Yang-R58472
>>>>>> Subject: Re: [PATCH v2 2/2] powerpc/mpic: add global timer support
>>>>>>
>>>>>> On 08/13/2012 01:18 AM, Wang Dongsheng-B40534 wrote:
>>>>>>>>> +	p = of_get_property(np, "available-ranges", &len);
>>>>>>>>> +	if (p && len % (2 * sizeof(u32)) != 0) {
>>>>>>>>> +		pr_err("%s: malformed fsl,available-ranges property.\n",
>>>>>>>>> +				np->full_name);
>>>>>>>>> +		return -EINVAL;
>>>>>>>>> +	}
>>>>>>>>
>>>>>>>> You need to support fsl,available-ranges since that's in an
>>>>>>>> accepted binding and people could have partitioned setups already
>>>> using it.
>>>>>>>>
>>>>>>> [Wang Dongsheng] FSL chip or OPEN-PIC specification(Only a group)
>>>>>>> in each group only four timer. This is unified. So i use a generic
>> name.
>>>>>>> I think there is not compatible with existing mpic timer nodes.
>>>>>>
>>>>>> We need to be compatible with existing trees, so you'd need to
>>>>>> check for both -- but I think any further discussion of the details
>>>>>> is premature until we decide whether this is worthwhile to begin
>>>>>> with (both the support of non-FSL timers, and the creation of a new
>>>>>> device tree binding which will not be implemented by many of the
>>>>>> machines that have non-FSL openpic because they run real Open
>> Firmware).
>>>>>>
>>>>> [Wang Dongsheng]
>>>>> 	p = of_get_property(np, "available-ranges", &len);
>>>>> 	if (!p)
>>>>> 		p = of_get_property(np, "fsl,available-ranges", &len);
>>>>>
>>>>> 	this code be compatible with existing trees.
>>>>
>>>> Yes, that's what I meant by checking both.
>>>>
>>>> I still think we need to discuss why we're doing this first.  What
>>>> specific machines are going to have these new openpic timer nodes?
>>>>
>>> [Wang Dongsheng] It's support to power management awakening. At
>>> present, the power management more and more important. This way is
>>> important to wake up machine. At least need support power management
>>> of machine still needs such a driver.
>>
>> I mean specifically for the non-Freescale openpic nodes.
>>
> [Wang Dongsheng] I think non-Freescale chips can also use this function
> to wake up the machine. 

Maybe (it's very machine-specific what can be used as a wake source),
but what I asked was what specific machines could make use of this.
Name *one* machine for which these new openpic timer nodes will actually
be created.

> And There is also an important feature, It can
> periodically generate an interrupt.

That's not important at all.  We already have a way to do that using the
decrementer.

> For example, the network periodically check the hardware device(link status).

And it uses standard Linux software timers to do it.

-Scott
diff mbox

Patch

diff --git a/arch/powerpc/include/asm/mpic_timer.h b/arch/powerpc/include/asm/mpic_timer.h
new file mode 100644
index 0000000..01d58a2
--- /dev/null
+++ b/arch/powerpc/include/asm/mpic_timer.h
@@ -0,0 +1,15 @@ 
+#ifndef __MPIC_TIMER__
+#define __MPIC_TIMER__
+
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+struct mpic_timer *mpic_request_timer(irq_handler_t fn,  void *dev,
+		const struct timeval *time);
+
+void mpic_start_timer(struct mpic_timer *handle);
+
+void mpic_stop_timer(struct mpic_timer *handle);
+
+void mpic_free_timer(struct mpic_timer *handle);
+#endif
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index e7a896a..d82a822 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -87,6 +87,11 @@  config MPIC
 	bool
 	default n
 
+config MPIC_TIMER
+	bool "MPIC Global Timer"
+	depends on MPIC && FSL_SOC
+	default n
+
 config PPC_EPAPR_HV_PIC
 	bool
 	default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1bd7ecb..b1a9e4d 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -6,6 +6,7 @@  mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 mpic-msgr-obj-$(CONFIG_MPIC_MSGR)	+= mpic_msgr.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
+obj-$(CONFIG_MPIC_TIMER)	+= mpic_timer.o
 obj-$(CONFIG_PPC_EPAPR_HV_PIC)	+= ehv_pic.o
 fsl-msi-obj-$(CONFIG_PCI_MSI)	+= fsl_msi.o
 obj-$(CONFIG_PPC_MSI_BITMAP)	+= msi_bitmap.o
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
new file mode 100644
index 0000000..1b3ee59
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -0,0 +1,525 @@ 
+/*
+ * Copyright (c) 2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <sysdev/fsl_soc.h>
+#include <asm/mpic_timer.h>
+
+#define FSL_GLOBAL_TIMER		0x1
+
+#define MPIC_TIMER_TCR_CLKDIV_64	0x00000300
+#define MPIC_TIMER_TCR_ROVR_OFFSET	24
+
+#define TIMER_STOP			0x80000000
+#define ALL_TIMER			4
+#define MAX_TICKS			(~0U>>1)
+#define MAX_TICKS_CASCADE		(~0U)
+#define TIMER_OFFSET(num)		(1 << (ALL_TIMER - 1 - num))
+#define ONE_SECOND			1000000
+
+struct timer_regs {
+	u32	gtccr;
+	u32	res0[3];
+	u32	gtbcr;
+	u32	res1[3];
+	u32	gtvpr;
+	u32	res2[3];
+	u32	gtdr;
+	u32	res3[3];
+};
+
+struct cascade_priv {
+	u32 tcr_value;			/* TCR register: CASC & ROVR value */
+	unsigned int cascade_map;	/* cascade map */
+	unsigned int timer_num;		/* cascade control timer */
+};
+
+struct mpic_timer {
+	void			*dev;
+	struct cascade_priv	*cascade_handle;
+	unsigned int		num;
+	int			irq;
+};
+
+struct group_priv {
+	struct timer_regs __iomem	*regs;
+	struct mpic_timer		timer[ALL_TIMER];
+	struct list_head		node;
+	unsigned int			timerfreq;
+	unsigned int			idle;
+	unsigned int			flags;
+	spinlock_t			lock;
+	void __iomem			*group_tcr;
+	void __iomem			*group_tfrr;
+};
+
+static struct cascade_priv cascade_timer[] = {
+	/* cascade timer 0 and 1 */
+	{0x1, 0xc, 0x1},
+	/* cascade timer 1 and 2 */
+	{0x2, 0x6, 0x2},
+	/* cascade timer 2 and 3 */
+	{0x4, 0x3, 0x3}
+};
+
+static u32 ccbfreq;
+static LIST_HEAD(group_list);
+
+/* the time set by the user is converted to "ticks" */
+static int transform_time(struct group_priv *priv, const struct timeval *time,
+		u64 *ticks)
+{
+	u64 max_value;		/* prevent u64 overflow */
+	u64 tmp = 0;
+
+	u64 tmp_sec = 0;
+	u64 tmp_ms = 0;
+	u64 tmp_us = 0;
+	u32 div = 0;
+
+	if (priv->flags & FSL_GLOBAL_TIMER)
+		max_value = div_u64(ULLONG_MAX, ccbfreq);
+	else
+		max_value = div_u64(ULLONG_MAX, priv->timerfreq);
+
+	if (time->tv_sec > max_value ||
+			(time->tv_sec == max_value && time->tv_usec > 0))
+		return -EINVAL;
+
+	if (!(priv->flags & FSL_GLOBAL_TIMER)) {
+		tmp = time->tv_sec * priv->timerfreq;
+		*ticks = tmp;
+
+		return 0;
+	}
+
+	div = (1 << (MPIC_TIMER_TCR_CLKDIV_64 >> 8)) * 8;
+
+	tmp_sec = div_u64((u64)time->tv_sec * (u64)ccbfreq, div);
+	tmp += tmp_sec;
+
+	tmp_ms = time->tv_usec / 1000;
+	tmp_ms = div_u64((u64)tmp_ms * (u64)ccbfreq, div * 1000);
+	tmp += tmp_ms;
+
+	tmp_us = time->tv_usec % 1000;
+	tmp_us = div_u64((u64)tmp_us * (u64)ccbfreq, div * 1000000);
+	tmp += tmp_us;
+
+	*ticks = tmp;
+
+	return 0;
+}
+
+/* detect whether there is a cascade timer available */
+static struct mpic_timer *detect_idle_cascade_timer(struct group_priv *priv)
+{
+	struct cascade_priv *casc_priv;
+	unsigned int tmp;
+	unsigned int array_size = ARRAY_SIZE(cascade_timer);
+	unsigned int num;
+	unsigned int i;
+	unsigned long flags;
+
+	casc_priv = cascade_timer;
+	for (i = 0; i < array_size; i++) {
+		spin_lock_irqsave(&priv->lock, flags);
+		tmp = casc_priv->cascade_map & priv->idle;
+		if (tmp == casc_priv->cascade_map) {
+			num = casc_priv->timer_num;
+			priv->timer[num].cascade_handle = casc_priv;
+
+			/* set timer busy */
+			priv->idle &= ~casc_priv->cascade_map;
+			spin_unlock_irqrestore(&priv->lock, flags);
+			return &priv->timer[num];
+		}
+		spin_unlock_irqrestore(&priv->lock, flags);
+		casc_priv++;
+	}
+
+	return NULL;
+}
+
+static int set_cascade_timer(struct group_priv *priv, u64 ticks,
+		unsigned int num)
+{
+	struct cascade_priv *casc_priv;
+	u32 tmp;
+	u32 tmp_ticks;
+	u32 rem_ticks;
+
+	/* set group tcr reg for cascade */
+	casc_priv = priv->timer[num].cascade_handle;
+	if (!casc_priv)
+		return -EINVAL;
+
+	tmp = casc_priv->tcr_value |
+		(casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
+	setbits32(priv->group_tcr, tmp);
+
+	tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
+
+	out_be32(&priv->regs[num].gtccr, 0);
+	out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
+
+	out_be32(&priv->regs[num - 1].gtccr, 0);
+	out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
+
+	return 0;
+}
+
+static struct mpic_timer *get_cascade_timer(struct group_priv *priv, u64 ticks)
+{
+	struct mpic_timer *allocated_timer = NULL;
+
+	/* Two cascade timers: Support the maximum time */
+	const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
+	int ret;
+
+	if (ticks > max_ticks)
+		return NULL;
+
+	/* detect idle timer */
+	allocated_timer = detect_idle_cascade_timer(priv);
+	if (!allocated_timer)
+		return NULL;
+
+	/* set ticks to timer */
+	ret = set_cascade_timer(priv, ticks, allocated_timer->num);
+	if (ret < 0)
+		return NULL;
+
+	return allocated_timer;
+}
+
+static struct mpic_timer *get_timer(const struct timeval *time)
+{
+	struct group_priv *priv;
+	struct mpic_timer *timer = NULL;
+
+	u64 ticks = 0;
+	unsigned int num;
+	unsigned int i;
+	unsigned long flags;
+	int ret = 0;
+
+	list_for_each_entry(priv, &group_list, node) {
+		ret = transform_time(priv, time, &ticks);
+		if (ret < 0)
+			return NULL;
+
+		if (ticks > MAX_TICKS) {
+			if (!(priv->flags & FSL_GLOBAL_TIMER))
+				return NULL;
+
+			timer = get_cascade_timer(priv, ticks);
+			if (!timer)
+				continue;
+			else
+				return timer;
+		}
+
+		for (i = 0; i < ALL_TIMER; i++) {
+			/* one timer: Reverse allocation */
+			num = ALL_TIMER - 1 - i;
+			spin_lock_irqsave(&priv->lock, flags);
+			if (priv->idle & (1 << i)) {
+				/* set timer busy */
+				priv->idle &= ~(1 << i);
+				/* set ticks & stop timer */
+				out_be32(&priv->regs[num].gtbcr,
+					ticks | TIMER_STOP);
+				out_be32(&priv->regs[num].gtccr, 0);
+				priv->timer[num].cascade_handle = NULL;
+				spin_unlock_irqrestore(&priv->lock, flags);
+				return &priv->timer[num];
+			}
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * mpic_request_timer - get a hardware timer
+ * @fn: interrupt handler function
+ * @dev: callback function of the data
+ * @time: time for timer
+ *
+ * This executes the "request_irq", returning NULL
+ * else "handle" on success.
+ */
+struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
+					const struct timeval *time)
+{
+	struct mpic_timer *allocated_timer = NULL;
+
+	int ret = 0;
+
+	if (list_empty(&group_list))
+		return NULL;
+
+	if ((time->tv_sec + time->tv_usec) == 0 ||
+			time->tv_sec < 0 || time->tv_usec < 0)
+		return NULL;
+
+	if (time->tv_usec > ONE_SECOND)
+		return NULL;
+
+	allocated_timer = get_timer(time);
+	if (!allocated_timer)
+		return NULL;
+
+	ret = request_irq(allocated_timer->irq, fn, IRQF_TRIGGER_LOW,
+			"global-timer", dev);
+	if (ret)
+		return NULL;
+
+	allocated_timer->dev = dev;
+
+	return allocated_timer;
+}
+EXPORT_SYMBOL_GPL(mpic_request_timer);
+
+/**
+ * mpic_start_timer - start hardware timer
+ * @handle: the timer to be started.
+ *
+ * It will do ->fn(->dev) callback from the hardware interrupt at
+ * the ->timeval point in the future.
+ */
+void mpic_start_timer(struct mpic_timer *handle)
+{
+	struct group_priv *priv = container_of(handle, struct group_priv,
+			timer[handle->num]);
+
+	clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+}
+EXPORT_SYMBOL_GPL(mpic_start_timer);
+
+/**
+ * mpic_stop_timer - stop hardware timer
+ * @handle: the timer to be stoped
+ *
+ * The timer periodically generates an interrupt. Unless user stops the timer.
+ */
+void mpic_stop_timer(struct mpic_timer *handle)
+{
+	struct group_priv *priv = container_of(handle, struct group_priv,
+			timer[handle->num]);
+
+	setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+}
+EXPORT_SYMBOL_GPL(mpic_stop_timer);
+
+/**
+ * mpic_free_timer - free hardware timer
+ * @handle: the timer to be removed.
+ *
+ * Free the timer.
+ *
+ * Note: can not be used in interrupt context.
+ */
+void mpic_free_timer(struct mpic_timer *handle)
+{
+	struct group_priv *priv = container_of(handle, struct group_priv,
+			timer[handle->num]);
+
+	struct cascade_priv *casc_priv = NULL;
+	unsigned long flags;
+
+	mpic_stop_timer(handle);
+
+	casc_priv = priv->timer[handle->num].cascade_handle;
+
+	free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (casc_priv) {
+		u32 tmp;
+		tmp = casc_priv->tcr_value | (casc_priv->tcr_value <<
+					MPIC_TIMER_TCR_ROVR_OFFSET);
+		clrbits32(priv->group_tcr, tmp);
+		priv->idle |= casc_priv->cascade_map;
+		priv->timer[handle->num].cascade_handle = NULL;
+	} else {
+		priv->idle |= TIMER_OFFSET(handle->num);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_free_timer);
+
+static int group_get_freq(struct group_priv *priv)
+{
+	if (priv->flags & FSL_GLOBAL_TIMER) {
+		ccbfreq = fsl_get_sys_freq();
+		priv->timerfreq = ccbfreq;
+	} else {
+		priv->timerfreq = in_be32(priv->group_tfrr);
+	}
+
+	if (priv->timerfreq <= 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int group_init_regmap(struct device_node *np, struct group_priv *priv)
+{
+	priv->group_tfrr = of_iomap(np, 0);
+	if (!priv->group_tfrr) {
+		pr_err("%s: cannot ioremap tfrr address.\n",
+				np->full_name);
+		return -EINVAL;
+	}
+
+	priv->regs = of_iomap(np, 1);
+	if (!priv->regs) {
+		pr_err("%s: cannot ioremap timer register address.\n",
+				np->full_name);
+		return -EINVAL;
+	}
+
+	if (!(priv->flags & FSL_GLOBAL_TIMER))
+		return 0;
+
+	priv->group_tcr = of_iomap(np, 2);
+	if (!priv->group_tcr) {
+		pr_err("%s: cannot ioremap tcr address.\n", np->full_name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int group_get_irq(struct device_node *np, struct group_priv *priv)
+{
+	const u32 all_timer[] = { 0, ALL_TIMER };
+	const u32 *p = NULL;
+	u32 offset;
+	u32 count;
+
+	unsigned int i = 0;
+	unsigned int j = 0;
+	unsigned int irq_index = 0;
+	int irq = 0;
+	int len = 0;
+
+	p = of_get_property(np, "available-ranges", &len);
+	if (p && len % (2 * sizeof(u32)) != 0) {
+		pr_err("%s: malformed fsl,available-ranges property.\n",
+				np->full_name);
+		return -EINVAL;
+	}
+
+	if (!p) {
+		p = all_timer;
+		len = sizeof(all_timer);
+	}
+
+	len /= 2 * sizeof(u32);
+
+	for (i = 0; i < len; i++) {
+		offset = p[i * 2];
+		count = p[i * 2 + 1];
+		for (j = 0; j < count; j++) {
+			irq = irq_of_parse_and_map(np, irq_index);
+			if (!irq)
+				break;
+			/* Set timer idle */
+			priv->idle |= TIMER_OFFSET((offset + j));
+			priv->timer[offset + j].irq = irq;
+			priv->timer[offset + j].num = offset + j;
+			irq_index++;
+		}
+	}
+
+	return 0;
+}
+
+static void group_init(struct device_node *np)
+{
+	struct group_priv *priv = NULL;
+	int ret = 0;
+
+	priv = kzalloc(sizeof(struct group_priv), GFP_KERNEL);
+	if (!priv) {
+		pr_err("%s: cannot allocate memory for group.\n",
+				np->full_name);
+		return;
+	}
+
+	if (of_device_is_compatible(np, "fsl,global-timer"))
+		priv->flags |= FSL_GLOBAL_TIMER;
+
+	ret = group_init_regmap(np, priv);
+	if (ret < 0)
+		goto out;
+
+	ret = group_get_freq(priv);
+	if (ret < 0)
+		goto out;
+
+	ret = group_get_irq(np, priv);
+	if (ret < 0)
+		goto out;
+
+	spin_lock_init(&priv->lock);
+
+	/* Init FSL timer hardware */
+	if (priv->flags & FSL_GLOBAL_TIMER)
+		setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV_64);
+
+	list_add_tail(&priv->node, &group_list);
+
+	return;
+out:
+	if (priv->group_tcr)
+		iounmap(priv->group_tcr);
+
+	if (priv->regs)
+		iounmap(priv->regs);
+
+	if (priv->group_tfrr)
+		iounmap(priv->group_tfrr);
+
+	kfree(priv);
+}
+
+static const struct of_device_id mpic_timer_ids[] = {
+	{ .compatible = "open-pic,global-timer", },
+	{ .compatible = "fsl,global-timer", },
+	{},
+};
+
+static int __init mpic_timer_init(void)
+{
+	struct device_node *np = NULL;
+
+	for_each_node_by_type(np, "open-pic")
+		if (of_match_node(mpic_timer_ids, np))
+			group_init(np);
+
+	if (list_empty(&group_list))
+		return -ENODEV;
+
+	return 0;
+}
+arch_initcall(mpic_timer_init);