diff mbox

DM3730 sprz319 erratum 2.1

Message ID 20160322153332.GA1042@localhost.localdomain (mailing list archive)
State New, archived
Headers show

Commit Message

Ladislav Michl March 22, 2016, 3:33 p.m. UTC
On Tue, Mar 22, 2016 at 08:57:13AM +0200, Tero Kristo wrote:
> On 03/22/2016 03:22 AM, Ladislav Michl wrote:
> >Something like patch v0 bellow. However note, that rate is determined using
> >determine_rate, therefore omap3630_noncore_dpll_determine_rate which is just
> >a copy of omap2_noncore_dpll_determine_rate is calling
> >omap3630_dpll_round_rate - shame, shall we use function pointer
> >determine_rate? Neither is nice and elegant. Also we somehow need to know
> >soc_is_omap3630() and bringing is to drivers/clk does not seem as an option.
> >Also note, that there's no choice between options for 26MHz. Hints?
> 
> What do you mean, no choice between options for 26MHz?

Table 36 list two options with 26MHz clocks: m=443, n=11 and m=480, n=12
with a statement: "The choice between these two options with a 26 MHz input
should be based on characterization on the end system."

[... patch updated]
> >--- drivers/clk/ti/clkt_dpll.c.orig	2016-03-22 01:59:21.724896607 +0100
> >+++ drivers/clk/ti/clkt_dpll.c	2016-03-22 01:53:41.072896607 +0100
> >@@ -368,3 +368,46 @@
> >
> >  	return dd->last_rounded_rate;
> >  }
> >+
> >+/**
> >+ * omap3630_dpll_round_rate - round a target rate for an OMAP DPLL
> >+ * @clk: struct clk * for a DPLL
> >+ * @target_rate: desired DPLL clock rate
> >+ *
> >+ * DM3730 errata (sprz319e), advisory 2.1, table 36 implementation
> >+ */
> >+long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
> >+			      unsigned long *parent_rate)
> >+{
> >+	unsigned long rate;
> >+	struct dpll_data *dd;
> >+	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
> >+
> >+	if (!clk || !clk->dpll_data)
> >+		return ~0;
> 
> I don't think you need these checks here, this condition can never happen.

I just did it consistently with other clock functions. Then those checks all
around should be removed instead. Also see bellow (*)

[... patch updated]
> >+int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
> >+					 struct clk_rate_request *req)
> >+{
> >+	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
> >+	struct dpll_data *dd;
> >+
> >+	if (!req->rate)
> >+		return -EINVAL;
> >+
> >+	dd = clk->dpll_data;
> >+	if (!dd)
> >+		return -EINVAL;
> >+
> >+	if (clk_get_rate(dd->clk_bypass) == req->rate &&
> >+	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
> >+		req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
> >+	} else {
> >+		req->rate = omap3630_dpll_round_rate(hw, req->rate,
> >+					  &req->best_parent_rate);
> >+		req->best_parent_hw = __clk_get_hw(dd->clk_ref);
> >+	}
> >+
> >+	req->best_parent_rate = req->rate;
> >+
> >+	return 0;
> 
> How about something like:
> 
> int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
> 					 struct clk_rate_request *req)
> {
> 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
> 	struct dpll_data *dd;
> 
> 	dd = clk->dpll_data;

(*) why it is here then?

> 	if (!dd)
> 		return -EINVAL;
> 
> 	if (req->rate == 120000000) {
> 		req->rate = omap3630_dpll_round_rate(hw, req->rate,
> 					  &req->best_parent_rate);
> 		req->best_parent_hw = __clk_get_hw(dd->clk_ref);
> 
> 		return 0;
> 	}
> 
> 	return omap3_noncore_dpll_determine_rate(hw, req);
> }
> 
> You can drop the checks against 120MHz inside round_rate then.

What if omap3630_dpll_round_rate is called directly as ops->round_rate()?

best regards,
	ladis



--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Tony Lindgren April 26, 2016, 4:19 p.m. UTC | #1
Tero,

* Ladislav Michl <ladis@linux-mips.org> [160322 08:34]:
> On Tue, Mar 22, 2016 at 08:57:13AM +0200, Tero Kristo wrote:
> > You can drop the checks against 120MHz inside round_rate then.
> 
> What if omap3630_dpll_round_rate is called directly as ops->round_rate()?

What's the status of this fix? Would be good to have this
out of the way.

Regards,

Tony

> --- drivers/clk/ti/dpll3xxx.c.orig	2016-03-21 22:55:29.515746383 +0100
> +++ drivers/clk/ti/dpll3xxx.c	2016-03-22 01:43:54.004896607 +0100
> @@ -534,6 +534,33 @@
>  	return 0;
>  }
>  
> +int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
> +					 struct clk_rate_request *req)
> +{
> +	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
> +	struct dpll_data *dd;
> +
> +	if (!req->rate)
> +		return -EINVAL;
> +
> +	dd = clk->dpll_data;
> +	if (!dd)
> +		return -EINVAL;
> +
> +	if (clk_get_rate(dd->clk_bypass) == req->rate &&
> +	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
> +		req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
> +	} else {
> +		req->rate = omap3630_dpll_round_rate(hw, req->rate,
> +					  &req->best_parent_rate);
> +		req->best_parent_hw = __clk_get_hw(dd->clk_ref);
> +	}
> +
> +	req->best_parent_rate = req->rate;
> +
> +	return 0;
> +}
> +
>  /**
>   * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
>   * @hw: pointer to the clock to set parent for
> --- drivers/clk/ti/clkt_dpll.c.orig	2016-03-22 01:59:21.724896607 +0100
> +++ drivers/clk/ti/clkt_dpll.c	2016-03-22 16:23:22.804383248 +0100
> @@ -368,3 +368,52 @@
>  
>  	return dd->last_rounded_rate;
>  }
> +
> +/**
> + * omap3630_dpll_round_rate - round a target rate for an OMAP DPLL
> + * @clk: struct clk * for a DPLL
> + * @target_rate: desired DPLL clock rate
> + *
> + * DM3730 errata (sprz319e), advisory 2.1
> + */
> +long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
> +			      unsigned long *parent_rate)
> +{
> +	unsigned int i, m, n;
> +	unsigned long r;
> +	struct dpll_data *dd;
> +
> +	static const struct {
> +		unsigned long rate;
> +		unsigned int m;
> +		unsigned int n;	/* value of the register is n - 1 */
> +	} dpll5_advisory[] = {
> +		{ 12000000,  80,  0 + 1, },
> +		{ 19200000,  50,  0 + 1, },
> +		{ 38400000,  25,  0 + 1, },
> +		{ 13000000, 443,  5 + 1, },
> +		{ 26000000, 443, 11 + 1, },
> +		{ 26000000, 480, 12 + 1, },
> +	};
> +
> +	if (target_rate == 120000000)
> +		for (i = 0; i < ARRAY_SIZE(dpll5_advisory); i++)
> +			if (*parent_rate == dpll5_advisory[i].rate) {
> +				m = dpll5_advisory[i].m;
> +				n = dpll5_advisory[i].n;
> +				r = _dpll_compute_new_rate(*parent_rate, m, n);
> +				r /= 8;
> +
> +				printk("clock %s: m=%d, n=%d, rate=%lu\n",
> +					 clk_hw_get_name(hw), m, n, r);
> +
> +				dd = to_clk_hw_omap(hw)->dpll_data;
> +				dd->last_rounded_m = m;
> +				dd->last_rounded_n = n;
> +				dd->last_rounded_rate = r;
> +
> +				return r;
> +			}
> +
> +	return omap2_dpll_round_rate(hw, target_rate, parent_rate);
> +}
> --- drivers/clk/ti/dpll.c.orig	2016-03-21 22:53:16.379746383 +0100
> +++ drivers/clk/ti/dpll.c	2016-03-22 16:27:08.284383248 +0100
> @@ -114,6 +114,18 @@
>  	.round_rate	= &omap2_dpll_round_rate,
>  };
>  
> +static const struct clk_ops omap3630_dpll_ck_ops = {
> +	.enable		= &omap3_noncore_dpll_enable,
> +	.disable	= &omap3_noncore_dpll_disable,
> +	.get_parent	= &omap2_init_dpll_parent,
> +	.recalc_rate	= &omap3_dpll_recalc,
> +	.set_rate	= &omap3_noncore_dpll_set_rate,
> +	.set_parent	= &omap3_noncore_dpll_set_parent,
> +	.set_rate_and_parent	= &omap3_noncore_dpll_set_rate_and_parent,
> +	.determine_rate	= &omap3630_noncore_dpll_determine_rate,
> +	.round_rate	= &omap3630_dpll_round_rate,
> +};
> +
>  static const struct clk_ops omap3_dpll_per_ck_ops = {
>  	.enable		= &omap3_noncore_dpll_enable,
>  	.disable	= &omap3_noncore_dpll_disable,
> @@ -466,6 +478,26 @@
>  CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
>  	       of_ti_omap3_dpll_setup);
>  
> +static void __init of_ti_omap3630_dpll5_setup(struct device_node *node)
> +{
> +	const struct dpll_data dd = {
> +		.idlest_mask = 0x1,
> +		.enable_mask = 0x7,
> +		.autoidle_mask = 0x7,
> +		.mult_mask = 0x7ff << 8,
> +		.div1_mask = 0x7f,
> +		.max_multiplier = 2047,
> +		.max_divider = 128,
> +		.min_divider = 1,
> +		.freqsel_mask = 0xf0,
> +		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
> +	};
> +
> +	of_ti_dpll_setup(node, &omap3630_dpll_ck_ops, &dd);
> +}
> +CLK_OF_DECLARE(ti_omap3630_dpll5_clock, "ti,omap3630-dpll5-clock",
> +	       of_ti_omap3630_dpll5_setup);
> +
>  static void __init of_ti_omap3_core_dpll_setup(struct device_node *node)
>  {
>  	const struct dpll_data dd = {
> --- drivers/clk/ti/clock.h.orig	2016-03-21 22:55:09.011746383 +0100
> +++ drivers/clk/ti/clock.h	2016-03-22 01:42:45.840896607 +0100
> @@ -252,8 +252,12 @@
>  					   u8 index);
>  int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
>  				      struct clk_rate_request *req);
> +int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
> +					 struct clk_rate_request *req);
>  long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
>  			   unsigned long *parent_rate);
> +long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
> +			      unsigned long *parent_rate);
>  unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
>  				    unsigned long parent_rate);
>  
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tero Kristo April 26, 2016, 5:46 p.m. UTC | #2
On 26/04/16 19:19, Tony Lindgren wrote:
> Tero,
>
> * Ladislav Michl <ladis@linux-mips.org> [160322 08:34]:
>> On Tue, Mar 22, 2016 at 08:57:13AM +0200, Tero Kristo wrote:
>>> You can drop the checks against 120MHz inside round_rate then.
>>
>> What if omap3630_dpll_round_rate is called directly as ops->round_rate()?
>
> What's the status of this fix? Would be good to have this
> out of the way.

Sorry I think this got buried in my inbox...

Yea I think the last inline patch looks reasonably good to me. Added a 
couple of comments below, but once those are fixed (+ any checkpatch 
issues), it should be good to go. I haven't tested the patch itself 
though as I don't have local access to omap36xx hw.

>
> Regards,
>
> Tony
>
>> --- drivers/clk/ti/dpll3xxx.c.orig	2016-03-21 22:55:29.515746383 +0100
>> +++ drivers/clk/ti/dpll3xxx.c	2016-03-22 01:43:54.004896607 +0100
>> @@ -534,6 +534,33 @@
>>   	return 0;
>>   }
>>
>> +int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
>> +					 struct clk_rate_request *req)
>> +{
>> +	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
>> +	struct dpll_data *dd;
>> +
>> +	if (!req->rate)
>> +		return -EINVAL;
>> +
>> +	dd = clk->dpll_data;
>> +	if (!dd)
>> +		return -EINVAL;
>> +
>> +	if (clk_get_rate(dd->clk_bypass) == req->rate &&
>> +	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
>> +		req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
>> +	} else {
>> +		req->rate = omap3630_dpll_round_rate(hw, req->rate,
>> +					  &req->best_parent_rate);
>> +		req->best_parent_hw = __clk_get_hw(dd->clk_ref);
>> +	}
>> +
>> +	req->best_parent_rate = req->rate;
>> +
>> +	return 0;
>> +}
>> +
>>   /**
>>    * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
>>    * @hw: pointer to the clock to set parent for
>> --- drivers/clk/ti/clkt_dpll.c.orig	2016-03-22 01:59:21.724896607 +0100
>> +++ drivers/clk/ti/clkt_dpll.c	2016-03-22 16:23:22.804383248 +0100
>> @@ -368,3 +368,52 @@
>>
>>   	return dd->last_rounded_rate;
>>   }
>> +
>> +/**
>> + * omap3630_dpll_round_rate - round a target rate for an OMAP DPLL
>> + * @clk: struct clk * for a DPLL
>> + * @target_rate: desired DPLL clock rate
>> + *
>> + * DM3730 errata (sprz319e), advisory 2.1
>> + */
>> +long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
>> +			      unsigned long *parent_rate)
>> +{
>> +	unsigned int i, m, n;
>> +	unsigned long r;
>> +	struct dpll_data *dd;
>> +
>> +	static const struct {
>> +		unsigned long rate;
>> +		unsigned int m;
>> +		unsigned int n;	/* value of the register is n - 1 */
>> +	} dpll5_advisory[] = {
>> +		{ 12000000,  80,  0 + 1, },
>> +		{ 19200000,  50,  0 + 1, },
>> +		{ 38400000,  25,  0 + 1, },
>> +		{ 13000000, 443,  5 + 1, },
>> +		{ 26000000, 443, 11 + 1, },
>> +		{ 26000000, 480, 12 + 1, },
>> +	};

I would avoid local/mixed definition like this.

>> +
>> +	if (target_rate == 120000000)
>> +		for (i = 0; i < ARRAY_SIZE(dpll5_advisory); i++)
>> +			if (*parent_rate == dpll5_advisory[i].rate) {
>> +				m = dpll5_advisory[i].m;
>> +				n = dpll5_advisory[i].n;
>> +				r = _dpll_compute_new_rate(*parent_rate, m, n);
>> +				r /= 8;
>> +
>> +				printk("clock %s: m=%d, n=%d, rate=%lu\n",
>> +					 clk_hw_get_name(hw), m, n, r);

Debugging info should be dropped.

Thanks, Tero.

>> +
>> +				dd = to_clk_hw_omap(hw)->dpll_data;
>> +				dd->last_rounded_m = m;
>> +				dd->last_rounded_n = n;
>> +				dd->last_rounded_rate = r;
>> +
>> +				return r;
>> +			}
>> +
>> +	return omap2_dpll_round_rate(hw, target_rate, parent_rate);
>> +}
>> --- drivers/clk/ti/dpll.c.orig	2016-03-21 22:53:16.379746383 +0100
>> +++ drivers/clk/ti/dpll.c	2016-03-22 16:27:08.284383248 +0100
>> @@ -114,6 +114,18 @@
>>   	.round_rate	= &omap2_dpll_round_rate,
>>   };
>>
>> +static const struct clk_ops omap3630_dpll_ck_ops = {
>> +	.enable		= &omap3_noncore_dpll_enable,
>> +	.disable	= &omap3_noncore_dpll_disable,
>> +	.get_parent	= &omap2_init_dpll_parent,
>> +	.recalc_rate	= &omap3_dpll_recalc,
>> +	.set_rate	= &omap3_noncore_dpll_set_rate,
>> +	.set_parent	= &omap3_noncore_dpll_set_parent,
>> +	.set_rate_and_parent	= &omap3_noncore_dpll_set_rate_and_parent,
>> +	.determine_rate	= &omap3630_noncore_dpll_determine_rate,
>> +	.round_rate	= &omap3630_dpll_round_rate,
>> +};
>> +
>>   static const struct clk_ops omap3_dpll_per_ck_ops = {
>>   	.enable		= &omap3_noncore_dpll_enable,
>>   	.disable	= &omap3_noncore_dpll_disable,
>> @@ -466,6 +478,26 @@
>>   CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
>>   	       of_ti_omap3_dpll_setup);
>>
>> +static void __init of_ti_omap3630_dpll5_setup(struct device_node *node)
>> +{
>> +	const struct dpll_data dd = {
>> +		.idlest_mask = 0x1,
>> +		.enable_mask = 0x7,
>> +		.autoidle_mask = 0x7,
>> +		.mult_mask = 0x7ff << 8,
>> +		.div1_mask = 0x7f,
>> +		.max_multiplier = 2047,
>> +		.max_divider = 128,
>> +		.min_divider = 1,
>> +		.freqsel_mask = 0xf0,
>> +		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
>> +	};
>> +
>> +	of_ti_dpll_setup(node, &omap3630_dpll_ck_ops, &dd);
>> +}
>> +CLK_OF_DECLARE(ti_omap3630_dpll5_clock, "ti,omap3630-dpll5-clock",
>> +	       of_ti_omap3630_dpll5_setup);
>> +
>>   static void __init of_ti_omap3_core_dpll_setup(struct device_node *node)
>>   {
>>   	const struct dpll_data dd = {
>> --- drivers/clk/ti/clock.h.orig	2016-03-21 22:55:09.011746383 +0100
>> +++ drivers/clk/ti/clock.h	2016-03-22 01:42:45.840896607 +0100
>> @@ -252,8 +252,12 @@
>>   					   u8 index);
>>   int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
>>   				      struct clk_rate_request *req);
>> +int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
>> +					 struct clk_rate_request *req);
>>   long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
>>   			   unsigned long *parent_rate);
>> +long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
>> +			      unsigned long *parent_rate);
>>   unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
>>   				    unsigned long parent_rate);
>>
>>
>>

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- drivers/clk/ti/dpll3xxx.c.orig	2016-03-21 22:55:29.515746383 +0100
+++ drivers/clk/ti/dpll3xxx.c	2016-03-22 01:43:54.004896607 +0100
@@ -534,6 +534,33 @@ 
 	return 0;
 }
 
+int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+	struct dpll_data *dd;
+
+	if (!req->rate)
+		return -EINVAL;
+
+	dd = clk->dpll_data;
+	if (!dd)
+		return -EINVAL;
+
+	if (clk_get_rate(dd->clk_bypass) == req->rate &&
+	    (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+		req->best_parent_hw = __clk_get_hw(dd->clk_bypass);
+	} else {
+		req->rate = omap3630_dpll_round_rate(hw, req->rate,
+					  &req->best_parent_rate);
+		req->best_parent_hw = __clk_get_hw(dd->clk_ref);
+	}
+
+	req->best_parent_rate = req->rate;
+
+	return 0;
+}
+
 /**
  * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
  * @hw: pointer to the clock to set parent for
--- drivers/clk/ti/clkt_dpll.c.orig	2016-03-22 01:59:21.724896607 +0100
+++ drivers/clk/ti/clkt_dpll.c	2016-03-22 16:23:22.804383248 +0100
@@ -368,3 +368,52 @@ 
 
 	return dd->last_rounded_rate;
 }
+
+/**
+ * omap3630_dpll_round_rate - round a target rate for an OMAP DPLL
+ * @clk: struct clk * for a DPLL
+ * @target_rate: desired DPLL clock rate
+ *
+ * DM3730 errata (sprz319e), advisory 2.1
+ */
+long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+			      unsigned long *parent_rate)
+{
+	unsigned int i, m, n;
+	unsigned long r;
+	struct dpll_data *dd;
+
+	static const struct {
+		unsigned long rate;
+		unsigned int m;
+		unsigned int n;	/* value of the register is n - 1 */
+	} dpll5_advisory[] = {
+		{ 12000000,  80,  0 + 1, },
+		{ 19200000,  50,  0 + 1, },
+		{ 38400000,  25,  0 + 1, },
+		{ 13000000, 443,  5 + 1, },
+		{ 26000000, 443, 11 + 1, },
+		{ 26000000, 480, 12 + 1, },
+	};
+
+	if (target_rate == 120000000)
+		for (i = 0; i < ARRAY_SIZE(dpll5_advisory); i++)
+			if (*parent_rate == dpll5_advisory[i].rate) {
+				m = dpll5_advisory[i].m;
+				n = dpll5_advisory[i].n;
+				r = _dpll_compute_new_rate(*parent_rate, m, n);
+				r /= 8;
+
+				printk("clock %s: m=%d, n=%d, rate=%lu\n",
+					 clk_hw_get_name(hw), m, n, r);
+
+				dd = to_clk_hw_omap(hw)->dpll_data;
+				dd->last_rounded_m = m;
+				dd->last_rounded_n = n;
+				dd->last_rounded_rate = r;
+
+				return r;
+			}
+
+	return omap2_dpll_round_rate(hw, target_rate, parent_rate);
+}
--- drivers/clk/ti/dpll.c.orig	2016-03-21 22:53:16.379746383 +0100
+++ drivers/clk/ti/dpll.c	2016-03-22 16:27:08.284383248 +0100
@@ -114,6 +114,18 @@ 
 	.round_rate	= &omap2_dpll_round_rate,
 };
 
+static const struct clk_ops omap3630_dpll_ck_ops = {
+	.enable		= &omap3_noncore_dpll_enable,
+	.disable	= &omap3_noncore_dpll_disable,
+	.get_parent	= &omap2_init_dpll_parent,
+	.recalc_rate	= &omap3_dpll_recalc,
+	.set_rate	= &omap3_noncore_dpll_set_rate,
+	.set_parent	= &omap3_noncore_dpll_set_parent,
+	.set_rate_and_parent	= &omap3_noncore_dpll_set_rate_and_parent,
+	.determine_rate	= &omap3630_noncore_dpll_determine_rate,
+	.round_rate	= &omap3630_dpll_round_rate,
+};
+
 static const struct clk_ops omap3_dpll_per_ck_ops = {
 	.enable		= &omap3_noncore_dpll_enable,
 	.disable	= &omap3_noncore_dpll_disable,
@@ -466,6 +478,26 @@ 
 CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
 	       of_ti_omap3_dpll_setup);
 
+static void __init of_ti_omap3630_dpll5_setup(struct device_node *node)
+{
+	const struct dpll_data dd = {
+		.idlest_mask = 0x1,
+		.enable_mask = 0x7,
+		.autoidle_mask = 0x7,
+		.mult_mask = 0x7ff << 8,
+		.div1_mask = 0x7f,
+		.max_multiplier = 2047,
+		.max_divider = 128,
+		.min_divider = 1,
+		.freqsel_mask = 0xf0,
+		.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+	};
+
+	of_ti_dpll_setup(node, &omap3630_dpll_ck_ops, &dd);
+}
+CLK_OF_DECLARE(ti_omap3630_dpll5_clock, "ti,omap3630-dpll5-clock",
+	       of_ti_omap3630_dpll5_setup);
+
 static void __init of_ti_omap3_core_dpll_setup(struct device_node *node)
 {
 	const struct dpll_data dd = {
--- drivers/clk/ti/clock.h.orig	2016-03-21 22:55:09.011746383 +0100
+++ drivers/clk/ti/clock.h	2016-03-22 01:42:45.840896607 +0100
@@ -252,8 +252,12 @@ 
 					   u8 index);
 int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
 				      struct clk_rate_request *req);
+int omap3630_noncore_dpll_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req);
 long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 			   unsigned long *parent_rate);
+long omap3630_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+			      unsigned long *parent_rate);
 unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
 				    unsigned long parent_rate);