[PATCH v2 0/3] fix macb phy probe failure if phy-reset is not handled

2020-11-10 Thread Sagar Shrikant Kadam
HiFive Unleashed is having VSC8541-01 ethernet phy device and requires a
specific reset sequence of 0-1-0-1 in order to use it in unmanaged mode.
This series addresses a corner case where phy reset is not handled by boot
stages prior to linux.
Somewhat similar unreliable phy probe failure was reported and discussed
here [1].
The macb driver fails to detect the ethernet phy device if the bootloader
doesn't provide a proper reset sequence to the phy device or the phy itself
is in some invalid state. Currently, the FSBL or u-boot-spl is resetting
the phy device, and so there is no issue observed in the linux network
setup.

The series is based on linux-5.10-rc5.
Patch 1: Add the OUI to the phy dt node to fix issue of missing mdio device
Patch 2 and 3:
Resetting phy needs GPIO support so add to dt and defconfig.

[1] https://lkml.org/lkml/2018/11/29/154

To reproduce the issue: 
Using FSBL:
1. Comment out VSC8541 reset sequence in fsbl/main.c
   from within the freedom-u540-c000-bootloader.
2. Build and flash fsbl.bin to micro sdcard.

Using u-boot:
1. Comment out VSC8541 reset sequence in board/sifive/fu540/spl.c
   from mainline u-boot source code.
2. Build and flash u-boot binaries to micro sdcard.

Boot the board and bootlog will show network setup failure messages as:

[  1.069474] libphy: MACB_mii_bus: probed
[  1.073092] mdio_bus 1009.ethernet-: MDIO device at address 0
   is missing 
.
[  1.979252] macb 1009.ethernet eth0: Could not attach PHY (-19)

3. Now apply the series build, and boot kernel.
4. MACB and VSC8541 driver get successfully probed and the network is set
   without any failure.


So irrespective of whether the prior stages handle the phy reset sequence,
the probing is successful in both the cases of cold boot and warm boot.

Change History:
===
V2:
-Rebased v1 on linux kernel v5.10-rc3.

V1:
-Ignore 4th patch as suggested and so removed it from the series.
-Verified this series on 5.7-rc5.

V0: Base RFC patch. Verified on 5.7-rc2

Sagar Shrikant Kadam (3):
  dts: phy: fix missing mdio device and probe failure of vsc8541-01
device
  dts: phy: add GPIO number and active state used for phy reset
  riscv: defconfig: enable gpio support for HiFive Unleashed

 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 2 ++
 arch/riscv/configs/defconfig| 2 ++
 2 files changed, 4 insertions(+)

-- 
2.7.4



[PATCH v2 1/3] dts: phy: fix missing mdio device and probe failure of vsc8541-01 device

2020-11-10 Thread Sagar Shrikant Kadam
HiFive unleashed A00 board has VSC8541-01 ethernet phy, this device is
identified as a Revision B device as described in device identification
registers. In order to use this phy in the unmanaged mode, it requires
a specific reset sequence of logical 0-1-0-1 transition on the NRESET pin
as documented here [1].

Currently, the bootloader (fsbl or u-boot-spl) takes care of the phy reset.
If due to some reason the phy device hasn't received the reset by the prior
stages before the linux macb driver comes into the picture, the MACB mii
bus gets probed but the mdio scan fails and is not even able to read the
phy ID registers. It gives an error message:

"libphy: MACB_mii_bus: probed
mdio_bus 1009.ethernet-: MDIO device at address 0 is missing."

Thus adding the device OUI (Organizationally Unique Identifier) to the phy
device node helps to probe the phy device.

[1]: VSC8541-01 datasheet:
https://www.mouser.com/ds/2/523/Microsemi_VSC8541-01_Datasheet_10496_V40-1148034.pdf

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 4a2729f..60846e8 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -88,6 +88,7 @@
phy-mode = "gmii";
phy-handle = <>;
phy0: ethernet-phy@0 {
+   compatible = "ethernet-phy-id0007.0771";
reg = <0>;
};
 };
-- 
2.7.4



[PATCH v2 3/3] riscv: defconfig: enable gpio support for HiFive Unleashed

2020-11-10 Thread Sagar Shrikant Kadam
Ethernet phy VSC8541-01 on HiFive Unleashed has its reset line
connected to a gpio, so enable GPIO driver's required to reset
the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index d222d35..8c3d1e4 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -64,6 +64,8 @@ CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
-- 
2.7.4



[PATCH v2 2/3] dts: phy: add GPIO number and active state used for phy reset

2020-11-10 Thread Sagar Shrikant Kadam
The GEMGXL_RST line on HiFive Unleashed is pulled low and is
using GPIO number 12. Add these reset-gpio details to dt-node
using which the linux phylib can reset the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 60846e8..24d75a1 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -90,6 +90,7 @@
phy0: ethernet-phy@0 {
compatible = "ethernet-phy-id0007.0771";
reg = <0>;
+   reset-gpios = < 12 GPIO_ACTIVE_LOW>;
};
 };
 
-- 
2.7.4



[PATCH v4 0/1] fix i2c polling mode workaround for FU540-C000 SoC

2020-10-21 Thread Sagar Shrikant Kadam
The polling mode workaround for the FU540-C000 on HiFive Unleashed A00
board was added earlier. The logic for this seems to work only in case
the interrupt property was missing/not added into the i2c0 device node.

Here we address this issue by identifying the SOC based on compatibility
string and set the master xfer's to polling mode if it's the FU540-C000
SoC.

The fix has been tested on mainline Linux 5.9 with a PMOD based RTCC sensor
connected to I2C pins J1 header of the board. Log for reference

# uname -a
Linux buildroot 5.9.0-1-ge092bd7 #1 SMP Wed Oct 21 06:19:31 PDT 2020 
riscv64 GNU/Linux

# i2cdetect -y 0
 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:  -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6f
70: -- -- -- -- -- -- -- --

# i2cget 0 0x57 0 b -y
0xf9
# i2cset 0 0x57 0 0xa5 b -y
# i2cget 0 0x57 0 b -y
0xa5
# i2cget 0 0x57 1 b -y
0xa9
# i2cset 0 0x57 1 0x9a b -y
# i2cget 0 0x57 1 b -y
0x9a
# i2cget 0 0x6f 0x20 b -y
0x98
# i2cset 0 0x6f 0x20 0x5a b -y
# i2cget 0 0x6f 0x20 b -y
0x5a
# i2cget 0 0x6f 0x5f b -y
0x55
# i2cset 0 0x6f 0x5f 0xa5 b -y
# i2cget 0 0x6f 0x5f b -y
0xa5
#

Without the fix here, it's observed that "i2cdetect -y 0"
turns the system unresponsive, with CPU stall messages.

Patch History:
===
V4:
-Used alternate implementation as suggested here:
 https://lkml.org/lkml/2020/10/15/513
-Removed TYPE_SIFIVE_REV0 field as it is no longer needed to set the polling 
mode
 and OCORES_FLAG_BROKEN_IRQ flag.

V3:
-Rectified typo as suggested here:
 https://lkml.org/lkml/2020/10/9/902

V2: 
-Incorporated changes as suggested by Peter Kosgaard
 https://lkml.org/lkml/2020/10/8/663

V1: Base version

Sagar Shrikant Kadam (1):
  i2c: ocores: fix polling mode workaround on FU540-C000 SoC

 drivers/i2c/busses/i2c-ocores.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

-- 
2.7.4



[PATCH v4 1/1] i2c: ocores: fix polling mode workaround on FU540-C000 SoC

2020-10-21 Thread Sagar Shrikant Kadam
The FU540-C000 has a broken IRQ and support was added earlier
so that it will operate in polling mode, but seems to work only
in case interrupts property is missing from the i2c0 dt-node.
This should not be the case and the driver should handle polling
mode with the interrupt property present in i2c0 node of the
device tree.
So check if it's the FU540-C000 soc and enable polling mode master
xfers, as the IRQ for this chip is broken.

Fixes commit c45d4ba86731 ("i2c: ocores: add polling mode workaround
for Sifive FU540-C000 SoC")

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f5fc75b..a97cbaa 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -83,7 +83,6 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
-#define TYPE_SIFIVE_REV0   2
 
 #define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
 
@@ -476,11 +475,9 @@ static const struct of_device_id ocores_i2c_match[] = {
},
{
.compatible = "sifive,fu540-c000-i2c",
-   .data = (void *)TYPE_SIFIVE_REV0,
},
{
.compatible = "sifive,i2c0",
-   .data = (void *)TYPE_SIFIVE_REV0,
},
{},
 };
@@ -606,7 +603,6 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
-   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -687,16 +683,19 @@ static int ocores_i2c_probe(struct platform_device *pdev)
init_waitqueue_head(>wait);
 
irq = platform_get_irq(pdev, 0);
+   /*
+* Since the SoC does have an interrupt, its DT has an interrupt
+* property - But this should be bypassed as the IRQ logic in this
+* SoC is broken.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "sifive,fu540-c000-i2c")) {
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+   irq = -ENXIO;
+   }
+
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
-   /*
-* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
-* FU540-C000 SoC in polling mode.
-*/
-   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
-   if (match && (long)match->data == TYPE_SIFIVE_REV0)
-   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
2.7.4



[PATCH v3 0/1] fix i2c polling mode workaround for FU540-C000 SoC

2020-10-15 Thread Sagar Shrikant Kadam
The polling mode workaround for the FU540-C000 on HiFive Unleashed A00
board was added earlier. The logic for this seems to work only in case
the interrupt property was missing/not added into the i2c0 device node.

Here we address this issue by identifying the SOC based on compatibility
string and set the master xfer's to polling mode if it's the FU540-C000
SoC.

The fix has been tested on Linux 5.9.0-rc8 with a PMOD based RTCC sensor
connected to I2C pins J1 header of the board. Log for reference

# uname -a
Linux buildroot 5.9.0-rc8-1-g9da7791 #1 SMP Fri Oct 9 07:56:13 PDT 2020 
riscv64 GNU/Linux
# i2cdetect -y 0
 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:  -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6f
70: -- -- -- -- -- -- -- --
# i2cget 0 0x57 0 b -y
0xa5
# i2cset 0 0x57 0 0x9f b -y
# i2cget 0 0x57 0 b -y
0x9f
# i2cget 0 0x57 1 b -y
0xff
# i2cset 0 0x57 1 0xa9 b -y
# i2cget 0 0x57 1 b -y
0xa9
# i2cget 0 0x6f 0x20 b -y
0x98
# i2cset 0 0x6f 0x20 0xa5 b -y
# i2cget 0 0x6f 0x20 b -y
0xa5
# i2cget 0 0x6f 0x5f b -y
0x55
# i2cset 0 0x6f 0x5f 0x5a b -y
# i2cget 0 0x6f 0x5f b -y
0x5a
#

Without the fix here, it's observed that "i2cdetect -y 0"
turns the system unresponsive, with CPU stall messages.

Patch History:
===
V3:
-Rectified typo as suggested here:
 https://lkml.org/lkml/2020/10/9/902

V2: 
-Incorporated changes as suggested by Peter Kosgaard
 https://lkml.org/lkml/2020/10/8/663

V1: Base version



Sagar Shrikant Kadam (1):
  i2c: ocores: fix polling mode workaround on FU540-C000 SoC

 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

-- 
2.7.4



[PATCH v3 1/1] i2c: ocores: fix polling mode workaround on FU540-C000 SoC

2020-10-15 Thread Sagar Shrikant Kadam
The FU540-C000 has a broken IRQ and support was added earlier
so that it will operate in polling mode, but seems to work only
in case interrupts property is missing from the i2c0 dt-node.
This should not be the case and the driver should handle polling
mode with the interrupt property present in i2c0 node of the
device tree.
So check if it's the FU540-C000 soc and enable polling mode master
xfers, as the IRQ for this chip is broken.

Fixes commit c45d4ba86731 ("i2c: ocores: add polling mode workaround
for Sifive FU540-C000 SoC")

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f5fc75b..1dab02d 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -686,17 +686,21 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
init_waitqueue_head(>wait);
 
+   /*
+* Set OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+* Since the SoC does have interrupt its dt has the interrupt
+* defined but it should be bypassed in driver as this SoC has
+* a broken IRQ, hence update the master_xfer to use polling
+* transfers.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "sifive,fu540-c000-i2c"))
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+
irq = platform_get_irq(pdev, 0);
-   if (irq == -ENXIO) {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ || irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
-   /*
-* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
-* FU540-C000 SoC in polling mode.
-*/
-   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
-   if (match && (long)match->data == TYPE_SIFIVE_REV0)
-   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
2.7.4



[PATCH v2 0/1] fix i2c polling mode workaround for FU540-C000 SoC

2020-10-09 Thread Sagar Shrikant Kadam
The polling mode workaround for the FU540-C000 on HiFive Unleashed A00
board was added earlier. The logic for this seems to work only in case
the interrupt property was missing/not added into the i2c0 device node.

Here we address this issue by identifying the SOC based on compatibility
string and set the master xfer's to polling mode if it's the FU540-C000
SoC.

The fix has been tested on Linux 5.9.0-rc8 with a PMOD based RTCC sensor
connected to I2C pins J1 header of the board. Log for reference

# uname -a
Linux buildroot 5.9.0-rc8-1-g9da7791 #1 SMP Fri Oct 9 07:56:13 PDT 2020 
riscv64 GNU/Linux
# i2cdetect -y 0
 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:  -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6f
70: -- -- -- -- -- -- -- --
# i2cget 0 0x57 0 b -y
0xa5
# i2cset 0 0x57 0 0x9f b -y
# i2cget 0 0x57 0 b -y
0x9f
# i2cget 0 0x57 1 b -y
0xff
# i2cset 0 0x57 1 0xa9 b -y
# i2cget 0 0x57 1 b -y
0xa9
# i2cget 0 0x6f 0x20 b -y
0x98
# i2cset 0 0x6f 0x20 0xa5 b -y
# i2cget 0 0x6f 0x20 b -y
0xa5
# i2cget 0 0x6f 0x5f b -y
0x55
# i2cset 0 0x6f 0x5f 0x5a b -y
# i2cget 0 0x6f 0x5f b -y
0x5a
#

Without the fix here, it's observed that "i2cdetect -y 0"
turns the system unresponsive, with CPU stall messages.

Patch History:
===
V2: 
-Incorporated changes as suggested by Peter Kosgaard
 https://lkml.org/lkml/2020/10/8/663

V1: Base version

Sagar Shrikant Kadam (1):
  i2c: ocores: fix polling mode workaround on FU540-C000 SoC

 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

-- 
2.7.4



[PATCH v2 1/1] i2c: ocores: fix polling mode workaround on FU540-C000 SoC

2020-10-09 Thread Sagar Shrikant Kadam
The FU540-C000 has a broken IRQ and support was added earlier
so that it will operate in polling mode, but seems to work only
in case interrupts property is missing from the i2c0 dt-node.
This should not be the case and the driver should handle polling
mode with the interrupt property present in i2c0 node of the
device tree.
So check if it's the FU540-C000 soc and enable polling mode master
xfers, as the IRQ for this chip is broken.

Fixes commit c45d4ba86731 ("i2c: ocores: add polling mode workaround
for Sifive FU540-C000 SoC")

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f5fc75b..9b3d1ab 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -686,17 +686,21 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
init_waitqueue_head(>wait);
 
+   /*
+* Set OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+* Since the SoC does have interrupt it's dt has the interrupt
+* defined but it should be bypassed in driver as this SoC has
+* a broken IRQ, hence update the master_xfer to use polling
+* transfers.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "sifive,fu540-c000-i2c"))
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+
irq = platform_get_irq(pdev, 0);
-   if (irq == -ENXIO) {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ || irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
-   /*
-* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
-* FU540-C000 SoC in polling mode.
-*/
-   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
-   if (match && (long)match->data == TYPE_SIFIVE_REV0)
-   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
2.7.4



[PATCH 1/1] i2c: ocores: fix polling mode workaround on FU540-C000 SoC

2020-10-06 Thread Sagar Shrikant Kadam
The FU540-C000 has a broken IRQ and support was added earlier
so that it will operate in polling mode, but seems to work only
in case interrupts property is missing from the i2c0 dt-node.
This should not be the case and the driver should handle polling
mode with the interrupt property present in i2c0 node of the
device tree.
So check if it's the FU540-C000 soc and enable polling mode master
xfers, as the IRQ for this chip is broken.

Fixes commit c45d4ba86731 ("i2c: ocores: add polling mode workaround
for Sifive FU540-C000 SoC")

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f5fc75b..4405244 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -686,17 +686,21 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
init_waitqueue_head(>wait);
 
+   /*
+* Set OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+* Since the SoC does have interrupt it's dt has the interrupt
+* defined but it should be bypassed in driver as this SoC has
+* a broken IRQ, hence update the master_xfer to use polling
+* transfers.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+
irq = platform_get_irq(pdev, 0);
-   if (irq == -ENXIO) {
+   if (i2c->flags == OCORES_FLAG_BROKEN_IRQ || irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
-   /*
-* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
-* FU540-C000 SoC in polling mode.
-*/
-   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
-   if (match && (long)match->data == TYPE_SIFIVE_REV0)
-   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
2.7.4



[PATCH 0/1] fix i2c polling mode workaround for FU540-C000 SoC

2020-10-06 Thread Sagar Shrikant Kadam
The polling mode workaround for the FU540-C000 on HiFive Unleashed A00
board was added earlier. The logic for this seems to work only in case
the interrupt property was missing/not added into the i2c0 device node.

Here we address this issue by identifying the SOC based on compatibility
string and set the master xfer's to polling mode if it's the FU540-C000
SoC.

The fix has been tested on Linux 5.9.0-rc8 with a PMOD based RTCC sensor
connected to I2C pins J1 header of the board. Log for reference

# uname -a
Linux buildroot 5.9.0-rc8-1-gf806864 #2 SMP Tue Oct 6 09:51:24 PDT 2020 
riscv64 GNU/Linux
#
# i2cdetect -y 0
 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:  -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6f
70: -- -- -- -- -- -- -- --
# i2cget  0 0x57 0 b -y
0xa9
# i2cset  0 0x57 0 0xa5 b -y
# i2cget  0 0x57 0 b -y
0xa5
# i2cset  0 0x57 0 0x5a b -y
# i2cget  0 0x57 0 b -y
0x5a
# i2cget  0 0x6f 0 b -y
0x00
# i2cset  0 0x6f 0 0x5a b -y
# i2cget  0 0x6f 0 b -y
0x5a

Without the fix here, it's observed that "i2cdetect -y 0" turns the 
system unresponsive, with CPU stall messages.

Sagar Shrikant Kadam (1):
  i2c: ocores: fix polling mode workaround on FU540-C000 SoC

 drivers/i2c/busses/i2c-ocores.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

-- 
2.7.4



[PATCH v2 1/2] riscv: defconfig: enable spi nor on Hifive Unleashed A00

2020-05-19 Thread Sagar Shrikant Kadam
Enable MTD based SPI-NOR framework in order to use spi flash available
on HiFive Unleashed A00 board, and move SPI_SIFIVE to Kconfig.socs. The
configurability of SPI_SIFIVE is retained and still can be enabled or
disabled as required.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/Kconfig.socs  | 1 +
 arch/riscv/configs/defconfig | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 216286d..bcb0b1a 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -7,6 +7,7 @@ config SOC_SIFIVE
select CLK_SIFIVE
select CLK_SIFIVE_FU540_PRCI
select SIFIVE_PLIC
+   imply SPI_SIFIVE if SPI
help
  This enables support for SiFive SoC platform hardware.
 
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4da4886..8e2d467 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -62,7 +62,6 @@ CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
-CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
@@ -80,6 +79,8 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
-- 
2.7.4



[PATCH v2 2/2] spi: nor: update page program settings for is25wp256 using post bfpt fixup

2020-05-19 Thread Sagar Shrikant Kadam
Make a generic post_bfpt fixup handler which uses part specific fixup's
based on device id, as done here for is25lp256 and is25wp256 devices.

During SFDP parsing it is seen that the IS25WP256d device is missing 4BAIT
(4-Byte address instruction table), due to which it's page program
capacity doesn't get correctly populated and the device gets configured
with 4-byte Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1
even though it can work with SNOR_PROTO_1_1_4.

Here using the post bfpt fixup hooks we update the page program
settings to 4-byte QUAD Input Page program operations.

The patch is tested on HiFive Unleashed A00 board and it benefits
few seconds of average write time for entire flash write.

QUAD Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 35.23s
user0m 0.00s
sys 0m 23.97s

Serial Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 39.25s
user0m 0.00s
sys 0m 27.93s

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/issi.c | 72 ++
 1 file changed, 60 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index ffcb60e..efa0fe7 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -8,26 +8,74 @@
 
 #include "core.h"
 
-static int
-is25lp256_post_bfpt_fixups(struct spi_nor *nor,
-  const struct sfdp_parameter_header *bfpt_header,
-  const struct sfdp_bfpt *bfpt,
-  struct spi_nor_flash_parameter *params)
+static int issi_fix_addr_width(struct spi_nor *nor,
+  const struct sfdp_bfpt *bfpt)
 {
/*
-* IS25LP256 supports 4B opcodes, but the BFPT advertises a
+* If device supports 4B opcodes, but the BFPT advertises a
 * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
 * Overwrite the address width advertised by the BFPT.
 */
-   if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
-   BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
+   if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK)
+   == BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
nor->addr_width = 4;
 
return 0;
 }
 
-static struct spi_nor_fixups is25lp256_fixups = {
-   .post_bfpt = is25lp256_post_bfpt_fixups,
+static int issi_update_proto(struct spi_nor *nor,
+struct spi_nor_flash_parameter *params)
+{
+   /*
+* For a device whose 4-Byte address instruction table doesn't
+* get populated and the device get's configured with 4-byte
+* Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1 even
+* though it supports SNOR_PROTO_1_1_4, so priorotize QUAD write
+* over SINGLE write if device id table holds SPI_NOR_QUAD_READ.
+*/
+   if (nor->info->flags & SPI_NOR_QUAD_READ) {
+   params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
+   spi_nor_set_pp_settings
+   (>page_programs[SNOR_CMD_PP_1_1_4],
+SPINOR_OP_PP_1_1_4,
+SNOR_PROTO_1_1_4);
+   }
+
+   return 0;
+}
+
+static int
+issi_post_bfpt_fixups(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
+{
+   long deviceid;
+
+   deviceid = (nor->info->id[1] << 8 | nor->info->id[2]);
+
+   /* As this is for same MFR i.e ISSI, just check the device ID's */
+   switch (deviceid) {
+   case 0x6019:
+   /* is25lp256 */
+   issi_fix_addr_width(nor, bfpt);
+   break;
+
+   case 0x7019:
+   /* is25wp256 */
+   issi_fix_addr_width(nor, bfpt);
+   issi_update_proto(nor, params);
+   break;
+
+   default:
+   break;
+   }
+
+   return 0;
+}
+
+static struct spi_nor_fixups is25_fixups = {
+   .post_bfpt = issi_post_bfpt_fixups,
 };
 
 static const struct flash_info issi_parts[] = {
@@ -48,7 +96,7 @@ static const struct flash_info issi_parts[] = {
{ "is25lp256",  INFO(0x9d6019, 0, 64 * 1024, 512,
 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 SPI_NOR_4B_OPCODES)
-   .fixups = _fixups },
+   .fixups = _fixups },
{ "is25wp032",  INFO(0x9d7016, 0, 64 * 1024,  64,
 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp064",  INFO(0x9d7017, 0, 64 * 1

[PATCH v2 0/2] enable spi flash and update is25wp256d page write capabilities

2020-05-19 Thread Sagar Shrikant Kadam
HiFive Unleashed A00 board has is25wp256d snor chip. It is observed
that it gets configured with Serial Input Page program by the end
of spi_nor_scan. Using the post bfpt fixup hook we prioritize the
page program settings to use quad input page program (opcode:0x34)
over serial input page program (opcode: 0x12).

The patchset is tested on Linux 5.7.0-rc5.

Changelog:
===
V2:
-Split common code between is25lp256 and is25wp256 devices as suggested
 Added a generic post bfpt fixup handler that identifies the flash parts
 based on their device id and uses the corresponding fixup. Other device's
 that need a post bfpt fixup can just add the device id check and either
 reuse the available fixups or write the necessary fixup code if one is not
 available.
 
V1:
-Moved SPI_SIFIVE from defconfig to Kconfig.socs for SOC_SIFIVE.
 Retained it's configurability using "imply" instead of "select"

V0: Base version patch (Tested on 5.7.0-rc3).


Sagar Shrikant Kadam (2):
  riscv: defconfig: enable spi nor on Hifive Unleashed A00
  spi: nor: update page program settings for is25wp256 using post bfpt
fixup

 arch/riscv/Kconfig.socs  |  1 +
 arch/riscv/configs/defconfig |  3 +-
 drivers/mtd/spi-nor/issi.c   | 72 
 3 files changed, 63 insertions(+), 13 deletions(-)

-- 
2.7.4



[PATCH v1 0/2] update is25wp256d page write capabilities

2020-05-14 Thread Sagar Shrikant Kadam
HiFive Unleashed A00 board has is25wp256d snor chip. It is observed
that it gets configured with Serial Input Page program by the end
of spi_nor_scan. Using the post bfpt fixup hook we prioritize the
page program settings to use quad input page program (opcode:0x34)
over serial input page program (opcode: 0x12).

The patchset is tested on Linux 5.7.0-rc5.

Changelog:
===
V1:
-Moved SPI_SIFIVE from defconfig to Kconfig.socs for SOC_SIFIVE.
 Retained it's configurability using "imply" instead of "select"

V0: Base version patch (Tested on 5.7.0-rc3).



Sagar Shrikant Kadam (2):
  riscv: defconfig: enable spi nor on Hifive Unleashed A00 board.
  spi: nor: update page program settings for is25wp256 using post bfpt
fixup

 arch/riscv/Kconfig.socs  |  1 +
 arch/riscv/configs/defconfig |  3 ++-
 drivers/mtd/spi-nor/issi.c   | 16 
 3 files changed, 19 insertions(+), 1 deletion(-)

-- 
2.7.4



[PATCH v1 1/2] riscv: defconfig: enable spi nor on Hifive Unleashed A00 board.

2020-05-14 Thread Sagar Shrikant Kadam
Enable MTD based SPI-NOR framework in order to use spi flash available
on HiFive Unleashed A00 board, and move SPI_SIFIVE to Kconfig.socs. The
configurability of SPI_SIFIVE is retained and still can be enabled or
disabled as required.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/Kconfig.socs  | 1 +
 arch/riscv/configs/defconfig | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 216286d..bcb0b1a 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -7,6 +7,7 @@ config SOC_SIFIVE
select CLK_SIFIVE
select CLK_SIFIVE_FU540_PRCI
select SIFIVE_PLIC
+   imply SPI_SIFIVE if SPI
help
  This enables support for SiFive SoC platform hardware.
 
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4da4886..8e2d467 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -62,7 +62,6 @@ CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
-CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
@@ -80,6 +79,8 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
-- 
2.7.4



[PATCH v1 2/2] spi: nor: update page program settings for is25wp256 using post bfpt fixup

2020-05-14 Thread Sagar Shrikant Kadam
During SFDP parsing it is seen that the IS25WP256d device is missing 4BAIT
(4-Byte address instruction table), due to which it's page program
capacity doesn't get correctly populated and the device gets configured
with 4-byte Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1
even though it can work with SNOR_PROTO_1_1_4.

Here using the post bfpt fixup hooks we update the page program
settings to 4-byte QUAD Input Page program operations.

The patch is tested on HiFive Unleashed A00 board and it benefits
few seconds of average write time for entire flash write.

QUAD Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 32.85s
user0m 0.00s
sys 0m 31.79s

Serial Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 35.87s
user0m 0.00s
sys 0m 35.42s

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/issi.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index ffcb60e..9eb6e82 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -23,6 +23,22 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor,
BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
nor->addr_width = 4;
 
+   /*
+* On IS25WP256d device 4-Byte address instruction table doesn't
+* get populated and so the device get's configured with 4-byte
+* Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1 even
+* though it supports SNOR_PROTO_1_1_4, so priorotize QUAD write
+* over SINGLE write if device id table holds SPI_NOR_QUAD_READ.
+*/
+   if (strcmp(nor->info->name, "is25wp256") == 0) {
+   if (nor->info->flags & SPI_NOR_QUAD_READ) {
+   params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
+   spi_nor_set_pp_settings
+   (>page_programs[SNOR_CMD_PP_1_1_4],
+SPINOR_OP_PP_1_1_4,
+SNOR_PROTO_1_1_4);
+   }
+   }
return 0;
 }
 
-- 
2.7.4



[PATCH v1 1/3] dts: phy: fix missing mdio device and probe failure of vsc8541-01 device

2020-05-13 Thread Sagar Shrikant Kadam
HiFive unleashed A00 board has VSC8541-01 ethernet phy, this device is
identified as a Revision B device as described in device identification
registers. In order to use this phy in the unmanaged mode, it requires
a specific reset sequence of logical 0-1-0-1 transition on the NRESET pin
as documented here [1].

Currently, the bootloader (fsbl) takes care of the phy reset. If due to
some reason the phy device hasn't received the reset by the prior stages
before the linux macb driver comes into the picture, the MACB mii bus gets
probed but the mdio scan fails and is not even able to read the phy ID
registers. It gives an error message:

"libphy: MACB_mii_bus: probed
mdio_bus 1009.ethernet-: MDIO device at address 0 is missing."

Thus adding the device OUI (Organizationally Unique Identifier) to the phy
device node helps to probe the phy device.

[1]: VSC8541-01 datasheet:
https://www.mouser.com/ds/2/523/Microsemi_VSC8541-01_Datasheet_10496_V40-1148034.pdf

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 4a2729f..60846e8 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -88,6 +88,7 @@
phy-mode = "gmii";
phy-handle = <>;
phy0: ethernet-phy@0 {
+   compatible = "ethernet-phy-id0007.0771";
reg = <0>;
};
 };
-- 
2.7.4



[PATCH v1 2/3] dts: phy: add GPIO number and active state used for phy reset

2020-05-13 Thread Sagar Shrikant Kadam
The GEMGXL_RST line on HiFive Unleashed is pulled low and is
using GPIO number 12. Add these reset-gpio details to dt-node
using which the linux phylib can reset the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 60846e8..24d75a1 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -90,6 +90,7 @@
phy0: ethernet-phy@0 {
compatible = "ethernet-phy-id0007.0771";
reg = <0>;
+   reset-gpios = < 12 GPIO_ACTIVE_LOW>;
};
 };
 
-- 
2.7.4



[PATCH v1 0/3] fix macb phy probe failure if phy-reset is not handled

2020-05-13 Thread Sagar Shrikant Kadam
HiFive Unleashed is having VSC8541-01 ethernet phy device and requires a
specific reset sequence of 0-1-0-1 in order to use it in unmanaged mode.
This series addresses a corner case where phy reset is not handled by boot
stages prior to linux.
Somewhat similar unreliable phy probe failure was reported and discussed
here [1].
The macb driver fails to detect the ethernet phy device if the bootloader
doesn't provide a proper reset sequence to the phy device or the phy itself
is in some invalid state. Currently, the FSBL is resetting the phy device,
and so there is no issue observed in the linux network setup.

The series is based on linux-5.7-rc5.
Patch 1: Add the OUI to the phy dt node to fix issue of missing mdio device
Patch 2 and 3:
Resetting phy needs GPIO support so add to dt and defconfig.

[1] https://lkml.org/lkml/2018/11/29/154

To reproduce the issue: 
1. Comment out VSC8541 reset sequence in fsbl/main.c
   from within the freedom-u540-c000-bootloader.
2. Build and flash fsbl.bin to micro sdcard.

Boot the board and bootlog will show network setup failure messages as:

[  1.069474] libphy: MACB_mii_bus: probed
[  1.073092] mdio_bus 1009.ethernet-: MDIO device at address 0
   is missing 
.
[  1.979252] macb 1009.ethernet eth0: Could not attach PHY (-19)

3. Now apply the series build, and boot kernel.
4. MACB and VSC8541 driver get successfully probed and the network is set
   without any failure.


So irrespective of whether the prior stages handle the phy reset sequence,
the probing is successful in both the cases of cold boot and warm boot.

Change History:
===
V1:
-Ignore 4th patch as suggested and so removed it from the series.
-Verified this series on 5.7-rc5.

V0: Base RFC patch. Verified on 5.7-rc2


Sagar Shrikant Kadam (3):
  dts: phy: fix missing mdio device and probe failure of vsc8541-01
device
  dts: phy: add GPIO number and active state used for phy reset
  riscv: defconfig: enable gpio support for HiFive Unleashed

 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 2 ++
 arch/riscv/configs/defconfig| 2 ++
 2 files changed, 4 insertions(+)

-- 
2.7.4



[PATCH v1 3/3] riscv: defconfig: enable gpio support for HiFive Unleashed

2020-05-13 Thread Sagar Shrikant Kadam
Ethernet phy VSC8541-01 on HiFive Unleashed has its reset line
connected to a gpio, so enable GPIO driver's required to reset
the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4da4886..20c38b59 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -63,6 +63,8 @@ CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
-- 
2.7.4



[PATCH v1 1/1] tty: serial: add missing spin_lock_init for SiFive serial console

2020-05-09 Thread Sagar Shrikant Kadam
An uninitialised spin lock for sifive serial console raises a bad
magic spin_lock error as reported and discussed here [1].
Initialising the spin lock resolves the issue.

The fix is tested on HiFive Unleashed A00 board with Linux 5.7-rc4
and OpenSBI v0.7

[1] 
https://lore.kernel.org/linux-riscv/b9fe49483a903f404e7acc15a6efbef756db28ae.ca...@wdc.com

Fixes: 45c054d0815b ("tty: serial: add driver for the SiFive UART")
Reported-by: Atish Patra 
Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/tty/serial/sifive.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 13eadcb..0b5110d 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -883,6 +883,7 @@ console_initcall(sifive_console_init);
 
 static void __ssp_add_console_port(struct sifive_serial_port *ssp)
 {
+   spin_lock_init(>port.lock);
sifive_serial_console_ports[ssp->port.line] = ssp;
 }
 
-- 
2.7.4



[PATCH v1 0/1] fix for spin lock bad magic on SiFive UART

2020-05-09 Thread Sagar Shrikant Kadam
9] [] kernel_init+0x12/0x118
[0.866007] [] ret_from_exception+0x0/0xc
[0.871690] printk: console [ttySIF0] enabled
[0.871690] printk: console [ttySIF0] enabled
[0.880442] printk: bootconsole [sbi0] disabled
[0.880442] printk: bootconsole [sbi0] disabled
[0.889866] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 10, base_baud 
= 0) is a SiFive UART v0
[0.899328] [drm] radeon kernel modesetting enabled.
[0.918039] loop: module loaded
[0.921025] sifive_spi 1004.spi: mapped; irq=12, cs=1

The kernel doesn't hang and boots to prompt.

===
Adding the missing spin_lock_init fixes the spinlock error. With the patch
the serial port is tested with basic sanity checks of baudrate change,
receive and transmit using:

Change baud rate : stty -F /dev/ttySIF0 9600
Recive mode  : cat /dev/ttySIF0
Transmit mode: echo "Hello" > /dev/ttySIF0

Some of the relevant working boot log:
===
[0.697617] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[0.704441] 1001.serial: ttySIF0 at MMIO 0x1001 (irq = 1, base_baud 
= 0) is a SiFive UART v0
[0.712916] printk: console [ttySIF0] enabled
[0.712916] printk: console [ttySIF0] enabled
[0.721663] printk: bootconsole [sbi0] disabled
[0.721663] printk: bootconsole [sbi0] disabled
[0.731077] 10011000.serial: ttySIF1 at MMIO 0x10011000 (irq = 10, base_baud 
= 0) is a SiFive UART v0

Change History:

V1 : Incorporated suggestions
- Initialised spin lock for sifive console as suggested.
- Updated reference link of reported issue from lore.kernel.org both in
  cover-letter and in patch.

V0 : Base patch.

Sagar Shrikant Kadam (1):
  tty: serial: add missing spin_lock_init for SiFive serial console

 drivers/tty/serial/sifive.c | 1 +
 1 file changed, 1 insertion(+)

-- 
2.7.4



[PATCH 1/2] riscv: defconfig: enable spi nor on Hifive Unleashed A00 board.

2020-04-30 Thread Sagar Shrikant Kadam
Enable MTD based SPI-NOR framework in order to use spi flash
available on HiFive Unleashed A00 board.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4da4886..970580b 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -80,6 +80,8 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
 CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
-- 
2.7.4



[PATCH 0/2] update is25wp256d page write capabilities

2020-04-30 Thread Sagar Shrikant Kadam
HiFive Unleashed A00 board has is25wp256d snor chip. It is observed
that it gets configured with Serial Input Page program by the end
of spi_nor_scan. Using the post bfpt fixup hook we prioritize the
page program settings to use quad input page program (opcode:0x34)
over serial input page program (opcode: 0x12).

The patchset is tested on Linux 5.7-rc3.

Sagar Shrikant Kadam (2):
  riscv: defconfig: enable spi nor on Hifive Unleashed A00 board.
  spi: nor: update page program settings for is25wp256 using post bfpt
fixup

 arch/riscv/configs/defconfig |  2 ++
 drivers/mtd/spi-nor/issi.c   | 16 
 2 files changed, 18 insertions(+)

-- 
2.7.4



[PATCH 2/2] spi: nor: update page program settings for is25wp256 using post bfpt fixup

2020-04-30 Thread Sagar Shrikant Kadam
During SFDP parsing it is seen that the IS25WP256d device is missing 4BAIT
(4-Byte address instruction table), due to which it's page program
capacity doesn't get correctly populated and the device gets configured
with 4-byte Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1
even though it can work with SNOR_PROTO_1_1_4.

Here using the post bfpt fixup hooks we update the page program
settings to 4-byte QUAD Input Page program operations.

The patch is tested on HiFive Unleashed A00 board and it benefits
few seconds of average write time for entire flash write.

QUAD Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 32.85s
user0m 0.00s
sys 0m 31.79s

Serial Input Page Program operations:
> time mtd_debug write /dev/mtd0 0 33554432 rd32M
Copied 33554432 bytes from rd32M to address 0x in flash
real0m 35.87s
user0m 0.00s
sys 0m 35.42s

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/issi.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index ffcb60e..9eb6e82 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -23,6 +23,22 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor,
BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
nor->addr_width = 4;
 
+   /*
+* On IS25WP256d device 4-Byte address instruction table doesn't
+* get populated and so the device get's configured with 4-byte
+* Address Serial Input Page Program i.e. SNOR_PROTO_1_1_1 even
+* though it supports SNOR_PROTO_1_1_4, so priorotize QUAD write
+* over SINGLE write if device id table holds SPI_NOR_QUAD_READ.
+*/
+   if (strcmp(nor->info->name, "is25wp256") == 0) {
+   if (nor->info->flags & SPI_NOR_QUAD_READ) {
+   params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
+   spi_nor_set_pp_settings
+   (>page_programs[SNOR_CMD_PP_1_1_4],
+SPINOR_OP_PP_1_1_4,
+SNOR_PROTO_1_1_4);
+   }
+   }
return 0;
 }
 
-- 
2.7.4



[RFC PATCH 4/4] dt-bindings: net: phy: extend dt binding for VSC8541 ethernet-phy

2020-04-28 Thread Sagar Shrikant Kadam
Adding a OUI (Organizationally Unique Identifier) for VSC8541-01
device to dt node requires a corresponding dt-binding entry as well
so that checkpatch doesn't complain with a warning:

DT compatible string "ethernet-phy-id0007.0771" appears un-documented

Here extend the existing dt binding of VSC8531 device to include
VSC8541 device example.

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt 
b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
index 5ff37c6..774448a 100644
--- a/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
+++ b/Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt
@@ -68,3 +68,6 @@ Example:
 vsc8531,led-0-mode = ;
 vsc8531,led-1-mode = ;
 };
+vsc8541_0: ethernet-phy@0 {
+compatible = "ethernet-phy-id0007.0771";
+   };
-- 
2.7.4



[RFC PATCH 3/4] riscv: defconfig: enable gpio support for HiFive Unleashed

2020-04-28 Thread Sagar Shrikant Kadam
Ethernet phy VSC8541-01 on HiFive Unleashed has its reset line
connected to a gpio, so enable GPIO driver's required to reset
the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 4da4886..20c38b59 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -63,6 +63,8 @@ CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_POWER_RESET=y
 CONFIG_DRM=y
-- 
2.7.4



[RFC PATCH 0/4] fix macb phy probe failure if phy-reset is not handled

2020-04-28 Thread Sagar Shrikant Kadam
HiFive Unleashed is having VSC8541-01 ethernet phy device and requires a
specific reset sequence of 0-1-0-1 in order to use it in unmanaged mode.
This series addresses a corner case where phy reset is not handled by boot
stages prior to linux.
Somewhat similar unreliable phy probe failure was reported and discussed
here [1].
The macb driver fails to detect the ethernet phy device if the bootloader
doesn't provide a proper reset sequence to the phy device or the phy itself
is in some invalid state. Currently, the FSBL is resetting the phy device,
and so there is no issue observed in the linux network setup.

The series is based on linux-5.7-rc2.
Patch 1: Add the OUI to the phy dt node to fix issue of missing mdio device
Patch 2 and 3:
Resetting phy needs GPIO support so add to dt and defconfig.
Patch 4: Add dt binding for OUI introduced in patch 1.

[1] https://lkml.org/lkml/2018/11/29/154

To reproduce the issue: 
1. Comment out VSC8541 reset sequence in fsbl/main.c
   from within the freedom-u540-c000-bootloader.
2. Build and add fsbl.bin to micro sdcard.

Boot the board and bootlog will show network setup failure messages as:

[  1.069474] libphy: MACB_mii_bus: probed
[  1.073092] mdio_bus 1009.ethernet-: MDIO device at address 0
   is missing 
.
[  1.979252] macb 1009.ethernet eth0: Could not attach PHY (-19)

3. Now apply the series build, and boot kernel.
4. MACB and VSC8541 driver get successfully probed and the network is set
   without any failure.


So irrespective of whether the prior stages handle the phy reset sequence,
the probing is successful in both the cases of cold boot and warm boot.

Sagar Shrikant Kadam (4):
  dts: phy: fix missing mdio device and probe failure of vsc8541-01
device
  dts: phy: add GPIO number and active state used for phy reset
  riscv: defconfig: enable gpio support for HiFive Unleashed
  dt-bindings: net: phy: extend dt binding for VSC8541 ethernet-phy

 Documentation/devicetree/bindings/net/mscc-phy-vsc8531.txt | 3 +++
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts| 2 ++
 arch/riscv/configs/defconfig   | 2 ++
 3 files changed, 7 insertions(+)

-- 
2.7.4



[RFC PATCH 2/4] dts: phy: add GPIO number and active state used for phy reset

2020-04-28 Thread Sagar Shrikant Kadam
The GEMGXL_RST line on HiFive Unleashed is pulled low and is
using GPIO number 12. Add these reset-gpio details to dt-node
using which the linux phylib can reset the phy.

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 60846e8..24d75a1 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -90,6 +90,7 @@
phy0: ethernet-phy@0 {
compatible = "ethernet-phy-id0007.0771";
reg = <0>;
+   reset-gpios = < 12 GPIO_ACTIVE_LOW>;
};
 };
 
-- 
2.7.4



[RFC PATCH 1/4] dts: phy: fix missing mdio device and probe failure of vsc8541-01 device

2020-04-28 Thread Sagar Shrikant Kadam
HiFive unleashed A00 board has VSC8541-01 ethernet phy, this device is
identified as a Revision B device as described in device identification
registers. In order to use this phy in the unmanaged mode, it requires
a specific reset sequence of logical 0-1-0-1 transition on the NRESET pin
as documented here [1].

Currently, the bootloader (fsbl) takes care of the phy reset. If due to
some reason the phy device hasn't received the reset by the prior stages
before the linux macb driver comes into the picture, the MACB mii bus gets
probed but the mdio scan fails and is not even able to read the phy ID
registers. It gives an error message:

"libphy: MACB_mii_bus: probed
mdio_bus 1009.ethernet-: MDIO device at address 0 is missing."

Thus adding the device OUI (Organizationally Unique Identifier) to the phy
device node helps to probe the phy device.

[1]: VSC8541-01 datasheet:
https://www.mouser.com/ds/2/523/Microsemi_VSC8541-01_Datasheet_10496_V40-1148034.pdf

Signed-off-by: Sagar Shrikant Kadam 
---
 arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts 
b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
index 4a2729f..60846e8 100644
--- a/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
+++ b/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
@@ -88,6 +88,7 @@
phy-mode = "gmii";
phy-handle = <>;
phy0: ethernet-phy@0 {
+   compatible = "ethernet-phy-id0007.0771";
reg = <0>;
};
 };
-- 
2.7.4



[PATCH v9 2/2] mtd: spi-nor: fix nor->addr_width for is25wp256

2019-09-18 Thread Sagar Shrikant Kadam
Use the post bfpt fixup hook for the is25wp256 device as done for
is25lp256 device to overwrite the address width advertised by BFPT.

For instance the standard devices eg: IS25WP256D-JMLE where J stands
for "standard" does not support SFDP.

Signed-off-by: Sagar Shrikant Kadam 
Reviewed-by: Vignesh Raghavendra 
---
 drivers/mtd/spi-nor/spi-nor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 003c1c7..75e8560 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1949,7 +1949,7 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor 
*nor)
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES)
-   },
+   .fixups = _fixups },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-- 
1.9.1



[PATCH v9 1/2] mtd: spi-nor: add support for is25wp256

2019-09-18 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB) device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
Reviewed-by: Vignesh Raghavendra 
---
 drivers/mtd/spi-nor/spi-nor.c | 9 -
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 654bdc4..003c1c7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1946,7 +1946,10 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor 
*nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -3776,6 +3779,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
default:
/* Kept only for backward compatibility purpose. */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 9f57cdf..5d6583e 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -21,6 +21,7 @@
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
 #define SNOR_MFR_SPANSION  CFI_MFR_AMD
 #define SNOR_MFR_SST   CFI_MFR_SST
-- 
1.9.1



[PATCH v9 0/2] mtd: spi-nor: add support for is25wp256 spi-nor flash

2019-09-18 Thread Sagar Shrikant Kadam
The patch series adds basic support for 32MiB spi-nor is25wp256 present on 
HiFive
Unleashed A00 board. The flash device gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY
from BFPT table for address width, whereas the flash can support 4 byte
address width, so the address width is configured by using the post bfpt
fixup hook as done for is25lp256 device in
commit cf580a924005 ("mtd: spi-nor: fix nor->addr_width when its value
configured from SFDP does not match the actual width")

Patches are based on original work done by Wesley Terpstra and/or
Palmer Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and
flash utils (v1.5.2):
1. mtd_debug: Options available are : erase/read/write.
2. flashcp  : Single utility that erases flash, writes a file to flash and 
verifies the data back.

The changes are available under branch dev/sagark/spi-nor-v9 at
https://github.com/sagsifive/riscv-linux-hifive 

Revision history:
V8<->V9:
-Rebased this series to mainline v5.3-rc8
-Corrected number of sectors in the spi nor id table for is25wp256 device as 
suggested in the review.
-The lock/unlock scheme in the V8 version of this series needs to have a more 
generic approach.
 These protection scheme patches are not included in this series, will submit 
those separately.

V7<->V8:
-Rebased this series on mainline v5.3-rc4.
-Removed remaining func_reg reference from issi_lock as updating OTP region was 
dropped as part of V6.
-Updated Reviewed-By tags to 1st and 2nd patch.

V6<->V7:
-Incorporated review comments from Vignesh.
-Used post bfpt fixup hook as suggested by Vignesh.
-Introduce SPI_NOR_HAS_BP3 to identify whether the flash has 4th bit protect 
bit.
-Prefix generic flash access functions with spi_nor_.

V5<->V6:
-Incorporated review comments from Vignesh.
-Set addr width based on device size and if SPI_NOR_4B_OPCODES is set.
-Added 4th block protect identifier (SPI_NOR_HAS_BP3) to flash_info structure 
-Changed flash_info: flag from u16 to u32 to accommodate SPI_NOR_HAS_BP3
-Prefix newly added function with spi_nor_xxx.
-Dropped write_fr function, as updating OTP bit's present in function register 
doesn't seem to be a good idea.
-Set lock/unlock schemes based on whether the ISSI device has locking support 
and  BP3 bit present.

V4<->V5:
-Rebased to linux version v5.2-rc1.
-Updated heading of this cover letter with sub-system, instead of just plain 
"add support for is25wp256..."

V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5.
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device.
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.

Sagar Shrikant Kadam (2):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: fix nor->addr_width for is25wp256

 drivers/mtd/spi-nor/spi-nor.c | 9 -
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

-- 
1.9.1



[PATCH v8 4/4] mtd: spi-nor: add locking support for is25wp256 device

2019-08-13 Thread Sagar Shrikant Kadam
Implement a locking scheme for ISSI devices based on the stm_lock scheme.
The is25wp256  device has 4 bits for selecting the range of blocks to
be locked/protected from erase/write operations and function register
gives feasibility to select the top / bottom area for protection.
Added opcode to read and write function registers.

The current implementation enables block protection as per the table
defined in the datasheet for the is25wp256 device having erase size of
0x1000. ISSI and stm devices differ in terms of TBS (top/bottom area
protection) bits. In case of issi this bit is in Function register and
is OTP memory, so once FR bits are programmed cannot be modified.

Some common code from stm_lock/unlock implementation is extracted so that
it can be re-used for issi devices. The locking scheme has been tested on
HiFive Unleashed board Rev A00  having is25wp256 flash memory.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 265 ++
 include/linux/mtd/spi-nor.h   |   5 +
 2 files changed, 222 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 24c1c11..247454a 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -295,6 +295,29 @@ struct flash_info {
 
 #define JEDEC_MFR(info)((info)->id[0])
 
+/**
+ * spi_nor_read_fr() - read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or negative if error.
+ */
+static int spi_nor_read_fr(struct spi_nor *nor)
+{
+   int ret;
+   u8 val;
+
+   ret = nor->read_reg(nor, SPINOR_OP_RDFR, , 1);
+   if (ret < 0) {
+   pr_err("error %d reading FR\n", ret);
+   return ret;
+   }
+
+   return val;
+}
+
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -1095,10 +1118,18 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
 uint64_t *len)
 {
struct mtd_info *mtd = >mtd;
-   u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-   int shift = ffs(mask) - 1;
+   u8 mask = 0;
+   u8 fr = 0;
+   int shift = 0;
int pow;
 
+   if (nor->flags & SNOR_F_HAS_BP3)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   shift = ffs(mask) - 1;
+
if (!(sr & mask)) {
/* No protection */
*ofs = 0;
@@ -1106,10 +1137,19 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
} else {
pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow;
-   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-   *ofs = 0;
-   else
-   *ofs = mtd->size - *len;
+   /* ISSI device's have top/bottom select bit in func reg */
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+   fr = spi_nor_read_fr(nor);
+   if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   } else {
+   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   }
}
 }
 
@@ -1136,18 +1176,108 @@ static int stm_check_lock_status_sr(struct spi_nor 
*nor, loff_t ofs, uint64_t le
return (ofs >= lock_offs + lock_len) || (ofs + len <= 
lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-   u8 sr)
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+   u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
- u8 sr)
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t 
len,
+ u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
+/**
+ * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
+ * @nor: pointer t

[PATCH v8 2/4] mtd: spi-nor: fix nor->addr_width for is25wp256

2019-08-13 Thread Sagar Shrikant Kadam
Use the post bfpt fixup hook for the is25wp256 device as done for
is25lp256 device to overwrite the address width advertised by BFPT.

For instance the standard devices eg: IS25WP256D-JMLE where J stands
for "standard" does not support SFDP.

Signed-off-by: Sagar Shrikant Kadam 
Reviewed-by: Vignesh Raghavendra 
---
 drivers/mtd/spi-nor/spi-nor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 6635127..cb40b1b 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1949,7 +1949,7 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor 
*nor)
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES)
-   },
+   .fixups = _fixups },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-- 
1.9.1



[PATCH v8 1/4] mtd: spi-nor: add support for is25wp256

2019-08-13 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB) device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
Reviewed-by: Vignesh Raghavendra 
---
 drivers/mtd/spi-nor/spi-nor.c | 9 -
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 03cc788..6635127 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1946,7 +1946,10 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor 
*nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -3776,6 +3779,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
default:
/* Kept only for backward compatibility purpose. */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 9f57cdf..5d6583e 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -21,6 +21,7 @@
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
 #define SNOR_MFR_SPANSION  CFI_MFR_AMD
 #define SNOR_MFR_SST   CFI_MFR_SST
-- 
1.9.1



[PATCH v8 3/4] mtd: spi-nor: add support to unlock the flash device

2019-08-13 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].
Add an identifier within the flash info structure to indicate that a
particular flash device has the fourth block protect bit (SPI_NOR_HAS_BP3).

Increase size of flash_info flags from u16 to u32 to avoid flag overflow
due SPI_NOR_HAS_BP3.
Clear block protection bits unlocks the flash memory regions.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

spell correction: "Configuration" in spansion_quad_enable function
description.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 72 ---
 include/linux/mtd/spi-nor.h   |  2 ++
 2 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index cb40b1b..24c1c11 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -250,7 +250,7 @@ struct flash_info {
u16 page_size;
u16 addr_width;
 
-   u16 flags;
+   u32 flags;
 #define SECT_4KBIT(0)  /* SPINOR_OP_BE_4K works 
uniformly */
 #define SPI_NOR_NO_ERASE   BIT(1)  /* No erase command needed */
 #define SST_WRITE  BIT(2)  /* use SST byte programming */
@@ -279,6 +279,13 @@ struct flash_info {
 #define SPI_NOR_SKIP_SFDP  BIT(13) /* Skip parsing of SFDP tables */
 #define USE_CLSR   BIT(14) /* use CLSR command */
 #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
+#define SPI_NOR_HAS_BP3BIT(16) /*
+* Flash SR has block protect bits
+* for lock/unlock purpose, few support
+* BP0-BP2 while few support BP0-BP3.
+* This flag identifies devices that
+* support BP3 bit.
+*/
 
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
@@ -1461,7 +1468,55 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
- * spansion_quad_enable() - set QE bit in Configuraiton Register.
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask;
+
+   if (nor->flags & SNOR_F_HAS_BP3)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
+ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI block protect bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
+ * spansion_quad_enable() - set QE bit in Configuration Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
  * Set the Quad Enable (QE) bit in the Configuration Register.
@@ -1948,8 +2003,10 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor 
*nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
-   .fixups = _fixups },
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB |
+   SPI_NOR_HAS_BP3)
+   .fixups = _fixups
+   },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -4207,6 +4264,13 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JED

[PATCH v8 0/4] mtd: spi-nor: add support for is25wp256 spi-nor flash

2019-08-13 Thread Sagar Shrikant Kadam
The patch series adds support for 32MiB spi-nor is25wp256 present on HiFive
Unleashed A00 board. The flash device gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY
from BFPT table for address width, whereas the flash can support 4 byte
address width, so the address width is configured by using the post bfpt
fixup hook as done for is25lp256 device in
commit cf580a924005 ("mtd: spi-nor: fix nor->addr_width when its value
configured from SFDP does not match the actual width") 

Patches 1 and 3 are based on original work done by Wesley Terpstra and/or
Palmer Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and
flash utils (v1.5.2):
1. mtd_debug: Options available are : erase/read/write.
2. flashcp  : Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock : Unlock flash memory blocks. Arguments: are offset and number 
of blocks.
3. flash_lock   : Lock flash memory blocks. Arguments: are offset and number of 
blocks. 

The Unlock scheme clears the protection bits of all blocks in the Status 
register.

Lock scheme:
A basic implementation based on the stm_lock scheme and is validated for a 
different
number of blocks passed to flash_lock. ISSI devices have top/bottom area 
selection
in function register which is OTP memory so we are not updating the OTP section
of function register.

The changes along are available under branch dev/sagark/spi-nor-v8 at:
https://github.com/sagsifive/riscv-linux-hifive 
 
Revision history:
V7<->V8:
-Rebased this series on mainline v5.3-rc4.
-Removed func_reg reference from issi_lock as updating OTP region was dropped 
as part of V6.
-Updated Reviewed-By tags to 1st and 2nd patch.

V6<->V7:
-Incorporated review comments from Vignesh.
-Used post bfpt fixup hook as suggested by Vignesh.
-Introduce SPI_NOR_HAS_BP3 to identify whether the flash has 4th bit protect 
bit.
-Prefix generic flash access functions with spi_nor_.

V5<->V6:
-Incorporated review comments from Vignesh.
-Set addr width based on device size and if SPI_NOR_4B_OPCODES is set.
-Added 4th block protect identifier (SPI_NOR_HAS_BP3) to flash_info structure 
-Changed flash_info: flag from u16 to u32 to accommodate SPI_NOR_HAS_BP3
-Prefix newly added function with spi_nor_xxx.
-Dropped write_fr function, as updating OTP bit's present in function register 
doesn't seem to be a good idea.
-Set lock/unlock schemes based on whether the ISSI device has locking support 
and  BP3 bit present.

V4<->V5:
-Rebased to linux version v5.2-rc1.
-Updated heading of this cover letter with sub-system, instead of just plain 
"add support for is25wp256..."

V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5.
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device.
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.


Sagar Shrikant Kadam (4):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: fix nor->addr_width for is25wp256
  mtd: spi-nor: add support to unlock the flash device
  mtd: spi-nor: add locking support for is25wp256 device

 drivers/mtd/spi-nor/spi-nor.c | 342 +++---
 include/linux/mtd/spi-nor.h   |   8 +
 2 files changed, 299 insertions(+), 51 deletions(-)

-- 
1.9.1



[PATCH v7 2/4] mtd: spi-nor: fix nor->addr_width for is25wp256

2019-07-02 Thread Sagar Shrikant Kadam
Use the post bfpt fixup hook for the is25wp256 device as done for
is25lp256 device to overwrite the address width advertised by BFPT.

For instance the standard devices eg: IS25WP256D-JMLE where J stands
for "standard" does not support SFDP.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 971f0f3..315eeec 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1860,7 +1860,7 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES)
-   },
+   .fixups = _fixups },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-- 
1.9.1



[PATCH v7 3/4] mtd: spi-nor: add support to unlock the flash device

2019-07-02 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].
Add an identifier within the flash info structure to indicate that a
particular flash device has the fourth block protect bit (SPI_NOR_HAS_BP3).

Increase size of flash_info flags from u16 to u32 to avoid flag overflow
due SPI_NOR_HAS_BP3.
Clear block protection bits unlocks the flash memory regions.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

spell correction: "Configuration" in spansion_quad_enable function
description.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 72 ---
 include/linux/mtd/spi-nor.h   |  2 ++
 2 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 315eeec..4ed241d 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -250,7 +250,7 @@ struct flash_info {
u16 page_size;
u16 addr_width;
 
-   u16 flags;
+   u32 flags;
 #define SECT_4KBIT(0)  /* SPINOR_OP_BE_4K works 
uniformly */
 #define SPI_NOR_NO_ERASE   BIT(1)  /* No erase command needed */
 #define SST_WRITE  BIT(2)  /* use SST byte programming */
@@ -279,6 +279,13 @@ struct flash_info {
 #define SPI_NOR_SKIP_SFDP  BIT(13) /* Skip parsing of SFDP tables */
 #define USE_CLSR   BIT(14) /* use CLSR command */
 #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
+#define SPI_NOR_HAS_BP3BIT(16) /*
+* Flash SR has block protect bits
+* for lock/unlock purpose, few support
+* BP0-BP2 while few support BP0-BP3.
+* This flag identifies devices that
+* support BP3 bit.
+*/
 
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
@@ -1461,7 +1468,55 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
- * spansion_quad_enable() - set QE bit in Configuraiton Register.
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask;
+
+   if (nor->flags & SNOR_F_HAS_BP3)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
+ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI block protect bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
+ * spansion_quad_enable() - set QE bit in Configuration Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
  * Set the Quad Enable (QE) bit in the Configuration Register.
@@ -1859,8 +1914,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
-   .fixups = _fixups },
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB |
+   SPI_NOR_HAS_BP3)
+   .fixups = _fixups
+   },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -4110,6 +4167,13 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JEDEC_MFR(info) == SN

[PATCH v7 4/4] mtd: spi-nor: add locking support for is25wp256 device

2019-07-02 Thread Sagar Shrikant Kadam
Implement a locking scheme for ISSI devices based on the stm_lock scheme.
The is25wp256  device has 4 bits for selecting the range of blocks to
be locked/protected from erase/write operations and function register
gives feasibility to select the top / bottom area for protection.
Added opcode to read and write function registers.

The current implementation enables block protection as per the table
defined in the datasheet for the is25wp256 device having erase size of
0x1000. ISSI and stm devices differ in terms of TBS (top/bottom area
protection) bits. In case of issi this bit is in Function register and
is OTP memory, so once FR bits are programmed cannot be modified.

Some common code from stm_lock/unlock implementation is extracted so that
it can be re-used for issi devices. The locking scheme has been tested on
HiFive Unleashed board Rev A00  having is25wp256 flash memory.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 266 ++
 include/linux/mtd/spi-nor.h   |   5 +
 2 files changed, 223 insertions(+), 48 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4ed241d..847a848 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -295,6 +295,29 @@ struct flash_info {
 
 #define JEDEC_MFR(info)((info)->id[0])
 
+/**
+ * spi_nor_read_fr() - read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or negative if error.
+ */
+static int spi_nor_read_fr(struct spi_nor *nor)
+{
+   int ret;
+   u8 val;
+
+   ret = nor->read_reg(nor, SPINOR_OP_RDFR, , 1);
+   if (ret < 0) {
+   pr_err("error %d reading FR\n", ret);
+   return ret;
+   }
+
+   return val;
+}
+
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -1095,10 +1118,18 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
 uint64_t *len)
 {
struct mtd_info *mtd = >mtd;
-   u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-   int shift = ffs(mask) - 1;
+   u8 mask = 0;
+   u8 fr = 0;
+   int shift = 0;
int pow;
 
+   if (nor->flags & SNOR_F_HAS_BP3)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   shift = ffs(mask) - 1;
+
if (!(sr & mask)) {
/* No protection */
*ofs = 0;
@@ -1106,10 +1137,19 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
} else {
pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow;
-   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-   *ofs = 0;
-   else
-   *ofs = mtd->size - *len;
+   /* ISSI device's have top/bottom select bit in func reg */
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+   fr = spi_nor_read_fr(nor);
+   if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   } else {
+   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   }
}
 }
 
@@ -1136,18 +1176,108 @@ static int stm_check_lock_status_sr(struct spi_nor 
*nor, loff_t ofs, uint64_t le
return (ofs >= lock_offs + lock_len) || (ofs + len <= 
lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-   u8 sr)
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+   u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
- u8 sr)
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t 
len,
+ u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
+/**
+ * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
+ * @nor: pointer t

[PATCH v7 0/4] mtd: spi-nor: add support for is25wp256 spi-nor flash

2019-07-02 Thread Sagar Shrikant Kadam
The patch series adds support for 32MiB spi-nor is25wp256 present on HiFive
Unleashed A00 board. The flash device gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY
from BFPT table for address width, whereas the flash can support 4 byte
address width, so the address width is configured by using the post bfpt
fixup hook as done for is25lp256 device in
commit cf580a924005 ("mtd: spi-nor: fix nor->addr_width when its value
configured from SFDP does not match the actual width") queued in
spi-nor/next branch [1].

Patches 1 and 3 are based on original work done by Wesley Terpstra and/or
Palmer Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and
flash utils (v1.5.2):
1. mtd_debug: Options available are : erase/read/write.
2. flashcp  : Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock : Unlock flash memory blocks. Arguments: are offset and number 
of blocks.
3. flash_lock   : Lock flash memory blocks. Arguments: are offset and number of 
blocks. 

The Unlock scheme clears the protection bits of all blocks in the Status 
register.

Lock scheme:
A basic implementation based on the stm_lock scheme and is validated for a 
different
number of blocks passed to flash_lock. ISSI devices have top/bottom area 
selection
in function register which is OTP memory. so we are not updating the OTP section
of function register.

The changes along are available under branch v5.2-rc1-mtd-spi-nor/next at:
https://github.com/sagsifive/riscv-linux-hifive 
 
[1] 
https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git/log/?h=spi-nor/next

Revision history:
V6<->V7:
-Incorporated review comments from Vignesh.
-Used post bfpt fixup hook as suggested by Vignesh.
-Introduce SPI_NOR_HAS_BP3 to identify whether the flash has 4th bit protect 
bit.
-Prefix generic flash access functions with spi_nor_.

V5<->V6:
-Incorporated review comments from Vignesh.
-Set addr width based on device size and if SPI_NOR_4B_OPCODES is set.
-Added 4th block protect identifier (SPI_NOR_HAS_BP3) to flash_info structure 
-Changed flash_info: flag from u16 to u32 to accommodate SPI_NOR_HAS_BP3
-Prefix newly added function with spi_nor_xxx.
-Dropped write_fr function, as updating OTP bit's present in function register 
doesn't seem to be a good idea.
-Set lock/unlock schemes based on whether the ISSI device has locking support 
and  BP3 bit present.

V4<->V5:
-Rebased to linux version v5.2-rc1.
-Updated heading of this cover letter with sub-system, instead of just plain 
"add support for is25wp256..."

V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5.
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device.
-Add support for locking is25xxxxxx device.

v1:
-Add support for is25wp256 device.

Sagar Shrikant Kadam (4):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: fix nor->addr_width for is25wp256
  mtd: spi-nor: add support to unlock the flash device
  mtd: spi-nor: add locking support for is25wp256 device

 drivers/mtd/spi-nor/spi-nor.c | 343 +++---
 include/linux/mtd/spi-nor.h   |   8 +
 2 files changed, 300 insertions(+), 51 deletions(-)

-- 
1.9.1



[PATCH v7 1/4] mtd: spi-nor: add support for is25wp256

2019-07-02 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB) device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 9 -
 include/linux/mtd/spi-nor.h   | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index e3a28c0..971f0f3 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1857,7 +1857,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -3687,6 +3690,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
default:
/* Kept only for backward compatibility purpose. */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b..b0e42b3 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -21,6 +21,7 @@
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
 #define SNOR_MFR_SPANSION  CFI_MFR_AMD
 #define SNOR_MFR_SST   CFI_MFR_SST
-- 
1.9.1



[PATCH v6 2/3] mtd: spi-nor: add support to unlock flash device

2019-06-21 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].
Add identifier within flash info structure to indicate that a particular
flash device has the fourth block protect bit (SPI_NOR_HAS_BP3).
Increase size of flash_info flags from u16 to u32 to accommodate
SPI_NOR_HAS_BP3.

Clearing block protection bits, unlocks the flash memory regions
The unlock scheme is registered during nor scans.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

spell correction: "Configuration" in spansion_quad_enable function
description.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 66 ---
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index c816f0c..d165fcd 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -250,7 +250,7 @@ struct flash_info {
u16 page_size;
u16 addr_width;
 
-   u16 flags;
+   u32 flags;
 #define SECT_4KBIT(0)  /* SPINOR_OP_BE_4K works 
uniformly */
 #define SPI_NOR_NO_ERASE   BIT(1)  /* No erase command needed */
 #define SST_WRITE  BIT(2)  /* use SST byte programming */
@@ -279,6 +279,13 @@ struct flash_info {
 #define SPI_NOR_SKIP_SFDP  BIT(13) /* Skip parsing of SFDP tables */
 #define USE_CLSR   BIT(14) /* use CLSR command */
 #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
+#define SPI_NOR_HAS_BP3BIT(16) /*
+* Flash SR has block protect bits
+* for lock/unlock purpose, few support
+* BP0-BP2 while few support BP0-BP3.
+* This flag identifies devices that
+* support BP3 bit.
+*/
 
/* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups;
@@ -1461,7 +1468,50 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
- * spansion_quad_enable() - set QE bit in Configuraiton Register.
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
+ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI block protect bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
+ * spansion_quad_enable() - set QE bit in Configuration Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
  * Set the Quad Enable (QE) bit in the Configuration Register.
@@ -1834,9 +1884,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   { "is25wp256",  INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB |
+   SPI_NOR_HAS_BP3)
},
 
/* Macronix */
@@ -4080,6 +4131,13 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JEDEC_MFR(info) == SNOR_MFR_ISSI &&
+   info->flags & SPI_NOR_HAS_LOCK &&
+   info->flags & SPI_NOR_HA

[PATCH v6 3/3] mtd: spi-nor: add locking support for is25xxxxx device

2019-06-21 Thread Sagar Shrikant Kadam
Implement a locking scheme for ISSI devices based on stm_lock mechanism.
The is25x  devices have 4 bits for selecting the range of blocks to
be locked/protected from erase/write operations and function register
gives feasibility to select TOP / Bottom area for protection.
Added opcode to read and write function registers.

The current implementation enables block protection as per the table
defined into datasheet for is25wp256 device having erase size of 0x1000.
ISSI and stm devices differ in terms of TBS (Top/Bottom area protection)
bits. In case of issi this is in Function register and is OTP memory, so
once FR bits are programmed  cannot be modified.

Some common code from stm_lock/unlock implementation is extracted so that
it can be re-used for issi devices. The locking scheme has been tested on
HiFive Unleashed board, having is25wp256 flash memory.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 261 ++
 include/linux/mtd/spi-nor.h   |   6 +
 2 files changed, 217 insertions(+), 50 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index d165fcd..16735fc 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -295,6 +295,29 @@ struct flash_info {
 
 #define JEDEC_MFR(info)((info)->id[0])
 
+/**
+ * spi_nor_read_fr() -read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or negative if error.
+ */
+static int spi_nor_read_fr(struct spi_nor *nor)
+{
+   int ret;
+   u8 val;
+
+   ret = nor->read_reg(nor, SPINOR_OP_RDFR, , 1);
+   if (ret < 0) {
+   pr_err("error %d reading FR\n", ret);
+   return ret;
+   }
+
+   return val;
+}
+
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -1095,10 +1118,18 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
 uint64_t *len)
 {
struct mtd_info *mtd = >mtd;
-   u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-   int shift = ffs(mask) - 1;
+   u8 mask = 0;
+   u8 fr = 0;
+   int shift = 0;
int pow;
 
+   if (nor->flags & SNOR_F_HAS_BP3)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   shift = ffs(mask) - 1;
+
if (!(sr & mask)) {
/* No protection */
*ofs = 0;
@@ -1106,10 +1137,19 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
} else {
pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow;
-   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-   *ofs = 0;
-   else
-   *ofs = mtd->size - *len;
+   /* ISSI device's have top/bottom select bit in func reg */
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+   fr = spi_nor_read_fr(nor);
+   if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   } else {
+   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   }
}
 }
 
@@ -1136,18 +1176,108 @@ static int stm_check_lock_status_sr(struct spi_nor 
*nor, loff_t ofs, uint64_t le
return (ofs >= lock_offs + lock_len) || (ofs + len <= 
lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
-   u8 sr)
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+   u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
- u8 sr)
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t 
len,
+ u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, false);
 }
 
+/**
+ * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
+ * @nor: pointer to a 'struct spi_nor'.
+ 

[PATCH v6 1/3] mtd: spi-nor: add support for is25wp256

2019-06-21 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB) device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table. Set address width to 4byte if device supports 4Byte opcode and
it's size is greater than 16MiB.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 19 +++
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 73172d7..c816f0c 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1834,6 +1834,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
 
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -3652,6 +3656,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_MACRONIX:
params->quad_enable = macronix_quad_enable;
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
@@ -4129,13 +4137,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret)
return ret;
 
-   if (nor->addr_width) {
+   if (info->flags & SPI_NOR_4B_OPCODES && mtd->size > 0x100) {
+   /*
+* enable 4-byte addressing if device supports it and
+* its size exceeds 16MiB.
+*/
+   nor->addr_width = 4;
+   } else if (nor->addr_width) {
/* already configured from SFDP */
} else if (info->addr_width) {
nor->addr_width = info->addr_width;
-   } else if (mtd->size > 0x100) {
-   /* enable 4-byte addressing if the device exceeds 16MiB */
-   nor->addr_width = 4;
} else {
nor->addr_width = 3;
}
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b..ff13297 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -19,6 +19,7 @@
 #define SNOR_MFR_ATMEL CFI_MFR_ATMEL
 #define SNOR_MFR_GIGADEVICE0xc8
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
-- 
1.9.1



[PATCH v6 0/3] mtd: spi-nor: add support for is25wp256 spi-nor flash

2019-06-21 Thread Sagar Shrikant Kadam
The patch set is tested on HiFive Unleashed A00 board and is based on
mainline kernel v5.2-rc1. Its intended to add support for 32 MB spi-nor
flash mounted on the board. Memory Device supports 4/32/ and 64 KB sectors
size. The device id table is updated accordingly.

Flash parameter table for ISSI device is set to use macronix_quad_enable
procedure to set the QE (quad-enable) bit of Status register.

A unilaterlay block unlocking scheme is added in patch 2.

These patches are based on original work done by Wesley Terpstra and/or
Palmer Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and flash utils (v1.5.2):
1. mtd_debug:Options available are : erase/read/write.
2. flashcp  :Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock: Unlock flash memory blocks.Arguments: are offset and number of 
blocks.
3. flash_lock:   Lock flash memory blocks. Arguments: are offset and number of 
blocks. 

Unlock scheme clears the protection bits of all blocks in the Status register.

Lock scheme:
A basic implementation based on stm_lock scheme and is validated for different 
number of blocks passed
to flash_lock. ISSI devices have top/bottom area selection in "function 
register" which is OTP memory.

The changes along with other relevant patches are available under 
branch dev/sagark/spi-nor_v5.2-rc1 at:
https://github.com/sagsifive/riscv-linux-hifive 
 

Revision history:
V5<->V6:
-Incorporated review comments from Vignesh.
-Set addr width based on device size and if SPI_NOR_4B_OPCODES is set.
-Added 4th block protect identifier (SPI_NOR_HAS_BP3) to flash_info structure 
-Changed flash_info: flag from u16 to u32 to accommodate SPI_NOR_HAS_BP3
-Prefix newly added function with spi_nor_xxx.
-Dropped write_fr function, as updating OTP bit's present in function register 
doesn't seem to be a good idea.
-Set lock/unlock schemes based on whether the ISSI device has locking support 
and  BP3 bit present.

V4<->V5:
-Rebased to linux version v5.2-rc1.
-Updated heading of this cover letter with sub-system, instead of just plain 
"add support for is25wp256..."

V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5.
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device.
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.


Sagar Shrikant Kadam (3):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: add support to unlock flash device
  mtd: spi-nor: add locking support for is25x device

 drivers/mtd/spi-nor/spi-nor.c | 342 +++---
 include/linux/mtd/spi-nor.h   |   8 +
 2 files changed, 294 insertions(+), 56 deletions(-)

-- 
1.9.1



[PATCH v5 0/3] mtd: spi-nor: add support for is25wp256 spi-nor flash

2019-06-12 Thread Sagar Shrikant Kadam
The patch set is tested on HiFive Unleashed A00 board and is based on mainline
kernel v5.2-rc1. Its intended to add support for 32 MB spi-nor flash
mounted on the board. Memory Device supports 4/32/ and 64 KB sectors size.
The device id table is updated accordingly.

Flash parameter table for ISSI device is set to use macronix_quad_enable
procedure to set the QE (quad-enable) bit of Status register.

A unilaterlay block unlocking scheme is added in patch 2.

These patches are based on original work done by Wesley Terpstra and/or Palmer 
Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and flash utils (v1.5.2):
1. mtd_debug:Options available are : erase/read/write.
2. flashcp  :Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock: Unlock flash memory blocks.Arguments: are offset and number of 
blocks.
3. flash_lock:   Lock flash memory blocks. Arguments: are offset and number of 
blocks. 

Unlock scheme clears the protection bits of all blocks in the Status register.

Lock scheme:
A basic implementation based on stm_lock scheme and is validated for different 
number of blocks passed
to flash_lock. ISSI devices have Top/Bottom area selection in "function 
register" which is OTP memory.
 

Revision history:

V4<->V5:
-Rebased to linux version v5.2-rc1.
-Updated heading of this cover letter with sub-system, instead of just plain 
"add support for is25wp256..."

V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5.
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device.
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.


Sagar Shrikant Kadam (3):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: add support to unlock flash device
  mtd: spi-nor: add locking support for is25x device

 drivers/mtd/spi-nor/spi-nor.c | 348 +++---
 include/linux/mtd/spi-nor.h   |   7 +
 2 files changed, 304 insertions(+), 51 deletions(-)

-- 
1.9.1



[PATCH v5 1/3] mtd: spi-nor: add support for is25wp256

2019-06-12 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB)device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 10 +-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 73172d7..2d5a925 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1834,6 +1834,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
 
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -3652,6 +3656,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_MACRONIX:
params->quad_enable = macronix_quad_enable;
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
@@ -4129,7 +4137,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret)
return ret;
 
-   if (nor->addr_width) {
+   if (nor->addr_width && JEDEC_MFR(info) != SNOR_MFR_ISSI) {
/* already configured from SFDP */
} else if (info->addr_width) {
nor->addr_width = info->addr_width;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b..ff13297 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -19,6 +19,7 @@
 #define SNOR_MFR_ATMEL CFI_MFR_ATMEL
 #define SNOR_MFR_GIGADEVICE0xc8
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
-- 
1.9.1



[PATCH v5 2/3] mtd: spi-nor: add support to unlock flash device

2019-06-12 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].

Clearing block protection bits,unlocks the flash memory regions
The unlock scheme is registered during nor scans.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 51 ++-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 2d5a925..b7c6261 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1461,6 +1461,49 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev,
+   "ISSI Block Protection Bits cleared SR=0x%x", ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI Block Protection Bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
  * spansion_quad_enable() - set QE bit in Configuraiton Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
@@ -1836,7 +1879,7 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK)
},
 
/* Macronix */
@@ -4080,6 +4123,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JEDEC_MFR(info) == SNOR_MFR_ISSI ||
+   info->flags & SPI_NOR_HAS_LOCK) {
+   nor->flash_unlock = issi_unlock;
+
+   }
if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ff13297..9a7d719 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -127,6 +127,7 @@
 #define SR_BP0 BIT(2)  /* Block protect 0 */
 #define SR_BP1 BIT(3)  /* Block protect 1 */
 #define SR_BP2 BIT(4)  /* Block protect 2 */
+#define SR_BP3 BIT(5)  /* Block protect 3 for ISSI device*/
 #define SR_TB  BIT(5)  /* Top/Bottom protect */
 #define SR_SRWDBIT(7)  /* SR write protect */
 /* Spansion/Cypress specific status bits */
-- 
1.9.1



[PATCH v5 3/3] mtd: spi-nor: add locking support for is25xxxxx device

2019-06-12 Thread Sagar Shrikant Kadam
Implement a locking scheme for ISSI devices based on stm_lock mechanism.
The is25x  devices have 4 bits for selecting the range of blocks to
be locked/protected from erase/write operations and function register
gives feasibility to select TOP / Bottom area for protection.
Added opcodes to read and write function registers.

The current implementation enables block protection as per the table
defined into datasheet for is25wp256 device having erase size of 0x1000.
ISSI and stm devices differ in terms of TBS (Top/Bottom area protection)
bits. In case of issi this is in Function register and is OTP memory, so
once FR bits are programmed  cannot be modified.

Some common code from stm_lock/unlock implementation is extracted so that
it can be re-used for issi devices. The locking scheme has been tested on
HiFive Unleashed board, having is25wp256 flash memory.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 291 ++
 include/linux/mtd/spi-nor.h   |   5 +
 2 files changed, 245 insertions(+), 51 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index b7c6261..9281ec0 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -288,6 +288,45 @@ struct flash_info {
 
 #define JEDEC_MFR(info)((info)->id[0])
 
+/**
+ * read_fr() -read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg.The bits in FR are OTP.So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or Negative if error.
+ */
+static int read_fr(struct spi_nor *nor)
+{
+   int ret;
+   u8 val;
+
+   ret = nor->read_reg(nor, SPINOR_OP_RDFR, , 1);
+   if (ret < 0) {
+   pr_err("error %d reading FR\n", (int) ret);
+   return ret;
+   }
+
+   return val;
+}
+
+/**
+ * write_fr() -Write function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area selection protection bits into function
+ * reg whereas other devices have the TBS bit into Status Register.
+ * The bits in FR are OTP.So once it's written, it cannot be changed.
+ *
+ * Return: Negative if error
+ */
+static int write_fr(struct spi_nor *nor, u8 val)
+{
+   nor->cmd_buf[0] = val;
+   return nor->write_reg(nor, SPINOR_OP_WRFR, nor->cmd_buf, 1);
+}
+
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -1088,10 +1127,17 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
 uint64_t *len)
 {
struct mtd_info *mtd = >mtd;
-   u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-   int shift = ffs(mask) - 1;
+   u8 mask = 0;
+   int shift = 0;
int pow;
 
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   shift = ffs(mask) - 1;
+
if (!(sr & mask)) {
/* No protection */
*ofs = 0;
@@ -1099,10 +1145,19 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
} else {
pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow;
-   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-   *ofs = 0;
-   else
-   *ofs = mtd->size - *len;
+
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+   if (nor->flags & SNOR_F_HAS_SR_TB &&
+   (read_fsr(nor) & FR_TB))
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   } else {
+   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   }
}
 }
 
@@ -1129,18 +1184,108 @@ static int stm_check_lock_status_sr(struct spi_nor 
*nor, loff_t ofs, uint64_t le
return (ofs >= lock_offs + lock_len) || (ofs + len <= 
lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int fl_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locke

[PATCH REPOST v8 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-06-01 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
Reviewed-by: Andrew Lunn 
---
 drivers/i2c/busses/i2c-ocores.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..4117f1a 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+   unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -84,6 +85,8 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -353,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -595,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -677,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH REPOST v8 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-06-01 Thread Sagar Shrikant Kadam
Reformatted compatibility strings to one valid combination on
each line.
Add FU540-C000 specific device tree bindings to already available
i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt under optional
property list as this can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..6b25a80 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible  : "opencores,i2c-ocores"
+"aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c", "sifive,i2c0"
+For Opencore based I2C IP block reimplemented in
+FU540-C000 SoC. Please refer to 
sifive-blocks-ip-versioning.txt
+for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH REPOST v8 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-06-01 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.2-rc1 and extends DT-bindings for Opencore 
based I2C IP block reimplemented
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets.

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and BUSY flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and
appropriate device node is added into board specific device tree as per the 
information provided in
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-ocores.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
V7<->V8:
-Incorporated review comments for cosmetic changes like: space, comma and 
period(.)

V6<->V7:
-Rectified space and tab issue in dt bindings strings.
-Implemented workaround based on i2c->flags, as per review comment on v6.

V5<->V6:
-Incorporated suggestions on v5 patch as follows:
-Reformatted compatibility strings in dt doc with one valid combination on each 
line.
-Removed interrupt-parents from optional property list. 
-With rebase to v5.2-rc1, the v5 variant of polling workaround PATCH becomes 
in-compatible.
 Till kernel v5.1 the polling mode was enabled based on i2c->flags, wherease in 
kernel v5.2-rc1 polling mode is set as
 master transfer algorithim at probe time itself, and i2c->flags checks are 
removed.
-Modified v5 to check for SiFive device type in polling function and include 
the workaround/fix for broken IRQ.

v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.


Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  9 --
 drivers/i2c/busses/i2c-ocores.c| 33 --
 2 files changed, 38 insertions(+), 4 deletions(-)

-- 
1.9.1



[PATCH REPOST v8 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-06-01 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee..b334fa2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -82,6 +82,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -462,6 +463,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH REPOST v8 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-31 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
Acked-by: Andrew Lunn 
---
 drivers/i2c/busses/i2c-ocores.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..4117f1a 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+   unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -84,6 +85,8 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -353,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -595,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -677,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH REPOST v8 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-31 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.2-rc1 and extends DT-bindings for Opencore 
based I2C IP block reimplemented
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets.

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and BUSY flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and
appropriate device node is added into board specific device tree as per the 
information provided in
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-ocores.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
V7<->V8:
-Incorporated review comments for cosmetic changes like: space, comma and 
period(.)

V6<->V7:
-Rectified space and tab issue in dt bindings strings.
-Implemented workaround based on i2c->flags, as per review comment on v6.

V5<->V6:
-Incorporated suggestions on v5 patch as follows:
-Reformatted compatibility strings in dt doc with one valid combination on each 
line.
-Removed interrupt-parents from optional property list. 
-With rebase to v5.2-rc1, the v5 variant of polling workaround PATCH becomes 
in-compatible.
 Till kernel v5.1 the polling mode was enabled based on i2c->flags, wherease in 
kernel v5.2-rc1 polling mode is set as
 master transfer algorithim at probe time itself, and i2c->flags checks are 
removed.
-Modified v5 to check for SiFive device type in polling function and include 
the workaround/fix for broken IRQ.

v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.


Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  9 --
 drivers/i2c/busses/i2c-ocores.c| 33 --
 2 files changed, 38 insertions(+), 4 deletions(-)

-- 
1.9.1



[PATCH REPOST v8 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-31 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee..b334fa2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -82,6 +82,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -462,6 +463,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH REPOST v8 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-31 Thread Sagar Shrikant Kadam
Reformatted compatibility strings to one valid combination on
each line.
Add FU540-C000 specific device tree bindings to already available
i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt under optional
property list as this can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..6b25a80 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible  : "opencores,i2c-ocores"
+"aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c", "sifive,i2c0"
+For Opencore based I2C IP block reimplemented in
+FU540-C000 SoC. Please refer to 
sifive-blocks-ip-versioning.txt
+for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v8 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-28 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..4117f1a 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+   unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -84,6 +85,8 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -353,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -595,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -677,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH v8 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-28 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.2-rc1 and extends DT-bindings for Opencore 
based I2C IP block reimplemented
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets.

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and BUSY flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and
appropriate device node is added into board specific device tree as per the 
information provided in
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-ocores.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
V7<->V8:
-Incorporated review comments for cosmetic changes like: space, comma and 
period(.)

V6<->V7:
-Rectified space and tab issue in dt bindings strings.
-Implemented workaround based on i2c->flags, as per review comment on v6.

V5<->V6:
-Incorporated suggestions on v5 patch as follows:
-Reformatted compatibility strings in dt doc with one valid combination on each 
line.
-Removed interrupt-parents from optional property list. 
-With rebase to v5.2-rc1, the v5 variant of polling workaround PATCH becomes 
in-compatible.
 Till kernel v5.1 the polling mode was enabled based on i2c->flags, wherease in 
kernel v5.2-rc1 polling mode is set as
 master transfer algorithim at probe time itself, and i2c->flags checks are 
removed.
-Modified v5 to check for SiFive device type in polling function and include 
the workaround/fix for broken IRQ.

v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.

Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  9 --
 drivers/i2c/busses/i2c-ocores.c| 33 --
 2 files changed, 38 insertions(+), 4 deletions(-)

-- 
1.9.1



[PATCH v8 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-28 Thread Sagar Shrikant Kadam
Reformatted compatibility strings to one valid combination on
each line.
Add FU540-C000 specific device tree bindings to already available
i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt under optional
property list as this can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..6b25a80 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible  : "opencores,i2c-ocores"
+"aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c", "sifive,i2c0"
+For Opencore based I2C IP block reimplemented in
+FU540-C000 SoC. Please refer to 
sifive-blocks-ip-versioning.txt
+for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v8 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-28 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee..b334fa2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -82,6 +82,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -462,6 +463,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v8 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-28 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..4117f1a 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+   unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -84,6 +85,8 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -353,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -595,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -677,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH v7 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-22 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..4117f1a 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -35,6 +35,7 @@ struct ocores_i2c {
int iobase;
u32 reg_shift;
u32 reg_io_width;
+   unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
@@ -84,6 +85,8 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -353,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -595,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -677,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
+
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH v7 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-22 Thread Sagar Shrikant Kadam
Reformatted compatibility strings to one valid combination on
each line.
Add FU540-C000 specific device tree bindings to already available
i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt under optional
property list as this can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..db96951 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible  : "opencores,i2c-ocores",
+"aeroflexgaisler,i2cmst",
+"sifive,fu540-c000-i2c","sifive,i2c0".
+For Opencore based I2C IP block reimplemented in
+FU540-C000 SoC.Please refer sifive-blocks-ip-versioning.txt
+for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v7 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-22 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee..b334fa2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -82,6 +82,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -462,6 +463,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v7 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-22 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.2-rc1 and extends DT-bindings for Opencore 
based I2C IP block reimplemented
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets.

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and BUSY flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and
appropriate device node is added into board specific device tree as per the 
information provided in
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-ocores.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
V6<->V7:
-Rectified space and tab issue in dt bindings strings.
-Implemented workaround based on i2c->flags, as per review comment on v6.

V5<->V6:
-Incorporated suggestions on v5 patch as follows:
-Reformatted compatibility strings in dt doc with one valid combination on each 
line.
-Removed interrupt-parents from optional property list. 
-With rebase to v5.2-rc1, the v5 variant of polling workaround PATCH becomes 
in-compatible.
 Till kernel v5.1 the polling mode was enabled based on i2c->flags, wherease in 
kernel v5.2-rc1 polling mode is set as
 master transfer algorithim at probe time itself, and i2c->flags checks are 
removed.
-Modified v5 to check for SiFive device type in polling function and include 
the workaround/fix for broken IRQ.

v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.



Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  9 --
 drivers/i2c/busses/i2c-ocores.c| 33 --
 2 files changed, 38 insertions(+), 4 deletions(-)

-- 
1.9.1



[PATCH v6 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-21 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:
commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

The polling function identifies a SiFive device based on the device node
and enables the workaround.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 38 +-
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index b334fa2..3175c72 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -84,6 +84,10 @@ struct ocores_i2c {
 #define TYPE_GRLIB 1
 #define TYPE_SIFIVE_REV0   2
 
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
+
+static const struct of_device_id ocores_i2c_match[];
+
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
iowrite8(value, i2c->base + (reg << i2c->reg_shift));
@@ -236,9 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (irq == OCORES_FLAG_BROKEN_IRQ) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -340,6 +348,10 @@ static int ocores_poll_wait(struct ocores_i2c *i2c)
  */
 static void ocores_process_polling(struct ocores_i2c *i2c)
 {
+   const struct of_device_id *match;
+
+   match = of_match_node(ocores_i2c_match, i2c->adap.dev.of_node);
+
while (1) {
irqreturn_t ret;
int err;
@@ -350,9 +362,25 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
break; /* timeout */
}
 
-   ret = ocores_isr(-1, i2c);
-   if (ret == IRQ_NONE)
-   break; /* all messages have been transferred */
+   /*
+* If it's a SiFive Device(FU540-C000 SoC ) use
+* OCORES_FLAG_BROKEN_IRQ to enable workaround in
+* polling mode.
+*/
+   if (match && (long)match->data == TYPE_SIFIVE_REV0) {
+   ret = ocores_isr(OCORES_FLAG_BROKEN_IRQ, i2c);
+   if (ret == IRQ_NONE)
+   break; /* all messages have been transferred */
+   else
+   if (i2c->state == STATE_DONE)
+   break;
+   } else {
+   ret = ocores_isr(-1, i2c);
+   if (ret == IRQ_NONE)
+   break; /* all messages have been transferred */
+
+   }
+
}
 }
 
-- 
1.9.1



[PATCH v6 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-21 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index c3dabee..b334fa2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -82,6 +82,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -462,6 +463,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v6 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-21 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.2-rc1 and extends DT-bindings for Opencore 
based I2C IP block reimplemented 
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets. 

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and BUSY flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and 
appropriate device node is added into board specific device tree as per the 
information provided in 
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-sifive.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
V5<->V6:
-Incorporated suggestions on v5 patch as follows:
-Reformatted compatibility strings in dt doc with one valid combination on each 
line.
-Removed interrupt-parents from optional property list. 
-With rebase to v5.2-rc1, the v5 variant of polling workaround PATCH becomes 
in-compatible.
 Till kernel v5.1 the polling mode was enabled based on i2c->flags, wherease in 
kernel v5.2-rc1 polling mode is set as
 master transfer algorithim at probe time itself, and i2c->flags checks are 
removed.
-Modified v5 to check for SiFive device type in polling function and include 
the workaround/fix for broken IRQ.

v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.



Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  9 -
 drivers/i2c/busses/i2c-ocores.c| 47 +++---
 2 files changed, 49 insertions(+), 7 deletions(-)

-- 
1.9.1



[PATCH v6 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-21 Thread Sagar Shrikant Kadam
Reformatted compatibility strings to one valid combination on
each line.
Add FU540-C000 specific device tree bindings to already available
i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt under optional
property list as this can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..6ac062c 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -1,9 +1,13 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+- compatible  : "opencores,i2c-ocores",
+   "aeroflexgaisler,i2cmst",
+"sifive,fu540-c000-i2c","sifive,i2c0".
+   For Opencore based I2C IP block reimplemented in
+   FU540-C000 SoC.Please refer sifive-blocks-ip-versioning.txt
+   for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +16,7 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v5 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-20 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 4e1a077..aee1d86 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -85,6 +85,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -468,6 +469,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v5 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-20 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:previous polling mode support in mainline

commit 69c8c0c0efa8 ("i2c: ocores: add polling interface")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 22 --
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index aee1d86..c3bc97d 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -27,6 +27,7 @@
 #include 
 
 #define OCORES_FLAG_POLL BIT(0)
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
 
 /*
  * 'process_lock' exists because ocores_process() and ocores_process_timeout()
@@ -239,9 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -356,6 +361,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -601,6 +611,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -683,6 +694,13 @@ static int ocores_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
i2c->flags |= OCORES_FLAG_POLL;
+   /*
+* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
-- 
1.9.1



[PATCH v5 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-20 Thread Sagar Shrikant Kadam
Add FU540-C000 specific device tree bindings to already
available i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt and interrupt
parents under optional property list as these can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..b73960e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -2,8 +2,11 @@ Device tree configuration for i2c-ocores
 
 Required properties:
 - compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c" or "sifive,i2c0".
+   for Opencore based I2C IP block reimplemented in
+   FU540-C000 SoC.Please refer sifive-blocks-ip-versioning.txt
+   for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +15,8 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupt-parent: handle to interrupt controller.
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v5 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-20 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.1 and extends DT-bindings for Opencore based 
I2C IP block reimplemented 
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets. 

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and TIP flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and 
appropriate device node is added into board specific device tree as per the 
information provided in 
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-sifive.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:
v4<->V5:
-Removed un-necessary checks of OCORES_FLAG_BROKEN_IRQ.

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.



Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt |  7 -
 drivers/i2c/busses/i2c-ocores.c| 31 --
 2 files changed, 35 insertions(+), 3 deletions(-)

-- 
1.9.1



[PATCH v4 2/3] i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-20 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 4e1a077..aee1d86 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -85,6 +85,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -468,6 +469,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v4 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-20 Thread Sagar Shrikant Kadam
Add FU540-C000 specific device tree bindings to already
available i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt and interrupt
parents under optional property list as these can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..b73960e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -2,8 +2,11 @@ Device tree configuration for i2c-ocores
 
 Required properties:
 - compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c" or "sifive,i2c0".
+   for Opencore based I2C IP block reimplemented in
+   FU540-C000 SoC.Please refer sifive-blocks-ip-versioning.txt
+   for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +15,8 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupt-parent: handle to interrupt controller.
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v4 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC

2019-05-20 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:previous polling mode support in mainline

commit 69c8c0c0efa8 ("i2c: ocores: add polling interface")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 31 ++-
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index aee1d86..e0d7f24 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -27,6 +27,7 @@
 #include 
 
 #define OCORES_FLAG_POLL BIT(0)
+#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
 
 /*
  * 'process_lock' exists because ocores_process() and ocores_process_timeout()
@@ -239,9 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -356,6 +361,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -406,7 +416,7 @@ static int ocores_xfer(struct i2c_adapter *adap,
 {
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
 
-   if (i2c->flags & OCORES_FLAG_POLL)
+   if ((i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ)))
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
 }
@@ -601,6 +611,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -682,13 +693,23 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
-   i2c->flags |= OCORES_FLAG_POLL;
+   /*
+* Set a OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode interface of i2c-ocore driver.
+* Else enable default polling mode interface for SIFIVE/OCORE
+* device types.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+   else
+   i2c->flags |= OCORES_FLAG_POLL;
} else {
if (irq < 0)
return irq;
}
 
-   if (!(i2c->flags & OCORES_FLAG_POLL)) {
+   if (!(i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ))) {
ret = devm_request_irq(>dev, irq, ocores_isr, 0,
   pdev->name, i2c);
if (ret) {
-- 
1.9.1



[PATCH v4 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-20 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.1 and extends DT-bindings for Opencore based 
I2C IP block reimplemented 
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets. 

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and TIP flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and 
appropriate device node is added into board specific device tree as per the 
information provided in 
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-sifive.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:

V3<->V4:
-Incorporated suggestions on v3 patch as follows:
-OCORES_FLAG_BROKEN_IRQ BIT position rectified.
-Updated BORKEN_IRQ flag checks such that if sifive device (Fu540-C000) is 
identified,then use polling mode as IRQ is broken.

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.

Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocores: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC

 .../devicetree/bindings/i2c/i2c-ocores.txt |  7 +++-
 drivers/i2c/busses/i2c-ocores.c| 40 +++---
 2 files changed, 41 insertions(+), 6 deletions(-)

-- 
1.9.1



[PATCH v3 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC

2019-05-15 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

Ref:previous polling mode support in mainline

commit 69c8c0c0efa8 ("i2c: ocores: add polling interface")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 34 --
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index aee1d86..00ee45c 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -27,6 +27,7 @@
 #include 
 
 #define OCORES_FLAG_POLL BIT(0)
+#define OCORES_FLAG_BROKEN_IRQ BIT(2) /* Broken IRQ in HiFive Unleashed */
 
 /*
  * 'process_lock' exists because ocores_process() and ocores_process_timeout()
@@ -239,9 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
-
+   }
ocores_process(i2c, stat);
 
return IRQ_HANDLED;
@@ -356,6 +361,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -406,7 +416,7 @@ static int ocores_xfer(struct i2c_adapter *adap,
 {
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
 
-   if (i2c->flags & OCORES_FLAG_POLL)
+   if ((i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ)))
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
 }
@@ -471,7 +481,7 @@ static u32 ocores_func(struct i2c_adapter *adap)
},
{
.compatible = "sifive,fu540-c000-i2c",
-   .data = (void *)TYPE_SIFIVE_REV0,
+   .data = (void *)(TYPE_SIFIVE_REV0 | OCORES_FLAG_BROKEN_IRQ),
},
{
.compatible = "sifive,i2c0",
@@ -601,6 +611,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -682,13 +693,24 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
-   i2c->flags |= OCORES_FLAG_POLL;
+   /*
+* Set a OCORES_FLAG_BROKEN_IRQ to enable workaround for
+* FU540-C000 SoC in polling mode interface of i2c-ocore driver.
+* Else enable default polling mode interface for SIFIVE/OCORE
+* device types.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data ==
+   (TYPE_SIFIVE_REV0 | OCORES_FLAG_BROKEN_IRQ))
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+   else
+   i2c->flags |= OCORES_FLAG_POLL;
} else {
if (irq < 0)
return irq;
}
 
-   if (!(i2c->flags & OCORES_FLAG_POLL)) {
+   if (!(i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ))) {
ret = devm_request_irq(>dev, irq, ocores_isr, 0,
   pdev->name, i2c);
if (ret) {
-- 
1.9.1



[PATCH v3 2/3] i2c-ocore: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-15 Thread Sagar Shrikant Kadam
Update device id table for Opencore's I2C master based re-implementation
used in FU540-c000 chipset on HiFive Unleashed platform.

Device ID's include Sifive, soc-specific device for chip specific tweaks
and sifive IP block specific device for generic programming model.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 4e1a077..aee1d86 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -85,6 +85,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -468,6 +469,14 @@ static u32 ocores_func(struct i2c_adapter *adap)
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
+   {
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
+   .compatible = "sifive,i2c0",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
{},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-- 
1.9.1



[PATCH v3 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-15 Thread Sagar Shrikant Kadam
Add FU540-C000 specific device tree bindings to already
available i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board. Move interrupt and interrupt
parents under optional property list as these can be optional.

The FU540-C000 SoC from sifive, has an Opencore's I2C block
reimplementation.

The DT compatibility string for this IP is present in HDL and available at.
https://github.com/sifive/sifive-blocks/blob/master/src/main/scala/devices/i2c/I2C.scala#L73

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..b73960e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -2,8 +2,11 @@ Device tree configuration for i2c-ocores
 
 Required properties:
 - compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c" or "sifive,i2c0".
+   for Opencore based I2C IP block reimplemented in
+   FU540-C000 SoC.Please refer sifive-blocks-ip-versioning.txt
+   for additional details.
 - reg : bus address start and address range size of device
-- interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
 Mutually exclusive with opencores,ip-clock-frequency
 - opencores,ip-clock-frequency: frequency of the controller clock in Hz;
@@ -12,6 +15,8 @@ Required properties:
 - #size-cells : should be <0>
 
 Optional properties:
+- interrupt-parent: handle to interrupt controller.
+- interrupts  : interrupt number.
 - clock-frequency : frequency of bus clock in Hz; see the note below.
 Defaults to 100 KHz when the property is not specified
 - reg-shift   : device register offsets are shifted by this value
-- 
1.9.1



[PATCH v3 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-15 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.1 and extends DT-bindings for Opencore based 
I2C IP block reimplemented 
in FU540 SoC, available on HiFive unleashed board (Rev A00), and also provides 
a workaround for broken IRQ
which affects the already available I2C polling mode interface in mainline, for 
FU540-C000 chipsets. 

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and TIP flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and 
appropriate device node is added into board specific device tree as per the 
information provided in 
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-sifive.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:

V2<->V3:
-Incorporated review comments on v2 patch as follows:
-Rectified compatibility string sequence with the most specific one at the 
first (dt bindings). 
-Moved interrupts and interrupt-parent under optional property list 
(dt-bindings).
-Updated reference to sifive-blocks-ip-versioning.txt and URL to IP repository 
used (dt-bindings).
-Removed example for i2c0 device node from binding doc (dt-bindings).
-Included sifive,i2c0 device under compatibility table in i2c-ocores driver 
(i2c-ocores).
-Updated polling mode hooks for SoC specific fix to handle broken IRQ 
(i2c-ocores).


V1<->V2:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V1:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.

Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocore: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC

 .../devicetree/bindings/i2c/i2c-ocores.txt |  7 +++-
 drivers/i2c/busses/i2c-ocores.c| 41 +++---
 2 files changed, 42 insertions(+), 6 deletions(-)

-- 
1.9.1



[PATCH v4 2/3] mtd: spi-nor: add support to unlock flash device.

2019-05-11 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].

Clearing block protection bits,unlocks the flash memory regions
The unlock scheme is registered during nor scans.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 51 ++-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index c5408ed..3942b26 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1461,6 +1461,49 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev,
+   "ISSI Block Protection Bits cleared SR=0x%x", ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI Block Protection Bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
  * spansion_quad_enable() - set QE bit in Configuraiton Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
@@ -1836,7 +1879,7 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK)
},
 
/* Macronix */
@@ -4078,6 +4121,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JEDEC_MFR(info) == SNOR_MFR_ISSI ||
+   info->flags & SPI_NOR_HAS_LOCK) {
+   nor->flash_unlock = issi_unlock;
+
+   }
if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ff13297..9a7d719 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -127,6 +127,7 @@
 #define SR_BP0 BIT(2)  /* Block protect 0 */
 #define SR_BP1 BIT(3)  /* Block protect 1 */
 #define SR_BP2 BIT(4)  /* Block protect 2 */
+#define SR_BP3 BIT(5)  /* Block protect 3 for ISSI device*/
 #define SR_TB  BIT(5)  /* Top/Bottom protect */
 #define SR_SRWDBIT(7)  /* SR write protect */
 /* Spansion/Cypress specific status bits */
-- 
1.9.1



[PATCH v4 3/3] mtd: spi-nor: add locking support for is25xxxxx device

2019-05-11 Thread Sagar Shrikant Kadam
Implement a locking scheme for ISSI devices based on stm_lock mechanism.
The is25x  devices have 4 bits for selecting the range of blocks to
be locked/protected from erase/write operations and function register
gives feasibility to select TOP / Bottom area for protection.

The current implementation enables block protection as per the table
defined into datasheet for is25wp256d device with sector size of 0x1.
ISSI and stm devices differ in terms of TBS (Top/Bottom area protection)
bits. In case of issi this is in Function register and is OTP memory, so
once FR bits are programmed  cannot be modified.

Some common code from stm_lock/unlock implementation is extracted so that
it can be re-used for issi devices.The locking scheme has been tested on
HiFive Unleashed board, having is25wp256 flash memory.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 288 ++
 include/linux/mtd/spi-nor.h   |   5 +
 2 files changed, 242 insertions(+), 51 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 3942b26..1692965 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -288,6 +288,45 @@ struct flash_info {
 
 #define JEDEC_MFR(info)((info)->id[0])
 
+/**
+ * read_fr() -read function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area protection bits selection into function
+ * reg.The bits in FR are OTP.So once it's written, it cannot be changed.
+ *
+ * Return: Value in function register or Negative if error.
+ */
+static int read_fr(struct spi_nor *nor)
+{
+   int ret;
+   u8 val;
+
+   ret = nor->read_reg(nor, SPINOR_OP_RDFR, , 1);
+   if (ret < 0) {
+   pr_err("error %d reading FR\n", (int) ret);
+   return ret;
+   }
+
+   return val;
+}
+
+/**
+ * write_fr() -Write function register
+ * @nor: pointer to a 'struct spi_nor'.
+ *
+ * ISSI devices have top/bottom area selection protection bits into function
+ * reg whereas other devices have the TBS bit into Status Register.
+ * The bits in FR are OTP.So once it's written, it cannot be changed.
+ *
+ * Return: Negative if error
+ */
+static int write_fr(struct spi_nor *nor, u8 val)
+{
+   nor->cmd_buf[0] = val;
+   return nor->write_reg(nor, SPINOR_OP_WRFR, nor->cmd_buf, 1);
+}
+
 /*
  * Read the status register, returning its value in the location
  * Return the status register value.
@@ -1088,10 +1127,17 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
 uint64_t *len)
 {
struct mtd_info *mtd = >mtd;
-   u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
-   int shift = ffs(mask) - 1;
+   u8 mask = 0;
+   int shift = 0;
int pow;
 
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI)
+   mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   else
+   mask = SR_BP2 | SR_BP1 | SR_BP0;
+
+   shift = ffs(mask) - 1;
+
if (!(sr & mask)) {
/* No protection */
*ofs = 0;
@@ -1099,10 +1145,19 @@ static void stm_get_locked_range(struct spi_nor *nor, 
u8 sr, loff_t *ofs,
} else {
pow = ((sr & mask) ^ mask) >> shift;
*len = mtd->size >> pow;
-   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
-   *ofs = 0;
-   else
-   *ofs = mtd->size - *len;
+
+   if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
+   if (nor->flags & SNOR_F_HAS_SR_TB &&
+   (read_fsr(nor) & FR_TB))
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   } else {
+   if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
+   *ofs = 0;
+   else
+   *ofs = mtd->size - *len;
+   }
}
 }
 
@@ -1129,18 +1184,105 @@ static int stm_check_lock_status_sr(struct spi_nor 
*nor, loff_t ofs, uint64_t le
return (ofs >= lock_offs + lock_len) || (ofs + len <= 
lock_offs);
 }
 
-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+/*
+ * check if memory region is locked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int fl_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
u8 sr)
 {
return stm_check_lock_status_sr(nor, ofs, len, sr, true);
 }
 
-static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+/*
+ * check if memory region is unlocked
+ *
+ * Returns false if region is locked 0 otherwise.
+ */
+static int fl_is_unlocked_sr(struct s

[PATCH v4 1/3] mtd: spi-nor: add support for is25wp256

2019-05-11 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB)device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 10 +-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index fae1474..c5408ed 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1834,6 +1834,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
 
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -3650,6 +3654,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_MACRONIX:
params->quad_enable = macronix_quad_enable;
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
@@ -4127,7 +4135,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret)
return ret;
 
-   if (nor->addr_width) {
+   if (nor->addr_width && JEDEC_MFR(info) != SNOR_MFR_ISSI) {
/* already configured from SFDP */
} else if (info->addr_width) {
nor->addr_width = info->addr_width;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b..ff13297 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -19,6 +19,7 @@
 #define SNOR_MFR_ATMEL CFI_MFR_ATMEL
 #define SNOR_MFR_GIGADEVICE0xc8
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
-- 
1.9.1



[PATCH v4 0/3] add support for is25wp256 spi-nor device.

2019-05-11 Thread Sagar Shrikant Kadam
The patch set is tested on HiFive Unleashed board and is based on mainline
kernel v5.1. Its intended to add support for 32 MB spi-nor flash
mounted on the board. Memory Device supports 4/32/and 64 KB sectors size.
The device id table is updated accordingly.

Flash parameter table for ISSI device is set to use macronix_quad_enable
procedure to set the QE (quad-enable) bit of Status register.

A unilaterlay block unlocking scheme is added in patch 2.

These patches are based on original work done by Wesley Terpstra and/or Palmer 
Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and flash utils (v1.5.2):
1. mtd_debug:Options available are : erase/read/write.
2. flashcp  :Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock: Unlock flash memory blocks.Arguments: are offset and number of 
blocks.
3. flash_lock:   Lock flash memory blocks. Arguments: are offset and number of 
blocks. 

Unlock scheme clears the protection bits of all blocks in the Status register.

Lock scheme:
A basic implementation based on stm_lock scheme and is validated for different 
number of blocks passed
to flash_lock. ISSI devices have Top/Bottom area selection in "function 
register" which is OTP memory.
 

Revision history:
V3<->V4:
-Extracted comman code and renamed few stm functions so that it can be reused 
for issi lock implementation.
-Added function's to read and write FR register, for selecting Top/Bottom area.

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.




Sagar Shrikant Kadam (3):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: add support to unlock flash device.
  mtd: spi-nor: add locking support for is25x device

 drivers/mtd/spi-nor/spi-nor.c | 345 +++---
 include/linux/mtd/spi-nor.h   |   7 +
 2 files changed, 301 insertions(+), 51 deletions(-)

-- 
1.9.1



[PATCH v3 v3 3/3] mtd: spi-nor: add locking support for is25xxxxx device

2019-05-07 Thread Sagar Shrikant Kadam
Implement a basic locking scheme for ISSI devices similar to that of
stm_lock mechanism. The is25x  devices have 4 bits for selecting
the range of blocks to be locked/protected from erase/write.

The current implementation enables block protection as per the table
defined into datasheet for is25wp256d device.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 3942b26..5986260 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1459,6 +1459,56 @@ static int macronix_quad_enable(struct spi_nor *nor)
 
return 0;
 }
+/**
+ * issi_lock() - set BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to lock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Lock a region of the flash.Implementation is based on stm_lock
+ * Supports the block protection bits BP{0,1,2,3} in the status register
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int status_old, status_new, blk_prot;
+   u8 mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+   u8 shift = ffs(mask) - 1;
+   u8 pow;
+   loff_t num_blks;
+
+   status_old = read_sr(nor);
+
+   /* if status reg is Write protected don't update bit protection */
+   if (status_old & SR_SRWD) {
+   dev_err(nor->dev,
+   "Status register is Write Protected, can't lock bit
+   protection bits...\n");
+   return -EINVAL;
+   }
+   num_blks = len / nor->info->sector_size;
+
+   pow = order_base_2(num_blks);
+
+   blk_prot = mask & (((pow+1) & 0xf)<> shift) & 0x0f) > blk_prot) {
+   dev_info(nor->dev, "newly requested blocks are
+   already protected ");
+   return 0;
+   }
+
+   status_new = status_old | blk_prot;
+
+   if (status_old == status_new)
+   return 0;
+
+   return write_sr_and_check(nor, status_new, mask);
+}
 
 /**
  * issi_unlock() - clear BP[0123] write-protection.
@@ -4124,6 +4174,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
/* NOR protection support for ISSI chips */
if (JEDEC_MFR(info) == SNOR_MFR_ISSI ||
info->flags & SPI_NOR_HAS_LOCK) {
+   nor->flash_lock = issi_lock;
nor->flash_unlock = issi_unlock;
 
}
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v3 v3 2/3] mtd: spi-nor: add support to unlock flash device.

2019-05-07 Thread Sagar Shrikant Kadam
Nor device (is25wp256 mounted on HiFive unleashed Rev A00 board) from ISSI
have memory blocks guarded by block protection bits BP[0,1,2,3].

Clearing block protection bits,unlocks the flash memory regions
The unlock scheme is registered during nor scans.

Based on code developed by Wesley Terpstra 
and/or Palmer Dabbelt .
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 51 ++-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index c5408ed..3942b26 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1461,6 +1461,49 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 
 /**
+ * issi_unlock() - clear BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to unlock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Bits [2345] of the Status Register are BP[0123].
+ * ISSI chips use a different block protection scheme than other chips.
+ * Just disable the write-protect unilaterally.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   int ret, val;
+   u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
+
+   val = read_sr(nor);
+   if (val < 0)
+   return val;
+   if (!(val & mask))
+   return 0;
+
+   write_enable(nor);
+
+   write_sr(nor, val & ~mask);
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   return ret;
+
+   ret = read_sr(nor);
+   if (ret > 0 && !(ret & mask)) {
+   dev_info(nor->dev,
+   "ISSI Block Protection Bits cleared SR=0x%x", ret);
+   ret = 0;
+   } else {
+   dev_err(nor->dev, "ISSI Block Protection Bits not cleared\n");
+   ret = -EINVAL;
+   }
+   return ret;
+}
+
+/**
  * spansion_quad_enable() - set QE bit in Configuraiton Register.
  * @nor:   pointer to a 'struct spi_nor'
  *
@@ -1836,7 +1879,7 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-   SPI_NOR_4B_OPCODES)
+   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK)
},
 
/* Macronix */
@@ -4078,6 +4121,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
nor->flash_is_locked = stm_is_locked;
}
 
+   /* NOR protection support for ISSI chips */
+   if (JEDEC_MFR(info) == SNOR_MFR_ISSI ||
+   info->flags & SPI_NOR_HAS_LOCK) {
+   nor->flash_unlock = issi_unlock;
+
+   }
if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ff13297..9a7d719 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -127,6 +127,7 @@
 #define SR_BP0 BIT(2)  /* Block protect 0 */
 #define SR_BP1 BIT(3)  /* Block protect 1 */
 #define SR_BP2 BIT(4)  /* Block protect 2 */
+#define SR_BP3 BIT(5)  /* Block protect 3 for ISSI device*/
 #define SR_TB  BIT(5)  /* Top/Bottom protect */
 #define SR_SRWDBIT(7)  /* SR write protect */
 /* Spansion/Cypress specific status bits */
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v3 v3 1/3] mtd: spi-nor: add support for is25wp256

2019-05-07 Thread Sagar Shrikant Kadam
Update spi_nor_id table for is25wp256 (32MB)device from ISSI,
present on HiFive Unleashed dev board (Rev: A00).

Set method to enable quad mode for ISSI device in flash parameters
table.

Based on code originally written by Wesley Terpstra 
and/or Palmer Dabbelt 
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/mtd/spi-nor/spi-nor.c | 10 +-
 include/linux/mtd/spi-nor.h   |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index fae1474..c5408ed 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1834,6 +1834,10 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128",  INFO(0x9d7018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+   { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 1024,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_4B_OPCODES)
+   },
 
/* Macronix */
{ "mx25l512e",   INFO(0xc22010, 0, 64 * 1024,   1, SECT_4K) },
@@ -3650,6 +3654,10 @@ static int spi_nor_init_params(struct spi_nor *nor,
case SNOR_MFR_MACRONIX:
params->quad_enable = macronix_quad_enable;
break;
+   case SNOR_MFR_ISSI:
+   params->quad_enable = macronix_quad_enable;
+   break;
+
 
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
@@ -4127,7 +4135,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret)
return ret;
 
-   if (nor->addr_width) {
+   if (nor->addr_width && JEDEC_MFR(info) != SNOR_MFR_ISSI) {
/* already configured from SFDP */
} else if (info->addr_width) {
nor->addr_width = info->addr_width;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index b3d360b..ff13297 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -19,6 +19,7 @@
 #define SNOR_MFR_ATMEL CFI_MFR_ATMEL
 #define SNOR_MFR_GIGADEVICE0xc8
 #define SNOR_MFR_INTEL CFI_MFR_INTEL
+#define SNOR_MFR_ISSI  0x9d/* ISSI */
 #define SNOR_MFR_STCFI_MFR_ST  /* ST Micro */
 #define SNOR_MFR_MICRONCFI_MFR_MICRON  /* Micron */
 #define SNOR_MFR_MACRONIX  CFI_MFR_MACRONIX
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v3 v3 0/3] add support for is25wp256 spi-nor device.

2019-05-07 Thread Sagar Shrikant Kadam
The patch set is tested on HiFive Unleashed board and is based on mainline
kernel v5.1. Its intended to add support for 32 MB spi-nor flash
mounted on the board. Memory Device supports 4/32/and 64 KB sectors size.
The device id table is updated accordingly.

Flash parameter table for ISSI device is set to use macronix_quad_enable
procedure to set the QE (quad-enable) bit of Status register.

A unilaterlay block unlocking scheme is added in patch 2.

These patches are based on original work done by Wesley Terpstra and/or Palmer 
Dabbelt:
https://github.com/riscv/riscv-linux/commit/c94e267766d62bc9a669611c3d0c8ed5ea26569b

Erase/Read/Write operations are verified on HiFive Unleashed board using  mtd 
and flash utils (v1.5.2):
1. mtd_debug:Options available are : erase/read/write.
2. flashcp  :Single utility that erases flash, writes a file to flash and 
verifies the data back.
3. flash_unlock: Unlock flash memory blocks.
3. flash_lock:   Lock flash memory blocks. 

Unlock scheme clears the protection bits of all blocks in the Status register.

Lock scheme:
It is a basic implementation similar to stm_lock scheme and is validated for 
different number of blocks passed
to flash_lock.

Revision history:

V2<->V3:
-Rebased patch to mainline v5.1 from earlier v5.1-rc5
-Updated commit messages, and cover letter with reference to git URL and author 
information.
-Deferred flash_lock mechanism and can go as separate patch. 

V1<-> V2:
-Incorporated changes suggested by reviewers regarding patch/cover letter 
versioning, references of patch.
-Updated cover letter with description for flash operations verified with these 
changes.
-Add support for unlocking is25xx device
-Add support for locking is25xx device.

v1:
-Add support for is25wp256 device.


Sagar Shrikant Kadam (3):
  mtd: spi-nor: add support for is25wp256
  mtd: spi-nor: add support to unlock flash device.
  mtd: spi-nor: add locking support for is25x device

 drivers/mtd/spi-nor/spi-nor.c | 110 +-
 include/linux/mtd/spi-nor.h   |   2 +
 2 files changed, 111 insertions(+), 1 deletion(-)

-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v2 v2 0/3] Extend dt bindings to support I2C on sifive devices and a fix broken IRQ in polling mode.

2019-05-07 Thread Sagar Shrikant Kadam
The patch is based on mainline v5.1 and extends DT-bindings for Opencore based 
I2C device in FU540 
SoC, available on HiFive unleashed board (Rev A00), and also provides a 
workaround for broken IRQ
which affect I2C polling mode interface on FU540 chipsets. 

The polling mode workaround patch fixes the CPU stall issue, when-ever i2c 
transfer are initiated.

This workaround checks if it's a FU540 chipset based on device tree 
information, and check's for open
core's IF(interrupt flag) and TIP flags to break from the polling loop upon 
completion of transfer.

To test the patch, a PMOD-AD2 sensor is connected to HiFive Unleashed board 
over J1 connector, and 
appropriate device node is added into board specific device tree as per the 
information provided in 
dt-bindings in Documentation/devicetree/bindings/i2c/i2c-sifive.txt.
Without this workaround, the CPU stall's infinitely.

Busybox i2c utilities used to verify workaround : i2cdetect, i2cdump, i2cset, 
i2cget


Patch History:

V0<->V1:
-Incorporate review comments from Andrew
-Extend dt bindings into i2c-ocores.txt instead of adding new file
-Rename SIFIVE_FLAG_POLL to OCORES_FLAG_BROKEN_IRQ

V0:
-Update dt bindings for sifive i2c devices
-Fix broken IRQ affecting i2c polling mode interface.


Sagar Shrikant Kadam (3):
  dt-bindings: i2c: extend existing opencore bindings.
  i2c-ocore: sifive: add support for i2c device on FU540-c000 SoC.
  i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

 .../devicetree/bindings/i2c/i2c-ocores.txt | 20 +
 drivers/i2c/busses/i2c-ocores.c| 33 +++---
 2 files changed, 49 insertions(+), 4 deletions(-)

-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v2 v2 2/3] i2c-ocore: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-07 Thread Sagar Shrikant Kadam
Update device id table for Opencores I2C master used in HiFive Unleashed
platform having FU540-c000 chipset.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 4e1a077..7bf7b0c 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -85,6 +85,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -465,6 +466,10 @@ static u32 ocores_func(struct i2c_adapter *adap)
.data = (void *)TYPE_OCORES,
},
{
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v2 v2 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-07 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

commit 69c8c0c0efa8 ("i2c: ocores: add polling interface")

The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for
FU540-COOO SoC.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 28 
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 7bf7b0c..8b994b4 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -27,6 +27,7 @@
 #include 
 
 #define OCORES_FLAG_POLL BIT(0)
+#define OCORES_FLAG_BROKEN_IRQ BIT(1)
 
 /*
  * 'process_lock' exists because ocores_process() and ocores_process_timeout()
@@ -239,8 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
+   }
 
ocores_process(i2c, stat);
 
@@ -356,6 +362,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags & OCORES_FLAG_BROKEN_IRQ)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -406,7 +417,7 @@ static int ocores_xfer(struct i2c_adapter *adap,
 {
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
 
-   if (i2c->flags & OCORES_FLAG_POLL)
+   if ((i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ)))
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
 }
@@ -597,6 +608,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -678,13 +690,21 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
-   i2c->flags |= OCORES_FLAG_POLL;
+   /*
+* Set a OCORES_FLAG_BROKEN_IRQ to enable workaround for FU540
+* in polling mode interface of i2c-ocore driver.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+   else
+   i2c->flags |= OCORES_FLAG_POLL;
} else {
if (irq < 0)
return irq;
}
 
-   if (!(i2c->flags & OCORES_FLAG_POLL)) {
+   if (!(i2c->flags & (OCORES_FLAG_POLL | OCORES_FLAG_BROKEN_IRQ))) {
ret = devm_request_irq(>dev, irq, ocores_isr, 0,
   pdev->name, i2c);
if (ret) {
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v2 v2 1/3] dt-bindings: i2c: extend existing opencore bindings.

2019-05-07 Thread Sagar Shrikant Kadam
Add FU540-C000 specific device tree bindings to already
available i2-ocores file. This device is available on
HiFive Unleashed Rev A00 board.

Signed-off-by: Sagar Shrikant Kadam 
---
 Documentation/devicetree/bindings/i2c/i2c-ocores.txt | 20 
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt 
b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
index 17bef9a..f6bcf90 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
@@ -2,6 +2,7 @@ Device tree configuration for i2c-ocores
 
 Required properties:
 - compatible  : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
+"sifive,fu540-c000-i2c" or "sifive,i2c0"
 - reg : bus address start and address range size of device
 - interrupts  : interrupt number
 - clocks  : handle to the controller clock; see the note below.
@@ -67,3 +68,22 @@ or
reg = <0x60>;
};
};
+or
+   /*
+ An Opencore based I2C node in FU540-C000 chip from SiFive
+ This chip has a hardware erratum for broken IRQ
+ so it's recommended not to define interrupt in the device node
+   */
+   i2c@1003 {
+   compatible = "sifive,i2c0","sifive,fu540-c000-i2c";
+   reg = <0x0 0x1003 0x0 0x1000>;
+   reg-names = "i2c-control";
+   clocks = <>;
+   clock-frequency = <10>;
+
+   reg-shift = <2>;
+   reg-io-width = <1>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+   };
-- 
1.9.1


-- 
The information transmitted is intended only for the person or entity to 
which it is addressed and may contain confidential and/or privileged 
material. If you are not the intended recipient of this message please do 
not read, copy, use or disclose this communication and notify the sender 
immediately. It should be noted that any review, retransmission, 
dissemination or other use of, or taking action or reliance upon, this 
information by persons or entities other than the intended recipient is 
prohibited.


[PATCH v1 v1 2/3] i2c-ocore: sifive: add support for i2c device on FU540-c000 SoC.

2019-05-06 Thread Sagar Shrikant Kadam
Update device id table for Opencores I2C master used in HiFive Unleashed
platform having FU540-c000 chipset.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 4e1a077..7bf7b0c 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -85,6 +85,7 @@ struct ocores_i2c {
 
 #define TYPE_OCORES0
 #define TYPE_GRLIB 1
+#define TYPE_SIFIVE_REV0   2
 
 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
 {
@@ -465,6 +466,10 @@ static u32 ocores_func(struct i2c_adapter *adap)
.data = (void *)TYPE_OCORES,
},
{
+   .compatible = "sifive,fu540-c000-i2c",
+   .data = (void *)TYPE_SIFIVE_REV0,
+   },
+   {
.compatible = "aeroflexgaisler,i2cmst",
.data = (void *)TYPE_GRLIB,
},
-- 
1.9.1



[PATCH v1 v1 3/3] i2c-ocores: sifive: add polling mode workaround for FU540-C000 SoC.

2019-05-06 Thread Sagar Shrikant Kadam
The i2c-ocore driver already has a polling mode interface.But it needs
a workaround for FU540 Chipset on HiFive unleashed board (RevA00).
There is an erratum in FU540 chip that prevents interrupt driven i2c
transfers from working, and also the I2C controller's interrupt bit
cannot be cleared if set, due to this the existing i2c polling mode
interface added in mainline earlier doesn't work, and CPU stall's
infinitely, when-ever i2c transfer is initiated.

commit 69c8c0c0efa8 ("i2c: ocores: add polling interface")

The workaround / fix is particularly for FU540-COOO SoC.

Signed-off-by: Sagar Shrikant Kadam 
---
 drivers/i2c/busses/i2c-ocores.c | 28 
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 7bf7b0c..08cdfed 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -27,6 +27,7 @@
 #include 
 
 #define OCORES_FLAG_POLL BIT(0)
+#define SIFIVE_FLAG_POLL BIT(1)
 
 /*
  * 'process_lock' exists because ocores_process() and ocores_process_timeout()
@@ -239,8 +240,13 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
 
-   if (!(stat & OCI2C_STAT_IF))
+   if (i2c->flags && SIFIVE_FLAG_POLL) {
+   if (stat & OCI2C_STAT_IF)
+   if (!(stat & OCI2C_STAT_BUSY))
+   return IRQ_NONE;
+   } else if (!(stat & OCI2C_STAT_IF)) {
return IRQ_NONE;
+   }
 
ocores_process(i2c, stat);
 
@@ -356,6 +362,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c)
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
+   else {
+   if (i2c->flags && SIFIVE_FLAG_POLL)
+   if (i2c->state == STATE_DONE)
+   break;
+   }
}
 }
 
@@ -406,7 +417,7 @@ static int ocores_xfer(struct i2c_adapter *adap,
 {
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
 
-   if (i2c->flags & OCORES_FLAG_POLL)
+   if ((i2c->flags & OCORES_FLAG_POLL) || (i2c->flags & SIFIVE_FLAG_POLL))
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
 }
@@ -597,6 +608,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 {
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
+   const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
@@ -678,13 +690,21 @@ static int ocores_i2c_probe(struct platform_device *pdev)
 
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
-   i2c->flags |= OCORES_FLAG_POLL;
+   /*
+* Set a SIFIVE_FLAG_POLL to enable workaround for FU540
+* in polling mode interface of i2c-ocore driver.
+*/
+   match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+   if (match && (long)match->data == TYPE_SIFIVE_REV0)
+   i2c->flags |= SIFIVE_FLAG_POLL;
+   else
+   i2c->flags |= OCORES_FLAG_POLL;
} else {
if (irq < 0)
return irq;
}
 
-   if (!(i2c->flags & OCORES_FLAG_POLL)) {
+   if (!(i2c->flags & (OCORES_FLAG_POLL | SIFIVE_FLAG_POLL))) {
ret = devm_request_irq(>dev, irq, ocores_isr, 0,
   pdev->name, i2c);
if (ret) {
-- 
1.9.1



  1   2   >