diff mbox

HACK: fpga: cyclone-ps-spi: adapt to Arria 10 specifics

Message ID 20170413152916.19896-2-bst@pengutronix.de (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Bastian Krause April 13, 2017, 3:29 p.m. UTC
---
 drivers/fpga/cyclone-ps-spi.c | 51 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 5 deletions(-)

Comments

Anatolij Gustschin May 17, 2017, 8:15 a.m. UTC | #1
Hi Bastian,

I'm merging this patch to prepare v10 patch with cyclone_ps_spi driver,
but have some questions, please see below.

On Thu, 13 Apr 2017 17:29:16 +0200
Bastian Stender bst@pengutronix.de wrote:
...
>@@ -117,12 +134,29 @@ static int cyclonespi_write_complete(struct fpga_manager *mgr,
> 				     struct fpga_image_info *info)
> {
> 	struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
>+	const char dummy[] = {0, 0};
>+	int ret;
> 
> 	if (gpiod_get_value(conf->status)) {
> 		dev_err(&mgr->dev, "Error during configuration.\n");
> 		return -EIO;
> 	}
> 
>+	if (gpiod_get_value(conf->confd)) {
>+		dev_err(&mgr->dev, "CONF_DONE is high!\n");
>+		return -EIO;
>+	}

isn't CONF_DONE high pin state expected here? Below comment also sounds
like it is expected. But you return here when confd gpio is high?

>+	/*
>+	 * After CONF_DONE goes high, send two additional falling edges on DCLK
>+	 * to begin initialization and enter user mode
>+	 */
>+	ret = spi_write(conf->spi, dummy, 2);

isn't sending one byte enough here? Two falling edges with single
byte transfer.

...
>@@ -149,6 +183,13 @@ static int cyclonespi_probe(struct spi_device *spi)
> 		return PTR_ERR(conf->config);
> 	}
> 
>+	conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN);
>+	if (IS_ERR(conf->confd)) {
>+		dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
>+		PTR_ERR(conf->confd));
>+		return PTR_ERR(conf->confd);

there are designs with CONF_DONE not connected, so this should be
optional, like in the binding description. I'll drop this return.

Thanks,

Anatolij
--
To unsubscribe from this list: send the line "unsubscribe linux-fpga" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bastian Krause May 17, 2017, 9:41 a.m. UTC | #2
Hi Anatolij,

On 05/17/2017 10:15 AM, Anatolij Gustschin wrote:
> I'm merging this patch to prepare v10 patch with cyclone_ps_spi driver,
> but have some questions, please see below.

Nice.

> On Thu, 13 Apr 2017 17:29:16 +0200
> Bastian Stender bst@pengutronix.de wrote:
> ...
>> @@ -117,12 +134,29 @@ static int cyclonespi_write_complete(struct fpga_manager *mgr,
>> 				     struct fpga_image_info *info)
>> {
>> 	struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
>> +	const char dummy[] = {0, 0};
>> +	int ret;
>>
>> 	if (gpiod_get_value(conf->status)) {
>> 		dev_err(&mgr->dev, "Error during configuration.\n");
>> 		return -EIO;
>> 	}
>>
>> +	if (gpiod_get_value(conf->confd)) {
>> +		dev_err(&mgr->dev, "CONF_DONE is high!\n");
>> +		return -EIO;
>> +	}
>
> isn't CONF_DONE high pin state expected here? Below comment also sounds
> like it is expected. But you return here when confd gpio is high?

With the corresponding device tree entry it is working as expected:

&spi1 {
         ..
         fpga: arria@0 {
                 compatible = "altr,fpga-passive-serial";
                 confd-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
                 ..
         };
};

>> +	/*
>> +	 * After CONF_DONE goes high, send two additional falling edges on DCLK
>> +	 * to begin initialization and enter user mode
>> +	 */
>> +	ret = spi_write(conf->spi, dummy, 2);
>
> isn't sending one byte enough here? Two falling edges with single
> byte transfer.

Yes, sending one byte is sufficient.

>
> ...
>> @@ -149,6 +183,13 @@ static int cyclonespi_probe(struct spi_device *spi)
>> 		return PTR_ERR(conf->config);
>> 	}
>>
>> +	conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN);
>> +	if (IS_ERR(conf->confd)) {
>> +		dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
>> +		PTR_ERR(conf->confd));
>> +		return PTR_ERR(conf->confd);
>
> there are designs with CONF_DONE not connected, so this should be
> optional, like in the binding description. I'll drop this return.

Right.

Thank you.

Regards,
Bastian
Uwe Kleine-König May 17, 2017, 10:19 a.m. UTC | #3
On Wed, May 17, 2017 at 11:41:08AM +0200, Bastian Stender wrote:
> Hi Anatolij,
> 
> On 05/17/2017 10:15 AM, Anatolij Gustschin wrote:
> > I'm merging this patch to prepare v10 patch with cyclone_ps_spi driver,
> > but have some questions, please see below.
> 
> Nice.
> 
> > On Thu, 13 Apr 2017 17:29:16 +0200
> > Bastian Stender bst@pengutronix.de wrote:
> > ...
> > > @@ -117,12 +134,29 @@ static int cyclonespi_write_complete(struct fpga_manager *mgr,
> > > 				     struct fpga_image_info *info)
> > > {
> > > 	struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
> > > +	const char dummy[] = {0, 0};
> > > +	int ret;
> > > 
> > > 	if (gpiod_get_value(conf->status)) {
> > > 		dev_err(&mgr->dev, "Error during configuration.\n");
> > > 		return -EIO;
> > > 	}
> > > 
> > > +	if (gpiod_get_value(conf->confd)) {
> > > +		dev_err(&mgr->dev, "CONF_DONE is high!\n");
> > > +		return -EIO;
> > > +	}
> > 
> > isn't CONF_DONE high pin state expected here? Below comment also sounds
> > like it is expected. But you return here when confd gpio is high?
> 
> With the corresponding device tree entry it is working as expected:
> 
> &spi1 {
>         ..
>         fpga: arria@0 {
>                 compatible = "altr,fpga-passive-serial";
>                 confd-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
>                 ..
>         };
> };
> 
> > > +	/*
> > > +	 * After CONF_DONE goes high, send two additional falling edges on DCLK
> > > +	 * to begin initialization and enter user mode
> > > +	 */
> > > +	ret = spi_write(conf->spi, dummy, 2);
> > 
> > isn't sending one byte enough here? Two falling edges with single
> > byte transfer.
> 
> Yes, sending one byte is sufficient.

In the meantime Bastian is more into that topic, but IIRC completely
removing that dummy write also worked for me.

Best regards
Uwe
Anatolij Gustschin May 17, 2017, 11:24 a.m. UTC | #4
On Wed, 17 May 2017 11:41:08 +0200
Bastian Stender bst@pengutronix.de wrote:
...
>>> +	if (gpiod_get_value(conf->confd)) {
>>> +		dev_err(&mgr->dev, "CONF_DONE is high!\n");
>>> +		return -EIO;
>>> +	}  
>>
>> isn't CONF_DONE high pin state expected here? Below comment also sounds
>> like it is expected. But you return here when confd gpio is high?  
>
>With the corresponding device tree entry it is working as expected:
>
>&spi1 {
>         ..
>         fpga: arria@0 {
>                 compatible = "altr,fpga-passive-serial";
>                 confd-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
>                 ..
>         };
>};

Ah, okay. Then it makes sense to use gpiod_get_raw_value() here.
Other devices trees might be using active high flag.

Thanks,

Anatolij
--
To unsubscribe from this list: send the line "unsubscribe linux-fpga" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König May 17, 2017, 2:40 p.m. UTC | #5
On Wed, May 17, 2017 at 01:24:50PM +0200, Anatolij Gustschin wrote:
> On Wed, 17 May 2017 11:41:08 +0200
> Bastian Stender bst@pengutronix.de wrote:
> ...
> >>> +	if (gpiod_get_value(conf->confd)) {
> >>> +		dev_err(&mgr->dev, "CONF_DONE is high!\n");
> >>> +		return -EIO;
> >>> +	}  
> >>
> >> isn't CONF_DONE high pin state expected here? Below comment also sounds
> >> like it is expected. But you return here when confd gpio is high?  
> >
> >With the corresponding device tree entry it is working as expected:
> >
> >&spi1 {
> >         ..
> >         fpga: arria@0 {
> >                 compatible = "altr,fpga-passive-serial";
> >                 confd-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
> >                 ..
> >         };
> >};
> 
> Ah, okay. Then it makes sense to use gpiod_get_raw_value() here.
> Other devices trees might be using active high flag.

Other device trees might be using active high because the signal is
inverted between the FPGA and the gpio controller.

So the argument is to use gpiod_get_value because others might want the
gpio to be active high. There are many drivers out there that got this
wrong and now we have to live with kludges because of this.

Using gpiod_get_value has only one downside: If the device tree is wrong
your device doesn't work. But that's sort of expected ...

Best regards
Uwe
Anatolij Gustschin May 18, 2017, 1:36 p.m. UTC | #6
On Wed, 17 May 2017 16:40:35 +0200
Uwe Kleine-König u.kleine-koenig@pengutronix.de wrote:
...
>> >&spi1 {
>> >         ..
>> >         fpga: arria@0 {
>> >                 compatible = "altr,fpga-passive-serial";
>> >                 confd-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
>> >                 ..
>> >         };
>> >};  
>> 
>> Ah, okay. Then it makes sense to use gpiod_get_raw_value() here.
>> Other devices trees might be using active high flag.  
>
>Other device trees might be using active high because the signal is
>inverted between the FPGA and the gpio controller.

CONF_DONE signal is active high, so I would expect device trees
to describe it as GPIO_ACTIVE_HIGH, unless an inverter is used.
Invertor users should set GPIO_ACTIVE_LOW.

>So the argument is to use gpiod_get_value because others might want the
>gpio to be active high. There are many drivers out there that got this
>wrong and now we have to live with kludges because of this.
>
>Using gpiod_get_value has only one downside: If the device tree is wrong
>your device doesn't work. But that's sort of expected ...

then, with the correct device tree the driver code should be:

	if (!gpiod_get_value(conf->confd)) {
		dev_err(&mgr->dev, "CONF_DONE is low!\n");
		return -EIO;
	}

This will work for users with and without a CONF_DONE invertor.

Thanks,

Anatolij
--
To unsubscribe from this list: send the line "unsubscribe linux-fpga" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König May 18, 2017, 1:55 p.m. UTC | #7
Hello,

On Thu, May 18, 2017 at 03:36:52PM +0200, Anatolij Gustschin wrote:
> then, with the correct device tree the driver code should be:
> 
> 	if (!gpiod_get_value(conf->confd)) {
> 		dev_err(&mgr->dev, "CONF_DONE is low!\n");
> 		return -EIO;
> 	}
> 
> This will work for users with and without a CONF_DONE invertor.

IMHO "inactive" is better than "low".

Best regards
Uwe
Joshua Clayton May 18, 2017, 8:44 p.m. UTC | #8
On Thursday, May 18, 2017 3:55:39 PM PDT Uwe Kleine-König wrote:
> Hello,
> 
> On Thu, May 18, 2017 at 03:36:52PM +0200, Anatolij Gustschin wrote:
> > then, with the correct device tree the driver code should be:
> > 	if (!gpiod_get_value(conf->confd)) {
> > 	
> > 		dev_err(&mgr->dev, "CONF_DONE is low!\n");
> > 		return -EIO;
> > 	
> > 	}
> > 
> > This will work for users with and without a CONF_DONE invertor.
> 
> IMHO "inactive" is better than "low".
> 
> Best regards
> Uwe

Agreed. Since gpiod deals with "logical" 1 and 0, it is better to call out its 
meaning.
diff mbox

Patch

diff --git a/drivers/fpga/cyclone-ps-spi.c b/drivers/fpga/cyclone-ps-spi.c
index 56c385347bb7..175370d27404 100644
--- a/drivers/fpga/cyclone-ps-spi.c
+++ b/drivers/fpga/cyclone-ps-spi.c
@@ -22,12 +22,12 @@ 
 #include <linux/spi/spi.h>
 #include <linux/sizes.h>
 
-#define FPGA_RESET_TIME		50   /* time in usecs to trigger FPGA config */
-#define FPGA_MIN_DELAY		50   /* min usecs to wait for config status */
-#define FPGA_MAX_DELAY		1000 /* max usecs to wait for config status */
+#define FPGA_MIN_DELAY		268  /* min usecs to wait for config status -> min(t_STATUS) */
+#define FPGA_MAX_DELAY		3000 /* max usecs to wait for config status -> max(t_STATUS) */
 
 struct cyclonespi_conf {
 	struct gpio_desc *config;
+	struct gpio_desc *confd;
 	struct gpio_desc *status;
 	struct spi_device *spi;
 };
@@ -48,6 +48,15 @@  static enum fpga_mgr_states cyclonespi_state(struct fpga_manager *mgr)
 	return FPGA_MGR_STATE_UNKNOWN;
 }
 
+/*          |   Arria 10  |
+ * t_CF2ST0 |     [; 600] | ns
+ * t_CFG    |        [2;] | µs
+ * t_STATUS | [268; 3000] | µs
+ * t_CF2ST1 |    [; 3000] | µs
+ * t_CF2CK  |  [3010 µs;] | µs
+ * t_ST2CK  |       [10;] | µs
+ * t_CD2UM  |  [175; 830] | µs
+ */
 static int cyclonespi_write_init(struct fpga_manager *mgr,
 				 struct fpga_image_info *info,
 				 const char *buf, size_t count)
@@ -61,17 +70,25 @@  static int cyclonespi_write_init(struct fpga_manager *mgr,
 	}
 
 	gpiod_set_value(conf->config, 1);
-	usleep_range(FPGA_RESET_TIME, FPGA_RESET_TIME + 20);
+	/* max { min(t_CFG), max(tCF2ST0) } */
+	udelay(2);
 	if (!gpiod_get_value(conf->status)) {
 		dev_err(&mgr->dev, "Status pin failed to show a reset\n");
 		return -EIO;
 	}
 
 	gpiod_set_value(conf->config, 0);
+
+	/* wait for max { max(t_STATUS), max(t_CF2ST1) } */
 	for (i = 0; i < (FPGA_MAX_DELAY / FPGA_MIN_DELAY); i++) {
 		usleep_range(FPGA_MIN_DELAY, FPGA_MIN_DELAY + 20);
-		if (!gpiod_get_value(conf->status))
+		if (!gpiod_get_value(conf->status)) {
+			/*
+			 * wait for min(t_ST2CK)
+			 */
+			udelay(10);
 			return 0;
+		}
 	}
 
 	dev_err(&mgr->dev, "Status pin not ready.\n");
@@ -117,12 +134,29 @@  static int cyclonespi_write_complete(struct fpga_manager *mgr,
 				     struct fpga_image_info *info)
 {
 	struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+	const char dummy[] = {0, 0};
+	int ret;
 
 	if (gpiod_get_value(conf->status)) {
 		dev_err(&mgr->dev, "Error during configuration.\n");
 		return -EIO;
 	}
 
+	if (gpiod_get_value(conf->confd)) {
+		dev_err(&mgr->dev, "CONF_DONE is high!\n");
+		return -EIO;
+	}
+
+	/*
+	 * After CONF_DONE goes high, send two additional falling edges on DCLK
+	 * to begin initialization and enter user mode
+	 */
+	ret = spi_write(conf->spi, dummy, 2);
+	if (ret) {
+		dev_err(&mgr->dev, "spi error during end sequence: %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -149,6 +183,13 @@  static int cyclonespi_probe(struct spi_device *spi)
 		return PTR_ERR(conf->config);
 	}
 
+	conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN);
+	if (IS_ERR(conf->confd)) {
+		dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
+		PTR_ERR(conf->confd));
+		return PTR_ERR(conf->confd);
+	}
+
 	conf->status = devm_gpiod_get(&spi->dev, "nstat", GPIOD_IN);
 	if (IS_ERR(conf->status)) {
 		dev_err(&spi->dev, "Failed to get status gpio: %ld\n",