All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tero Kristo <t-kristo@ti.com>
To: Stephen Boyd <sboyd@codeaurora.org>
Cc: nm@ti.com, devicetree@vger.kernel.org, mturquette@baylibre.com,
	ssantosh@kernel.org, linux-clk@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 3/3] clk: keystone: Add sci-clk driver support
Date: Thu, 8 Dec 2016 12:45:49 +0200	[thread overview]
Message-ID: <cb608729-b617-0eab-5ddf-d78ff47b237e@ti.com> (raw)
In-Reply-To: <20161208001348.GC5423@codeaurora.org>

On 08/12/16 02:13, Stephen Boyd wrote:
> On 10/21, Tero Kristo wrote:
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 6a8ac04..dce08a7 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -169,6 +169,15 @@ config COMMON_CLK_NXP
>>  	---help---
>>  	  Support for clock providers on NXP platforms.
>>
>> +config TI_SCI_CLK
>> +	tristate "TI System Control Interface clock drivers"
>> +	depends on (TI_SCI_PROTOCOL && COMMON_CLK_KEYSTONE) || COMPILE_TEST
>
> Given that we depend on COMMON_CLK_KEYSTONE (just for the
> Makefile dependency?) this should be moved to right below the
> COMMON_CLK_KEYSTONE config. And we should consider making a
> Kconfig file in drivers/clk/keystone/ to hold both those configs
> instead of having them at the toplevel.

Its a makefile dependency only right now. I'll have a look at how to 
handle this properly.

>
>> +	default TI_SCI_PROTOCOL
>> +	---help---
>> +	  This adds the clock driver support over TI System Control Interface.
>> +	  If you wish to use clock resources from the PMMC firmware, say Y.
>> +	  Otherwise, say N.
>> +
>>  config COMMON_CLK_PALMAS
>>  	tristate "Clock driver for TI Palmas devices"
>>  	depends on MFD_PALMAS
>> diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile
>> index 0477cf6..0e7993d 100644
>> --- a/drivers/clk/keystone/Makefile
>> +++ b/drivers/clk/keystone/Makefile
>> @@ -1 +1,2 @@
>>  obj-y			+= pll.o gate.o
>> +obj-$(CONFIG_TI_SCI_CLK)	+= sci-clk.o
>> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
>> new file mode 100644
>> index 0000000..f6af5bd
>> --- /dev/null
>> +++ b/drivers/clk/keystone/sci-clk.c
>> @@ -0,0 +1,589 @@
> [...]
>> +
>> +/**
>> + * sci_clk_recalc_rate - Get clock rate for a TI SCI clock
>> + * @hw: clock to get rate for
>> + * @parent_rate: parent rate provided by common clock framework, not used
>> + *
>> + * Gets the current clock rate of a TI SCI clock. Returns the current
>> + * clock rate, or zero in failure.
>> + */
>> +static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
>> +					 unsigned long parent_rate)
>> +{
>> +	struct sci_clk *clk = to_sci_clk(hw);
>> +	u64 freq;
>> +	int ret;
>> +
>> +	ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
>> +					   clk->clk_id, &freq);
>> +	if (ret) {
>> +		dev_err(clk->provider->dev,
>> +			"recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
>> +			clk->dev_id, clk->clk_id, ret);
>> +		return 0;
>> +	}
>> +
>> +	return (u32)freq;
>
> Do we need the cast? sizeof(u32) doesn't always equal
> sizeof(unsigned long).

Hmm, not sure where that came from. But yea, can be dropped.


>
>> +
>> +/**
>> + * _sci_clk_get - Gets a handle for an SCI clock
>> + * @provider: Handle to SCI clock provider
>> + * @dev_id: device ID for the clock to register
>> + * @clk_id: clock ID for the clock to register
>> + *
>> + * Gets a handle to an existing TI SCI hw clock, or builds a new clock
>> + * entry and registers it with the common clock framework. Called from
>> + * the common clock framework, when a corresponding of_clk_get call is
>> + * executed, or recursively from itself when parsing parent clocks.
>> + * Returns a pointer to the hw clock struct, or ERR_PTR value in failure.
>> + */
>> +static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider,
>> +				     u16 dev_id, u8 clk_id)
>> +{
>> +	struct clk_init_data init = { NULL };
>> +	struct sci_clk *sci_clk = NULL;
>> +	char *name = NULL;
>> +	char **parent_names = NULL;
>> +	int i;
>> +	int ret;
>> +
>> +	sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL);
>> +	if (!sci_clk)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	sci_clk->dev_id = dev_id;
>> +	sci_clk->clk_id = clk_id;
>> +	sci_clk->provider = provider;
>> +
>> +	ret = provider->ops->get_num_parents(provider->sci, dev_id,
>> +					     clk_id,
>> +					     &init.num_parents);
>> +	if (ret)
>> +		goto err;
>> +
>> +	name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
>> +			 sci_clk->dev_id, sci_clk->clk_id);
>> +
>> +	init.name = name;
>> +
>> +	if (init.num_parents < 2)
>> +		init.num_parents = 0;
>
> This deserves a comment. Why is num_parents == 1 the same as
> num_parents == 0?

I'll add a comment on this. Basically some clocks can be root clocks 
which don't have parents, and we only want to have parent control for 
clocks that can switch their parent. This is kind of a quirk of the 
firmware.

>
>> +
>> +	if (init.num_parents) {
>> +		parent_names = devm_kcalloc(provider->dev, init.num_parents,
>> +					    sizeof(char *), GFP_KERNEL);
>> +
>> +		if (!parent_names) {
>> +			ret = -ENOMEM;
>> +			goto err;
>> +		}
>> +
>> +		for (i = 0; i < init.num_parents; i++) {
>> +			char *parent_name;
>> +
>> +			parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
>> +						dev_name(provider->dev),
>> +						sci_clk->dev_id,
>> +						sci_clk->clk_id + 1 + i);
>> +			if (!parent_name) {
>> +				ret = -ENOMEM;
>> +				goto err;
>> +			}
>> +			parent_names[i] = parent_name;
>> +		}
>> +		init.parent_names = (const char * const *)parent_names;
>
> Does that really need a cast?

Doesn't seem like so... I think without this it was generating some 
checkpatch issue sometime back, but doesn't seem to be the case anymore.

>
>> +	}
>> +
>> +	init.ops = &sci_clk_ops;
>> +	sci_clk->hw.init = &init;
>> +
>> +	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
>> +	if (ret) {
>> +		dev_err(provider->dev, "failed clk register with %d\n", ret);
>> +		goto err;
>> +	}
>> +	kfree(name);
>> +
>> +	return &sci_clk->hw;
>> +
>> +err:
>> +	if (parent_names) {
>> +		for (i = 0; i < init.num_parents; i++)
>> +			devm_kfree(provider->dev, parent_names[i]);
>> +
>> +		devm_kfree(provider->dev, parent_names);
>
> Shouldn't we be freeing the parent names all the time? It should
> be deep copied in the framework.

I'll check this.

>
>> +	}
>> +
>> +	devm_kfree(provider->dev, sci_clk);
>> +
>> +	kfree(name);
>> +
>> +	return ERR_PTR(ret);
>> +}
> [..]
>> +
>> +static int ti_sci_init_clocks(struct sci_clk_provider *p)
>> +{
>> +	struct sci_clk_data *data = p->clocks;
>> +	struct clk_hw *hw;
>> +	int i;
>> +
>> +	while (data->num_clks) {
>> +		data->clocks = devm_kcalloc(p->dev, data->num_clks,
>> +					    sizeof(struct sci_clk),
>> +					    GFP_KERNEL);
>> +		if (!data->clocks)
>> +			return -ENOMEM;
>> +
>> +		for (i = 0; i < data->num_clks; i++) {
>> +			hw = _sci_clk_build(p, data->dev, i);
>> +			if (!IS_ERR(hw)) {
>> +				data->clocks[i] = hw;
>> +				continue;
>> +			}
>> +
>> +			/* Skip any holes in the clock lists */
>> +			if (PTR_ERR(hw) == -ENODEV)
>
> Does this happen? I don't see where _sci_clk_build() returns
> -ENODEV.

Yes, it can and will happen. get_num_parents() called by sci_clk_build 
will return ENODEV for device/clock pairs that don't exist.

>
>> +				continue;
>> +
>> +			return PTR_ERR(hw);
>> +		}
>> +		data++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>
>> +
>> +/**
>> + * ti_sci_clk_probe - Probe function for the TI SCI clock driver
>> + * @pdev: platform device pointer to be probed
>> + *
>> + * Probes the TI SCI clock device. Allocates a new clock provider
>> + * and registers this to the common clock framework. Also applies
>> + * any required flags to the identified clocks via clock lists
>> + * supplied from DT. Returns 0 for success, negative error value
>> + * for failure.
>> + */
>> +static int ti_sci_clk_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct sci_clk_provider *provider;
>> +	const struct ti_sci_handle *handle;
>> +	struct sci_clk_data *data;
>> +	int ret;
>> +
>> +	data = (struct sci_clk_data *)
>> +		of_match_node(ti_sci_clk_of_match, np)->data;
>
> Just use of_device_get_match_data() instead.

All righty.

>
>> +
>> +	handle = devm_ti_sci_get_handle(dev);
>> +	if (IS_ERR(handle))
>> +		return PTR_ERR(handle);
>> +
>> +	provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
>> +	if (!provider)
>> +		return -ENOMEM;
>> +
>> +	provider->clocks = data;
>> +
>> +	provider->sci = handle;
>> +	provider->ops = &handle->ops.clk_ops;
>> +	provider->dev = dev;
>> +
>> +	ti_sci_init_clocks(provider);
>
> And if this fails?

Yea this is kind of controversial. ti_sci_init_clocks() can fail if any 
of the clocks registered will fail. I decided to have it this way so 
that at least some clocks might work in failure cause, and you might 
have a booting device instead of total lock-up.

Obviously it could be done so that if any clock fails, we would 
de-register all clocks at that point, but personally I think this is a 
worse option.

ti_sci_init_clocks could probably be modified to continue registering 
clocks when a single clock fails though. Currently it aborts at first 
failure.

Thoughts on that?

>
>> +
>> +	ret = of_clk_add_hw_provider(np, sci_clk_get, provider);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>
> Just "return of_clk_add_hw_provider()" please.

True that, will fix.

-Tero

WARNING: multiple messages have this Message-ID (diff)
From: Tero Kristo <t-kristo@ti.com>
To: Stephen Boyd <sboyd@codeaurora.org>
Cc: <linux-clk@vger.kernel.org>, <mturquette@baylibre.com>,
	<ssantosh@kernel.org>, <nm@ti.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<devicetree@vger.kernel.org>
Subject: Re: [PATCH 3/3] clk: keystone: Add sci-clk driver support
Date: Thu, 8 Dec 2016 12:45:49 +0200	[thread overview]
Message-ID: <cb608729-b617-0eab-5ddf-d78ff47b237e@ti.com> (raw)
In-Reply-To: <20161208001348.GC5423@codeaurora.org>

On 08/12/16 02:13, Stephen Boyd wrote:
> On 10/21, Tero Kristo wrote:
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 6a8ac04..dce08a7 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -169,6 +169,15 @@ config COMMON_CLK_NXP
>>  	---help---
>>  	  Support for clock providers on NXP platforms.
>>
>> +config TI_SCI_CLK
>> +	tristate "TI System Control Interface clock drivers"
>> +	depends on (TI_SCI_PROTOCOL && COMMON_CLK_KEYSTONE) || COMPILE_TEST
>
> Given that we depend on COMMON_CLK_KEYSTONE (just for the
> Makefile dependency?) this should be moved to right below the
> COMMON_CLK_KEYSTONE config. And we should consider making a
> Kconfig file in drivers/clk/keystone/ to hold both those configs
> instead of having them at the toplevel.

Its a makefile dependency only right now. I'll have a look at how to 
handle this properly.

>
>> +	default TI_SCI_PROTOCOL
>> +	---help---
>> +	  This adds the clock driver support over TI System Control Interface.
>> +	  If you wish to use clock resources from the PMMC firmware, say Y.
>> +	  Otherwise, say N.
>> +
>>  config COMMON_CLK_PALMAS
>>  	tristate "Clock driver for TI Palmas devices"
>>  	depends on MFD_PALMAS
>> diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile
>> index 0477cf6..0e7993d 100644
>> --- a/drivers/clk/keystone/Makefile
>> +++ b/drivers/clk/keystone/Makefile
>> @@ -1 +1,2 @@
>>  obj-y			+= pll.o gate.o
>> +obj-$(CONFIG_TI_SCI_CLK)	+= sci-clk.o
>> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
>> new file mode 100644
>> index 0000000..f6af5bd
>> --- /dev/null
>> +++ b/drivers/clk/keystone/sci-clk.c
>> @@ -0,0 +1,589 @@
> [...]
>> +
>> +/**
>> + * sci_clk_recalc_rate - Get clock rate for a TI SCI clock
>> + * @hw: clock to get rate for
>> + * @parent_rate: parent rate provided by common clock framework, not used
>> + *
>> + * Gets the current clock rate of a TI SCI clock. Returns the current
>> + * clock rate, or zero in failure.
>> + */
>> +static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
>> +					 unsigned long parent_rate)
>> +{
>> +	struct sci_clk *clk = to_sci_clk(hw);
>> +	u64 freq;
>> +	int ret;
>> +
>> +	ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
>> +					   clk->clk_id, &freq);
>> +	if (ret) {
>> +		dev_err(clk->provider->dev,
>> +			"recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
>> +			clk->dev_id, clk->clk_id, ret);
>> +		return 0;
>> +	}
>> +
>> +	return (u32)freq;
>
> Do we need the cast? sizeof(u32) doesn't always equal
> sizeof(unsigned long).

Hmm, not sure where that came from. But yea, can be dropped.


>
>> +
>> +/**
>> + * _sci_clk_get - Gets a handle for an SCI clock
>> + * @provider: Handle to SCI clock provider
>> + * @dev_id: device ID for the clock to register
>> + * @clk_id: clock ID for the clock to register
>> + *
>> + * Gets a handle to an existing TI SCI hw clock, or builds a new clock
>> + * entry and registers it with the common clock framework. Called from
>> + * the common clock framework, when a corresponding of_clk_get call is
>> + * executed, or recursively from itself when parsing parent clocks.
>> + * Returns a pointer to the hw clock struct, or ERR_PTR value in failure.
>> + */
>> +static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider,
>> +				     u16 dev_id, u8 clk_id)
>> +{
>> +	struct clk_init_data init = { NULL };
>> +	struct sci_clk *sci_clk = NULL;
>> +	char *name = NULL;
>> +	char **parent_names = NULL;
>> +	int i;
>> +	int ret;
>> +
>> +	sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL);
>> +	if (!sci_clk)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	sci_clk->dev_id = dev_id;
>> +	sci_clk->clk_id = clk_id;
>> +	sci_clk->provider = provider;
>> +
>> +	ret = provider->ops->get_num_parents(provider->sci, dev_id,
>> +					     clk_id,
>> +					     &init.num_parents);
>> +	if (ret)
>> +		goto err;
>> +
>> +	name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
>> +			 sci_clk->dev_id, sci_clk->clk_id);
>> +
>> +	init.name = name;
>> +
>> +	if (init.num_parents < 2)
>> +		init.num_parents = 0;
>
> This deserves a comment. Why is num_parents == 1 the same as
> num_parents == 0?

I'll add a comment on this. Basically some clocks can be root clocks 
which don't have parents, and we only want to have parent control for 
clocks that can switch their parent. This is kind of a quirk of the 
firmware.

>
>> +
>> +	if (init.num_parents) {
>> +		parent_names = devm_kcalloc(provider->dev, init.num_parents,
>> +					    sizeof(char *), GFP_KERNEL);
>> +
>> +		if (!parent_names) {
>> +			ret = -ENOMEM;
>> +			goto err;
>> +		}
>> +
>> +		for (i = 0; i < init.num_parents; i++) {
>> +			char *parent_name;
>> +
>> +			parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
>> +						dev_name(provider->dev),
>> +						sci_clk->dev_id,
>> +						sci_clk->clk_id + 1 + i);
>> +			if (!parent_name) {
>> +				ret = -ENOMEM;
>> +				goto err;
>> +			}
>> +			parent_names[i] = parent_name;
>> +		}
>> +		init.parent_names = (const char * const *)parent_names;
>
> Does that really need a cast?

Doesn't seem like so... I think without this it was generating some 
checkpatch issue sometime back, but doesn't seem to be the case anymore.

>
>> +	}
>> +
>> +	init.ops = &sci_clk_ops;
>> +	sci_clk->hw.init = &init;
>> +
>> +	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
>> +	if (ret) {
>> +		dev_err(provider->dev, "failed clk register with %d\n", ret);
>> +		goto err;
>> +	}
>> +	kfree(name);
>> +
>> +	return &sci_clk->hw;
>> +
>> +err:
>> +	if (parent_names) {
>> +		for (i = 0; i < init.num_parents; i++)
>> +			devm_kfree(provider->dev, parent_names[i]);
>> +
>> +		devm_kfree(provider->dev, parent_names);
>
> Shouldn't we be freeing the parent names all the time? It should
> be deep copied in the framework.

I'll check this.

>
>> +	}
>> +
>> +	devm_kfree(provider->dev, sci_clk);
>> +
>> +	kfree(name);
>> +
>> +	return ERR_PTR(ret);
>> +}
> [..]
>> +
>> +static int ti_sci_init_clocks(struct sci_clk_provider *p)
>> +{
>> +	struct sci_clk_data *data = p->clocks;
>> +	struct clk_hw *hw;
>> +	int i;
>> +
>> +	while (data->num_clks) {
>> +		data->clocks = devm_kcalloc(p->dev, data->num_clks,
>> +					    sizeof(struct sci_clk),
>> +					    GFP_KERNEL);
>> +		if (!data->clocks)
>> +			return -ENOMEM;
>> +
>> +		for (i = 0; i < data->num_clks; i++) {
>> +			hw = _sci_clk_build(p, data->dev, i);
>> +			if (!IS_ERR(hw)) {
>> +				data->clocks[i] = hw;
>> +				continue;
>> +			}
>> +
>> +			/* Skip any holes in the clock lists */
>> +			if (PTR_ERR(hw) == -ENODEV)
>
> Does this happen? I don't see where _sci_clk_build() returns
> -ENODEV.

Yes, it can and will happen. get_num_parents() called by sci_clk_build 
will return ENODEV for device/clock pairs that don't exist.

>
>> +				continue;
>> +
>> +			return PTR_ERR(hw);
>> +		}
>> +		data++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>
>> +
>> +/**
>> + * ti_sci_clk_probe - Probe function for the TI SCI clock driver
>> + * @pdev: platform device pointer to be probed
>> + *
>> + * Probes the TI SCI clock device. Allocates a new clock provider
>> + * and registers this to the common clock framework. Also applies
>> + * any required flags to the identified clocks via clock lists
>> + * supplied from DT. Returns 0 for success, negative error value
>> + * for failure.
>> + */
>> +static int ti_sci_clk_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct sci_clk_provider *provider;
>> +	const struct ti_sci_handle *handle;
>> +	struct sci_clk_data *data;
>> +	int ret;
>> +
>> +	data = (struct sci_clk_data *)
>> +		of_match_node(ti_sci_clk_of_match, np)->data;
>
> Just use of_device_get_match_data() instead.

All righty.

>
>> +
>> +	handle = devm_ti_sci_get_handle(dev);
>> +	if (IS_ERR(handle))
>> +		return PTR_ERR(handle);
>> +
>> +	provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
>> +	if (!provider)
>> +		return -ENOMEM;
>> +
>> +	provider->clocks = data;
>> +
>> +	provider->sci = handle;
>> +	provider->ops = &handle->ops.clk_ops;
>> +	provider->dev = dev;
>> +
>> +	ti_sci_init_clocks(provider);
>
> And if this fails?

Yea this is kind of controversial. ti_sci_init_clocks() can fail if any 
of the clocks registered will fail. I decided to have it this way so 
that at least some clocks might work in failure cause, and you might 
have a booting device instead of total lock-up.

Obviously it could be done so that if any clock fails, we would 
de-register all clocks at that point, but personally I think this is a 
worse option.

ti_sci_init_clocks could probably be modified to continue registering 
clocks when a single clock fails though. Currently it aborts at first 
failure.

Thoughts on that?

>
>> +
>> +	ret = of_clk_add_hw_provider(np, sci_clk_get, provider);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>
> Just "return of_clk_add_hw_provider()" please.

True that, will fix.

-Tero

WARNING: multiple messages have this Message-ID (diff)
From: t-kristo@ti.com (Tero Kristo)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 3/3] clk: keystone: Add sci-clk driver support
Date: Thu, 8 Dec 2016 12:45:49 +0200	[thread overview]
Message-ID: <cb608729-b617-0eab-5ddf-d78ff47b237e@ti.com> (raw)
In-Reply-To: <20161208001348.GC5423@codeaurora.org>

On 08/12/16 02:13, Stephen Boyd wrote:
> On 10/21, Tero Kristo wrote:
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 6a8ac04..dce08a7 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -169,6 +169,15 @@ config COMMON_CLK_NXP
>>  	---help---
>>  	  Support for clock providers on NXP platforms.
>>
>> +config TI_SCI_CLK
>> +	tristate "TI System Control Interface clock drivers"
>> +	depends on (TI_SCI_PROTOCOL && COMMON_CLK_KEYSTONE) || COMPILE_TEST
>
> Given that we depend on COMMON_CLK_KEYSTONE (just for the
> Makefile dependency?) this should be moved to right below the
> COMMON_CLK_KEYSTONE config. And we should consider making a
> Kconfig file in drivers/clk/keystone/ to hold both those configs
> instead of having them at the toplevel.

Its a makefile dependency only right now. I'll have a look at how to 
handle this properly.

>
>> +	default TI_SCI_PROTOCOL
>> +	---help---
>> +	  This adds the clock driver support over TI System Control Interface.
>> +	  If you wish to use clock resources from the PMMC firmware, say Y.
>> +	  Otherwise, say N.
>> +
>>  config COMMON_CLK_PALMAS
>>  	tristate "Clock driver for TI Palmas devices"
>>  	depends on MFD_PALMAS
>> diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile
>> index 0477cf6..0e7993d 100644
>> --- a/drivers/clk/keystone/Makefile
>> +++ b/drivers/clk/keystone/Makefile
>> @@ -1 +1,2 @@
>>  obj-y			+= pll.o gate.o
>> +obj-$(CONFIG_TI_SCI_CLK)	+= sci-clk.o
>> diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
>> new file mode 100644
>> index 0000000..f6af5bd
>> --- /dev/null
>> +++ b/drivers/clk/keystone/sci-clk.c
>> @@ -0,0 +1,589 @@
> [...]
>> +
>> +/**
>> + * sci_clk_recalc_rate - Get clock rate for a TI SCI clock
>> + * @hw: clock to get rate for
>> + * @parent_rate: parent rate provided by common clock framework, not used
>> + *
>> + * Gets the current clock rate of a TI SCI clock. Returns the current
>> + * clock rate, or zero in failure.
>> + */
>> +static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
>> +					 unsigned long parent_rate)
>> +{
>> +	struct sci_clk *clk = to_sci_clk(hw);
>> +	u64 freq;
>> +	int ret;
>> +
>> +	ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
>> +					   clk->clk_id, &freq);
>> +	if (ret) {
>> +		dev_err(clk->provider->dev,
>> +			"recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
>> +			clk->dev_id, clk->clk_id, ret);
>> +		return 0;
>> +	}
>> +
>> +	return (u32)freq;
>
> Do we need the cast? sizeof(u32) doesn't always equal
> sizeof(unsigned long).

Hmm, not sure where that came from. But yea, can be dropped.


>
>> +
>> +/**
>> + * _sci_clk_get - Gets a handle for an SCI clock
>> + * @provider: Handle to SCI clock provider
>> + * @dev_id: device ID for the clock to register
>> + * @clk_id: clock ID for the clock to register
>> + *
>> + * Gets a handle to an existing TI SCI hw clock, or builds a new clock
>> + * entry and registers it with the common clock framework. Called from
>> + * the common clock framework, when a corresponding of_clk_get call is
>> + * executed, or recursively from itself when parsing parent clocks.
>> + * Returns a pointer to the hw clock struct, or ERR_PTR value in failure.
>> + */
>> +static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider,
>> +				     u16 dev_id, u8 clk_id)
>> +{
>> +	struct clk_init_data init = { NULL };
>> +	struct sci_clk *sci_clk = NULL;
>> +	char *name = NULL;
>> +	char **parent_names = NULL;
>> +	int i;
>> +	int ret;
>> +
>> +	sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL);
>> +	if (!sci_clk)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	sci_clk->dev_id = dev_id;
>> +	sci_clk->clk_id = clk_id;
>> +	sci_clk->provider = provider;
>> +
>> +	ret = provider->ops->get_num_parents(provider->sci, dev_id,
>> +					     clk_id,
>> +					     &init.num_parents);
>> +	if (ret)
>> +		goto err;
>> +
>> +	name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
>> +			 sci_clk->dev_id, sci_clk->clk_id);
>> +
>> +	init.name = name;
>> +
>> +	if (init.num_parents < 2)
>> +		init.num_parents = 0;
>
> This deserves a comment. Why is num_parents == 1 the same as
> num_parents == 0?

I'll add a comment on this. Basically some clocks can be root clocks 
which don't have parents, and we only want to have parent control for 
clocks that can switch their parent. This is kind of a quirk of the 
firmware.

>
>> +
>> +	if (init.num_parents) {
>> +		parent_names = devm_kcalloc(provider->dev, init.num_parents,
>> +					    sizeof(char *), GFP_KERNEL);
>> +
>> +		if (!parent_names) {
>> +			ret = -ENOMEM;
>> +			goto err;
>> +		}
>> +
>> +		for (i = 0; i < init.num_parents; i++) {
>> +			char *parent_name;
>> +
>> +			parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
>> +						dev_name(provider->dev),
>> +						sci_clk->dev_id,
>> +						sci_clk->clk_id + 1 + i);
>> +			if (!parent_name) {
>> +				ret = -ENOMEM;
>> +				goto err;
>> +			}
>> +			parent_names[i] = parent_name;
>> +		}
>> +		init.parent_names = (const char * const *)parent_names;
>
> Does that really need a cast?

Doesn't seem like so... I think without this it was generating some 
checkpatch issue sometime back, but doesn't seem to be the case anymore.

>
>> +	}
>> +
>> +	init.ops = &sci_clk_ops;
>> +	sci_clk->hw.init = &init;
>> +
>> +	ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
>> +	if (ret) {
>> +		dev_err(provider->dev, "failed clk register with %d\n", ret);
>> +		goto err;
>> +	}
>> +	kfree(name);
>> +
>> +	return &sci_clk->hw;
>> +
>> +err:
>> +	if (parent_names) {
>> +		for (i = 0; i < init.num_parents; i++)
>> +			devm_kfree(provider->dev, parent_names[i]);
>> +
>> +		devm_kfree(provider->dev, parent_names);
>
> Shouldn't we be freeing the parent names all the time? It should
> be deep copied in the framework.

I'll check this.

>
>> +	}
>> +
>> +	devm_kfree(provider->dev, sci_clk);
>> +
>> +	kfree(name);
>> +
>> +	return ERR_PTR(ret);
>> +}
> [..]
>> +
>> +static int ti_sci_init_clocks(struct sci_clk_provider *p)
>> +{
>> +	struct sci_clk_data *data = p->clocks;
>> +	struct clk_hw *hw;
>> +	int i;
>> +
>> +	while (data->num_clks) {
>> +		data->clocks = devm_kcalloc(p->dev, data->num_clks,
>> +					    sizeof(struct sci_clk),
>> +					    GFP_KERNEL);
>> +		if (!data->clocks)
>> +			return -ENOMEM;
>> +
>> +		for (i = 0; i < data->num_clks; i++) {
>> +			hw = _sci_clk_build(p, data->dev, i);
>> +			if (!IS_ERR(hw)) {
>> +				data->clocks[i] = hw;
>> +				continue;
>> +			}
>> +
>> +			/* Skip any holes in the clock lists */
>> +			if (PTR_ERR(hw) == -ENODEV)
>
> Does this happen? I don't see where _sci_clk_build() returns
> -ENODEV.

Yes, it can and will happen. get_num_parents() called by sci_clk_build 
will return ENODEV for device/clock pairs that don't exist.

>
>> +				continue;
>> +
>> +			return PTR_ERR(hw);
>> +		}
>> +		data++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>
>> +
>> +/**
>> + * ti_sci_clk_probe - Probe function for the TI SCI clock driver
>> + * @pdev: platform device pointer to be probed
>> + *
>> + * Probes the TI SCI clock device. Allocates a new clock provider
>> + * and registers this to the common clock framework. Also applies
>> + * any required flags to the identified clocks via clock lists
>> + * supplied from DT. Returns 0 for success, negative error value
>> + * for failure.
>> + */
>> +static int ti_sci_clk_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device_node *np = dev->of_node;
>> +	struct sci_clk_provider *provider;
>> +	const struct ti_sci_handle *handle;
>> +	struct sci_clk_data *data;
>> +	int ret;
>> +
>> +	data = (struct sci_clk_data *)
>> +		of_match_node(ti_sci_clk_of_match, np)->data;
>
> Just use of_device_get_match_data() instead.

All righty.

>
>> +
>> +	handle = devm_ti_sci_get_handle(dev);
>> +	if (IS_ERR(handle))
>> +		return PTR_ERR(handle);
>> +
>> +	provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
>> +	if (!provider)
>> +		return -ENOMEM;
>> +
>> +	provider->clocks = data;
>> +
>> +	provider->sci = handle;
>> +	provider->ops = &handle->ops.clk_ops;
>> +	provider->dev = dev;
>> +
>> +	ti_sci_init_clocks(provider);
>
> And if this fails?

Yea this is kind of controversial. ti_sci_init_clocks() can fail if any 
of the clocks registered will fail. I decided to have it this way so 
that at least some clocks might work in failure cause, and you might 
have a booting device instead of total lock-up.

Obviously it could be done so that if any clock fails, we would 
de-register all clocks at that point, but personally I think this is a 
worse option.

ti_sci_init_clocks could probably be modified to continue registering 
clocks when a single clock fails though. Currently it aborts at first 
failure.

Thoughts on that?

>
>> +
>> +	ret = of_clk_add_hw_provider(np, sci_clk_get, provider);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>
> Just "return of_clk_add_hw_provider()" please.

True that, will fix.

-Tero

  reply	other threads:[~2016-12-08 10:45 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-21 12:45 [PATCH 0/3] clk: keystone: add sci clock support Tero Kristo
2016-10-21 12:45 ` Tero Kristo
2016-10-21 12:45 ` Tero Kristo
2016-10-21 12:45 ` [PATCH 1/3] Documentation: dt: Add TI SCI clock driver Tero Kristo
2016-10-21 12:45   ` Tero Kristo
2016-10-21 12:45   ` Tero Kristo
2016-10-30 20:41   ` Rob Herring
2016-10-30 20:41     ` Rob Herring
2016-10-31 12:50     ` Tero Kristo
2016-10-31 12:50       ` Tero Kristo
2016-10-31 12:50       ` Tero Kristo
2016-10-31 20:34       ` Nishanth Menon
2016-10-31 20:34         ` Nishanth Menon
2016-10-31 20:34         ` Nishanth Menon
2016-11-18 17:20       ` Rob Herring
2016-11-18 17:20         ` Rob Herring
     [not found]         ` <CAL_JsqLtSs6ifnMdEOsfXpGoWnmXuGAx83+ziB9yU+zurvob+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-11-21  8:14           ` Tero Kristo
2016-11-21  8:14             ` Tero Kristo
2016-11-21  8:14             ` Tero Kristo
2016-12-02  8:19             ` Tero Kristo
2016-12-02  8:19               ` Tero Kristo
2016-12-02 18:45               ` Rob Herring
2016-12-02 18:45                 ` Rob Herring
2016-12-02 18:58                 ` Stephen Boyd
2016-12-02 18:58                   ` Stephen Boyd
     [not found]                   ` <5f146fb6-ec88-b7ee-ef5b-a5ad32c54a74-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-12-02 21:07                     ` Tero Kristo
2016-12-02 21:07                       ` Tero Kristo
2016-12-02 21:07                       ` Tero Kristo
2016-10-21 12:46 ` [PATCH 2/3] dt-binding: clock: Add k2g clock definitions Tero Kristo
2016-10-21 12:46   ` Tero Kristo
2016-10-21 12:46   ` Tero Kristo
2017-05-16 15:03   ` Tero Kristo
2017-05-16 15:03     ` Tero Kristo
2016-10-21 12:46 ` [PATCH 3/3] clk: keystone: Add sci-clk driver support Tero Kristo
2016-10-21 12:46   ` Tero Kristo
2016-10-21 12:46   ` Tero Kristo
2016-12-08  0:13   ` Stephen Boyd
2016-12-08  0:13     ` Stephen Boyd
2016-12-08 10:45     ` Tero Kristo [this message]
2016-12-08 10:45       ` Tero Kristo
2016-12-08 10:45       ` Tero Kristo
2016-12-08 21:10       ` Stephen Boyd
2016-12-08 21:10         ` Stephen Boyd
     [not found]         ` <20161208211044.GI5423-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-12-09  8:05           ` Tero Kristo
2016-12-09  8:05             ` Tero Kristo
2016-12-09  8:05             ` Tero Kristo
2016-12-12 19:38             ` Stephen Boyd
2016-12-12 19:38               ` Stephen Boyd
     [not found]               ` <20161212193800.GL5423-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-12-13  9:01                 ` Tero Kristo
2016-12-13  9:01                   ` Tero Kristo
2016-12-13  9:01                   ` Tero Kristo
  -- strict thread matches above, loose matches on Subject: below --
2016-08-20  0:33 [PATCH 0/3] ARM: K2G: Add support for TI-SCI Clocks Nishanth Menon
2016-08-20  0:33 ` [PATCH 3/3] clk: keystone: Add sci-clk driver support Nishanth Menon
2016-08-20  0:33   ` Nishanth Menon
2016-08-20  0:33   ` Nishanth Menon
2016-08-24  8:34   ` Stephen Boyd
2016-08-24  8:34     ` Stephen Boyd
2016-08-24  8:34     ` Stephen Boyd
2016-08-31 18:35     ` Tero Kristo
2016-08-31 18:35       ` Tero Kristo
2016-08-31 18:35       ` Tero Kristo
2016-08-31 22:31       ` Stephen Boyd
2016-08-31 22:31         ` Stephen Boyd
2016-08-31 22:31         ` Stephen Boyd
2016-09-01 12:27         ` Tero Kristo
2016-09-01 12:27           ` Tero Kristo
2016-09-01 12:27           ` Tero Kristo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cb608729-b617-0eab-5ddf-d78ff47b237e@ti.com \
    --to=t-kristo@ti.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=nm@ti.com \
    --cc=sboyd@codeaurora.org \
    --cc=ssantosh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.