linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] pwm: atmel: Add link to reference manual
@ 2019-08-15 21:41 Uwe Kleine-König
  2019-08-15 21:41 ` [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value Uwe Kleine-König
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-15 21:41 UTC (permalink / raw)
  To: Claudiu Beznea, Thierry Reding
  Cc: linux-pwm, Alexandre Belloni, Ludovic Desroches, linux-arm-kernel

The reference manual for at least one of the supported variants is
publicly available. Add a link to it at the top of the driver.

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 drivers/pwm/pwm-atmel.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index e5e1eaf372fa..ac3d7a200b9e 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -4,6 +4,9 @@
  *
  * Copyright (C) 2013 Atmel Corporation
  *		 Bo Shen <voice.shen@atmel.com>
+ *
+ * Reference manual for "atmel,at91sam9rl-pwm":
+ *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
  */
 
 #include <linux/clk.h>
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value
  2019-08-15 21:41 [PATCH 1/3] pwm: atmel: Add link to reference manual Uwe Kleine-König
@ 2019-08-15 21:41 ` Uwe Kleine-König
  2019-08-19  9:27   ` Claudiu.Beznea
  2019-08-15 21:41 ` [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation Uwe Kleine-König
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-15 21:41 UTC (permalink / raw)
  To: Claudiu Beznea, Thierry Reding
  Cc: linux-pwm, Alexandre Belloni, Ludovic Desroches, linux-arm-kernel

The maximal prescale value is 10 for all supported variants. So drop the
member in the variant description and introduce a global constant instead.

This reduces the size of the variant descriptions and the .apply() callback
can be compiled a bit more effectively.

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 drivers/pwm/pwm-atmel.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index ac3d7a200b9e..d7a6d32b5774 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -50,6 +50,8 @@
 #define PWMV2_CPRD		0x0C
 #define PWMV2_CPRDUPD		0x10
 
+#define PWM_MAX_PRES		10
+
 struct atmel_pwm_registers {
 	u8 period;
 	u8 period_upd;
@@ -59,7 +61,6 @@ struct atmel_pwm_registers {
 
 struct atmel_pwm_config {
 	u32 max_period;
-	u32 max_pres;
 };
 
 struct atmel_pwm_data {
@@ -126,7 +127,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
 	for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
 		(*pres)++;
 
-	if (*pres > atmel_pwm->data->cfg.max_pres) {
+	if (*pres > PWM_MAX_PRES) {
 		dev_err(chip->dev, "pres exceeds the maximum value\n");
 		return -EINVAL;
 	}
@@ -289,7 +290,6 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
 	.cfg = {
 		/* 16 bits to keep period and duty. */
 		.max_period	= 0xffff,
-		.max_pres	= 10,
 	},
 };
 
@@ -303,7 +303,6 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
 	.cfg = {
 		/* 16 bits to keep period and duty. */
 		.max_period	= 0xffff,
-		.max_pres	= 10,
 	},
 };
 
@@ -317,7 +316,6 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
 	.cfg = {
 		/* 32 bits to keep period and duty. */
 		.max_period	= 0xffffffff,
-		.max_pres	= 10,
 	},
 };
 
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation
  2019-08-15 21:41 [PATCH 1/3] pwm: atmel: Add link to reference manual Uwe Kleine-König
  2019-08-15 21:41 ` [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value Uwe Kleine-König
@ 2019-08-15 21:41 ` Uwe Kleine-König
  2019-08-19  9:27   ` Claudiu.Beznea
  2019-08-16  9:37 ` [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software Uwe Kleine-König
  2019-08-19  9:26 ` [PATCH 1/3] pwm: atmel: Add link to reference manual Claudiu.Beznea
  3 siblings, 1 reply; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-15 21:41 UTC (permalink / raw)
  To: Claudiu Beznea, Thierry Reding
  Cc: linux-pwm, Alexandre Belloni, Ludovic Desroches, linux-arm-kernel

The calculated values are the same with the modified algorithm. The only
difference is that the calculation is a bit more efficient.

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 drivers/pwm/pwm-atmel.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index d7a6d32b5774..42fe7bc043a8 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -60,7 +60,7 @@ struct atmel_pwm_registers {
 };
 
 struct atmel_pwm_config {
-	u32 max_period;
+	u32 period_bits;
 };
 
 struct atmel_pwm_data {
@@ -119,17 +119,27 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
 {
 	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
 	unsigned long long cycles = state->period;
+	int shift;
 
 	/* Calculate the period cycles and prescale value */
 	cycles *= clk_get_rate(atmel_pwm->clk);
 	do_div(cycles, NSEC_PER_SEC);
 
-	for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
-		(*pres)++;
+	/*
+	 * The register for the period length is cfg.period_bits bits wide.
+	 * So for each bit the number of clock cycles is wider divide the input
+	 * clock frequency by two using pres and shift cprd accordingly.
+	 */
+	shift = fls(cycles) - atmel_pwm->data->cfg.period_bits;
 
-	if (*pres > PWM_MAX_PRES) {
+	if (shift > PWM_MAX_PRES) {
 		dev_err(chip->dev, "pres exceeds the maximum value\n");
 		return -EINVAL;
+	} else if (shift > 0) {
+		*pres = shift;
+		cycles >>= *pres;
+	} else {
+		*pres = 0;
 	}
 
 	*cprd = cycles;
@@ -289,7 +299,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
 	},
 	.cfg = {
 		/* 16 bits to keep period and duty. */
-		.max_period	= 0xffff,
+		.period_bits	= 16,
 	},
 };
 
@@ -302,7 +312,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
 	},
 	.cfg = {
 		/* 16 bits to keep period and duty. */
-		.max_period	= 0xffff,
+		.period_bits	= 16,
 	},
 };
 
@@ -315,7 +325,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
 	},
 	.cfg = {
 		/* 32 bits to keep period and duty. */
-		.max_period	= 0xffffffff,
+		.period_bits	= 32,
 	},
 };
 
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-15 21:41 [PATCH 1/3] pwm: atmel: Add link to reference manual Uwe Kleine-König
  2019-08-15 21:41 ` [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value Uwe Kleine-König
  2019-08-15 21:41 ` [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation Uwe Kleine-König
@ 2019-08-16  9:37 ` Uwe Kleine-König
  2019-08-16 20:43   ` Alexandre Belloni
  2019-08-19  9:26   ` Claudiu.Beznea
  2019-08-19  9:26 ` [PATCH 1/3] pwm: atmel: Add link to reference manual Claudiu.Beznea
  3 siblings, 2 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-16  9:37 UTC (permalink / raw)
  To: Claudiu Beznea, Thierry Reding
  Cc: linux-pwm, Alexandre Belloni, Ludovic Desroches, linux-arm-kernel

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 drivers/pwm/pwm-atmel.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 42fe7bc043a8..1ddb93db9627 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -7,6 +7,16 @@
  *
  * Reference manual for "atmel,at91sam9rl-pwm":
  *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
+ *
+ * Limitations:
+ * - Periods start with the inactive level.
+ * - Hardware has to be stopped in general to update settings.
+ *
+ * Software bugs/possible improvements:
+ * - When atmel_pwm_apply() is called with state->enabled=false a change in
+ *   state->polarity isn't honored.
+ * - Instead of sleeping to wait for a completed period, the interrupt
+ *   functionality could be used.
  */
 
 #include <linux/clk.h>
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-16  9:37 ` [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software Uwe Kleine-König
@ 2019-08-16 20:43   ` Alexandre Belloni
  2019-08-19  8:10     ` Uwe Kleine-König
  2019-08-19  9:26   ` Claudiu.Beznea
  1 sibling, 1 reply; 14+ messages in thread
From: Alexandre Belloni @ 2019-08-16 20:43 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, Ludovic Desroches, Thierry Reding, Claudiu Beznea,
	linux-arm-kernel

On 16/08/2019 11:37:48+0200, Uwe Kleine-König wrote:
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> ---
>  drivers/pwm/pwm-atmel.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> index 42fe7bc043a8..1ddb93db9627 100644
> --- a/drivers/pwm/pwm-atmel.c
> +++ b/drivers/pwm/pwm-atmel.c
> @@ -7,6 +7,16 @@
>   *
>   * Reference manual for "atmel,at91sam9rl-pwm":
>   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
> + *
> + * Limitations:
> + * - Periods start with the inactive level.
> + * - Hardware has to be stopped in general to update settings.
> + *
> + * Software bugs/possible improvements:
> + * - When atmel_pwm_apply() is called with state->enabled=false a change in
> + *   state->polarity isn't honored.
> + * - Instead of sleeping to wait for a completed period, the interrupt
> + *   functionality could be used.

This is definitively not trivial to do right. The main reason it is not
done so is that reading PWM_ISR will clear all the bits so it is
necessary to be very careful to avoid race conditions. I'm not sure it
is worth the effort.


-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-16 20:43   ` Alexandre Belloni
@ 2019-08-19  8:10     ` Uwe Kleine-König
  0 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-19  8:10 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: linux-pwm, Ludovic Desroches, Thierry Reding, Claudiu Beznea,
	linux-arm-kernel


[-- Attachment #1.1.1: Type: text/plain, Size: 1775 bytes --]

Hello Alexandre,

On 8/16/19 10:43 PM, Alexandre Belloni wrote:
> On 16/08/2019 11:37:48+0200, Uwe Kleine-König wrote:
>> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
>> ---
>>  drivers/pwm/pwm-atmel.c | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
>> index 42fe7bc043a8..1ddb93db9627 100644
>> --- a/drivers/pwm/pwm-atmel.c
>> +++ b/drivers/pwm/pwm-atmel.c
>> @@ -7,6 +7,16 @@
>>   *
>>   * Reference manual for "atmel,at91sam9rl-pwm":
>>   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
>> + *
>> + * Limitations:
>> + * - Periods start with the inactive level.
>> + * - Hardware has to be stopped in general to update settings.
>> + *
>> + * Software bugs/possible improvements:
>> + * - When atmel_pwm_apply() is called with state->enabled=false a change in
>> + *   state->polarity isn't honored.
>> + * - Instead of sleeping to wait for a completed period, the interrupt
>> + *   functionality could be used.
> 
> This is definitively not trivial to do right. The main reason it is not
> done so is that reading PWM_ISR will clear all the bits so it is
> necessary to be very careful to avoid race conditions. I'm not sure it
> is worth the effort.

I didn't intend to claim it is easy or even that it should be
implemented. This was just what I noticed while reading through driver
and manual. I thought it was a good idea to document that in case
someone finds time and motivation to work on this driver.

The first issue pointed out should however be easy to fix and IMHO is a
real bug. (Though it's a corner case that hardly ever triggers.)

Best regards
Uwe


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-16  9:37 ` [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software Uwe Kleine-König
  2019-08-16 20:43   ` Alexandre Belloni
@ 2019-08-19  9:26   ` Claudiu.Beznea
  2019-08-19 10:46     ` Uwe Kleine-König
  1 sibling, 1 reply; 14+ messages in thread
From: Claudiu.Beznea @ 2019-08-19  9:26 UTC (permalink / raw)
  To: uwe, thierry.reding
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, linux-arm-kernel



On 16.08.2019 12:37, Uwe Kleine-König wrote:
> External E-Mail
> 
> 
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> ---
>  drivers/pwm/pwm-atmel.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> index 42fe7bc043a8..1ddb93db9627 100644
> --- a/drivers/pwm/pwm-atmel.c
> +++ b/drivers/pwm/pwm-atmel.c
> @@ -7,6 +7,16 @@
>   *
>   * Reference manual for "atmel,at91sam9rl-pwm":
>   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
> + *
> + * Limitations:
> + * - Periods start with the inactive level.

Are you talking here about the normal polarity (from documentation: By
definition, normal polarity characterizes a signal starts high for the
duration of the duty cycle and goes low for the remainder of the period.)

If yes, this should be solved by playing with CPOL bit of CMR.

> + * - Hardware has to be stopped in general to update settings.

Sama5d2 has duty cycle that could be updated on the fly.

> + *
> + * Software bugs/possible improvements:
> + * - When atmel_pwm_apply() is called with state->enabled=false a change in
> + *   state->polarity isn't honored.

I know that when configuring a PWM one should get the current state of the
PWM, change it, then pass it to the driver via pwm_apply_state(). In case
one would call the pwm_apply_state() with state->enabled = false the state
would be stored in PWM specific object (of type struct pwm_device). On the
next apply, with enabled = true, all the PWM parameters would be actually
applied to hardware. So, until enable=true the PWM state would only be
cached by PWM core specific objects (in pwm_apply_state()).

> + * - Instead of sleeping to wait for a completed period, the interrupt
> + *   functionality could be used.
>   */
>  
>  #include <linux/clk.h>
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] pwm: atmel: Add link to reference manual
  2019-08-15 21:41 [PATCH 1/3] pwm: atmel: Add link to reference manual Uwe Kleine-König
                   ` (2 preceding siblings ...)
  2019-08-16  9:37 ` [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software Uwe Kleine-König
@ 2019-08-19  9:26 ` Claudiu.Beznea
  2019-08-19  9:46   ` Nicolas.Ferre
  3 siblings, 1 reply; 14+ messages in thread
From: Claudiu.Beznea @ 2019-08-19  9:26 UTC (permalink / raw)
  To: uwe, thierry.reding
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, linux-arm-kernel



On 16.08.2019 00:41, Uwe Kleine-König wrote:
> The reference manual for at least one of the supported variants is
> publicly available. Add a link to it at the top of the driver.
> 
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> ---
>  drivers/pwm/pwm-atmel.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> index e5e1eaf372fa..ac3d7a200b9e 100644
> --- a/drivers/pwm/pwm-atmel.c
> +++ b/drivers/pwm/pwm-atmel.c
> @@ -4,6 +4,9 @@
>   *
>   * Copyright (C) 2013 Atmel Corporation
>   *		 Bo Shen <voice.shen@atmel.com>
> + *
> + * Reference manual for "atmel,at91sam9rl-pwm":
> + *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf

Even SAM9G25 PWM have almost the same registers with AT91SAM9RL, the
datasheet for AT91SAM9RL is located at:
http://ww1.microchip.com/downloads/en/DeviceDoc/doc6289.pdf
Maybe we should use this one.

I'm not familiar with having reference manuals in this part of the driver
but if we are doing so would it be feasible to also have links for the rest
SoCs that introduces new PWM versions? I'm thinking here at all the
compatibles from atmel_pwm_dt_ids[]:
- atmel,sama5d3-pwm
- atmel,sama5d2-pwm
- microchip,sam9x60-pwm

Although the last one is not already public.

>   */
>  
>  #include <linux/clk.h>
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value
  2019-08-15 21:41 ` [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value Uwe Kleine-König
@ 2019-08-19  9:27   ` Claudiu.Beznea
  0 siblings, 0 replies; 14+ messages in thread
From: Claudiu.Beznea @ 2019-08-19  9:27 UTC (permalink / raw)
  To: uwe, thierry.reding
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, linux-arm-kernel



On 16.08.2019 00:41, Uwe Kleine-König wrote:
> External E-Mail
> 
> 
> The maximal prescale value is 10 for all supported variants. So drop the
> member in the variant description and introduce a global constant instead.
> 
> This reduces the size of the variant descriptions and the .apply() callback
> can be compiled a bit more effectively.
> 
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>

Acked-by: Claudiu Beznea <claudiu.beznea@microchip.com>

Tested on SAMA5D2_Xplained.

> ---
>  drivers/pwm/pwm-atmel.c | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> index ac3d7a200b9e..d7a6d32b5774 100644
> --- a/drivers/pwm/pwm-atmel.c
> +++ b/drivers/pwm/pwm-atmel.c
> @@ -50,6 +50,8 @@
>  #define PWMV2_CPRD		0x0C
>  #define PWMV2_CPRDUPD		0x10
>  
> +#define PWM_MAX_PRES		10
> +
>  struct atmel_pwm_registers {
>  	u8 period;
>  	u8 period_upd;
> @@ -59,7 +61,6 @@ struct atmel_pwm_registers {
>  
>  struct atmel_pwm_config {
>  	u32 max_period;
> -	u32 max_pres;
>  };
>  
>  struct atmel_pwm_data {
> @@ -126,7 +127,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
>  	for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
>  		(*pres)++;
>  
> -	if (*pres > atmel_pwm->data->cfg.max_pres) {
> +	if (*pres > PWM_MAX_PRES) {
>  		dev_err(chip->dev, "pres exceeds the maximum value\n");
>  		return -EINVAL;
>  	}
> @@ -289,7 +290,6 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
>  	.cfg = {
>  		/* 16 bits to keep period and duty. */
>  		.max_period	= 0xffff,
> -		.max_pres	= 10,
>  	},
>  };
>  
> @@ -303,7 +303,6 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
>  	.cfg = {
>  		/* 16 bits to keep period and duty. */
>  		.max_period	= 0xffff,
> -		.max_pres	= 10,
>  	},
>  };
>  
> @@ -317,7 +316,6 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
>  	.cfg = {
>  		/* 32 bits to keep period and duty. */
>  		.max_period	= 0xffffffff,
> -		.max_pres	= 10,
>  	},
>  };
>  
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation
  2019-08-15 21:41 ` [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation Uwe Kleine-König
@ 2019-08-19  9:27   ` Claudiu.Beznea
  0 siblings, 0 replies; 14+ messages in thread
From: Claudiu.Beznea @ 2019-08-19  9:27 UTC (permalink / raw)
  To: uwe, thierry.reding
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, linux-arm-kernel



On 16.08.2019 00:41, Uwe Kleine-König wrote:
> External E-Mail
> 
> 
> The calculated values are the same with the modified algorithm. The only
> difference is that the calculation is a bit more efficient.
> 
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>

Acked-by: Claudiu Beznea <claudiu.beznea@microchip.com>

Tested on SAMA5D2_Xplained.

> ---
>  drivers/pwm/pwm-atmel.c | 24 +++++++++++++++++-------
>  1 file changed, 17 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> index d7a6d32b5774..42fe7bc043a8 100644
> --- a/drivers/pwm/pwm-atmel.c
> +++ b/drivers/pwm/pwm-atmel.c
> @@ -60,7 +60,7 @@ struct atmel_pwm_registers {
>  };
>  
>  struct atmel_pwm_config {
> -	u32 max_period;
> +	u32 period_bits;
>  };
>  
>  struct atmel_pwm_data {
> @@ -119,17 +119,27 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
>  {
>  	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
>  	unsigned long long cycles = state->period;
> +	int shift;
>  
>  	/* Calculate the period cycles and prescale value */
>  	cycles *= clk_get_rate(atmel_pwm->clk);
>  	do_div(cycles, NSEC_PER_SEC);
>  
> -	for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
> -		(*pres)++;
> +	/*
> +	 * The register for the period length is cfg.period_bits bits wide.
> +	 * So for each bit the number of clock cycles is wider divide the input
> +	 * clock frequency by two using pres and shift cprd accordingly.
> +	 */
> +	shift = fls(cycles) - atmel_pwm->data->cfg.period_bits;
>  
> -	if (*pres > PWM_MAX_PRES) {
> +	if (shift > PWM_MAX_PRES) {
>  		dev_err(chip->dev, "pres exceeds the maximum value\n");
>  		return -EINVAL;
> +	} else if (shift > 0) {
> +		*pres = shift;
> +		cycles >>= *pres;
> +	} else {
> +		*pres = 0;
>  	}
>  
>  	*cprd = cycles;
> @@ -289,7 +299,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
>  	},
>  	.cfg = {
>  		/* 16 bits to keep period and duty. */
> -		.max_period	= 0xffff,
> +		.period_bits	= 16,
>  	},
>  };
>  
> @@ -302,7 +312,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
>  	},
>  	.cfg = {
>  		/* 16 bits to keep period and duty. */
> -		.max_period	= 0xffff,
> +		.period_bits	= 16,
>  	},
>  };
>  
> @@ -315,7 +325,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
>  	},
>  	.cfg = {
>  		/* 32 bits to keep period and duty. */
> -		.max_period	= 0xffffffff,
> +		.period_bits	= 32,
>  	},
>  };
>  
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] pwm: atmel: Add link to reference manual
  2019-08-19  9:26 ` [PATCH 1/3] pwm: atmel: Add link to reference manual Claudiu.Beznea
@ 2019-08-19  9:46   ` Nicolas.Ferre
  0 siblings, 0 replies; 14+ messages in thread
From: Nicolas.Ferre @ 2019-08-19  9:46 UTC (permalink / raw)
  To: Claudiu.Beznea, uwe, thierry.reding
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, linux-arm-kernel

On 19/08/2019 at 11:26, Claudiu Beznea - M18063 wrote:
> 
> 
> On 16.08.2019 00:41, Uwe Kleine-König wrote:
>> The reference manual for at least one of the supported variants is
>> publicly available. Add a link to it at the top of the driver.
>>
>> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
>> ---
>>   drivers/pwm/pwm-atmel.c | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
>> index e5e1eaf372fa..ac3d7a200b9e 100644
>> --- a/drivers/pwm/pwm-atmel.c
>> +++ b/drivers/pwm/pwm-atmel.c
>> @@ -4,6 +4,9 @@
>>    *
>>    * Copyright (C) 2013 Atmel Corporation
>>    *		 Bo Shen <voice.shen@atmel.com>
>> + *
>> + * Reference manual for "atmel,at91sam9rl-pwm":
>> + *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
> 
> Even SAM9G25 PWM have almost the same registers with AT91SAM9RL, the
> datasheet for AT91SAM9RL is located at:
> http://ww1.microchip.com/downloads/en/DeviceDoc/doc6289.pdf
> Maybe we should use this one.
> 
> I'm not familiar with having reference manuals in this part of the driver
> but if we are doing so would it be feasible to also have links for the rest
> SoCs that introduces new PWM versions? I'm thinking here at all the
> compatibles from atmel_pwm_dt_ids[]:
> - atmel,sama5d3-pwm
> - atmel,sama5d2-pwm

These documents are listed here:
Documentation/arm/microchip.rst
and must be maintained if URL are out of date. I don't believe that we 
should add another reference to them in this driver (and other source code).
Referring to the datasheet pointed out by the microchip.rst file is 
certainly the way to go...

Regards,
   Nicolas


> - microchip,sam9x60-pwm
> 
> Although the last one is not already public.
> 
>>    */
>>   
>>   #include <linux/clk.h>
>>


-- 
Nicolas Ferre
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-19  9:26   ` Claudiu.Beznea
@ 2019-08-19 10:46     ` Uwe Kleine-König
  2019-08-19 12:28       ` Claudiu.Beznea
  0 siblings, 1 reply; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-19 10:46 UTC (permalink / raw)
  To: Claudiu.Beznea
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, thierry.reding,
	linux-arm-kernel

On Mon, Aug 19, 2019 at 09:26:04AM +0000, Claudiu.Beznea@microchip.com wrote:
> 
> 
> On 16.08.2019 12:37, Uwe Kleine-König wrote:
> > External E-Mail
> > 
> > 
> > Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> > ---
> >  drivers/pwm/pwm-atmel.c | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> > 
> > diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> > index 42fe7bc043a8..1ddb93db9627 100644
> > --- a/drivers/pwm/pwm-atmel.c
> > +++ b/drivers/pwm/pwm-atmel.c
> > @@ -7,6 +7,16 @@
> >   *
> >   * Reference manual for "atmel,at91sam9rl-pwm":
> >   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
> > + *
> > + * Limitations:
> > + * - Periods start with the inactive level.
> 
> Are you talking here about the normal polarity (from documentation: By
> definition, normal polarity characterizes a signal starts high for the
> duration of the duty cycle and goes low for the remainder of the period.)

When .polarity = PWM_POLARITY_NORMAL is passed to atmel_pwm_apply() the
drivers sets PWM_CMR_CPOL=0 which according to the datasheet (linked
above) means: "The output waveform starts at a low level."

So maybe just the logic has to be inverted there, but then maybe the
output gets active instead of inactive when the PWM is disabled.
(Which in my book is ok, but it's Thierry's opinion that counts here.)

> If yes, this should be solved by playing with CPOL bit of CMR.
> 
> > + * - Hardware has to be stopped in general to update settings.
> 
> Sama5d2 has duty cycle that could be updated on the fly.

There is some functionality in the 9G25, too. I didn't understand it
completely but maybe it only helps updating one of period or duty cycle.
 
> > + *
> > + * Software bugs/possible improvements:
> > + * - When atmel_pwm_apply() is called with state->enabled=false a change in
> > + *   state->polarity isn't honored.
> 
> I know that when configuring a PWM one should get the current state of the
> PWM, change it, then pass it to the driver via pwm_apply_state().

That seems to be a common pattern at least. IMHO letting the consumer
just configure the state that should be used should be fine, too.

> In case one would call the pwm_apply_state() with state->enabled =
> false the state would be stored in PWM specific object (of type struct
> pwm_device). On the next apply, with enabled = true, all the PWM
> parameters would be actually applied to hardware. So, until
> enable=true the PWM state would only be cached by PWM core specific
> objects (in pwm_apply_state()).

I fail to follow what you mean here. If a PWM runs with (say) normal
polarity and you call pwm_apply_state(mypwm, { .polarity =
PWM_POLARITY_INVERSED, .enabled = false, }); the apply callback of the
lowlevel driver is called and supposed to configure the output to yield
a constant high.

> > + * - Instead of sleeping to wait for a completed period, the interrupt
> > + *   functionality could be used.
> >   */
> >  
> >  #include <linux/clk.h>
> > 

Best regards
Uwe

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

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-19 10:46     ` Uwe Kleine-König
@ 2019-08-19 12:28       ` Claudiu.Beznea
  2019-08-19 15:20         ` Uwe Kleine-König
  0 siblings, 1 reply; 14+ messages in thread
From: Claudiu.Beznea @ 2019-08-19 12:28 UTC (permalink / raw)
  To: u.kleine-koenig
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, thierry.reding,
	linux-arm-kernel



On 19.08.2019 13:46, Uwe Kleine-König wrote:
> External E-Mail
> 
> 
> On Mon, Aug 19, 2019 at 09:26:04AM +0000, Claudiu.Beznea@microchip.com wrote:
>>
>>
>> On 16.08.2019 12:37, Uwe Kleine-König wrote:
>>> External E-Mail
>>>
>>>
>>> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
>>> ---
>>>  drivers/pwm/pwm-atmel.c | 10 ++++++++++
>>>  1 file changed, 10 insertions(+)
>>>
>>> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
>>> index 42fe7bc043a8..1ddb93db9627 100644
>>> --- a/drivers/pwm/pwm-atmel.c
>>> +++ b/drivers/pwm/pwm-atmel.c
>>> @@ -7,6 +7,16 @@
>>>   *
>>>   * Reference manual for "atmel,at91sam9rl-pwm":
>>>   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
>>> + *
>>> + * Limitations:
>>> + * - Periods start with the inactive level.
>>
>> Are you talking here about the normal polarity (from documentation: By
>> definition, normal polarity characterizes a signal starts high for the
>> duration of the duty cycle and goes low for the remainder of the period.)
> 
> When .polarity = PWM_POLARITY_NORMAL is passed to atmel_pwm_apply() the
> drivers sets PWM_CMR_CPOL=0 which according to the datasheet (linked
> above) means: "The output waveform starts at a low level."
> 
> So maybe just the logic has to be inverted there,

Agree.

> but then maybe the
> output gets active instead of inactive when the PWM is disabled.

Yes, this would happen. Playing again with CPOL when disabling may be a
solution.

> (Which in my book is ok, but it's Thierry's opinion that counts here.)
> 
>> If yes, this should be solved by playing with CPOL bit of CMR.
>>
>>> + * - Hardware has to be stopped in general to update settings.
>>
>> Sama5d2 has duty cycle that could be updated on the fly.
> 
> There is some functionality in the 9G25, too. I didn't understand it
> completely but maybe it only helps updating one of period or duty cycle.
>  
>>> + *
>>> + * Software bugs/possible improvements:
>>> + * - When atmel_pwm_apply() is called with state->enabled=false a change in
>>> + *   state->polarity isn't honored.
>>
>> I know that when configuring a PWM one should get the current state of the
>> PWM, change it, then pass it to the driver via pwm_apply_state().
> 
> That seems to be a common pattern at least. IMHO letting the consumer
> just configure the state that should be used should be fine, too.>
>> In case one would call the pwm_apply_state() with state->enabled =
>> false the state would be stored in PWM specific object (of type struct
>> pwm_device). On the next apply, with enabled = true, all the PWM
>> parameters would be actually applied to hardware. So, until
>> enable=true the PWM state would only be cached by PWM core specific
>> objects (in pwm_apply_state()).
> 
> I fail to follow what you mean here. If a PWM runs with (say) normal
> polarity and you call pwm_apply_state(mypwm, { .polarity =
> PWM_POLARITY_INVERSED, .enabled = false, }); the apply callback of the
> lowlevel driver is called and supposed to configure the output to yield
> a constant high.

Ok, I see it now. I'll put it on my queue.

Thank you,
Claudiu Beznea

> 
>>> + * - Instead of sleeping to wait for a completed period, the interrupt
>>> + *   functionality could be used.
>>>   */
>>>  
>>>  #include <linux/clk.h>
>>>
> 
> Best regards
> Uwe
> 
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software
  2019-08-19 12:28       ` Claudiu.Beznea
@ 2019-08-19 15:20         ` Uwe Kleine-König
  0 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2019-08-19 15:20 UTC (permalink / raw)
  To: Claudiu.Beznea
  Cc: linux-pwm, alexandre.belloni, Ludovic.Desroches, thierry.reding,
	linux-arm-kernel

Hello Claudiu,

On Mon, Aug 19, 2019 at 12:28:59PM +0000, Claudiu.Beznea@microchip.com wrote:
> On 19.08.2019 13:46, Uwe Kleine-König wrote:
> > On Mon, Aug 19, 2019 at 09:26:04AM +0000, Claudiu.Beznea@microchip.com wrote:
> >> On 16.08.2019 12:37, Uwe Kleine-König wrote:
> >>> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> >>> ---
> >>>  drivers/pwm/pwm-atmel.c | 10 ++++++++++
> >>>  1 file changed, 10 insertions(+)
> >>>
> >>> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
> >>> index 42fe7bc043a8..1ddb93db9627 100644
> >>> --- a/drivers/pwm/pwm-atmel.c
> >>> +++ b/drivers/pwm/pwm-atmel.c
> >>> @@ -7,6 +7,16 @@
> >>>   *
> >>>   * Reference manual for "atmel,at91sam9rl-pwm":
> >>>   *   http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11032-32-bit-ARM926EJ-S-Microcontroller-SAM9G25_Datasheet.pdf
> >>> + *
> >>> + * Limitations:
> >>> + * - Periods start with the inactive level.
> >>
> >> Are you talking here about the normal polarity (from documentation: By
> >> definition, normal polarity characterizes a signal starts high for the
> >> duration of the duty cycle and goes low for the remainder of the period.)
> > 
> > When .polarity = PWM_POLARITY_NORMAL is passed to atmel_pwm_apply() the
> > drivers sets PWM_CMR_CPOL=0 which according to the datasheet (linked
> > above) means: "The output waveform starts at a low level."
> > 
> > So maybe just the logic has to be inverted there,
> 
> Agree.
> 
> > but then maybe the
> > output gets active instead of inactive when the PWM is disabled.
> 
> Yes, this would happen. Playing again with CPOL when disabling may be a
> solution.

Alternatively you could argue that it would be more sensible to drop the
requirement for a certain output level on disable. You would have my
support here.

> > (Which in my book is ok, but it's Thierry's opinion that counts here.)
> > 
> >> If yes, this should be solved by playing with CPOL bit of CMR.
> >>
> >>> + * - Hardware has to be stopped in general to update settings.
> >>
> >> Sama5d2 has duty cycle that could be updated on the fly.
> > 
> > There is some functionality in the 9G25, too. I didn't understand it
> > completely but maybe it only helps updating one of period or duty cycle.
> >  
> >>> + *
> >>> + * Software bugs/possible improvements:
> >>> + * - When atmel_pwm_apply() is called with state->enabled=false a change in
> >>> + *   state->polarity isn't honored.
> >>
> >> I know that when configuring a PWM one should get the current state of the
> >> PWM, change it, then pass it to the driver via pwm_apply_state().
> > 
> > That seems to be a common pattern at least. IMHO letting the consumer
> > just configure the state that should be used should be fine, too.>
> >> In case one would call the pwm_apply_state() with state->enabled =
> >> false the state would be stored in PWM specific object (of type struct
> >> pwm_device). On the next apply, with enabled = true, all the PWM
> >> parameters would be actually applied to hardware. So, until
> >> enable=true the PWM state would only be cached by PWM core specific
> >> objects (in pwm_apply_state()).
> > 
> > I fail to follow what you mean here. If a PWM runs with (say) normal
> > polarity and you call pwm_apply_state(mypwm, { .polarity =
> > PWM_POLARITY_INVERSED, .enabled = false, }); the apply callback of the
> > lowlevel driver is called and supposed to configure the output to yield
> > a constant high.
> 
> Ok, I see it now. I'll put it on my queue.

See above. The atmel driver is just part of my quest to get a general
picture what the common PWM implementation does. Thierry argued that it
is natural that a PWM drives the inactive level on disable.

I'd say that it would be more natural to not demand a certain level
because a) IMHO there are enough implementations that differ here and b)
consumers could just configure for duty_cycle=0 if they care.

In the case of the imx driver we could just put aside the discussions
about how we atomically switch the output to a GPIO to provide the
needed level. In case of the atmel driver you'd just invert polarity and
be done.

Best regards
Uwe

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

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2019-08-19 15:20 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-15 21:41 [PATCH 1/3] pwm: atmel: Add link to reference manual Uwe Kleine-König
2019-08-15 21:41 ` [PATCH 2/3] pwm: atmel: use a constant for maximum prescale value Uwe Kleine-König
2019-08-19  9:27   ` Claudiu.Beznea
2019-08-15 21:41 ` [PATCH 3/3] pwm: atmel: replace loop in prescale calculation by ad-hoc calculation Uwe Kleine-König
2019-08-19  9:27   ` Claudiu.Beznea
2019-08-16  9:37 ` [PATCH 4/3] pwm: atmel: document known weaknesses of both hardware and software Uwe Kleine-König
2019-08-16 20:43   ` Alexandre Belloni
2019-08-19  8:10     ` Uwe Kleine-König
2019-08-19  9:26   ` Claudiu.Beznea
2019-08-19 10:46     ` Uwe Kleine-König
2019-08-19 12:28       ` Claudiu.Beznea
2019-08-19 15:20         ` Uwe Kleine-König
2019-08-19  9:26 ` [PATCH 1/3] pwm: atmel: Add link to reference manual Claudiu.Beznea
2019-08-19  9:46   ` Nicolas.Ferre

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).