2021-06-03 10:09:04

by Jitao Shi

[permalink] [raw]
Subject: [PATCH v4 0/3] fix the clock on/off mismatch and switch pwm api to atomic API

Change since v3:
- Seperate the clock sequence as single patch.
- fixup the reg commit when clocks sequence changed
- Merege the apply and get_state as single patch

Change since v2:
- Change commit messages to remove the clock operations for atomic APIs.
- Rebase to v5.13 rc1

Changes since v1:
- Seperate clock operation as single patch.
- Seperate apply() as single patch.
- Seperate get_state() operation as single patch.

Jitao Shi (3):
pwm: mtk-disp: adjust the clocks to avoid them mismatch
pwm: mtk-disp: move the commit to clock enabled
pwm: mtk-disp: Switch to atomic API

drivers/pwm/pwm-mtk-disp.c | 167 +++++++++++++++++++++----------------
1 file changed, 93 insertions(+), 74 deletions(-)

--
2.25.1


2021-06-03 10:09:17

by Jitao Shi

[permalink] [raw]
Subject: [PATCH v4 2/3] pwm: mtk-disp: move the commit to clock enabled

Due to the clock sequence changing, so move the reg commit to
config().

Signed-off-by: Jitao Shi <[email protected]>
---
drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index b5771e2c54b8..b87b3c00a685 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
mdp->data->commit_mask,
0x0);
+ } else {
+ mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
+ mdp->data->bls_debug_mask,
+ mdp->data->bls_debug_mask);
+ mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+ mdp->data->con0_sel,
+ mdp->data->con0_sel);
}

return 0;
@@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, mdp);

- /*
- * For MT2701, disable double buffer before writing register
- * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
- */
- if (!mdp->data->has_commit) {
- mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
- mdp->data->bls_debug_mask,
- mdp->data->bls_debug_mask);
- mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
- mdp->data->con0_sel,
- mdp->data->con0_sel);
- }
-
return 0;
}

--
2.25.1

2021-06-03 10:09:44

by Jitao Shi

[permalink] [raw]
Subject: [PATCH v4 1/3] pwm: mtk-disp: adjust the clocks to avoid them mismatch

The clk_main and clk_mm clocks are still on when system enter
suspend. That will casue the power consumption.

The clocks call the clk_prepare() in probe(), but the clk_unprepare()
is called in remove(), it isn't called when system suspend.

Remove the clcok opterations from probe() and remove.
Add the clk_prepare_enable() in config().
Add the clk_disable_unprepare() in disable().

Signed-off-by: Jitao Shi <[email protected]>
---
drivers/pwm/pwm-mtk-disp.c | 81 ++++++++++++++++----------------------
1 file changed, 33 insertions(+), 48 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 9b3ba401a3db..b5771e2c54b8 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -47,6 +47,7 @@ struct mtk_disp_pwm {
struct clk *clk_main;
struct clk *clk_mm;
void __iomem *base;
+ bool enabled;
};

static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
@@ -74,6 +75,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 div, rate;
int err;

+ if (!mdp->enabled) {
+ err = clk_prepare_enable(mdp->clk_main);
+ if (err < 0) {
+ dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n",
+ err);
+ return err;
+ }
+ err = clk_prepare_enable(mdp->clk_mm);
+ if (err < 0) {
+ dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n",
+ err);
+ clk_disable_unprepare(mdp->clk_main);
+ return err;
+ }
+ }
+
/*
* Find period, high_width and clk_div to suit duty_ns and period_ns.
* Calculate proper div value to keep period value in the bound.
@@ -87,9 +104,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
rate = clk_get_rate(mdp->clk_main);
clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
PWM_PERIOD_BIT_WIDTH;
- if (clk_div > PWM_CLKDIV_MAX)
+ if (clk_div > PWM_CLKDIV_MAX) {
+ dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
+ rate);
+ if (!mdp->enabled) {
+ clk_disable_unprepare(mdp->clk_mm);
+ clk_disable_unprepare(mdp->clk_main);
+ }
return -EINVAL;
-
+ }
div = NSEC_PER_SEC * (clk_div + 1);
period = div64_u64(rate * period_ns, div);
if (period > 0)
@@ -98,16 +121,6 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
high_width = div64_u64(rate * duty_ns, div);
value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);

- err = clk_enable(mdp->clk_main);
- if (err < 0)
- return err;
-
- err = clk_enable(mdp->clk_mm);
- if (err < 0) {
- clk_disable(mdp->clk_main);
- return err;
- }
-
mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
PWM_CLKDIV_MASK,
clk_div << PWM_CLKDIV_SHIFT);
@@ -124,9 +137,6 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
0x0);
}

- clk_disable(mdp->clk_mm);
- clk_disable(mdp->clk_main);
-
return 0;
}

@@ -135,18 +145,9 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
int err;

- err = clk_enable(mdp->clk_main);
- if (err < 0)
- return err;
-
- err = clk_enable(mdp->clk_mm);
- if (err < 0) {
- clk_disable(mdp->clk_main);
- return err;
- }
-
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
mdp->data->enable_mask);
+ mdp->enabled = true;

return 0;
}
@@ -158,8 +159,11 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
0x0);

- clk_disable(mdp->clk_mm);
- clk_disable(mdp->clk_main);
+ if (mdp->enabled) {
+ clk_disable_unprepare(mdp->clk_mm);
+ clk_disable_unprepare(mdp->clk_main);
+ }
+ mdp->enabled = false;
}

static const struct pwm_ops mtk_disp_pwm_ops = {
@@ -192,14 +196,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
if (IS_ERR(mdp->clk_mm))
return PTR_ERR(mdp->clk_mm);

- ret = clk_prepare(mdp->clk_main);
- if (ret < 0)
- return ret;
-
- ret = clk_prepare(mdp->clk_mm);
- if (ret < 0)
- goto disable_clk_main;
-
mdp->chip.dev = &pdev->dev;
mdp->chip.ops = &mtk_disp_pwm_ops;
mdp->chip.npwm = 1;
@@ -207,7 +203,7 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
ret = pwmchip_add(&mdp->chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
- goto disable_clk_mm;
+ return ret;
}

platform_set_drvdata(pdev, mdp);
@@ -226,24 +222,13 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
}

return 0;
-
-disable_clk_mm:
- clk_unprepare(mdp->clk_mm);
-disable_clk_main:
- clk_unprepare(mdp->clk_main);
- return ret;
}

static int mtk_disp_pwm_remove(struct platform_device *pdev)
{
struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev);
- int ret;
-
- ret = pwmchip_remove(&mdp->chip);
- clk_unprepare(mdp->clk_mm);
- clk_unprepare(mdp->clk_main);

- return ret;
+ return pwmchip_remove(&mdp->chip);
}

static const struct mtk_pwm_data mt2701_pwm_data = {
--
2.25.1

2021-06-03 10:10:04

by Jitao Shi

[permalink] [raw]
Subject: [PATCH v4 3/3] pwm: mtk-disp: Switch to atomic API

Convert the legacy api to atomic API.

Signed-off-by: Jitao Shi <[email protected]>
---
drivers/pwm/pwm-mtk-disp.c | 78 ++++++++++++++++++++++++++++----------
1 file changed, 59 insertions(+), 19 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index b87b3c00a685..d77348d0527c 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -67,8 +67,8 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
writel(value, address);
}

-static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static int mtk_disp_pwm_config(struct pwm_chip *chip,
+ const struct pwm_state *state)
{
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
u32 clk_div, period, high_width, value;
@@ -102,7 +102,7 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
*/
rate = clk_get_rate(mdp->clk_main);
- clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
+ clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >>
PWM_PERIOD_BIT_WIDTH;
if (clk_div > PWM_CLKDIV_MAX) {
dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
@@ -114,11 +114,11 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return -EINVAL;
}
div = NSEC_PER_SEC * (clk_div + 1);
- period = div64_u64(rate * period_ns, div);
+ period = div64_u64(rate * state->period, div);
if (period > 0)
period--;

- high_width = div64_u64(rate * duty_ns, div);
+ high_width = div64_u64(rate * state->duty_cycle, div);
value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);

mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
@@ -144,39 +144,79 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
mdp->data->con0_sel);
}

+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
+ mdp->data->enable_mask);
+ mdp->enabled = true;
+
return 0;
}

-static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
- int err;

- mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
- mdp->data->enable_mask);
- mdp->enabled = true;
+ if (!state->enabled) {
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
+ 0x0);

- return 0;
+ if (mdp->enabled) {
+ clk_disable_unprepare(mdp->clk_mm);
+ clk_disable_unprepare(mdp->clk_main);
+ }
+ mdp->enabled = false;
+ return 0;
+ }
+
+ return mtk_disp_pwm_config(chip, state);
}

-static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+static void mtk_disp_pwm_get_state(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ struct pwm_state *state)
{
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
+ u32 clk_div, period, high_width, con0, con1;
+ u64 rate;
+ int err;

- mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
- 0x0);
+ if (!mdp->enabled) {
+ err = clk_prepare_enable(mdp->clk_main);
+ if (err < 0) {
+ dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n", err);
+ return;
+ }
+ err = clk_prepare_enable(mdp->clk_mm);
+ if (err < 0) {
+ dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n", err);
+ clk_disable_unprepare(mdp->clk_main);
+ return;
+ }
+ }
+
+ rate = clk_get_rate(mdp->clk_main);

- if (mdp->enabled) {
+ con0 = readl(mdp->base + mdp->data->con0);
+ con1 = readl(mdp->base + mdp->data->con1);
+
+ state->enabled = !!(con0 & BIT(0));
+
+ clk_div = (con0 & PWM_CLKDIV_MASK) >> PWM_CLKDIV_SHIFT;
+ period = con1 & PWM_PERIOD_MASK;
+ state->period = div_u64(period * (clk_div + 1) * NSEC_PER_SEC, rate);
+ high_width = (con1 & PWM_HIGH_WIDTH_MASK) >> PWM_HIGH_WIDTH_SHIFT;
+ state->duty_cycle = div_u64(high_width * (clk_div + 1) * NSEC_PER_SEC,
+ rate);
+
+ if (!mdp->enabled) {
clk_disable_unprepare(mdp->clk_mm);
clk_disable_unprepare(mdp->clk_main);
}
- mdp->enabled = false;
}

static const struct pwm_ops mtk_disp_pwm_ops = {
- .config = mtk_disp_pwm_config,
- .enable = mtk_disp_pwm_enable,
- .disable = mtk_disp_pwm_disable,
+ .apply = mtk_disp_pwm_apply,
+ .get_state = mtk_disp_pwm_get_state,
.owner = THIS_MODULE,
};

--
2.25.1

2021-06-06 21:15:50

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] pwm: mtk-disp: adjust the clocks to avoid them mismatch

Hello,

you missed to address Lee and me for your patch series. I just happend
to stumble over this series by a fluke.

On Thu, Jun 03, 2021 at 06:05:29PM +0800, Jitao Shi wrote:
> The clk_main and clk_mm clocks are still on when system enter
> suspend. That will casue the power consumption.
>
> The clocks call the clk_prepare() in probe(), but the clk_unprepare()
> is called in remove(), it isn't called when system suspend.

The English could be improved here. Something like:

The clks "main" and "mm" are prepared in .probe() (and
unprepared in .remove()). This results in the clocks being on
during suspend which results in unnecessarily increased power
consumption.

> Remove the clcok opterations from probe() and remove.

s/clcok/clock/, s/e\./e()/

> Add the clk_prepare_enable() in config().
> Add the clk_disable_unprepare() in disable().
>
> Signed-off-by: Jitao Shi <[email protected]>
> ---
> drivers/pwm/pwm-mtk-disp.c | 81 ++++++++++++++++----------------------
> 1 file changed, 33 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> index 9b3ba401a3db..b5771e2c54b8 100644
> --- a/drivers/pwm/pwm-mtk-disp.c
> +++ b/drivers/pwm/pwm-mtk-disp.c
> @@ -47,6 +47,7 @@ struct mtk_disp_pwm {
> struct clk *clk_main;
> struct clk *clk_mm;
> void __iomem *base;
> + bool enabled;
> };
>
> static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
> @@ -74,6 +75,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> u64 div, rate;
> int err;
>
> + if (!mdp->enabled) {
> + err = clk_prepare_enable(mdp->clk_main);
> + if (err < 0) {
> + dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n",
> + err);
> + return err;

Please use %pe to get symbolic error names which are better
understandable.

> + }
> + err = clk_prepare_enable(mdp->clk_mm);
> + if (err < 0) {
> + dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n",
> + err);
> + clk_disable_unprepare(mdp->clk_main);
> + return err;
> + }
> + }
> +
> /*
> * Find period, high_width and clk_div to suit duty_ns and period_ns.
> * Calculate proper div value to keep period value in the bound.
> @@ -87,9 +104,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> rate = clk_get_rate(mdp->clk_main);
> clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
> PWM_PERIOD_BIT_WIDTH;
> - if (clk_div > PWM_CLKDIV_MAX)
> + if (clk_div > PWM_CLKDIV_MAX) {
> + dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
> + rate);

Adding an error message here is orthogonal to this patch. Either drop it
or mention it in the commit log please.

> + if (!mdp->enabled) {
> + clk_disable_unprepare(mdp->clk_mm);
> + clk_disable_unprepare(mdp->clk_main);
> + }
> return -EINVAL;
> -
> + }
> div = NSEC_PER_SEC * (clk_div + 1);
> period = div64_u64(rate * period_ns, div);
> if (period > 0)
> [...]
> @@ -135,18 +145,9 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> int err;
>
> - err = clk_enable(mdp->clk_main);
> - if (err < 0)
> - return err;
> -
> - err = clk_enable(mdp->clk_mm);
> - if (err < 0) {
> - clk_disable(mdp->clk_main);
> - return err;
> - }
> -
> mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> mdp->data->enable_mask);
> + mdp->enabled = true;

The modification to .enable() looks wrong. After the PWM was disabled
the clocks are off, so .enable() must reenable them, doesn't it?

> return 0;
> }

Best regards
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | https://www.pengutronix.de/ |


Attachments:
(No filename) (3.83 kB)
signature.asc (499.00 B)
Download all attachments

2021-06-06 21:17:51

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] pwm: mtk-disp: move the commit to clock enabled

On Thu, Jun 03, 2021 at 06:05:30PM +0800, Jitao Shi wrote:
> Due to the clock sequence changing, so move the reg commit to

Which change do you refer to, here? The previous patch? If so, I assume
this means the series is not bisectable because the driver is broken
when only the first patch is applied?

> config().
>
> Signed-off-by: Jitao Shi <[email protected]>
> ---
> drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
> 1 file changed, 7 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> index b5771e2c54b8..b87b3c00a685 100644
> --- a/drivers/pwm/pwm-mtk-disp.c
> +++ b/drivers/pwm/pwm-mtk-disp.c
> @@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
> mdp->data->commit_mask,
> 0x0);
> + } else {

You dropped the code comment? Is it wrong? Or is it too obvious to be
mentioned?

> + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
> + mdp->data->bls_debug_mask,
> + mdp->data->bls_debug_mask);
> + mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> + mdp->data->con0_sel,
> + mdp->data->con0_sel);
> }
>
> return 0;
> @@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, mdp);
>
> - /*
> - * For MT2701, disable double buffer before writing register
> - * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
> - */
> - if (!mdp->data->has_commit) {
> - mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
> - mdp->data->bls_debug_mask,
> - mdp->data->bls_debug_mask);
> - mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> - mdp->data->con0_sel,
> - mdp->data->con0_sel);
> - }
> -
> return 0;
> }

Best regards
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | https://www.pengutronix.de/ |


Attachments:
(No filename) (2.00 kB)
signature.asc (499.00 B)
Download all attachments

2021-06-06 21:24:26

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [PATCH v4 3/3] pwm: mtk-disp: Switch to atomic API

Hello,

On Thu, Jun 03, 2021 at 06:05:31PM +0800, Jitao Shi wrote:
> Convert the legacy api to atomic API.
>
> Signed-off-by: Jitao Shi <[email protected]>
> ---
> drivers/pwm/pwm-mtk-disp.c | 78 ++++++++++++++++++++++++++++----------
> 1 file changed, 59 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> index b87b3c00a685..d77348d0527c 100644
> --- a/drivers/pwm/pwm-mtk-disp.c
> +++ b/drivers/pwm/pwm-mtk-disp.c
> @@ -67,8 +67,8 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
> writel(value, address);
> }
>
> -static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> - int duty_ns, int period_ns)
> +static int mtk_disp_pwm_config(struct pwm_chip *chip,
> + const struct pwm_state *state)
> {
> struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> u32 clk_div, period, high_width, value;
> @@ -102,7 +102,7 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
> */
> rate = clk_get_rate(mdp->clk_main);
> - clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
> + clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >>
> PWM_PERIOD_BIT_WIDTH;
> if (clk_div > PWM_CLKDIV_MAX) {
> dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
> @@ -114,11 +114,11 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> return -EINVAL;
> }
> div = NSEC_PER_SEC * (clk_div + 1);
> - period = div64_u64(rate * period_ns, div);
> + period = div64_u64(rate * state->period, div);
> if (period > 0)
> period--;
>
> - high_width = div64_u64(rate * duty_ns, div);
> + high_width = div64_u64(rate * state->duty_cycle, div);
> value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
>
> mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> @@ -144,39 +144,79 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> mdp->data->con0_sel);
> }
>
> + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> + mdp->data->enable_mask);
> + mdp->enabled = true;
> +
> return 0;
> }
>
> -static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> +static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> + const struct pwm_state *state)
> {
> struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> - int err;
>
> - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> - mdp->data->enable_mask);
> - mdp->enabled = true;
> + if (!state->enabled) {
> + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> + 0x0);
>
> - return 0;
> + if (mdp->enabled) {
> + clk_disable_unprepare(mdp->clk_mm);
> + clk_disable_unprepare(mdp->clk_main);
> + }
> + mdp->enabled = false;
> + return 0;
> + }
> +
> + return mtk_disp_pwm_config(chip, state);

Please unroll this function call. Having the old name is irritating.

> }
>
> -static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
> +static void mtk_disp_pwm_get_state(struct pwm_chip *chip,
> + struct pwm_device *pwm,
> + struct pwm_state *state)

Adding .get_state() is great and warrants a separate patch.

> {
> struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> + u32 clk_div, period, high_width, con0, con1;
> + u64 rate;
> + int err;
>
> - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> - 0x0);
> + if (!mdp->enabled) {
> + err = clk_prepare_enable(mdp->clk_main);
> + if (err < 0) {
> + dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n", err);
> + return;
> + }
> + err = clk_prepare_enable(mdp->clk_mm);
> + if (err < 0) {
> + dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n", err);
> + clk_disable_unprepare(mdp->clk_main);
> + return;
> + }
> + }
> +
> + rate = clk_get_rate(mdp->clk_main);
>
> - if (mdp->enabled) {
> + con0 = readl(mdp->base + mdp->data->con0);
> + con1 = readl(mdp->base + mdp->data->con1);
> +
> + state->enabled = !!(con0 & BIT(0));
> +
> + clk_div = (con0 & PWM_CLKDIV_MASK) >> PWM_CLKDIV_SHIFT;

clk_div = FIELD_GET(PWM_CLKDIV_MASK, con0);

> + period = con1 & PWM_PERIOD_MASK;
> + state->period = div_u64(period * (clk_div + 1) * NSEC_PER_SEC, rate);

Can this multiplication overflow? Note this is a 32bit multiplication
only. As .apply() uses round-down in the divisions (which is good)
please round up there to get idempotency between .get_state() and
.apply().

> + high_width = (con1 & PWM_HIGH_WIDTH_MASK) >> PWM_HIGH_WIDTH_SHIFT;
> + state->duty_cycle = div_u64(high_width * (clk_div + 1) * NSEC_PER_SEC,
> + rate);
> +
> + if (!mdp->enabled) {
> clk_disable_unprepare(mdp->clk_mm);
> clk_disable_unprepare(mdp->clk_main);
> }
> - mdp->enabled = false;
> }

If my review comments contain too little details for you to understand,
please feel free to ask. I'm willing to explain in more detail.

Best regards
Uwe

--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | https://www.pengutronix.de/ |


Attachments:
(No filename) (5.25 kB)
signature.asc (499.00 B)
Download all attachments

2021-06-11 02:31:08

by Jitao Shi

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] pwm: mtk-disp: move the commit to clock enabled

On Sun, 2021-06-06 at 23:14 +0200, Uwe Kleine-König wrote:
> On Thu, Jun 03, 2021 at 06:05:30PM +0800, Jitao Shi wrote:
> > Due to the clock sequence changing, so move the reg commit to
>
> Which change do you refer to, here? The previous patch? If so, I assume
> this means the series is not bisectable because the driver is broken
> when only the first patch is applied?
>
Yes, this patch is depend the previous patch.
I'll squash it to the previous patch in next version.


> > config().
> >
> > Signed-off-by: Jitao Shi <[email protected]>
> > ---
> > drivers/pwm/pwm-mtk-disp.c | 20 +++++++-------------
> > 1 file changed, 7 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> > index b5771e2c54b8..b87b3c00a685 100644
> > --- a/drivers/pwm/pwm-mtk-disp.c
> > +++ b/drivers/pwm/pwm-mtk-disp.c
> > @@ -135,6 +135,13 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
> > mdp->data->commit_mask,
> > 0x0);
> > + } else {
>
> You dropped the code comment? Is it wrong? Or is it too obvious to be
> mentioned?
>

I'll fix them next verison.

> > + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
> > + mdp->data->bls_debug_mask,
> > + mdp->data->bls_debug_mask);
> > + mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> > + mdp->data->con0_sel,
> > + mdp->data->con0_sel);
> > }
> >
> > return 0;
> > @@ -208,19 +215,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
> >
> > platform_set_drvdata(pdev, mdp);
> >
> > - /*
> > - * For MT2701, disable double buffer before writing register
> > - * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
> > - */
> > - if (!mdp->data->has_commit) {
> > - mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
> > - mdp->data->bls_debug_mask,
> > - mdp->data->bls_debug_mask);
> > - mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> > - mdp->data->con0_sel,
> > - mdp->data->con0_sel);
> > - }
> > -
> > return 0;
> > }
>
> Best regards
> Uwe
>

Best Regards
Jitao

2021-06-11 02:41:42

by Jitao Shi

[permalink] [raw]
Subject: Re: [PATCH v4 3/3] pwm: mtk-disp: Switch to atomic API

On Sun, 2021-06-06 at 23:22 +0200, Uwe Kleine-König wrote:
> Hello,
>
> On Thu, Jun 03, 2021 at 06:05:31PM +0800, Jitao Shi wrote:
> > Convert the legacy api to atomic API.
> >
> > Signed-off-by: Jitao Shi <[email protected]>
> > ---
> > drivers/pwm/pwm-mtk-disp.c | 78 ++++++++++++++++++++++++++++----------
> > 1 file changed, 59 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
> > index b87b3c00a685..d77348d0527c 100644
> > --- a/drivers/pwm/pwm-mtk-disp.c
> > +++ b/drivers/pwm/pwm-mtk-disp.c
> > @@ -67,8 +67,8 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
> > writel(value, address);
> > }
> >
> > -static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > - int duty_ns, int period_ns)
> > +static int mtk_disp_pwm_config(struct pwm_chip *chip,
> > + const struct pwm_state *state)
> > {
> > struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> > u32 clk_div, period, high_width, value;
> > @@ -102,7 +102,7 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
> > */
> > rate = clk_get_rate(mdp->clk_main);
> > - clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
> > + clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >>
> > PWM_PERIOD_BIT_WIDTH;
> > if (clk_div > PWM_CLKDIV_MAX) {
> > dev_err(chip->dev, "clock rate is too high: rate = %d Hz\n",
> > @@ -114,11 +114,11 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > return -EINVAL;
> > }
> > div = NSEC_PER_SEC * (clk_div + 1);
> > - period = div64_u64(rate * period_ns, div);
> > + period = div64_u64(rate * state->period, div);
> > if (period > 0)
> > period--;
> >
> > - high_width = div64_u64(rate * duty_ns, div);
> > + high_width = div64_u64(rate * state->duty_cycle, div);
> > value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
> >
> > mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
> > @@ -144,39 +144,79 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > mdp->data->con0_sel);
> > }
> >
> > + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> > + mdp->data->enable_mask);
> > + mdp->enabled = true;
> > +
> > return 0;
> > }
> >
> > -static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> > +static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> > + const struct pwm_state *state)
> > {
> > struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> > - int err;
> >
> > - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> > - mdp->data->enable_mask);
> > - mdp->enabled = true;
> > + if (!state->enabled) {
> > + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> > + 0x0);
> >
> > - return 0;
> > + if (mdp->enabled) {
> > + clk_disable_unprepare(mdp->clk_mm);
> > + clk_disable_unprepare(mdp->clk_main);
> > + }
> > + mdp->enabled = false;
> > + return 0;
> > + }
> > +
> > + return mtk_disp_pwm_config(chip, state);
>
> Please unroll this function call. Having the old name is irritating.

I'll fix it next version.

Thanks for your review.
>
> > }
> >
> > -static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
> > +static void mtk_disp_pwm_get_state(struct pwm_chip *chip,
> > + struct pwm_device *pwm,
> > + struct pwm_state *state)
>
> Adding .get_state() is great and warrants a separate patch.
>
I'll separate .get_state() next version.

Thanks for your review.

> > {
> > struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
> > + u32 clk_div, period, high_width, con0, con1;
> > + u64 rate;
> > + int err;
> >
> > - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
> > - 0x0);
> > + if (!mdp->enabled) {
> > + err = clk_prepare_enable(mdp->clk_main);
> > + if (err < 0) {
> > + dev_err(chip->dev, "Can't enable mdp->clk_main: %d\n", err);
> > + return;
> > + }
> > + err = clk_prepare_enable(mdp->clk_mm);
> > + if (err < 0) {
> > + dev_err(chip->dev, "Can't enable mdp->clk_mm: %d\n", err);
> > + clk_disable_unprepare(mdp->clk_main);
> > + return;
> > + }
> > + }
> > +
> > + rate = clk_get_rate(mdp->clk_main);
> >
> > - if (mdp->enabled) {
> > + con0 = readl(mdp->base + mdp->data->con0);
> > + con1 = readl(mdp->base + mdp->data->con1);
> > +
> > + state->enabled = !!(con0 & BIT(0));
> > +
> > + clk_div = (con0 & PWM_CLKDIV_MASK) >> PWM_CLKDIV_SHIFT;
>
> clk_div = FIELD_GET(PWM_CLKDIV_MASK, con0);

I'll fix it next version.


>
> > + period = con1 & PWM_PERIOD_MASK;
> > + state->period = div_u64(period * (clk_div + 1) * NSEC_PER_SEC, rate);
>
> Can this multiplication overflow? Note this is a 32bit multiplication
> only. As .apply() uses round-down in the divisions (which is good)
> please round up there to get idempotency between .get_state() and
> .apply().
>

I'll fix it next version.


> > + high_width = (con1 & PWM_HIGH_WIDTH_MASK) >> PWM_HIGH_WIDTH_SHIFT;
> > + state->duty_cycle = div_u64(high_width * (clk_div + 1) * NSEC_PER_SEC,
> > + rate);
> > +
> > + if (!mdp->enabled) {
> > clk_disable_unprepare(mdp->clk_mm);
> > clk_disable_unprepare(mdp->clk_main);
> > }
> > - mdp->enabled = false;
> > }
>
> If my review comments contain too little details for you to understand,
> please feel free to ask. I'm willing to explain in more detail.
>
> Best regards
> Uwe
>

Thanks for your review.

Best Regards
Jitao