mbox series

[v6,0/3] introduce TI reset controller for MT8192 SoC

Message ID 20200930022159.5559-1-crystal.guo@mediatek.com
Headers show
Series introduce TI reset controller for MT8192 SoC | expand

Message

Crystal Guo Sept. 30, 2020, 2:21 a.m. UTC
v6:
fix the format error of mediatek-syscon-reset.yaml

v5:
1. revert ti-syscon-reset.txt, and add a new mediatek reset binding.
2. split the patch [v4, 3/4] with the change to force write and the
change to integrate assert and deassert together.
3. separate the dts patch from this patch sets

v4:
fix typos on v3 commit message.

v3:
1. revert v2 changes.
2. add 'reset-duration-us' property to declare a minimum delay,
which needs to be waited between assert and deassert.
3. add 'mediatek,infra-reset' to compatible.

v2 changes:
https://patchwork.kernel.org/patch/11697371/
1. add 'assert-deassert-together' property to introduce a new reset handler,
which allows device to do serialized assert and deassert operations in a single
step by 'reset' method.
2. add 'update-force' property to introduce force-update method, which forces
the write operation in case the read already happens to return the correct value.
3. add 'generic-reset' to compatible

v1 changes:
https://patchwork.kernel.org/patch/11690523/
https://patchwork.kernel.org/patch/11690527/

Crystal Guo (3):
  dt-binding: reset-controller: mediatek: add YAML schemas
  reset-controller: ti: introduce a new reset handler
  reset-controller: ti: force the write operation when assert or
    deassert

 .../bindings/reset/mediatek-syscon-reset.yaml | 51 +++++++++++++++++++
 drivers/reset/reset-ti-syscon.c               | 44 ++++++++++++++--
 2 files changed, 92 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/reset/mediatek-syscon-reset.yaml

Comments

Ikjoon Jang Nov. 30, 2020, 10:35 a.m. UTC | #1
On Wed, Sep 30, 2020 at 10:21:58AM +0800, Crystal Guo wrote:
> Introduce ti_syscon_reset() to integrate assert and deassert together.
> If some modules need do serialized assert and deassert operations
> to reset itself, reset_control_reset can be called for convenience.
> 
> Such as reset-qcom-aoss.c, it integrates assert and deassert together
> by 'reset' method. MTK Socs also need this method to perform reset.
> 
> Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>

Reviewed-by: Ikjoon Jang <ikjn@chromium.org>

> ---
>  drivers/reset/reset-ti-syscon.c | 40 ++++++++++++++++++++++++++++++++-
>  1 file changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> index a2635c21db7f..5d1f8306cd4f 100644
> --- a/drivers/reset/reset-ti-syscon.c
> +++ b/drivers/reset/reset-ti-syscon.c
> @@ -15,15 +15,22 @@
>   * GNU General Public License for more details.
>   */
>  
> +#include <linux/delay.h>
>  #include <linux/mfd/syscon.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
>  #include <linux/reset-controller.h>
>  
>  #include <dt-bindings/reset/ti-syscon.h>
>  
> +struct mediatek_reset_data {
> +	unsigned char *reset_bits;
> +	unsigned int reset_duration_us;
> +};
> +
>  /**
>   * struct ti_syscon_reset_control - reset control structure
>   * @assert_offset: reset assert control register offset from syscon base
> @@ -56,6 +63,7 @@ struct ti_syscon_reset_data {
>  	struct regmap *regmap;
>  	struct ti_syscon_reset_control *controls;
>  	unsigned int nr_controls;
> +	const struct mediatek_reset_data *reset_data;
>  };
>  
>  #define to_ti_syscon_reset_data(rcdev)	\
> @@ -158,9 +166,29 @@ static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
>  		!(control->flags & STATUS_SET);
>  }
>  
> +static int ti_syscon_reset(struct reset_controller_dev *rcdev,
> +				  unsigned long id)
> +{
> +	struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
> +	int ret;
> +
> +	if (data->reset_data) {
> +		ret = ti_syscon_reset_assert(rcdev, id);
> +		if (ret)
> +			return ret;
> +		usleep_range(data->reset_data->reset_duration_us,
> +			data->reset_data->reset_duration_us * 2);
> +

There are many users using assert() and deassert() seperately
without any delay between them.

If there's a timing requirement between assertion and deassertion,
shouldn't there be a same amount of delay in assert?

> +		return ti_syscon_reset_deassert(rcdev, id);
> +	} else {
> +		return -ENOTSUPP;
> +	}
> +}
> +
>  static const struct reset_control_ops ti_syscon_reset_ops = {
>  	.assert		= ti_syscon_reset_assert,
>  	.deassert	= ti_syscon_reset_deassert,
> +	.reset		= ti_syscon_reset,
>  	.status		= ti_syscon_reset_status,
>  };
>  
> @@ -182,7 +210,11 @@ static int ti_syscon_reset_probe(struct platform_device *pdev)
>  	if (IS_ERR(regmap))
>  		return PTR_ERR(regmap);
>  
> -	list = of_get_property(np, "ti,reset-bits", &size);
> +	data->reset_data = of_device_get_match_data(&pdev->dev);
> +	if (data->reset_data)
> +		list = of_get_property(np, data->reset_data->reset_bits, &size);
> +	else
> +		list = of_get_property(np, "ti,reset-bits", &size);
>  	if (!list || (size / sizeof(*list)) % 7 != 0) {
>  		dev_err(dev, "invalid DT reset description\n");
>  		return -EINVAL;
> @@ -217,8 +249,14 @@ static int ti_syscon_reset_probe(struct platform_device *pdev)
>  	return devm_reset_controller_register(dev, &data->rcdev);
>  }
>  
> +static const struct mediatek_reset_data mtk_reset_data = {
> +	.reset_bits = "mediatek,reset-bits",
> +	.reset_duration_us = 10,
> +};
> +
>  static const struct of_device_id ti_syscon_reset_of_match[] = {
>  	{ .compatible = "ti,syscon-reset", },
> +	{ .compatible = "mediatek,syscon-reset", .data = &mtk_reset_data},
>  	{ /* sentinel */ },
>  };
>  MODULE_DEVICE_TABLE(of, ti_syscon_reset_of_match);
Ikjoon Jang Nov. 30, 2020, 11:13 a.m. UTC | #2
On Wed, Sep 30, 2020 at 10:21:59AM +0800, Crystal Guo wrote:
> Force the write operation in case the read already happens
> to return the correct value.
> 
> Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>
> ---
>  drivers/reset/reset-ti-syscon.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> index 5d1f8306cd4f..c34394f1e9e2 100644
> --- a/drivers/reset/reset-ti-syscon.c
> +++ b/drivers/reset/reset-ti-syscon.c
> @@ -97,7 +97,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
>  	mask = BIT(control->assert_bit);
>  	value = (control->flags & ASSERT_SET) ? mask : 0x0;
>  
> -	return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
> +	return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
>  }

I don't think there are no reset controllers with cached regmap,
thus I don't think this is needed.
Are there any specific reasons behind this, what I've missed here?

We need to be sure that all other devices using this driver
should have no side effects on write.

I can think of a weird controller doing unwanted things internally
on every write disregarding the current state. (or is this overly
paranoid?)

>  
>  /**
> @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
>  	mask = BIT(control->deassert_bit);
>  	value = (control->flags & DEASSERT_SET) ? mask : 0x0;
>  
> -	return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
> +	return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
>  }
>  
>  /**
Crystal Guo Dec. 2, 2020, 11:06 a.m. UTC | #3
On Mon, 2020-11-30 at 19:13 +0800, Ikjoon Jang wrote:
> On Wed, Sep 30, 2020 at 10:21:59AM +0800, Crystal Guo wrote:
> > Force the write operation in case the read already happens
> > to return the correct value.
> > 
> > Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>
> > ---
> >  drivers/reset/reset-ti-syscon.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> > index 5d1f8306cd4f..c34394f1e9e2 100644
> > --- a/drivers/reset/reset-ti-syscon.c
> > +++ b/drivers/reset/reset-ti-syscon.c
> > @@ -97,7 +97,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
> >  	mask = BIT(control->assert_bit);
> >  	value = (control->flags & ASSERT_SET) ? mask : 0x0;
> >  
> > -	return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
> > +	return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
> >  }
> 
> I don't think there are no reset controllers with cached regmap,
> thus I don't think this is needed.
> Are there any specific reasons behind this, what I've missed here?
> 
> We need to be sure that all other devices using this driver
> should have no side effects on write.
> 
> I can think of a weird controller doing unwanted things internally
> on every write disregarding the current state. (or is this overly
> paranoid?)
> 
The specific reason is that, the clear bit may keep the same value with
the set bit, but the clear operation can be only be completed by writing
1 to the clear bit, not just with the current fake state "1".

> >  
> >  /**
> > @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
> >  	mask = BIT(control->deassert_bit);
> >  	value = (control->flags & DEASSERT_SET) ? mask : 0x0;
> >  
> > -	return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
> > +	return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
> >  }
> >  
> >  /**
Ikjoon Jang Dec. 3, 2020, 3:30 a.m. UTC | #4
On Wed, Dec 2, 2020 at 7:07 PM Crystal Guo <crystal.guo@mediatek.com> wrote:
>
> On Mon, 2020-11-30 at 19:13 +0800, Ikjoon Jang wrote:
> > On Wed, Sep 30, 2020 at 10:21:59AM +0800, Crystal Guo wrote:
> > > Force the write operation in case the read already happens
> > > to return the correct value.
> > >
> > > Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>
> > > ---
> > >  drivers/reset/reset-ti-syscon.c | 4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> > > index 5d1f8306cd4f..c34394f1e9e2 100644
> > > --- a/drivers/reset/reset-ti-syscon.c
> > > +++ b/drivers/reset/reset-ti-syscon.c
> > > @@ -97,7 +97,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
> > >     mask = BIT(control->assert_bit);
> > >     value = (control->flags & ASSERT_SET) ? mask : 0x0;
> > >
> > > -   return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
> > > +   return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
> > >  }
> >
> > I don't think there are no reset controllers with cached regmap,
> > thus I don't think this is needed.
> > Are there any specific reasons behind this, what I've missed here?
> >
> > We need to be sure that all other devices using this driver
> > should have no side effects on write.
> >
> > I can think of a weird controller doing unwanted things internally
> > on every write disregarding the current state. (or is this overly
> > paranoid?)
> >
> The specific reason is that, the clear bit may keep the same value with
> the set bit, but the clear operation can be only be completed by writing
> 1 to the clear bit, not just with the current fake state "1".
>

sorry. I didn't think of that case,
then I think this patch must be applied. 8-)

I've thought that the bit automatically flipped to the current reset state
after the internal operation is done.



> > >
> > >  /**
> > > @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
> > >     mask = BIT(control->deassert_bit);
> > >     value = (control->flags & DEASSERT_SET) ? mask : 0x0;
> > >
> > > -   return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
> > > +   return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
> > >  }
> > >
> > >  /**
>
Philipp Zabel Dec. 3, 2020, 7:45 a.m. UTC | #5
On Wed, 2020-09-30 at 10:21 +0800, Crystal Guo wrote:
> Force the write operation in case the read already happens
> to return the correct value.
> 
> Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>
> ---
>  drivers/reset/reset-ti-syscon.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> index 5d1f8306cd4f..c34394f1e9e2 100644
> --- a/drivers/reset/reset-ti-syscon.c
> +++ b/drivers/reset/reset-ti-syscon.c
> @@ -97,7 +97,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
>  	mask = BIT(control->assert_bit);
>  	value = (control->flags & ASSERT_SET) ? mask : 0x0;
>  
> -	return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
> +	return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
>  }
>  
>  /**
> @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
>  	mask = BIT(control->deassert_bit);
>  	value = (control->flags & DEASSERT_SET) ? mask : 0x0;
>  
> -	return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
> +	return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
>  }
>  
>  /**
> -- 
> 2.18.0

Thank you. Since Suman tested v4, this should be safe.
Applied to reset/next.

regards
Philipp
Crystal Guo Dec. 4, 2020, 2:34 a.m. UTC | #6
On Mon, 2020-11-30 at 18:35 +0800, Ikjoon Jang wrote:
> On Wed, Sep 30, 2020 at 10:21:58AM +0800, Crystal Guo wrote:
> > Introduce ti_syscon_reset() to integrate assert and deassert together.
> > If some modules need do serialized assert and deassert operations
> > to reset itself, reset_control_reset can be called for convenience.
> > 
> > Such as reset-qcom-aoss.c, it integrates assert and deassert together
> > by 'reset' method. MTK Socs also need this method to perform reset.
> > 
> > Signed-off-by: Crystal Guo <crystal.guo@mediatek.com>
> 
> Reviewed-by: Ikjoon Jang <ikjn@chromium.org>
> 
> > ---
> >  drivers/reset/reset-ti-syscon.c | 40 ++++++++++++++++++++++++++++++++-
> >  1 file changed, 39 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> > index a2635c21db7f..5d1f8306cd4f 100644
> > --- a/drivers/reset/reset-ti-syscon.c
> > +++ b/drivers/reset/reset-ti-syscon.c
> > @@ -15,15 +15,22 @@
> >   * GNU General Public License for more details.
> >   */
> >  
> > +#include <linux/delay.h>
> >  #include <linux/mfd/syscon.h>
> >  #include <linux/module.h>
> >  #include <linux/of.h>
> > +#include <linux/of_device.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/regmap.h>
> >  #include <linux/reset-controller.h>
> >  
> >  #include <dt-bindings/reset/ti-syscon.h>
> >  
> > +struct mediatek_reset_data {
> > +	unsigned char *reset_bits;
> > +	unsigned int reset_duration_us;
> > +};
> > +
> >  /**
> >   * struct ti_syscon_reset_control - reset control structure
> >   * @assert_offset: reset assert control register offset from syscon base
> > @@ -56,6 +63,7 @@ struct ti_syscon_reset_data {
> >  	struct regmap *regmap;
> >  	struct ti_syscon_reset_control *controls;
> >  	unsigned int nr_controls;
> > +	const struct mediatek_reset_data *reset_data;
> >  };
> >  
> >  #define to_ti_syscon_reset_data(rcdev)	\
> > @@ -158,9 +166,29 @@ static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
> >  		!(control->flags & STATUS_SET);
> >  }
> >  
> > +static int ti_syscon_reset(struct reset_controller_dev *rcdev,
> > +				  unsigned long id)
> > +{
> > +	struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
> > +	int ret;
> > +
> > +	if (data->reset_data) {
> > +		ret = ti_syscon_reset_assert(rcdev, id);
> > +		if (ret)
> > +			return ret;
> > +		usleep_range(data->reset_data->reset_duration_us,
> > +			data->reset_data->reset_duration_us * 2);
> > +
> 
> There are many users using assert() and deassert() seperately
> without any delay between them.
> 
> If there's a timing requirement between assertion and deassertion,
> shouldn't there be a same amount of delay in assert?

The "reset_duration_us" is an optional configuration to make the reset
operation more generic, which was added based on Philipp's comment in
[v2,4/6].

Thanks,
Crystal
> 
> > +		return ti_syscon_reset_deassert(rcdev, id);
> > +	} else {
> > +		return -ENOTSUPP;
> > +	}
> > +}
> > +
> >  static const struct reset_control_ops ti_syscon_reset_ops = {
> >  	.assert		= ti_syscon_reset_assert,
> >  	.deassert	= ti_syscon_reset_deassert,
> > +	.reset		= ti_syscon_reset,
> >  	.status		= ti_syscon_reset_status,
> >  };
> >  
> > @@ -182,7 +210,11 @@ static int ti_syscon_reset_probe(struct platform_device *pdev)
> >  	if (IS_ERR(regmap))
> >  		return PTR_ERR(regmap);
> >  
> > -	list = of_get_property(np, "ti,reset-bits", &size);
> > +	data->reset_data = of_device_get_match_data(&pdev->dev);
> > +	if (data->reset_data)
> > +		list = of_get_property(np, data->reset_data->reset_bits, &size);
> > +	else
> > +		list = of_get_property(np, "ti,reset-bits", &size);
> >  	if (!list || (size / sizeof(*list)) % 7 != 0) {
> >  		dev_err(dev, "invalid DT reset description\n");
> >  		return -EINVAL;
> > @@ -217,8 +249,14 @@ static int ti_syscon_reset_probe(struct platform_device *pdev)
> >  	return devm_reset_controller_register(dev, &data->rcdev);
> >  }
> >  
> > +static const struct mediatek_reset_data mtk_reset_data = {
> > +	.reset_bits = "mediatek,reset-bits",
> > +	.reset_duration_us = 10,
> > +};
> > +
> >  static const struct of_device_id ti_syscon_reset_of_match[] = {
> >  	{ .compatible = "ti,syscon-reset", },
> > +	{ .compatible = "mediatek,syscon-reset", .data = &mtk_reset_data},
> >  	{ /* sentinel */ },
> >  };
> >  MODULE_DEVICE_TABLE(of, ti_syscon_reset_of_match);