Re: [PATCH] mtd: spi-nor: macronix: Add block protection support to mx25u6435f

2021-04-15 Thread Ikjoon Jang
On Wed, Apr 14, 2021 at 12:53:24PM +0200, Michael Walle wrote:
> Hi,
> 
> Am 2021-04-14 08:53, schrieb Ikjoon Jang:
> > On Tue, Apr 13, 2021 at 8:26 PM Michael Walle  wrote:
> > > Am 2021-04-13 14:02, schrieb Ikjoon Jang:
> > > > This patch adds block protection support to Macronix mx25u6432f and
> > > > mx25u6435f. Two different chips share the same JEDEC ID while only
> > > > mx25u6423f support section protections. And two chips have slightly
> > > > different definitions of BP bits than generic (ST Micro)
> > > > implementation.
> > > 
> > > What is different compared to the current implementation? Could you
> > > give
> > > an example?
> > 
> > Two chips have different definitions on BP and  T/B bits.
> > - 35f has 4 BPs without T/B, BP3 behaves like T/B bit.
> 
> See below.
> 
> > - 32f has 4 BPs plus T/B on CR.
> 
> Ok, so this scheme looks like what we have right now, only that the
> TB bit is OTP and at a different place, right?

yes, right.

> 
> > 
> > # MX25U6435F
> > 
> >  BPs | BP3=0 | BP3=1
> > -
> >  000 | None  | 1/2
> >  001 | 1/128 | 3/4
> >  010 | 1/64  | 7/8
> >  011 | 1/32  | 15/16
> >  100 | 1/16  | 31/32
> >  101 | 1/8   | 63/64
> >  110 | 1/4   | 127/128
> >  111 | 1/2   | All
> > 
> > # MX25U6432F
> > 
> >   BPs | T/B=0 | T/B=1
> > -
> >   | None  | None
> >  0001 | 1/128 | 1/128
> >  0010 | 1/64  | 1/64
> >  0011 | 1/32  | 1/32
> >  0100 | 1/16  | 1/16
> >  0101 | 1/8   | 1/8
> >  0110 | 1/4   | 1/4
> >  0111 | 1/2   | 1/2
> >  1xxx | All   | All
> > 
> > It seems that 35f has a unique definition on bottom protections than
> > others.
> 
> Oh my.. That looks more like an invert and the top protection is also
> different. That is, if you'd treat BP3 as T/B, then BP[2:0] = 111
> should be "lock all", but it is rather lock half.. I just looked at
> the mx25u3235f back then. There it looked correct. But now it looks
> like the top protection scheme clips on the lower end (i.e. always
> starts with 1 block), where on the current supported scheme, we clip
> on the upper end (i.e. we start with protect all and walk backwards).
> 

Yes, indeed, but it's still confusing. :)

Now I'm thinking of adding a 'table' which maps between BP mask
and lock_len in swp.c, instead of ilog2() calculations.

> > Assuming there's no way to distinguish between mx25u6435f and 32f,
> > This patch simply takes the common parts only - BP[2:0]
> > without using T/B or BP3 at all.
> 
> You could look for differences in the SFDP and then distiguish them
> during probe and set the corresponding flags. Where the flags would
> need to be implemented first. I wouldn't have a problem with saying
> we just support top protection for the MX25U6435F but then we'd need
> to make sure the BP3 is set to 0.
> 
> If you want to read out the SFDP, see here:
> https://patchwork.ozlabs.org/project/linux-mtd/list/?series=235475

you're right, those chips have different values - JESD216 and JESD216B.

> 
> > But the current swp implementation implies that "BP with all ones"
> > is to be 'all' protection while in this approach it's 1/2,
> > A hidden BP3 should be involved for 'all' protection.
> 
> Yes, so the MX25U6432F needs to have the 4bit BP flag set and the
> MX25U6435F seems to be completely different. Doh..
> 
> > > > So this patch defines a new spi_nor_locking_ops only for macronix
> > > > until this could be merged into a generic swp implementation.
> > > 
> > > TBH, I don't really like the code duplication and I'd presume that it
> > > won't ever be merged with the generic code.
> > 
> > Agree, I hope I could make a more generalized version into swp.c.
> > 
> > Honestly I expected that I just needed to add one line of
> > SPI_NOR_HAS_LOCK
> > to flash_info to support mx256432f (this was the main purpose of my
> > patch)
> > before I read the datasheets. :)
> > 
> > > 
> > > You also assume that both the WPSEL and T/B bit are 0, which might not
> > > be true. Please note that both are write-once, thus should only be
> > > read.
> > 
> > yep, that also should be considered,
> > I'm thinking just not to support WPSEL=1 case for now.
> 
> which is ok, but we should make sure it is not set at all. Now the
> question is what do we do if it is set? I'd say just don't register the
> locking ops and log a message.
> 

So the my current rough plan to support macronix's HAS_LOCK is:

a. respin your patches supporting macronix TB (OTP + CR)
b. fix swp.c to have a mapping between BP_mask and lock_len
   (or similar approach) to support unlinear/assymetric protection levels of
   MX25U35F, instead of calling ilog2()
c. Distinguish MX25U35F and MX25U32F at runtime and apply flags
   only when WPSEL==0 && SFDP==MX25U32F
   set HAS_LOCK | OTP_TB | CR_TB | HAS_4BIT_BP.
   (it's the only MX25U32F I can test the new features for now).

I'm not so sure on b part although..

> -michael

Super thanks for the review!



[PATCH v5 2/2] HID: google: Add of_match table to Whiskers switch device.

2021-04-14 Thread Ikjoon Jang
Add a device tree match table for "cros-cbas" switch device.

Signed-off-by: Ikjoon Jang 
Reviewed-by: Dmitry Torokhov 
Acked-by: Jiri Kosina 

---

(no changes since v1)

Please note that v3 was submitted in 28 Oct 2019, 1.5yrs ago.
Link(v2): 
https://patchwork.kernel.org/project/linux-input/patch/20191021030158.32464-1-i...@chromium.org/

---
 drivers/hid/hid-google-hammer.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
index d9319622da44..be4f9f3dbbba 100644
--- a/drivers/hid/hid-google-hammer.c
+++ b/drivers/hid/hid-google-hammer.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -272,12 +273,21 @@ static const struct acpi_device_id cbas_ec_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
 
+#ifdef CONFIG_OF
+static const struct of_device_id cbas_ec_of_match[] = {
+   { .compatible = "google,cros-cbas" },
+   { },
+};
+MODULE_DEVICE_TABLE(of, cbas_ec_of_match);
+#endif
+
 static struct platform_driver cbas_ec_driver = {
.probe = cbas_ec_probe,
.remove = cbas_ec_remove,
.driver = {
.name = "cbas_ec",
.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
+   .of_match_table = of_match_ptr(cbas_ec_of_match),
.pm = _ec_pm_ops,
},
 };
-- 
2.31.1.295.g9ea45b61b8-goog



[PATCH v5 1/2] mfd: google,cros-ec: add DT bindings for a baseboard's switch device

2021-04-14 Thread Ikjoon Jang
This is for ChromeOS tablets which have a 'cros_cbas' switch device
in the "Whiskers" base board. This device can be instantiated only by
device tree on ARM platforms. ChromeOS EC doesn't provide a way to
probe the device.

Signed-off-by: Ikjoon Jang 

---

Changes in v5:
 - Add missing blank lines and change the description property's position.
 - Add a note to description: "this device cannot be detected at runtime."

Changes in v4:
Define cros-cbase bindings inside google,cros-ec.yaml instead of
a separated binding document.

 .../bindings/mfd/google,cros-ec.yaml  | 20 +++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml 
b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
index 76bf16ee27ec..8dcce176b72e 100644
--- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
+++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
@@ -114,6 +114,22 @@ properties:
   - "#address-cells"
   - "#size-cells"
 
+  cbas:
+type: object
+
+description:
+  This device is used to signal when a detachable base is attached
+  to a Chrome OS tablet. This device cannot be detected at runtime.
+
+properties:
+  compatible:
+const: google,cros-cbas
+
+required:
+  - compatible
+
+additionalProperties: false
+
 patternProperties:
   "^i2c-tunnel[0-9]*$":
 type: object
@@ -180,6 +196,10 @@ examples:
 interrupts = <99 0>;
 interrupt-parent = <>;
 spi-max-frequency = <500>;
+
+base_detection: cbas {
+compatible = "google,cros-cbas";
+};
 };
 };
 
-- 
2.31.1.295.g9ea45b61b8-goog



[PATCH v5 0/2] HID: google: add device tree bindings for Whiskers switch device

2021-04-14 Thread Ikjoon Jang
Add device a tree binding for a "cros-cbas" switch device of
ChromeOS tablets with Whiskers base board.

Changes in v5:
 - Add missing blank lines and change the description property's position.
 - Add a note to description: "this device cannot be detected at runtime."

Changes in v4:
Define cros-cbase bindings inside google,cros-ec.yaml instead of
a separated binding document.

Ikjoon Jang (2):
  mfd: google,cros-ec: add DT bindings for a baseboard's switch device
  HID: google: Add of_match table to Whiskers switch device.

 .../bindings/mfd/google,cros-ec.yaml  | 20 +++
 drivers/hid/hid-google-hammer.c   | 10 ++
 2 files changed, 30 insertions(+)

-- 
2.31.1.295.g9ea45b61b8-goog



[PATCH v2] arm64: dts: mt8183: Add power-domains properity to mfgcfg

2021-04-14 Thread Ikjoon Jang
mfgcfg clock is under MFG_ASYNC power domain

Signed-off-by: Weiyi Lu 
Signed-off-by: Ikjoon Jang 
---

Changes in v2:
Fix a wrong power domain reference (scpsys to spm).

Link(v1): 
https://patchwork.kernel.org/project/linux-mediatek/patch/20210224091742.1060508-1-i...@chromium.org/#23997681

---
 arch/arm64/boot/dts/mediatek/mt8183.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi 
b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 0ff7b67a6806..64813634c3df 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1116,6 +1116,7 @@ mfgcfg: syscon@1300 {
compatible = "mediatek,mt8183-mfgcfg", "syscon";
reg = <0 0x1300 0 0x1000>;
#clock-cells = <1>;
+   power-domains = < MT8183_POWER_DOMAIN_MFG_ASYNC>;
};
 
mmsys: syscon@1400 {
-- 
2.31.1.295.g9ea45b61b8-goog



Re: [PATCH] mtd: spi-nor: macronix: Add block protection support to mx25u6435f

2021-04-14 Thread Ikjoon Jang
HI Michael, thanks for the review.

On Tue, Apr 13, 2021 at 8:26 PM Michael Walle  wrote:
>
> Hi Ikjoon,
>
> Am 2021-04-13 14:02, schrieb Ikjoon Jang:
> > This patch adds block protection support to Macronix mx25u6432f and
> > mx25u6435f. Two different chips share the same JEDEC ID while only
> > mx25u6423f support section protections. And two chips have slightly
> > different definitions of BP bits than generic (ST Micro)
> > implementation.
>
> What is different compared to the current implementation? Could you give
> an example?

Two chips have different definitions on BP and  T/B bits.
- 35f has 4 BPs without T/B, BP3 behaves like T/B bit.
- 32f has 4 BPs plus T/B on CR.

# MX25U6435F

 BPs | BP3=0 | BP3=1
-
 000 | None  | 1/2
 001 | 1/128 | 3/4
 010 | 1/64  | 7/8
 011 | 1/32  | 15/16
 100 | 1/16  | 31/32
 101 | 1/8   | 63/64
 110 | 1/4   | 127/128
 111 | 1/2   | All

# MX25U6432F

  BPs | T/B=0 | T/B=1
-
  | None  | None
 0001 | 1/128 | 1/128
 0010 | 1/64  | 1/64
 0011 | 1/32  | 1/32
 0100 | 1/16  | 1/16
 0101 | 1/8   | 1/8
 0110 | 1/4   | 1/4
 0111 | 1/2   | 1/2
 1xxx | All   | All

It seems that 35f has a unique definition on bottom protections than others.
Assuming there's no way to distinguish between mx25u6435f and 32f,
This patch simply takes the common parts only - BP[2:0]
without using T/B or BP3 at all.

But the current swp implementation implies that "BP with all ones"
is to be 'all' protection while in this approach it's 1/2,
A hidden BP3 should be involved for 'all' protection.

>
> > So this patch defines a new spi_nor_locking_ops only for macronix
> > until this could be merged into a generic swp implementation.
>
> TBH, I don't really like the code duplication and I'd presume that it
> won't ever be merged with the generic code.

Agree, I hope I could make a more generalized version into swp.c.

Honestly I expected that I just needed to add one line of SPI_NOR_HAS_LOCK
to flash_info to support mx256432f (this was the main purpose of my patch)
before I read the datasheets. :)

>
> You also assume that both the WPSEL and T/B bit are 0, which might not
> be true. Please note that both are write-once, thus should only be read.

yep, that also should be considered,
I'm thinking just not to support WPSEL=1 case for now.

>
> See also:
> https://lore.kernel.org/linux-mtd/346332bf6ab0dd92b9ffd9e126b6b...@walle.cc/
>

Thanks, let me try it.

> -michael


Re: [PATCH v4 1/2] mfd: google,cros-ec: add DT bindings for a baseboard's switch device

2021-04-13 Thread Ikjoon Jang
On Tue, Apr 13, 2021 at 10:57 PM Rob Herring  wrote:
>
> On Mon, Apr 12, 2021 at 07:30:19PM +0800, Ikjoon Jang wrote:
> > This is for ChromeOS tablets which have a 'cros_cbas' switch device
> > in the "Whiskers" base board. This device can be instantiated only by
> > device tree on ARM platforms. ChromeOS EC doesn't provide a way to
> > probe the device.
> >
> > Signed-off-by: Ikjoon Jang 
> >
> > ---
> >
> > Changes in v4:
> > Define cros-cbase bindings inside google,cros-ec.yaml instead of
> > a seperated binding document.
> >
> >  .../devicetree/bindings/mfd/google,cros-ec.yaml  | 16 
> >  1 file changed, 16 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml 
> > b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
> > index 76bf16ee27ec..c76809cd9f7f 100644
> > --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
> > +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
> > @@ -127,6 +127,18 @@ patternProperties:
> >  type: object
> >  $ref: "/schemas/extcon/extcon-usbc-cros-ec.yaml#"
> >
> > +  "^cbas$":
>
> Not a pattern, put under 'properties'.
>
> > +type: object
> > +properties:
> > +  compatible:
> > +const: google,cros-cbas
>
> Blank line
>
> > +required:
> > +  - compatible
>
> Blank line
>
> > +additionalProperties: false
> > +description:
>
> Make this 1st or at least before 'properties'.

ACKed, thanks!

>
> > +  This device is used to signal when a detachable base is attached
> > +  to a Chrome OS tablet.
>
> This can't happen at runtime?

There is no way to detect the switch device's existence at runtime.
I'll add a note to the description about this.

>
> > +
> >  required:
> >- compatible
> >
> > @@ -180,6 +192,10 @@ examples:
> >  interrupts = <99 0>;
> >  interrupt-parent = <>;
> >  spi-max-frequency = <500>;
> > +
> > +base_detection: cbas {
> > +compatible = "google,cros-cbas";
> > +};
> >  };
> >  };
> >
> > --
> > 2.31.1.295.g9ea45b61b8-goog
> >


[PATCH] mtd: spi-nor: macronix: Add block protection support to mx25u6435f

2021-04-13 Thread Ikjoon Jang
This patch adds block protection support to Macronix mx25u6432f and
mx25u6435f. Two different chips share the same JEDEC ID while only
mx25u6423f support section protections. And two chips have slightly
different definitions of BP bits than generic (ST Micro) implementation.

So this patch defines a new spi_nor_locking_ops only for macronix
until this could be merged into a generic swp implementation.

Signed-off-by: Ikjoon Jang 

---

 drivers/mtd/spi-nor/macronix.c | 193 -
 1 file changed, 192 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index 42c2cf31702e..563005830e46 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -8,6 +8,195 @@
 
 #include "core.h"
 
+/*
+ * mx25u6435f/mx25u6432f common protection table:
+ *
+ * mx25u6432f has T/B bit, but mx25u6435f doesn't.
+ * while both chips have the same JEDEC ID,
+ * Also BP bits are slightly different with generic swp.
+ * So here we only use common part of the BPs definitions.
+ *
+ * - Upper 2^(Prot Level - 1) blocks are protected.
+ * - Block size is hardcoded as 64Kib.
+ * - Assume T/B is always 0 (top protected, factory default).
+ *
+ *   BP3| BP2 | BP1 | BP0 | Prot Level
+ *  ---
+ *0 |  0  |  0  |  0  |  NONE
+ *0 |  0  |  0  |  1  |  1
+ *0 |  0  |  1  |  0  |  2
+ *0 |  0  |  1  |  1  |  3
+ *0 |  1  |  0  |  0  |  4
+ *0 |  1  |  0  |  1  |  5
+ *0 |  1  |  1  |  0  |  6
+ *0 |  1  |  1  |  1  |  7
+ *   .|  differ by 35f/32f, not used
+ *1 |  1  |  1  |  1  |  ALL
+ */
+
+#define MX_BP_MASK (SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3)
+#define MX_BP_SHIFT(SR_BP_SHIFT)
+
+static int mx_get_locked_len(struct spi_nor *nor, u8 sr, uint64_t *lock_len)
+{
+   struct mtd_info *mtd = >mtd;
+   u8 bp;
+
+   bp = (sr & MX_BP_MASK) >> MX_BP_SHIFT;
+
+   if (bp == 0xf) {
+   /* protected all */
+   *lock_len = mtd->size;
+   return 0;
+   }
+
+   /* sorry, not yet supported */
+   if (bp > 0x7)
+   return -EOPNOTSUPP;
+
+   /* block size = 64Kib */
+   *lock_len = bp ? (0x8000 << bp) : 0;
+   return 0;
+}
+
+static int mx_set_prot_level(struct spi_nor *nor, uint64_t lock_len, u8 *sr)
+{
+   uint64_t new_len;
+   u8 new_lvl;
+
+   if (lock_len) {
+   /* 64Kib block size harcoded */
+   new_lvl = ilog2(lock_len) - 15;
+   new_len = 1ULL << (15 + new_lvl);
+
+   if (new_len != lock_len)
+   return -EINVAL;
+   } else {
+   new_lvl = 0;
+   }
+
+   *sr &= ~MX_BP_MASK;
+   *sr |= (new_lvl) << MX_BP_SHIFT;
+
+   return 0;
+}
+
+static int mx_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   struct mtd_info *mtd = >mtd;
+   int ret;
+   uint64_t lock_len;
+   u8 sr;
+
+   ret = spi_nor_read_sr(nor, nor->bouncebuf);
+   if (ret)
+   return ret;
+
+   sr = nor->bouncebuf[0];
+
+   /* always 'top' protection */
+   if ((ofs + len) != mtd->size)
+   return -EINVAL;
+
+   ret = mx_get_locked_len(nor, sr, _len);
+   if (ret)
+   return ret;
+
+   /* already locked? */
+   if (len <= lock_len)
+   return 0;
+
+   ret = mx_set_prot_level(nor, len, );
+   if (ret)
+   return ret;
+
+   /* Disallow further writes if WP pin is asserted */
+   sr |= SR_SRWD;
+
+   return spi_nor_write_sr_and_check(nor, sr);
+}
+
+static int mx_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   struct mtd_info *mtd = >mtd;
+   int ret;
+   uint64_t lock_len;
+   u8 sr;
+
+   if ((ofs + len) > mtd->size)
+   return -EINVAL;
+
+   ret = spi_nor_read_sr(nor, nor->bouncebuf);
+   if (ret)
+   return ret;
+
+   sr = nor->bouncebuf[0];
+
+   ret = mx_get_locked_len(nor, sr, _len);
+   if (ret)
+   return ret;
+
+   /* already unlocked? */
+   if ((ofs + len) <= (mtd->size - lock_len))
+   return 0;
+
+   /* can't make a hole in a locked region */
+   if (ofs > (mtd->size - lock_len))
+   return -EINVAL;
+
+   lock_len = mtd->size - ofs - len;
+   ret = mx_set_prot_level(nor, lock_len, );
+   if (ret)
+   return ret;
+
+   /* Don't protect status register if we're fully unlocked */
+   if (lock_len == 0)
+   sr &= ~SR_SRWD;
+
+   return spi_nor_write_sr_and_check(nor, sr);
+}
+
+static int mx_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+   struct mtd_info *mtd = >mtd;
+   int ret;
+   uint64_t lock_len;
+   u8 sr;
+
+   if ((ofs + len) &

[PATCH v4 2/2] HID: google: Add of_match table to Whiskers switch device.

2021-04-12 Thread Ikjoon Jang
Add a device tree match table for "cros-cbas" switch device.

Signed-off-by: Ikjoon Jang 
Reviewed-by: Dmitry Torokhov 
Acked-by: Jiri Kosina 

---

(no changes since v1)

Please note that v3 was submitted in 28 Oct 2019, 1.5yrs ago.
Link(v2): 
https://patchwork.kernel.org/project/linux-input/patch/20191021030158.32464-1-i...@chromium.org/

---
 drivers/hid/hid-google-hammer.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
index d9319622da44..be4f9f3dbbba 100644
--- a/drivers/hid/hid-google-hammer.c
+++ b/drivers/hid/hid-google-hammer.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -272,12 +273,21 @@ static const struct acpi_device_id cbas_ec_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
 
+#ifdef CONFIG_OF
+static const struct of_device_id cbas_ec_of_match[] = {
+   { .compatible = "google,cros-cbas" },
+   { },
+};
+MODULE_DEVICE_TABLE(of, cbas_ec_of_match);
+#endif
+
 static struct platform_driver cbas_ec_driver = {
.probe = cbas_ec_probe,
.remove = cbas_ec_remove,
.driver = {
.name = "cbas_ec",
.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
+   .of_match_table = of_match_ptr(cbas_ec_of_match),
.pm = _ec_pm_ops,
},
 };
-- 
2.31.1.295.g9ea45b61b8-goog



[PATCH v4 1/2] mfd: google,cros-ec: add DT bindings for a baseboard's switch device

2021-04-12 Thread Ikjoon Jang
This is for ChromeOS tablets which have a 'cros_cbas' switch device
in the "Whiskers" base board. This device can be instantiated only by
device tree on ARM platforms. ChromeOS EC doesn't provide a way to
probe the device.

Signed-off-by: Ikjoon Jang 

---

Changes in v4:
Define cros-cbase bindings inside google,cros-ec.yaml instead of
a seperated binding document.

 .../devicetree/bindings/mfd/google,cros-ec.yaml  | 16 
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml 
b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
index 76bf16ee27ec..c76809cd9f7f 100644
--- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
+++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml
@@ -127,6 +127,18 @@ patternProperties:
 type: object
 $ref: "/schemas/extcon/extcon-usbc-cros-ec.yaml#"
 
+  "^cbas$":
+type: object
+properties:
+  compatible:
+const: google,cros-cbas
+required:
+  - compatible
+additionalProperties: false
+description:
+  This device is used to signal when a detachable base is attached
+  to a Chrome OS tablet.
+
 required:
   - compatible
 
@@ -180,6 +192,10 @@ examples:
 interrupts = <99 0>;
 interrupt-parent = <>;
 spi-max-frequency = <500>;
+
+base_detection: cbas {
+compatible = "google,cros-cbas";
+};
 };
 };
 
-- 
2.31.1.295.g9ea45b61b8-goog



[PATCH v4 0/2] HID: google: add device tree bindings for Whiskers switch device

2021-04-12 Thread Ikjoon Jang
Add device a tree binding for a "cros-cbas" switch device of
ChromeOS tablets with Whiskers base board.

Changes in v4:
Define cros-cbase bindings inside google,cros-ec.yaml instead of
a seperated binding document.

Ikjoon Jang (2):
  mfd: google,cros-ec: add DT bindings for a baseboard's switch device
  HID: google: Add of_match table to Whiskers switch device.

 .../devicetree/bindings/mfd/google,cros-ec.yaml  | 16 
 drivers/hid/hid-google-hammer.c  | 10 ++
 2 files changed, 26 insertions(+)

-- 
2.31.1.295.g9ea45b61b8-goog



Re: [PATCH 4/6] usb: xhci-mtk: add support runtime PM

2021-04-11 Thread Ikjoon Jang
On Fri, Apr 9, 2021 at 4:54 PM Chunfeng Yun  wrote:
>
> On Fri, 2021-04-09 at 13:45 +0800, Ikjoon Jang wrote:
> > On Thu, Apr 8, 2021 at 5:35 PM Chunfeng Yun  
> > wrote:
> > >
> > > A dedicated wakeup irq will be used to handle runtime suspend/resume,
> > > we use dev_pm_set_dedicated_wake_irq API to take care of requesting
> > > and attaching wakeup irq, then the suspend/resume framework will help
> > > to enable/disable wakeup irq.
> > >
> > > The runtime PM is default off since some platforms may not support it.
> > > users can enable it via power/control (set "auto") in sysfs.
> > >
> > > Signed-off-by: Chunfeng Yun 
> > > ---
> > >  drivers/usb/host/xhci-mtk.c | 140 +++-
> > >  1 file changed, 124 insertions(+), 16 deletions(-)
> > >
> > > diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> > > index a74764ab914a..30927f4064d4 100644
> > > --- a/drivers/usb/host/xhci-mtk.c
> > > +++ b/drivers/usb/host/xhci-mtk.c
> > > @@ -16,6 +16,7 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > > +#include 
> > >  #include 
> > >  #include 
> > >
> > > @@ -358,7 +359,6 @@ static int usb_wakeup_of_property_parse(struct 
> > > xhci_hcd_mtk *mtk,
> > > mtk->uwk_reg_base, mtk->uwk_vers);
> > >
> > > return PTR_ERR_OR_ZERO(mtk->uwk);
> > > -
> > >  }
> > >
> > >  static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
> > > @@ -458,6 +458,7 @@ static int xhci_mtk_probe(struct platform_device 
> > > *pdev)
> > > struct resource *res;
> > > struct usb_hcd *hcd;
> > > int ret = -ENODEV;
> > > +   int wakeup_irq;
> > > int irq;
> > >
> > > if (usb_disabled())
> > > @@ -485,6 +486,21 @@ static int xhci_mtk_probe(struct platform_device 
> > > *pdev)
> > > if (ret)
> > > return ret;
> > >
> > > +   irq = platform_get_irq_byname_optional(pdev, "host");
> > > +   if (irq < 0) {
> > > +   if (irq == -EPROBE_DEFER)
> > > +   return irq;
> > > +
> > > +   /* for backward compatibility */
> > > +   irq = platform_get_irq(pdev, 0);
> > > +   if (irq < 0)
> > > +   return irq;
> > > +   }
> > > +
> > > +   wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup");
> > > +   if (wakeup_irq == -EPROBE_DEFER)
> > > +   return wakeup_irq;
> > > +
> > > mtk->lpm_support = of_property_read_bool(node, 
> > > "usb3-lpm-capable");
> > > /* optional property, ignore the error if it does not exist */
> > > of_property_read_u32(node, "mediatek,u3p-dis-msk",
> > > @@ -496,9 +512,11 @@ static int xhci_mtk_probe(struct platform_device 
> > > *pdev)
> > > return ret;
> > > }
> > >
> > > +   pm_runtime_set_active(dev);
> > > +   pm_runtime_use_autosuspend(dev);
> > > +   pm_runtime_set_autosuspend_delay(dev, 4000);
> > > pm_runtime_enable(dev);
> > > pm_runtime_get_sync(dev);
> > > -   device_enable_async_suspend(dev);
> > >
> > > ret = xhci_mtk_ldos_enable(mtk);
> > > if (ret)
> > > @@ -508,12 +526,6 @@ static int xhci_mtk_probe(struct platform_device 
> > > *pdev)
> > > if (ret)
> > > goto disable_ldos;
> > >
> > > -   irq = platform_get_irq(pdev, 0);
> > > -   if (irq < 0) {
> > > -   ret = irq;
> > > -   goto disable_clk;
> > > -   }
> > > -
> > > hcd = usb_create_hcd(driver, dev, dev_name(dev));
> > > if (!hcd) {
> > > ret = -ENOMEM;
> > > @@ -579,8 +591,26 @@ static int xhci_mtk_probe(struct platform_device 
> > > *pdev)
> > > if (ret)
> > > goto dealloc_usb2_hcd;
> > >
> > > +   if (wakeup_irq > 0) {
> > > +   ret = dev_pm_set_dedicated_wake_irq(dev, wakeup_irq);
> > > +   if (ret) {
> > > +   

Re: [PATCH 4/6] usb: xhci-mtk: add support runtime PM

2021-04-08 Thread Ikjoon Jang
On Thu, Apr 8, 2021 at 5:35 PM Chunfeng Yun  wrote:
>
> A dedicated wakeup irq will be used to handle runtime suspend/resume,
> we use dev_pm_set_dedicated_wake_irq API to take care of requesting
> and attaching wakeup irq, then the suspend/resume framework will help
> to enable/disable wakeup irq.
>
> The runtime PM is default off since some platforms may not support it.
> users can enable it via power/control (set "auto") in sysfs.
>
> Signed-off-by: Chunfeng Yun 
> ---
>  drivers/usb/host/xhci-mtk.c | 140 +++-
>  1 file changed, 124 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> index a74764ab914a..30927f4064d4 100644
> --- a/drivers/usb/host/xhci-mtk.c
> +++ b/drivers/usb/host/xhci-mtk.c
> @@ -16,6 +16,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>
> @@ -358,7 +359,6 @@ static int usb_wakeup_of_property_parse(struct 
> xhci_hcd_mtk *mtk,
> mtk->uwk_reg_base, mtk->uwk_vers);
>
> return PTR_ERR_OR_ZERO(mtk->uwk);
> -
>  }
>
>  static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
> @@ -458,6 +458,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> struct resource *res;
> struct usb_hcd *hcd;
> int ret = -ENODEV;
> +   int wakeup_irq;
> int irq;
>
> if (usb_disabled())
> @@ -485,6 +486,21 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> +   irq = platform_get_irq_byname_optional(pdev, "host");
> +   if (irq < 0) {
> +   if (irq == -EPROBE_DEFER)
> +   return irq;
> +
> +   /* for backward compatibility */
> +   irq = platform_get_irq(pdev, 0);
> +   if (irq < 0)
> +   return irq;
> +   }
> +
> +   wakeup_irq = platform_get_irq_byname_optional(pdev, "wakeup");
> +   if (wakeup_irq == -EPROBE_DEFER)
> +   return wakeup_irq;
> +
> mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable");
> /* optional property, ignore the error if it does not exist */
> of_property_read_u32(node, "mediatek,u3p-dis-msk",
> @@ -496,9 +512,11 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> return ret;
> }
>
> +   pm_runtime_set_active(dev);
> +   pm_runtime_use_autosuspend(dev);
> +   pm_runtime_set_autosuspend_delay(dev, 4000);
> pm_runtime_enable(dev);
> pm_runtime_get_sync(dev);
> -   device_enable_async_suspend(dev);
>
> ret = xhci_mtk_ldos_enable(mtk);
> if (ret)
> @@ -508,12 +526,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> if (ret)
> goto disable_ldos;
>
> -   irq = platform_get_irq(pdev, 0);
> -   if (irq < 0) {
> -   ret = irq;
> -   goto disable_clk;
> -   }
> -
> hcd = usb_create_hcd(driver, dev, dev_name(dev));
> if (!hcd) {
> ret = -ENOMEM;
> @@ -579,8 +591,26 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> if (ret)
> goto dealloc_usb2_hcd;
>
> +   if (wakeup_irq > 0) {
> +   ret = dev_pm_set_dedicated_wake_irq(dev, wakeup_irq);
> +   if (ret) {
> +   dev_err(dev, "set wakeup irq %d failed\n", 
> wakeup_irq);
> +   goto dealloc_usb3_hcd;
> +   }
> +   dev_info(dev, "wakeup irq %d\n", wakeup_irq);
> +   }
> +
> +   device_enable_async_suspend(dev);
> +   pm_runtime_mark_last_busy(dev);
> +   pm_runtime_put_autosuspend(dev);
> +   pm_runtime_forbid(dev);
> +
> return 0;
>
> +dealloc_usb3_hcd:
> +   usb_remove_hcd(xhci->shared_hcd);
> +   xhci->shared_hcd = NULL;
> +
>  dealloc_usb2_hcd:
> usb_remove_hcd(hcd);
>
> @@ -601,25 +631,26 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> xhci_mtk_ldos_disable(mtk);
>
>  disable_pm:
> -   pm_runtime_put_sync(dev);
> +   pm_runtime_put_sync_autosuspend(dev);
> pm_runtime_disable(dev);
> return ret;
>  }
>
> -static int xhci_mtk_remove(struct platform_device *dev)
> +static int xhci_mtk_remove(struct platform_device *pdev)
>  {
> -   struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
> +   struct xhci_hcd_mtk *mtk = platform_get_drvdata(pdev);
> struct usb_hcd  *hcd = mtk->hcd;
> struct xhci_hcd *xhci = hcd_to_xhci(hcd);
> struct usb_hcd  *shared_hcd = xhci->shared_hcd;
> +   struct device *dev = >dev;
>
> -   pm_runtime_put_noidle(>dev);
> -   pm_runtime_disable(>dev);
> +   pm_runtime_get_sync(dev);
> +   xhci->xhc_state |= XHCI_STATE_REMOVING;
> +   dev_pm_clear_wake_irq(dev);
> +   device_init_wakeup(dev, false);
>
> usb_remove_hcd(shared_hcd);
> 

Re: [PATCH 1/6] PM: runtime: enable wake irq after runtime_suspend hook called

2021-04-08 Thread Ikjoon Jang
Hi Chunfeng,

On Thu, Apr 8, 2021 at 5:35 PM Chunfeng Yun  wrote:
>
> When the dedicated wake irq is level trigger, enable it before
> calling runtime_suspend, will trigger an interrupt.
>
> e.g.
> for a low level trigger type, it's low level at running time (0),
> and becomes high level when enters suspend (runtime_suspend (1) is
> called), a wakeup signal at (2) make it become low level, wake irq
> will be triggered.
>
> --
>|   ^ ^|
>    | | --
>  |<---(0)--->|<--(1)--|   (3)   (2)(4)
>

Can't we just use a falling edge type for this irq line?

> if we enable the wake irq before calling runtime_suspend during (0),
> an interrupt will arise, it causes resume immediately;
> enable wake irq after calling runtime_suspend, e.g. at (3) or (4),
> will works.
>
> This patch seems no side effect on edge trigger wake irq.
>
> Signed-off-by: Chunfeng Yun 
> ---
>  drivers/base/power/runtime.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
> index a46a7e30881b..796739a015a5 100644
> --- a/drivers/base/power/runtime.c
> +++ b/drivers/base/power/runtime.c
> @@ -619,12 +619,12 @@ static int rpm_suspend(struct device *dev, int rpmflags)
> __update_runtime_status(dev, RPM_SUSPENDING);
>
> callback = RPM_GET_CALLBACK(dev, runtime_suspend);
> -
> -   dev_pm_enable_wake_irq_check(dev, true);
> retval = rpm_callback(callback, dev);
> if (retval)
> goto fail;
>
> +   dev_pm_enable_wake_irq_check(dev, true);
> +
>   no_callback:
> __update_runtime_status(dev, RPM_SUSPENDED);
> pm_runtime_deactivate_timer(dev);
> @@ -659,7 +659,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
> return retval;
>
>   fail:
> -   dev_pm_disable_wake_irq_check(dev);
> __update_runtime_status(dev, RPM_ACTIVE);
> dev->power.deferred_resume = false;
> wake_up_all(>power.wait_queue);
> --
> 2.18.0
>


[PATCH 1/2] usb: xhci-mtk: remove unnecessary assignments in periodic TT scheduler

2021-03-30 Thread Ikjoon Jang
Remove unnecessary variables in check_sch_bw().
No functional changes, just for better readability.

Signed-off-by: Ikjoon Jang 
---

 drivers/usb/host/xhci-mtk-sch.c | 52 +
 1 file changed, 21 insertions(+), 31 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index a59d1f6d4744..0cb41007ec65 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -479,6 +479,9 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, 
u32 offset)
u32 start_cs, last_cs;
int i;
 
+   if (!sch_ep->sch_tt)
+   return 0;
+
start_ss = offset % 8;
 
if (sch_ep->ep_type == ISOC_OUT_EP) {
@@ -606,54 +609,41 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info 
*sch_ep)
 static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
struct mu3h_sch_ep_info *sch_ep)
 {
-   u32 offset;
-   u32 min_bw;
-   u32 min_index;
-   u32 worst_bw;
-   u32 bw_boundary;
-   u32 esit_boundary;
-   u32 min_num_budget;
-   u32 min_cs_count;
-   int ret = 0;
+   int i, found = -1;
+   const u32 esit_boundary = get_esit_boundary(sch_ep);
+   const u32 bw_boundary = get_bw_boundary(sch_ep->speed);
+   u32 min_bw = ~0;
 
/*
 * Search through all possible schedule microframes.
 * and find a microframe where its worst bandwidth is minimum.
 */
-   min_bw = ~0;
-   min_index = 0;
-   min_cs_count = sch_ep->cs_count;
-   min_num_budget = sch_ep->num_budget_microframes;
-   esit_boundary = get_esit_boundary(sch_ep);
-   for (offset = 0; offset < sch_ep->esit; offset++) {
-   if (sch_ep->sch_tt) {
-   ret = check_sch_tt(sch_ep, offset);
-   if (ret)
-   continue;
-   }
+   for (i = 0; i < sch_ep->esit; i++) {
+   u32 worst_bw;
 
-   if ((offset + sch_ep->num_budget_microframes) > esit_boundary)
+   if ((i + sch_ep->num_budget_microframes) > esit_boundary)
break;
 
-   worst_bw = get_max_bw(sch_bw, sch_ep, offset);
+   if (check_sch_tt(sch_ep, i))
+   continue;
+
+   worst_bw = get_max_bw(sch_bw, sch_ep, i);
+   if (worst_bw > bw_boundary)
+   continue;
+
if (min_bw > worst_bw) {
min_bw = worst_bw;
-   min_index = offset;
-   min_cs_count = sch_ep->cs_count;
-   min_num_budget = sch_ep->num_budget_microframes;
+   found = i;
}
if (min_bw == 0)
break;
}
 
-   bw_boundary = get_bw_boundary(sch_ep->speed);
/* check bandwidth */
-   if (min_bw > bw_boundary)
-   return ret ? ret : -ESCH_BW_OVERFLOW;
+   if (found < 0)
+   return -ESCH_BW_OVERFLOW;
 
-   sch_ep->offset = min_index;
-   sch_ep->cs_count = min_cs_count;
-   sch_ep->num_budget_microframes = min_num_budget;
+   sch_ep->offset = found;
 
return load_ep_bw(sch_bw, sch_ep, true);
 }
-- 
2.31.0.291.g576ba9dcdaf-goog



[PATCH 2/2] usb: xhci-mtk: relax periodic TT bandwidth checking

2021-03-30 Thread Ikjoon Jang
Software bandwidth checking logics used by xhci-mtk puts
a quite heavy constraints to TT periodic endpoint allocations.

This patch provides a relaxed bandwidth calculation by
- Allowing multiple periodic transactions in a same microframe
  for a device with multiple interrupt endpoints.
- Using best case budget instead of maximum number of
  complete-split when calculating byte budgets on lower speed bus

Without this patch, a typical full speed audio headset with
3 periodic endpoints (audio isoc-in/out, input int-in) cannot be
configured with xhci-mtk.

Signed-off-by: Ikjoon Jang 
---

 drivers/usb/host/xhci-mtk-sch.c | 68 ++---
 drivers/usb/host/xhci-mtk.h |  2 -
 2 files changed, 20 insertions(+), 50 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 0cb41007ec65..76827e48049a 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -388,13 +388,17 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
} else { /* INT_IN_EP or ISOC_IN_EP */
bwb_table[0] = 0; /* start split */
bwb_table[1] = 0; /* idle */
+
+   sch_ep->num_budget_microframes += 2;
+   if (sch_ep->num_budget_microframes > sch_ep->esit)
+   sch_ep->num_budget_microframes = sch_ep->esit;
/*
 * due to cs_count will be updated according to cs
 * position, assign all remainder budget array
 * elements as @bw_cost_per_microframe, but only first
 * @num_budget_microframes elements will be used later
 */
-   for (i = 2; i < TT_MICROFRAMES_MAX; i++)
+   for (i = 2; i < sch_ep->num_budget_microframes; i++)
bwb_table[i] =  sch_ep->bw_cost_per_microframe;
}
}
@@ -449,20 +453,17 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
 static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
 {
struct mu3h_sch_tt *tt = sch_ep->sch_tt;
-   u32 num_esit, tmp;
-   int base;
int i, j;
+   const int nr_lower_uframes =
+   DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
 
-   num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
-   for (i = 0; i < num_esit; i++) {
-   base = offset + i * sch_ep->esit;
-
+   for (i = offset; i < XHCI_MTK_MAX_ESIT; i += sch_ep->esit) {
/*
 * Compared with hs bus, no matter what ep type,
 * the hub will always delay one uframe to send data
 */
-   for (j = 0; j < sch_ep->cs_count; j++) {
-   tmp = tt->fs_bus_bw[base + j] + 
sch_ep->bw_cost_per_microframe;
+   for (j = 0; j < nr_lower_uframes; j++) {
+   u32 tmp = tt->fs_bus_bw[i + j + 1] + 
sch_ep->bw_cost_per_microframe;
if (tmp > FS_PAYLOAD_MAX)
return -ESCH_BW_OVERFLOW;
}
@@ -473,11 +474,9 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info 
*sch_ep, int offset)
 
 static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
 {
-   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
u32 start_ss, last_ss;
u32 start_cs, last_cs;
-   int i;
 
if (!sch_ep->sch_tt)
return 0;
@@ -494,10 +493,6 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, 
u32 offset)
if (!(start_ss == 7 || last_ss < 6))
return -ESCH_SS_Y6;
 
-   for (i = 0; i < sch_ep->cs_count; i++)
-   if (test_bit(offset + i, tt->ss_bit_map))
-   return -ESCH_SS_OVERLAP;
-
} else {
u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
 
@@ -524,19 +519,7 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, 
u32 offset)
if (cs_count > 7)
cs_count = 7; /* HW limit */
 
-   if (test_bit(offset, tt->ss_bit_map))
-   return -ESCH_SS_OVERLAP;
-
sch_ep->cs_count = cs_count;
-   /* one for ss, the other for idle */
-   sch_ep->num_budget_microframes = cs_count + 2;
-
-   /*
-* if interval=1, maxp >752, num_budge_micoframe is larger
-* than sch_ep->esit, will overstep boundary
-*/
-   if (sch_ep->num_budget_microframes > sch_ep->esit)
-   sch_ep->num_budget_microframes = sch_ep->esit;
}
 
return check_fs_bus_bw(sch_ep

[PATCH 0/2] usb: xhci-mtk: relax peridoc TT bandwidth checking

2021-03-30 Thread Ikjoon Jang
This series is for supporting typical full speed USB audio headsets
with speaker, microphone, and control knobs together.

With current implementation, such a device cannot be configured
due to xhci-mtk's bandwidth allocation failure even when there's
enough bandwidth available.

Ikjoon Jang (2):
  usb: xhci-mtk: remove unnecessary assignments in periodic TT scheduler
  usb: xhci-mtk: relax periodic TT bandwidth checking

 drivers/usb/host/xhci-mtk-sch.c | 120 +++-
 drivers/usb/host/xhci-mtk.h |   2 -
 2 files changed, 41 insertions(+), 81 deletions(-)

-- 
2.31.0.291.g576ba9dcdaf-goog



Re: [PATCH] ALSA: usb-audio: Apply sample rate quirk to Logitech Connect

2021-03-29 Thread Ikjoon Jang
On Wed, Mar 24, 2021 at 8:49 PM Takashi Iwai  wrote:
>
> On Wed, 24 Mar 2021 13:03:14 +0100,
> Ikjoon Jang wrote:
> >
> > On Wed, Mar 24, 2021, 7:16 PM Joakim Tjernlund 
> > 
> > wrote:
> >
> >     On Wed, 2021-03-24 at 18:51 +0800, Ikjoon Jang wrote:
> > > Logitech ConferenceCam Connect is a compound USB device with UVC and
> > > UAC. Not 100% reproducible but sometimes it keeps responding STALL to
> > > every control transfer once it receives get_freq request.
> > >
> > > This patch adds 046d:0x084c to a snd_usb_get_sample_rate_quirk list.
> > >
> > > Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203419
> > > Signed-off-by: Ikjoon Jang 
> >
> > Most Logitech USB headset I got needs a delay in snd_usb_ctl_msg_quirk()
> > Have you tried to add say 20 ms delay in there?
> >
> > I didn't try that. But it sounds reasonable to me.
> >
> > let me try that quirk here. If that is the case, HID might need that delay
> > also. Logitech Group webcam had a similar problem on control xfer of
> > get_report from an another interface for HID.
>
> The Logitech devices with 046d:* should be covered generally in
> snd_usb_ctl_msg_quirk(), so I guess it's a different problem.
> But please check it first.
>
> > And 20ms can be too long if it's applied to every control transfer. I will
> > test the device with shorter delay if you didn't try it before.
>
> Actually the delay applied to Logitech devices is from 1 to 2ms, not
> 20ms.  The 20ms delay is applied for some other devices.  But if
> extending the delay fixes the problem, we need to reconsider the delay
> length.

I tested this Logitech device with various delays 2..20ms
in snd_usb_ctl_msg_quirk() but it didn't help.

Disregarding the delay between control transfers,
This device is always stuck at get_cur, responding STALL to all
control transfers.

[   24.045618] usb 1-1.2.1.1: 1:1: cannot get freq at ep 0x82
[   24.167475] usb 1-1.2.1.1: 2:0: cannot get min/max values for
control 2 (id 2)
[   24.287393] usb 1-1.2.1.1: 6:0: cannot get min/max values for
control 2 (id 6)
[   24.289854] usbcore: registered new interface driver snd-usb-audio
[   24.877073] usb 1-1.2.1.1: 2:1: usb_set_interface failed (-32)

And I've also found that in some other platforms (with the same kernel),
this device fails at get_freq - timeout with NYETs or NAKs (instead of STALL),
and succeeded in following set_interface even without any delays
I've tried but couldn't find any differences between the two. ;-(

So until now, I think this approach of skipping get_rate is the only
one possible
workaround for Logitech Connect.

>
>
> Takashi


[PATCH] ALSA: usb-audio: Apply sample rate quirk to Logitech Connect

2021-03-24 Thread Ikjoon Jang
Logitech ConferenceCam Connect is a compound USB device with UVC and
UAC. Not 100% reproducible but sometimes it keeps responding STALL to
every control transfer once it receives get_freq request.

This patch adds 046d:0x084c to a snd_usb_get_sample_rate_quirk list.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203419
Signed-off-by: Ikjoon Jang 

---

 sound/usb/quirks.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index d3001fb18141..176437a441e6 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1521,6 +1521,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio 
*chip)
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
+   case USB_ID(0x046d, 0x084c): /* Logitech ConferenceCam Connect */
return true;
}
 
-- 
2.31.0.291.g576ba9dcdaf-goog



Re: [PATCH] i2c: mediatek: Get device clock-stretch time via dts

2021-03-02 Thread Ikjoon Jang
Hi Qii,

On Wed, Feb 3, 2021 at 6:43 PM  wrote:
>
> From: Qii Wang 
>
> tSU,STA/tHD,STA/tSU,STOP maybe out of spec due to device
> clock-stretching or circuit loss, we could get device
> clock-stretch time from dts to adjust these parameters
> to meet the spec via EXT_CONF register.
>
> Signed-off-by: Qii Wang 
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> index 2ffd2f3..47c7255 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -245,6 +245,7 @@ struct mtk_i2c {
> u16 irq_stat;   /* interrupt status */
> unsigned int clk_src_div;
> unsigned int speed_hz;  /* The speed in transfer */
> +   unsigned int clock_stretch_ns;
> enum mtk_trans_op op;
> u16 timing_reg;
> u16 high_speed_reg;
> @@ -607,7 +608,8 @@ static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
> else
> clk_ns = sample_ns / 2;
>
> -   su_sta_cnt = DIV_ROUND_UP(spec->min_su_sta_ns, clk_ns);
> +   su_sta_cnt = DIV_ROUND_UP(spec->min_su_sta_ns + i2c->clock_stretch_ns,
> + clk_ns);
> if (su_sta_cnt > max_sta_cnt)
> return -1;
>
> @@ -1171,6 +1173,8 @@ static int mtk_i2c_parse_dt(struct device_node *np, 
> struct mtk_i2c *i2c)
> if (i2c->clk_src_div == 0)
> return -EINVAL;
>
> +   of_property_read_u32(np, "clock-stretch-ns", >clock_stretch_ns);
> +

I think this new property "clock-stretch-ns" is for the same purpose of
"i2c-scl-falling-time-ns" + "i2c-scl-rising-time-ns" defined in
Documentation/devicetree/bindings/i2c/i2c.txt?

> i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic");
> i2c->use_push_pull =
> of_property_read_bool(np, "mediatek,use-push-pull");
> --
> 1.9.1
> ___
> Linux-mediatek mailing list
> linux-media...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek


[PATCH] arm64: dts: mt8183: Add power-domains properity to mfgcfg

2021-02-24 Thread Ikjoon Jang
mfgcfg clock is under MFG_ASYNC power domain

Signed-off-by: Weiyi Lu 
Signed-off-by: Ikjoon Jang 
---

 arch/arm64/boot/dts/mediatek/mt8183.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi 
b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 5b782a4769e7..3384df5284c0 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -962,6 +962,7 @@ mfgcfg: syscon@1300 {
compatible = "mediatek,mt8183-mfgcfg", "syscon";
reg = <0 0x1300 0 0x1000>;
#clock-cells = <1>;
+   power-domains = < MT8183_POWER_DOMAIN_MFG_ASYNC>;
};
 
mmsys: syscon@1400 {
-- 
2.30.0.617.g56c4b15f3c-goog



Re: [RFC v4 PATCH] usb: xhci-mtk: improve bandwidth scheduling with TT

2021-02-21 Thread Ikjoon Jang
On Mon, Feb 8, 2021 at 11:27 AM Chunfeng Yun  wrote:
>
> When the USB headset is plug into an external hub, sometimes
> can't set config due to not enough bandwidth, so need improve
> LS/FS INT/ISOC bandwidth scheduling with TT.
>
> Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
> multi-TT")
> Signed-off-by: Yaqii Wu 
> Signed-off-by: Chunfeng Yun 

Tested-by: Ikjoon Jang 

> ---
>  drivers/usb/host/xhci-mtk-sch.c | 270 +++-
>  drivers/usb/host/xhci-mtk.h |   8 +-
>  2 files changed, 201 insertions(+), 77 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> index b45e5bf08997..f3cdfcf4e5bf 100644
> --- a/drivers/usb/host/xhci-mtk-sch.c
> +++ b/drivers/usb/host/xhci-mtk-sch.c
> @@ -32,6 +32,35 @@
>  #define EP_BOFFSET(p)  ((p) & 0x3fff)
>  #define EP_BREPEAT(p)  (((p) & 0x7fff) << 16)
>
> +enum mtk_sch_err_type {
> +   SCH_SUCCESS = 0,
> +   SCH_ERR_Y6,
> +   SCH_SS_OVERLAP,
> +   SCH_CS_OVERFLOW,
> +   SCH_BW_OVERFLOW,
> +   SCH_FIXME,
> +};
> +
> +static char *sch_error_string(enum mtk_sch_err_type error)
> +{
> +   switch (error) {
> +   case SCH_SUCCESS:
> +   return "Success";
> +   case SCH_ERR_Y6:
> +   return "Can't schedule Start-Split in Y6";
> +   case SCH_SS_OVERLAP:
> +   return "Can't find a suitable Start-Split location";
> +   case SCH_CS_OVERFLOW:
> +   return "The last Complete-Split is greater than 7";
> +   case SCH_BW_OVERFLOW:
> +   return "Bandwidth exceeds the max limit";
> +   case SCH_FIXME:
> +   return "FIXME, to be resolved";
> +   default:
> +   return "Unknown error type";
> +   }
> +}
> +
>  static int is_fs_or_ls(enum usb_device_speed speed)
>  {
> return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW;
> @@ -81,11 +110,22 @@ static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
> return esit;
>  }
>
> +static u32 get_bw_boundary(enum usb_device_speed speed)
> +{
> +   switch (speed) {
> +   case USB_SPEED_SUPER_PLUS:
> +   return SSP_BW_BOUNDARY;
> +   case USB_SPEED_SUPER:
> +   return SS_BW_BOUNDARY;
> +   default:
> +   return HS_BW_BOUNDARY;
> +   }
> +}
> +
>  static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
>  {
> struct usb_tt *utt = udev->tt;
> struct mu3h_sch_tt *tt, **tt_index, **ptt;
> -   unsigned int port;
> bool allocated_index = false;
>
> if (!utt)
> @@ -107,10 +147,9 @@ static struct mu3h_sch_tt *find_tt(struct usb_device 
> *udev)
> utt->hcpriv = tt_index;
> allocated_index = true;
> }
> -   port = udev->ttport - 1;
> -   ptt = _index[port];
> +
> +   ptt = _index[udev->ttport - 1];
> } else {
> -   port = 0;
> ptt = (struct mu3h_sch_tt **) >hcpriv;
> }
>
> @@ -125,8 +164,7 @@ static struct mu3h_sch_tt *find_tt(struct usb_device 
> *udev)
> return ERR_PTR(-ENOMEM);
> }
> INIT_LIST_HEAD(>ep_list);
> -   tt->usb_tt = utt;
> -   tt->tt_port = port;
> +
> *ptt = tt;
> }
>
> @@ -206,6 +244,15 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
> usb_device *udev,
> return sch_ep;
>  }
>
> +static void delete_sch_ep(struct usb_device *udev, struct mu3h_sch_ep_info 
> *sch_ep)
> +{
> +   if (sch_ep->sch_tt)
> +   drop_tt(udev);
> +
> +   list_del(_ep->endpoint);
> +   kfree(sch_ep);
> +}
> +
>  static void setup_sch_info(struct usb_device *udev,
> struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
>  {
> @@ -375,21 +422,55 @@ static void update_bus_bw(struct mu3h_sch_bw_info 
> *sch_bw,
> sch_ep->bw_budget_table[j];
> }
> }
> -   sch_ep->allocated = used;
>  }
>
> -static int check_sch_tt(struct usb_device *udev,
> -   struct mu3h_sch_ep_info *sch_ep, u32 offset)
> +static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
> +{
> +   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
> +   u32 num_esit, base;
> +   u32 i, j;
> +   u32 tmp;
> +
> +   num_esit = XHCI

Re: [next PATCH] usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints

2021-02-01 Thread Ikjoon Jang
HI Chunfeng,

On Mon, Feb 1, 2021 at 1:58 PM Chunfeng Yun  wrote:
>
> For those unchecked endpoints, we don't allocate bandwidth for
> them, so no need free the bandwidth, otherwise will decrease
> the allocated bandwidth.
> Meanwhile use xhci_dbg() instead of dev_dbg() to print logs and
> rename bw_ep_list_new as bw_ep_chk_list.
>
> Fixes: 1d69f9d901ef ("usb: xhci-mtk: fix unreleased bandwidth data")
> Cc: stable 
> Signed-off-by: Chunfeng Yun 

Reviewed-and-tested-by: Ikjoon Jang 

> ---
>  drivers/usb/host/xhci-mtk-sch.c | 61 ++---
>  drivers/usb/host/xhci-mtk.h |  4 ++-
>  2 files changed, 36 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> index a313e75ff1c6..dee8a329076d 100644
> --- a/drivers/usb/host/xhci-mtk-sch.c
> +++ b/drivers/usb/host/xhci-mtk-sch.c
> @@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
> usb_device *udev,
>
> sch_ep->sch_tt = tt;
> sch_ep->ep = ep;
> +   INIT_LIST_HEAD(_ep->endpoint);
> INIT_LIST_HEAD(_ep->tt_endpoint);
>
> return sch_ep;
> @@ -374,6 +375,7 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
> sch_ep->bw_budget_table[j];
> }
> }
> +   sch_ep->allocated = used;

Yes, this is really needed!

>  }
>
>  static int check_sch_tt(struct usb_device *udev,
> @@ -542,6 +544,22 @@ static int check_sch_bw(struct usb_device *udev,
> return 0;
>  }
>
> +static void destroy_sch_ep(struct usb_device *udev,
> +   struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
> +{
> +   /* only release ep bw check passed by check_sch_bw() */
> +   if (sch_ep->allocated)
> +   update_bus_bw(sch_bw, sch_ep, 0);

So only these two lines really matter.

> +
> +   list_del(_ep->endpoint);
> +
> +   if (sch_ep->sch_tt) {
> +   list_del(_ep->tt_endpoint);
> +   drop_tt(udev);
> +   }
> +   kfree(sch_ep);
> +}
> +
>  static bool need_bw_sch(struct usb_host_endpoint *ep,
> enum usb_device_speed speed, int has_tt)
>  {
> @@ -584,7 +602,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
>
> mtk->sch_array = sch_array;
>
> -   INIT_LIST_HEAD(>bw_ep_list_new);
> +   INIT_LIST_HEAD(>bw_ep_chk_list);
>
> return 0;
>  }
> @@ -636,29 +654,12 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
> usb_device *udev,
>
> setup_sch_info(udev, ep_ctx, sch_ep);
>
> -   list_add_tail(_ep->endpoint, >bw_ep_list_new);
> +   list_add_tail(_ep->endpoint, >bw_ep_chk_list);
>
> return 0;
>  }
>  EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
>
> -static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device 
> *udev,
> -struct mu3h_sch_ep_info *sch_ep)
> -{
> -   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
> -   int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
> -   struct mu3h_sch_bw_info *sch_bw = >sch_array[bw_index];
> -
> -   update_bus_bw(sch_bw, sch_ep, 0);
> -   list_del(_ep->endpoint);
> -
> -   if (sch_ep->sch_tt) {
> -   list_del(_ep->tt_endpoint);
> -   drop_tt(udev);
> -   }
> -   kfree(sch_ep);
> -}
> -
>  void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
> struct usb_host_endpoint *ep)
>  {
> @@ -688,9 +689,8 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
> usb_device *udev,
> sch_bw = _array[bw_index];
>
> list_for_each_entry_safe(sch_ep, tmp, _bw->bw_ep_list, endpoint) {
> -   if (sch_ep->ep == ep) {
> -   xhci_mtk_drop_ep(mtk, udev, sch_ep);
> -   }
> +   if (sch_ep->ep == ep)
> +   destroy_sch_ep(udev, sch_bw, sch_ep);

not so critical but I've also missed 'break' here.
Can you please add a break statement here?

> }
>  }
>  EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
> @@ -704,9 +704,9 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct 
> usb_device *udev)
> struct mu3h_sch_ep_info *sch_ep, *tmp;
> int bw_index, ret;
>
> -   dev_dbg(>dev, "%s\n", __func__);
> +   xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(>dev));
>
> -   list_for_each_entry(sch_ep, >bw_ep_list_new, endpoint) {
> +   list_for_each_entry(sch_ep, >bw_ep_chk_list, en

Re: [v7,1/2] dt-binding: reset-controller: mediatek: add YAML schemas

2021-01-22 Thread Ikjoon Jang
On Fri, Jan 15, 2021 at 7:23 PM Crystal Guo  wrote:
>
> Add a YAML documentation for Mediatek, which uses ti reset-controller
> driver directly. The TI reset controller provides a common reset
> management, and is suitable for Mediatek SoCs.
>
> Signed-off-by: Crystal Guo 
> ---
>  .../bindings/reset/mediatek-syscon-reset.yaml | 51 +++
>  1 file changed, 51 insertions(+)
>  create mode 100644 
> Documentation/devicetree/bindings/reset/mediatek-syscon-reset.yaml
>
> diff --git 
> a/Documentation/devicetree/bindings/reset/mediatek-syscon-reset.yaml 
> b/Documentation/devicetree/bindings/reset/mediatek-syscon-reset.yaml
> new file mode 100644
> index ..85d241cdb0ea
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/mediatek-syscon-reset.yaml
> @@ -0,0 +1,51 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/reset/mediatek-syscon-reset.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mediatek Reset Controller
> +
> +maintainers:
> +  - Crystal Guo 
> +
> +description:
> +  The bindings describe the reset-controller for Mediatek SoCs,
> +  which is based on TI reset controller. For more detail, please
> +  visit Documentation/devicetree/bindings/reset/ti-syscon-reset.txt.
> +
> +properties:
> +  compatible:
> +const: mediatek,syscon-reset
> +
> +  '#reset-cells':
> +const: 1
> +
> +  ti,reset-bits:
> +description: >
> +  Contains the reset control register information, please refer to
> +  Documentation/devicetree/bindings/reset/ti-syscon-reset.txt.
> +

I remember that Rob didn't like adding new users of this property,

How about removing this from here and using a hardcoded version of
register layouts into driver code (and match it with compatible) ?

e.g.
struct ti_syscon_reset_data mt8192_reset_data { ... }

> +required:
> +  - compatible
> +  - '#reset-cells'
> +  - ti,reset-bits
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +#include 
> +infracfg: infracfg@10001000 {
> +compatible = "mediatek,mt8192-infracfg", "syscon", "simple-mfd";
> +reg = <0 0x10001000>;
> +#clock-cells = <1>;
> +
> +infracfg_rst: reset-controller {
> +compatible = "mediatek,syscon-reset";
> +#reset-cells = <1>;
> +ti,reset-bits = <
> +   0x140 15 0x144 15 0 0 (ASSERT_SET | DEASSERT_SET | 
> STATUS_NONE)
> +>;
> +};
> +};
> --
> 2.18.0
>


Re: [PATCH v5] usb: xhci-mtk: fix unreleased bandwidth data

2021-01-14 Thread Ikjoon Jang
On Thu, Jan 14, 2021 at 4:30 PM Chunfeng Yun  wrote:
>
> Hi Ikjoon,
>
> On Tue, 2021-01-12 at 13:48 +0800, Ikjoon Jang wrote:
> > On Fri, Jan 8, 2021 at 10:44 PM Mathias Nyman
> >  wrote:
> > >
> > > On 8.1.2021 8.11, Chunfeng Yun wrote:
> > > > On Thu, 2021-01-07 at 13:09 +0200, Mathias Nyman wrote:
> > > >> On 29.12.2020 8.24, Ikjoon Jang wrote:
> > > >>> xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> > > >>> to handle its own sw bandwidth managements and stores bandwidth data
> > > >>> into internal table every time add_endpoint() is called,
> > > >>> so when bandwidth allocation fails at one endpoint, all earlier
> > > >>> allocation from the same interface could still remain at the table.
> > > >>>
> > > >>> This patch adds two more hooks from check_bandwidth() and
> > > >>> reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > > >>> from reset_bandwidth().
> > > >>>
> > > >>> Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling 
> > > >>> with multi-TT")
> > > >>> Signed-off-by: Ikjoon Jang 
> > > >>>
> > > >>
> > > >> ...
> > > >>
> > > >>>
> > > >>> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> > > >>> index d4a8d0efbbc4..e1fcd3cf723f 100644
> > > >>> --- a/drivers/usb/host/xhci.c
> > > >>> +++ b/drivers/usb/host/xhci.c
> > > >>> @@ -2882,6 +2882,12 @@ static int xhci_check_bandwidth(struct usb_hcd 
> > > >>> *hcd, struct usb_device *udev)
> > > >>> xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
> > > >>> virt_dev = xhci->devs[udev->slot_id];
> > > >>>
> > > >>> +   if (xhci->quirks & XHCI_MTK_HOST) {
> > > >>> +   ret = xhci_mtk_check_bandwidth(hcd, udev);
> > > >>> +   if (ret < 0)
> > > >>> +   return ret;
> > > >>> +   }
> > > >>> +
> > > >>
> > > >> Just noticed that XHCI_MTK_HOST quirk is only set in xhci-mtk.c.
> > > >> xhci-mtk.c calls xhci_init_driver(..., xhci_mtk_overrides) with a 
> > > >> .reset override function.
> > > >>
> > > >> why not add override functions for .check_bandwidth and 
> > > >> .reset_bandwidth to xhci_mtk_overrides instead?
> > > >>
> > > >> Another patch to add similar overrides for .add_endpoint and 
> > > >> .drop_endpoint should probably be
> > > >> done so that we can get rid of the xhci_mtk_add/drop_ep_quirk() calls 
> > > >> in xhci.c as well
> > > > You mean, we can export xhci_add/drop_endpoint()?
> > >
> > > I think so, unless you have a better idea.
> > > I prefer exporting the generic add/drop_endpoint functions rather than 
> > > the vendor specific quirk functions.
> > >
> >
> > When moving out all MTK_HOST quirks and unlink xhci-mtk-sch from xhci,
> > xhci-mtk-sch still needs to touch the xhci internals, at least struct
> > xhci_ep_ctx.
> >
> > My naive idea is just let xhci export one more function to expose 
> > xhci_ep_ctx.
> > But I'm not sure whether this is acceptable:
> I find that xhci_add_endpoint() ignores some errors with return 0, for
> these cases we needn't call xhci_mtk_add_ep-quirk(), so may be not a
> good way to just export xhci_add_endpoint().

yeah, maybe that's from ep0 case?

And I've thought that we could also unlink xhci-mtk-sch from the xhci module
if MTK_HOST quirk functions are moved out to mtk platform driver's overrides.
I guess I've gone too far.

If we keep xhci-mtk-sch being built with the xhci module,
xhci-mtk-sch can directly access input control context and its drop/add flags,
so I think we can simply remove {add|drop}_endpoint() quirks and just handle
them all in {check|reset}_bandwidth() overrides.

>
> >
> > +struct xhci_ep_ctx* xhci_get_ep_contex(struct xhci_hcd *xhci, struct
> > usb_host_endpoint *ep)
> > +{ ... }
> > +EXPORT_SYMBOL(xhci_get_ep_context);
> >
> > But for v6, I'm going to submit a patch with {check|reset}_bandwidth()
> > quirk function
> >  switched into xhci_driver_overrides first. (and preserve existing
> > MTK_HOST quirk functions).
> >
> > Thanks!
> >
> > > -Mathias
> > >
>


[PATCH v6] usb: xhci-mtk: fix unreleased bandwidth data

2021-01-13 Thread Ikjoon Jang
xhci-mtk needs XHCI_MTK_HOST quirk functions in add_endpoint() and
drop_endpoint() to handle its own sw bandwidth management.

It stores bandwidth data into an internal table every time
add_endpoint() is called, and drops those in drop_endpoint().
But when bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch moves bandwidth management codes to check_bandwidth() and
reset_bandwidth() path. To do so, this patch also adds those functions
to xhci_driver_overrides and lets mtk-xhci to release all failed
endpoints in reset_bandwidth() path.

Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
multi-TT")
Signed-off-by: Ikjoon Jang 

---

Changes in v6:
- use xhci overrides instead of quirk functions for
  {check|reset}_bandwidth().

Changes in v5:
- Fix a wrong commit id in Fixes tag

Changes in v4:
- bugfix in v3, check_bandwidth() return uninitialized value
  when no new endpoints were added.
- change Fixes tag to keep dependency

Changes in v3:
- drop unrelated code cleanups
- change Fixes tag to keep dependency

Changes in v2:
- fix a 0-day warning from unused variable
- split one big patch into three patches
- fix wrong offset in mediatek hw flags

 drivers/usb/host/xhci-mtk-sch.c | 123 ++--
 drivers/usb/host/xhci-mtk.c |   2 +
 drivers/usb/host/xhci-mtk.h |  13 
 drivers/usb/host/xhci.c |   8 ++-
 drivers/usb/host/xhci.h |   4 ++
 5 files changed, 111 insertions(+), 39 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..a313e75ff1c6 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
 
sch_ep->sch_tt = tt;
sch_ep->ep = ep;
+   INIT_LIST_HEAD(_ep->tt_endpoint);
 
return sch_ep;
 }
@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
mtk->sch_array = sch_array;
 
+   INIT_LIST_HEAD(>bw_ep_list_new);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
-   struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_bw_info *sch_array;
unsigned int ep_index;
-   int bw_index;
-   int ret = 0;
 
xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
return 0;
}
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
-
sch_ep = create_sch_ep(udev, ep, ep_ctx);
if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
 
setup_sch_info(udev, ep_ctx, sch_ep);
 
-   ret = check_sch_bw(udev, sch_bw, sch_ep);
-   if (ret) {
-   xhci_err(xhci, "Not enough bandwidth!\n");
-   if (is_fs_or_ls(udev->speed))
-   drop_tt(udev);
-
-   kfree(sch_ep);
-   return -ENOSPC;
-   }
+   list_add_tail(_ep->endpoint, >bw_ep_list_new);
 
-   list_add_tail(_ep->endpoint, _bw->bw_ep_list);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
-   ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-   | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-   ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-   | EP_BREPEAT(sch_ep->repeat));
+static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+struct mu3h_sch_ep_info *sch_ep)
+{
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
+   int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+   struct mu3h_sch_bw_info *sch_bw = >sch_array[bw_index];
 
-   xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-   sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-   sch_ep->offset, sch_ep->repeat);
+   update_bus_bw(sch_bw, sch_ep, 0);
+   list_del(_ep->endpoint);
 
-   return 0;
+   if (sch_ep->sch_tt) {
+   

Re: [RFC PATCH v3 1/5] usb: xhci-mtk: improve bandwidth scheduling with multi-TT

2021-01-13 Thread Ikjoon Jang
On Tue, Dec 22, 2020 at 5:35 PM Chunfeng Yun  wrote:
>
> From: Zhanyong Wang 
>
> After inserted the usb type-c 3.5mm dongle with headset, dmesg showed:
> usb 1-1.1: new full-speed USB device number 5 using xhci-mtk
> usb 1-1.1: New USB device found, idVendor=05ac, idProduct=110a, 
> bcdDevice=26.11
> usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 1-1.1: Product: USB-C to 3.5mm Headphone Jack Adapter
> usb 1-1.1: Manufacturer: Apple, Inc.
> usb 1-1.1: SerialNumber: DWH915501TFJKLTAM
> xhci-mtk 1120.xhci: Not enough bandwidth!
> usb 1-1.1: can't set config #2, error -28
>
> improve low-speed/full-speed INT/ISOC bandwidth scheduling with USB
> muli-TT.
>
> Signed-off-by: Yaqii Wu 
> Signed-off-by: Chunfeng Yun 
> ---
> v2~v3: no changes
> ---
>  drivers/usb/host/xhci-mtk-sch.c | 91 -
>  drivers/usb/host/xhci-mtk.h |  8 ++-
>  2 files changed, 84 insertions(+), 15 deletions(-)
>  mode change 100644 => 100755 drivers/usb/host/xhci-mtk-sch.c
>
> diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> old mode 100644
> new mode 100755
> index 45c54d56ecbd..94292b9bbc63
> --- a/drivers/usb/host/xhci-mtk-sch.c
> +++ b/drivers/usb/host/xhci-mtk-sch.c
> @@ -383,7 +383,9 @@ static int check_sch_tt(struct usb_device *udev,
> u32 fs_budget_start;
> u32 start_ss, last_ss;
> u32 start_cs, last_cs;
> -   int i;
> +   u32 num_esit, base;
> +   int i, j;
> +   u32 tmp;
>
> start_ss = offset % 8;
> fs_budget_start = (start_ss + 1) % 8;
> @@ -398,10 +400,13 @@ static int check_sch_tt(struct usb_device *udev,
> if (!(start_ss == 7 || last_ss < 6))
> return -ERANGE;
>
> -   for (i = 0; i < sch_ep->cs_count; i++)
> -   if (test_bit(offset + i, tt->split_bit_map))
> +   for (i = 0; i < sch_ep->cs_count; i++) {
> +   if (test_bit(offset + i, tt->ss_bit_map))
> return -ERANGE;
>
> +   if (test_bit(offset + i, tt->cs_bit_map))
> +   return -ERANGE;
> +   }

Are there any reasons for doing this?
Why can only one split packet be scheduled in a u-frame for isochronous out?
This looks like overkill.

> } else {
> u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
>
> @@ -428,8 +433,10 @@ static int check_sch_tt(struct usb_device *udev,
> if (cs_count > 7)
> cs_count = 7; /* HW limit */
>
> -   for (i = 0; i < cs_count + 2; i++) {
> -   if (test_bit(offset + i, tt->split_bit_map))
> +   if (test_bit(offset, tt->ss_bit_map))
> +   return -ERANGE;
> +   for (i = 0; i < cs_count; i++) {
> +   if (test_bit(offset + 2 + i, tt->cs_bit_map))
> return -ERANGE;
> }
>

same here. It would be much better to understand
if you can provide some counterexamples of schedule
that can happen when this bitmap checking logic is omitted.

> @@ -445,11 +452,22 @@ static int check_sch_tt(struct usb_device *udev,
> sch_ep->num_budget_microframes = sch_ep->esit;
> }
>
> +   num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
> +   for (i = 0; i < num_esit; i++) {
> +   base = sch_ep->offset + i * sch_ep->esit;
> +   for (j = 0; j < sch_ep->num_budget_microframes; j++) {
> +   tmp = tt->fs_bus_bw[base + j]
> + + sch_ep->bw_cost_per_microframe;
> +   if (tmp > FS_PAYLOAD_MAX)
> +   return -ERANGE;
> +   }
> +   }

I guess this is enough to check the bandwidth limit of the
lower speed bus without a bitmap.

> +
> return 0;
>  }
>
>  static void update_sch_tt(struct usb_device *udev,
> -   struct mu3h_sch_ep_info *sch_ep)
> +   struct mu3h_sch_ep_info *sch_ep, bool used)
>  {
> struct mu3h_sch_tt *tt = sch_ep->sch_tt;
> u32 base, num_esit;
> @@ -458,11 +476,52 @@ static void update_sch_tt(struct usb_device *udev,
> num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
> for (i = 0; i < num_esit; i++) {
> base = sch_ep->offset + i * sch_ep->esit;
> -   for (j = 0; j < sch_ep->num_budget_microframes; j++)
> -   set_bit(base + j, tt->split_bit_map);
> +   for (j = 0; j < sch_ep->num_budget_microframes; j++) {
> +   if (used)
> +   set_bit(base + j, tt->split_bit_map);
> +   else
> +   clear_bit(base + j, tt->split_bit_map);
> +   }
> +
> +   if (sch_ep->ep_type == ISOC_OUT_EP) {
> +   for (j = 0; j < 

Re: [PATCH v5] usb: xhci-mtk: fix unreleased bandwidth data

2021-01-11 Thread Ikjoon Jang
On Fri, Jan 8, 2021 at 10:44 PM Mathias Nyman
 wrote:
>
> On 8.1.2021 8.11, Chunfeng Yun wrote:
> > On Thu, 2021-01-07 at 13:09 +0200, Mathias Nyman wrote:
> >> On 29.12.2020 8.24, Ikjoon Jang wrote:
> >>> xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> >>> to handle its own sw bandwidth managements and stores bandwidth data
> >>> into internal table every time add_endpoint() is called,
> >>> so when bandwidth allocation fails at one endpoint, all earlier
> >>> allocation from the same interface could still remain at the table.
> >>>
> >>> This patch adds two more hooks from check_bandwidth() and
> >>> reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> >>> from reset_bandwidth().
> >>>
> >>> Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
> >>> multi-TT")
> >>> Signed-off-by: Ikjoon Jang 
> >>>
> >>
> >> ...
> >>
> >>>
> >>> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> >>> index d4a8d0efbbc4..e1fcd3cf723f 100644
> >>> --- a/drivers/usb/host/xhci.c
> >>> +++ b/drivers/usb/host/xhci.c
> >>> @@ -2882,6 +2882,12 @@ static int xhci_check_bandwidth(struct usb_hcd 
> >>> *hcd, struct usb_device *udev)
> >>> xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
> >>> virt_dev = xhci->devs[udev->slot_id];
> >>>
> >>> +   if (xhci->quirks & XHCI_MTK_HOST) {
> >>> +   ret = xhci_mtk_check_bandwidth(hcd, udev);
> >>> +   if (ret < 0)
> >>> +   return ret;
> >>> +   }
> >>> +
> >>
> >> Just noticed that XHCI_MTK_HOST quirk is only set in xhci-mtk.c.
> >> xhci-mtk.c calls xhci_init_driver(..., xhci_mtk_overrides) with a .reset 
> >> override function.
> >>
> >> why not add override functions for .check_bandwidth and .reset_bandwidth 
> >> to xhci_mtk_overrides instead?
> >>
> >> Another patch to add similar overrides for .add_endpoint and 
> >> .drop_endpoint should probably be
> >> done so that we can get rid of the xhci_mtk_add/drop_ep_quirk() calls in 
> >> xhci.c as well
> > You mean, we can export xhci_add/drop_endpoint()?
>
> I think so, unless you have a better idea.
> I prefer exporting the generic add/drop_endpoint functions rather than the 
> vendor specific quirk functions.
>

When moving out all MTK_HOST quirks and unlink xhci-mtk-sch from xhci,
xhci-mtk-sch still needs to touch the xhci internals, at least struct
xhci_ep_ctx.

My naive idea is just let xhci export one more function to expose xhci_ep_ctx.
But I'm not sure whether this is acceptable:

+struct xhci_ep_ctx* xhci_get_ep_contex(struct xhci_hcd *xhci, struct
usb_host_endpoint *ep)
+{ ... }
+EXPORT_SYMBOL(xhci_get_ep_context);

But for v6, I'm going to submit a patch with {check|reset}_bandwidth()
quirk function
 switched into xhci_driver_overrides first. (and preserve existing
MTK_HOST quirk functions).

Thanks!

> -Mathias
>


Re: [PATCH v5] usb: xhci-mtk: fix unreleased bandwidth data

2021-01-08 Thread Ikjoon Jang
On Fri, Jan 8, 2021 at 2:34 PM Chunfeng Yun  wrote:
>
> On Tue, 2020-12-29 at 14:24 +0800, Ikjoon Jang wrote:
> > xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> > to handle its own sw bandwidth managements and stores bandwidth data
> > into internal table every time add_endpoint() is called,
> > so when bandwidth allocation fails at one endpoint, all earlier
> > allocation from the same interface could still remain at the table.
> If failed to add an endpoint, will cause failure of its interface
> config, then the other endpoints in the same interface will be dropped
> later? you mean some endpoints in an interface may fail but without
> affecting its function?

Yes, drop_endpoint() is called for a failed interface when set_interface()
fails to switch alt settings, but set_configuration() does not call
drop_endpoint().
TT data seems to remain allocated until a device gets removed.

>
> >
> > This patch adds two more hooks from check_bandwidth() and
> > reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > from reset_bandwidth().
> >
> > Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
> > multi-TT")
> > Signed-off-by: Ikjoon Jang 
>


Re: [PATCH v5] usb: xhci-mtk: fix unreleased bandwidth data

2021-01-07 Thread Ikjoon Jang
On Thu, Jan 7, 2021 at 7:07 PM Mathias Nyman
 wrote:
>
> On 29.12.2020 8.24, Ikjoon Jang wrote:
> > xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> > to handle its own sw bandwidth managements and stores bandwidth data
> > into internal table every time add_endpoint() is called,
> > so when bandwidth allocation fails at one endpoint, all earlier
> > allocation from the same interface could still remain at the table.
> >
> > This patch adds two more hooks from check_bandwidth() and
> > reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > from reset_bandwidth().
> >
> > Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
> > multi-TT")
> > Signed-off-by: Ikjoon Jang 
> >
>
> ...
>
> >
> > diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> > index d4a8d0efbbc4..e1fcd3cf723f 100644
> > --- a/drivers/usb/host/xhci.c
> > +++ b/drivers/usb/host/xhci.c
> > @@ -2882,6 +2882,12 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, 
> > struct usb_device *udev)
> >   xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
> >   virt_dev = xhci->devs[udev->slot_id];
> >
> > + if (xhci->quirks & XHCI_MTK_HOST) {
> > + ret = xhci_mtk_check_bandwidth(hcd, udev);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
>
> Just noticed that XHCI_MTK_HOST quirk is only set in xhci-mtk.c.
> xhci-mtk.c calls xhci_init_driver(..., xhci_mtk_overrides) with a .reset 
> override function.
>
> why not add override functions for .check_bandwidth and .reset_bandwidth to 
> xhci_mtk_overrides instead?
>
> Another patch to add similar overrides for .add_endpoint and .drop_endpoint 
> should probably be
> done so that we can get rid of the xhci_mtk_add/drop_ep_quirk() calls in 
> xhci.c as well

Yes, I agree.
Let me submit another patch adding more overridables to xhci_driver_overrides.
Thanks.

>
> Thanks
> -Mathias
>


Re: [PATCH v6 10/22] clk: mediatek: Add MT8192 basic clocks support

2021-01-06 Thread Ikjoon Jang
On Wed, Jan 6, 2021 at 7:06 PM Weiyi Lu  wrote:
>
> On Wed, 2021-01-06 at 18:52 +0800, Ikjoon Jang wrote:
> > On Wed, Jan 6, 2021 at 6:42 PM Weiyi Lu  wrote:
> > >
> > > On Wed, 2021-01-06 at 18:25 +0800, Ikjoon Jang wrote:
> > > > On Tue, Dec 22, 2020 at 9:14 PM Weiyi Lu  wrote:
> > > > >
> > > > > Add MT8192 basic clock providers, include topckgen, apmixedsys,
> > > > > infracfg and pericfg.
> > > > >
> > > > > Signed-off-by: Weiyi Lu 
> > > > > ---
> > > > >  drivers/clk/mediatek/Kconfig  |8 +
> > > > >  drivers/clk/mediatek/Makefile |1 +
> > > > >  drivers/clk/mediatek/clk-mt8192.c | 1326 
> > > > > +
> > > > >  drivers/clk/mediatek/clk-mux.h|   15 +
> > > > >  4 files changed, 1350 insertions(+)
> > > > >  create mode 100644 drivers/clk/mediatek/clk-mt8192.c
> > > > >
> > > >
> > > > 
> > > >
> > > > > diff --git a/drivers/clk/mediatek/clk-mux.h 
> > > > > b/drivers/clk/mediatek/clk-mux.h
> > > > > index f5625f4..afbc7df 100644
> > > > > --- a/drivers/clk/mediatek/clk-mux.h
> > > > > +++ b/drivers/clk/mediatek/clk-mux.h
> > > > > @@ -77,6 +77,21 @@ struct mtk_mux {
> > > > > _width, _gate, _upd_ofs, _upd,
> > > > >   \
> > > > > CLK_SET_RATE_PARENT)
> > > > >
> > > > > +#define MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,
> > > > >   \
> > > > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width,   
> > > > >   \
> > > > > +   _upd_ofs, _upd, _flags)   
> > > > >   \
> > > > > +   GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, 
> > > > > _mux_ofs,  \
> > > > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width,   
> > > > >   \
> > > > > +   0, _upd_ofs, _upd, _flags,
> > > > >   \
> > > > > +   mtk_mux_clr_set_upd_ops)
> > > > > +
> > > > > +#define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs,  
> > > > >   \
> > > > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width,   
> > > > >   \
> > > > > +   _upd_ofs, _upd)   
> > > > >   \
> > > > > +   MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents,   
> > > > >   \
> > > > > +   _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, 
> > > > >   \
> > > > > +   _width, _upd_ofs, _upd, CLK_SET_RATE_PARENT)
> > > > > +
> > > >
> > > > conflicts, these macros are already existed in upstream.
> > >
> > > really? These two macros don't show up in 5.11-rc1 yet.
> >
> > yep, maybe this one: a3ae549917f1 "clk: mediatek: Add new clkmux register 
> > API"
> >
>
> The new macros in this patch are for the clock MUX without gate control.
> It's a little different from those mux macros with gate control in
> a3ae549917f1 "clk: mediatek: Add new clkmux register API"
>

sorry, my bad. it's just a simple context conflict from

> > >
> > > > >  struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
> > > > >  struct regmap *regmap,
> > > > >  spinlock_t *lock);
> > > > > --

your another patch,
2aeff9d8c8e "clk: mediatek: Make mtk_clk_register_mux() a static function"
was applied before this series.

> > > > > 1.8.1.1.dirty
> > > > > ___
> > > > > Linux-mediatek mailing list
> > > > > linux-media...@lists.infradead.org
> > > > > http://lists.infradead.org/mailman/listinfo/linux-mediatek
> > >
> > > ___
> > > Linux-mediatek mailing list
> > > linux-media...@lists.infradead.org
> > > http://lists.infradead.org/mailman/listinfo/linux-mediatek
>


Re: [PATCH v6 10/22] clk: mediatek: Add MT8192 basic clocks support

2021-01-06 Thread Ikjoon Jang
On Wed, Jan 6, 2021 at 6:42 PM Weiyi Lu  wrote:
>
> On Wed, 2021-01-06 at 18:25 +0800, Ikjoon Jang wrote:
> > On Tue, Dec 22, 2020 at 9:14 PM Weiyi Lu  wrote:
> > >
> > > Add MT8192 basic clock providers, include topckgen, apmixedsys,
> > > infracfg and pericfg.
> > >
> > > Signed-off-by: Weiyi Lu 
> > > ---
> > >  drivers/clk/mediatek/Kconfig  |8 +
> > >  drivers/clk/mediatek/Makefile |1 +
> > >  drivers/clk/mediatek/clk-mt8192.c | 1326 
> > > +
> > >  drivers/clk/mediatek/clk-mux.h|   15 +
> > >  4 files changed, 1350 insertions(+)
> > >  create mode 100644 drivers/clk/mediatek/clk-mt8192.c
> > >
> >
> > 
> >
> > > diff --git a/drivers/clk/mediatek/clk-mux.h 
> > > b/drivers/clk/mediatek/clk-mux.h
> > > index f5625f4..afbc7df 100644
> > > --- a/drivers/clk/mediatek/clk-mux.h
> > > +++ b/drivers/clk/mediatek/clk-mux.h
> > > @@ -77,6 +77,21 @@ struct mtk_mux {
> > > _width, _gate, _upd_ofs, _upd,  \
> > > CLK_SET_RATE_PARENT)
> > >
> > > +#define MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,  \
> > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> > > +   _upd_ofs, _upd, _flags) \
> > > +   GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,  \
> > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> > > +   0, _upd_ofs, _upd, _flags,  \
> > > +   mtk_mux_clr_set_upd_ops)
> > > +
> > > +#define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs,  
> > >   \
> > > +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> > > +   _upd_ofs, _upd) \
> > > +   MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents, \
> > > +   _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift,   \
> > > +   _width, _upd_ofs, _upd, CLK_SET_RATE_PARENT)
> > > +
> >
> > conflicts, these macros are already existed in upstream.
>
> really? These two macros don't show up in 5.11-rc1 yet.

yep, maybe this one: a3ae549917f1 "clk: mediatek: Add new clkmux register API"

>
> > >  struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
> > >  struct regmap *regmap,
> > >  spinlock_t *lock);
> > > --
> > > 1.8.1.1.dirty
> > > ___
> > > Linux-mediatek mailing list
> > > linux-media...@lists.infradead.org
> > > http://lists.infradead.org/mailman/listinfo/linux-mediatek
>
> ___
> Linux-mediatek mailing list
> linux-media...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek


Re: [PATCH v6 08/22] clk: mediatek: Add configurable enable control to mtk_pll_data

2021-01-06 Thread Ikjoon Jang
On Tue, Dec 22, 2020 at 9:11 PM Weiyi Lu  wrote:
>
> In all MediaTek PLL design, bit0 of CON0 register is always
> the enable bit.
> However, there's a special case of usbpll on MT8192.
> The enable bit of usbpll is moved to bit2 of other register.
> Add configurable en_reg and pll_en_bit for enable control or
> default 0 where pll data are static variables.
> Hence, CON0_BASE_EN could also be removed.
> And there might have another special case on other chips,
> the enable bit is still on CON0 register but not at bit0.
>
> Signed-off-by: Weiyi Lu 

Reviewed-by: Ikjoon Jang 

> ---
>  drivers/clk/mediatek/clk-mtk.h |  2 ++
>  drivers/clk/mediatek/clk-pll.c | 15 ++-
>  2 files changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
> index c3d6756..c580663 100644
> --- a/drivers/clk/mediatek/clk-mtk.h
> +++ b/drivers/clk/mediatek/clk-mtk.h
> @@ -233,6 +233,8 @@ struct mtk_pll_data {
> uint32_t pcw_chg_reg;
> const struct mtk_pll_div_table *div_table;
> const char *parent_name;
> +   uint32_t en_reg;
> +   uint8_t pll_en_bit; /* Assume 0, indicates BIT(0) by default */
>  };
>
>  void mtk_clk_register_plls(struct device_node *node,
> diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
> index 11ed5d1..7fb001a 100644
> --- a/drivers/clk/mediatek/clk-pll.c
> +++ b/drivers/clk/mediatek/clk-pll.c
> @@ -44,6 +44,7 @@ struct mtk_clk_pll {
> void __iomem*tuner_en_addr;
> void __iomem*pcw_addr;
> void __iomem*pcw_chg_addr;
> +   void __iomem*en_addr;
> const struct mtk_pll_data *data;
>  };
>
> @@ -56,7 +57,7 @@ static int mtk_pll_is_prepared(struct clk_hw *hw)
>  {
> struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
>
> -   return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
> +   return (readl(pll->en_addr) & BIT(pll->data->pll_en_bit)) != 0;
>  }
>
>  static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
> @@ -248,8 +249,8 @@ static int mtk_pll_prepare(struct clk_hw *hw)
> writel(r, pll->pwr_addr);
> udelay(1);
>
> -   r = readl(pll->base_addr + REG_CON0) | CON0_BASE_EN;
> -   writel(r, pll->base_addr + REG_CON0);
> +   r = readl(pll->en_addr) | BIT(pll->data->pll_en_bit);
> +   writel(r, pll->en_addr);
>
> div_en_mask = pll->data->en_mask & ~CON0_BASE_EN;
> if (div_en_mask) {
> @@ -290,8 +291,8 @@ static void mtk_pll_unprepare(struct clk_hw *hw)
> writel(r, pll->base_addr + REG_CON0);
> }
>
> -   r = readl(pll->base_addr + REG_CON0) & ~CON0_BASE_EN;
> -   writel(r, pll->base_addr + REG_CON0);
> +   r = readl(pll->en_addr) & ~BIT(pll->data->pll_en_bit);
> +   writel(r, pll->en_addr);
>
> r = readl(pll->pwr_addr) | CON0_ISO_EN;
> writel(r, pll->pwr_addr);
> @@ -333,6 +334,10 @@ static struct clk *mtk_clk_register_pll(const struct 
> mtk_pll_data *data,
> pll->tuner_addr = base + data->tuner_reg;
> if (data->tuner_en_reg)
> pll->tuner_en_addr = base + data->tuner_en_reg;
> +   if (data->en_reg)
> +   pll->en_addr = base + data->en_reg;
> +   else
> +   pll->en_addr = pll->base_addr + REG_CON0;
> pll->hw.init = 
> pll->data = data;
>
> --
> 1.8.1.1.dirty
> ___
> Linux-mediatek mailing list
> linux-media...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek


Re: [PATCH v6 07/22] clk: mediatek: Fix asymmetrical PLL enable and disable control

2021-01-06 Thread Ikjoon Jang
On Tue, Dec 22, 2020 at 9:12 PM Weiyi Lu  wrote:
>
> In fact, the en_mask is a combination of divider enable mask
> and pll enable bit(bit0).
> Before this patch, we enabled both divider mask and bit0 in prepare(),
> but only cleared the bit0 in unprepare().
> In the future, we hope en_mask will only be used as divider enable mask.
> The enable register(CON0) will be set in 2 steps:
> first is divider mask, and then bit0 during prepare(), and vice versa.
> But considering backward compatibility, at this stage we allow en_mask
> to be a combination or a pure divider enable mask.
> And then we will make en_mask a pure divider enable mask in another
> following patch series.
>
> Signed-off-by: Weiyi Lu 

Reviewed-by: Ikjoon Jang 

> ---
>  drivers/clk/mediatek/clk-pll.c | 20 
>  1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
> index f440f2cd..11ed5d1 100644
> --- a/drivers/clk/mediatek/clk-pll.c
> +++ b/drivers/clk/mediatek/clk-pll.c
> @@ -238,6 +238,7 @@ static int mtk_pll_prepare(struct clk_hw *hw)
>  {
> struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> u32 r;
> +   u32 div_en_mask;
>
> r = readl(pll->pwr_addr) | CON0_PWR_ON;
> writel(r, pll->pwr_addr);
> @@ -247,10 +248,15 @@ static int mtk_pll_prepare(struct clk_hw *hw)
> writel(r, pll->pwr_addr);
> udelay(1);
>
> -   r = readl(pll->base_addr + REG_CON0);
> -   r |= pll->data->en_mask;
> +   r = readl(pll->base_addr + REG_CON0) | CON0_BASE_EN;
> writel(r, pll->base_addr + REG_CON0);
>
> +   div_en_mask = pll->data->en_mask & ~CON0_BASE_EN;
> +   if (div_en_mask) {
> +   r = readl(pll->base_addr + REG_CON0) | div_en_mask;
> +   writel(r, pll->base_addr + REG_CON0);
> +   }
> +
> __mtk_pll_tuner_enable(pll);
>
> udelay(20);
> @@ -268,6 +274,7 @@ static void mtk_pll_unprepare(struct clk_hw *hw)
>  {
> struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
> u32 r;
> +   u32 div_en_mask;
>
> if (pll->data->flags & HAVE_RST_BAR) {
> r = readl(pll->base_addr + REG_CON0);
> @@ -277,8 +284,13 @@ static void mtk_pll_unprepare(struct clk_hw *hw)
>
> __mtk_pll_tuner_disable(pll);
>
> -   r = readl(pll->base_addr + REG_CON0);
> -   r &= ~CON0_BASE_EN;
> +   div_en_mask = pll->data->en_mask & ~CON0_BASE_EN;
> +   if (div_en_mask) {
> +   r = readl(pll->base_addr + REG_CON0) & ~div_en_mask;
> +   writel(r, pll->base_addr + REG_CON0);
> +   }
> +
> +   r = readl(pll->base_addr + REG_CON0) & ~CON0_BASE_EN;
> writel(r, pll->base_addr + REG_CON0);
>
> r = readl(pll->pwr_addr) | CON0_ISO_EN;
> --
> 1.8.1.1.dirty
> ___
> Linux-mediatek mailing list
> linux-media...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek


Re: [PATCH v6 10/22] clk: mediatek: Add MT8192 basic clocks support

2021-01-06 Thread Ikjoon Jang
On Tue, Dec 22, 2020 at 9:14 PM Weiyi Lu  wrote:
>
> Add MT8192 basic clock providers, include topckgen, apmixedsys,
> infracfg and pericfg.
>
> Signed-off-by: Weiyi Lu 
> ---
>  drivers/clk/mediatek/Kconfig  |8 +
>  drivers/clk/mediatek/Makefile |1 +
>  drivers/clk/mediatek/clk-mt8192.c | 1326 
> +
>  drivers/clk/mediatek/clk-mux.h|   15 +
>  4 files changed, 1350 insertions(+)
>  create mode 100644 drivers/clk/mediatek/clk-mt8192.c
>



> diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
> index f5625f4..afbc7df 100644
> --- a/drivers/clk/mediatek/clk-mux.h
> +++ b/drivers/clk/mediatek/clk-mux.h
> @@ -77,6 +77,21 @@ struct mtk_mux {
> _width, _gate, _upd_ofs, _upd,  \
> CLK_SET_RATE_PARENT)
>
> +#define MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,  \
> +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> +   _upd_ofs, _upd, _flags) \
> +   GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs,  \
> +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> +   0, _upd_ofs, _upd, _flags,  \
> +   mtk_mux_clr_set_upd_ops)
> +
> +#define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs,  
>   \
> +   _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
> +   _upd_ofs, _upd) \
> +   MUX_CLR_SET_UPD_FLAGS(_id, _name, _parents, \
> +   _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift,   \
> +   _width, _upd_ofs, _upd, CLK_SET_RATE_PARENT)
> +

conflicts, these macros are already existed in upstream.

>  struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
>  struct regmap *regmap,
>  spinlock_t *lock);
> --
> 1.8.1.1.dirty
> ___
> Linux-mediatek mailing list
> linux-media...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek


Re: [RFC PATCH v3 4/5] usb: xhci-mtk: add support runtime pm

2020-12-28 Thread Ikjoon Jang
On Tue, Dec 22, 2020 at 5:35 PM Chunfeng Yun  wrote:
>
> From: CK Hu 
>
> add support runtime pm feature
>
> Signed-off-by: Zhanyong Wang 
> Signed-off-by: Chunfeng Yun 
> ---
> v3:
>   1. fix some issues
>   2. remove attribute files
>
> v2: fix error caused by request irq suggested by CK
> ---
>  drivers/usb/host/xhci-mtk.c | 285 +++-
>  drivers/usb/host/xhci-mtk.h |  14 ++
>  2 files changed, 294 insertions(+), 5 deletions(-)
>  mode change 100755 => 100644 drivers/usb/host/xhci-mtk.c
>
> diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> old mode 100755
> new mode 100644
> index 34bd3de090b1..c07d54acbcb7
> --- a/drivers/usb/host/xhci-mtk.c
> +++ b/drivers/usb/host/xhci-mtk.c
> @@ -14,6 +14,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -77,6 +78,72 @@ enum ssusb_uwk_vers {
> SSUSB_UWK_V3,
>  };
>
> +int xhci_mtk_runtime_ready;
> +
> +static int xhci_mtk_runtime_resume(struct device *dev);
> +
> +static void xhci_mtk_seal_work(struct work_struct *work)
> +{
> +   struct xhci_hcd_mtk *mtk =
> +   container_of(work, struct xhci_hcd_mtk, seal.work);
> +   struct usb_hcd *hcd = mtk->hcd;
> +   struct xhci_hcd *xhci = hcd_to_xhci(hcd);
> +
> +   xhci_dbg(xhci, "spm unseals xHCI controller %i\n", mtk->seal_status);
> +   if (mtk->seal_status == SEAL_SUSPENDED) {
> +   mtk->seal_status = SEAL_RESUMING;
> +   pm_runtime_mark_last_busy(mtk->dev);
> +   pm_runtime_put_sync_autosuspend(mtk->dev);

If I understand correctly, this function is for waking up the device
but this function calls put() only without get().

> +   } else {
> +   /*
> +* FIXME: Sometimes seal_status will keep it on SEAL_RESUMING 
> staus not to expect
> +* since pm_runtime_put_sync_autosuspend doesn't invoke 
> runtime_resume of callback.
> +* and to survey why not to invoke runtime_resume callback 
> named
> +* xhci_mtk_runtime_resume in time in short feature, Herely 
> provide one solution
> +* that make sure seal_status to match h/w state machine,and 
> MTK xHCI clocks
> +* on as soon as unseal event received.

I guess actual resuming should be happened only from the 1st interrupt
(when in SEAL_SUSPENDED)
and following spurious interrupts can be just ignored.

> +*/
> +   if (mtk->seal_status == SEAL_RESUMING)
> +   xhci_mtk_runtime_resume(mtk->dev);

xhci_mtk_runtime_resume() is defined as a runtime pm callback,
pm core will call that callback when pm usage counter reaches to zero.

> +   else
> +   xhci_warn(xhci,
> +   "Ignore seal wakeup source disordered in xHCI 
> controller\n");
> +   }
> +}
> +
> +static irqreturn_t xhci_mtk_seal_irq(int irq, void *data)
> +{
> +   struct xhci_hcd_mtk *mtk = data;
> +   struct usb_hcd *hcd = mtk->hcd;
> +   struct xhci_hcd *xhci = hcd_to_xhci(hcd);
> +
> +   xhci_dbg(xhci, "seal irq ISR invoked\n");
> +
> +   schedule_delayed_work(>seal, 0);
> +
> +   return IRQ_HANDLED;
> +}
> +
> +static void xhci_mtk_seal_wakeup_enable(struct xhci_hcd_mtk *mtk, bool 
> enable)
> +{
> +   struct irq_desc *desc;
> +   struct device *dev = mtk->dev;
> +
> +   if (mtk && mtk->seal_irq) {
> +   desc = irq_to_desc(mtk->seal_irq);
> +   if (enable) {
> +   desc->irq_data.chip->irq_ack(>irq_data);
> +   enable_irq(mtk->seal_irq);
> +   dev_dbg(dev, "%s: enable_irq %i\n",
> +__func__, mtk->seal_irq);
> +   } else {
> +   disable_irq(mtk->seal_irq);
> +   dev_dbg(dev, "%s: disable_irq %i\n",
> +__func__, mtk->seal_irq);
> +   }
> +   }
> +}
> +

I think this is unnecessary if this driver can check the current state
and ignore the spurious irqs if spm sometimes triggers the wake-up irqs.

>  static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
>  {
> struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
> @@ -347,7 +414,6 @@ static int usb_wakeup_of_property_parse(struct 
> xhci_hcd_mtk *mtk,
> mtk->uwk_reg_base, mtk->uwk_vers);
>
> return PTR_ERR_OR_ZERO(mtk->uwk);
> -
>  }
>
>  static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
> @@ -482,9 +548,11 @@ static int xhci_mtk_probe(struct platform_device *pdev)
> return ret;
> }
>
> +   pm_runtime_set_active(dev);
> +   pm_runtime_use_autosuspend(dev);
> +   pm_runtime_set_autosuspend_delay(dev,
> +   CONFIG_USB_AUTOSUSPEND_DELAY * 1000);
> pm_runtime_enable(dev);
> -   

Re: [PATCH v4] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-28 Thread Ikjoon Jang
On Mon, Dec 28, 2020 at 10:34 PM Greg Kroah-Hartman
 wrote:
>
> On Mon, Dec 14, 2020 at 04:39:53PM +0800, Ikjoon Jang wrote:
> > xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> > to handle its own sw bandwidth managements and stores bandwidth data
> > into internal table every time add_endpoint() is called,
> > so when bandwidth allocation fails at one endpoint, all earlier
> > allocation from the same interface could still remain at the table.
> >
> > This patch adds two more hooks from check_bandwidth() and
> > reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > from reset_bandwidth().
> >
> > Fixes: 4b0f7a77fb3c ("usb: xhci-mtk: supports bandwidth scheduling with 
> > multi-TT")
>
> This is not a git commit id that is in Linus's tree :(
>

Oops, I apologize, I sent a new v5 patch with
Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling
with multi-TT")


[PATCH v5] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-28 Thread Ikjoon Jang
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
from reset_bandwidth().

Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with 
multi-TT")
Signed-off-by: Ikjoon Jang 

---

Changes in v5:
- Fix a wrong commit id in Fixes tag

Changes in v4:
- bugfix in v3, check_bandwidth() return uninitialized value
  when no new endpoints were added.
- change Fixes tag to keep dependency

Changes in v3:
- drop unrelated code cleanups
- change Fixes tag to keep dependency

Changes in v2:
- fix a 0-day warning from unused variable
- split one big patch into three patches
- fix wrong offset in mediatek hw flags

 drivers/usb/host/xhci-mtk-sch.c | 124 ++--
 drivers/usb/host/xhci-mtk.h |  13 
 drivers/usb/host/xhci.c |   9 +++
 3 files changed, 109 insertions(+), 37 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..95d20de9fd1f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
 
sch_ep->sch_tt = tt;
sch_ep->ep = ep;
+   INIT_LIST_HEAD(_ep->tt_endpoint);
 
return sch_ep;
 }
@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
mtk->sch_array = sch_array;
 
+   INIT_LIST_HEAD(>bw_ep_list_new);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
-   struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_bw_info *sch_array;
unsigned int ep_index;
-   int bw_index;
-   int ret = 0;
 
xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
return 0;
}
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
-
sch_ep = create_sch_ep(udev, ep, ep_ctx);
if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
 
setup_sch_info(udev, ep_ctx, sch_ep);
 
-   ret = check_sch_bw(udev, sch_bw, sch_ep);
-   if (ret) {
-   xhci_err(xhci, "Not enough bandwidth!\n");
-   if (is_fs_or_ls(udev->speed))
-   drop_tt(udev);
-
-   kfree(sch_ep);
-   return -ENOSPC;
-   }
+   list_add_tail(_ep->endpoint, >bw_ep_list_new);
 
-   list_add_tail(_ep->endpoint, _bw->bw_ep_list);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
-   ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-   | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-   ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-   | EP_BREPEAT(sch_ep->repeat));
+static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+struct mu3h_sch_ep_info *sch_ep)
+{
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
+   int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+   struct mu3h_sch_bw_info *sch_bw = >sch_array[bw_index];
 
-   xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-   sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-   sch_ep->offset, sch_ep->repeat);
+   update_bus_bw(sch_bw, sch_ep, 0);
+   list_del(_ep->endpoint);
 
-   return 0;
+   if (sch_ep->sch_tt) {
+   list_del(_ep->tt_endpoint);
+   drop_tt(udev);
+   }
+   kfree(sch_ep);
 }
-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
 void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
@@ -675,7 +668,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, stru

[PATCH v4] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-14 Thread Ikjoon Jang
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
from reset_bandwidth().

Fixes: 4b0f7a77fb3c ("usb: xhci-mtk: supports bandwidth scheduling with 
multi-TT")
Signed-off-by: Ikjoon Jang 

---

Changes in v4:
- bugfix in v3, check_bandwidth() returns an uninitialized
  value when no endpoints were newly added.

Changes in v3:
- drop unrelated code cleanups
- change Fixes tag to keep dependency

Changes in v2:
- fix a 0-day warning from unused variable
- split one big patch into three patches
- fix wrong offset in mediatek hw flags

 drivers/usb/host/xhci-mtk-sch.c | 124 ++--
 drivers/usb/host/xhci-mtk.h |  13 
 drivers/usb/host/xhci.c |   9 +++
 3 files changed, 109 insertions(+), 37 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..95d20de9fd1f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
 
sch_ep->sch_tt = tt;
sch_ep->ep = ep;
+   INIT_LIST_HEAD(_ep->tt_endpoint);
 
return sch_ep;
 }
@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
mtk->sch_array = sch_array;
 
+   INIT_LIST_HEAD(>bw_ep_list_new);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
-   struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_bw_info *sch_array;
unsigned int ep_index;
-   int bw_index;
-   int ret = 0;
 
xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
return 0;
}
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
-
sch_ep = create_sch_ep(udev, ep, ep_ctx);
if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
 
setup_sch_info(udev, ep_ctx, sch_ep);
 
-   ret = check_sch_bw(udev, sch_bw, sch_ep);
-   if (ret) {
-   xhci_err(xhci, "Not enough bandwidth!\n");
-   if (is_fs_or_ls(udev->speed))
-   drop_tt(udev);
-
-   kfree(sch_ep);
-   return -ENOSPC;
-   }
+   list_add_tail(_ep->endpoint, >bw_ep_list_new);
 
-   list_add_tail(_ep->endpoint, _bw->bw_ep_list);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
-   ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-   | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-   ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-   | EP_BREPEAT(sch_ep->repeat));
+static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+struct mu3h_sch_ep_info *sch_ep)
+{
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
+   int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+   struct mu3h_sch_bw_info *sch_bw = >sch_array[bw_index];
 
-   xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-   sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-   sch_ep->offset, sch_ep->repeat);
+   update_bus_bw(sch_bw, sch_ep, 0);
+   list_del(_ep->endpoint);
 
-   return 0;
+   if (sch_ep->sch_tt) {
+   list_del(_ep->tt_endpoint);
+   drop_tt(udev);
+   }
+   kfree(sch_ep);
 }
-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
 void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
@@ -675,7 +668,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_virt_device *virt_dev;
struct mu3h_sch

[PATCH v3] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-13 Thread Ikjoon Jang
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
from reset_bandwidth().

Fixes: 4b0f7a77fb3c ("usb: xhci-mtk: supports bandwidth scheduling with 
multi-TT")
Signed-off-by: Ikjoon Jang 

---

Changes in v3:
- drop unrelated code cleanups in v2
- change Fixes tag to keep dependency

Changes in v2:
- fix a 0-day warning from unused variable
- split one big patch into three patches
- fix wrong offset in mediatek hw flags

 drivers/usb/host/xhci-mtk-sch.c | 121 ++--
 drivers/usb/host/xhci-mtk.h |  13 
 drivers/usb/host/xhci.c |   9 +++
 3 files changed, 106 insertions(+), 37 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..72c493758c3f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
 
sch_ep->sch_tt = tt;
sch_ep->ep = ep;
+   INIT_LIST_HEAD(_ep->tt_endpoint);
 
return sch_ep;
 }
@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
mtk->sch_array = sch_array;
 
+   INIT_LIST_HEAD(>bw_ep_list_new);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
-   struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_bw_info *sch_array;
unsigned int ep_index;
-   int bw_index;
-   int ret = 0;
 
xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
return 0;
}
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
-
sch_ep = create_sch_ep(udev, ep, ep_ctx);
if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
 
setup_sch_info(udev, ep_ctx, sch_ep);
 
-   ret = check_sch_bw(udev, sch_bw, sch_ep);
-   if (ret) {
-   xhci_err(xhci, "Not enough bandwidth!\n");
-   if (is_fs_or_ls(udev->speed))
-   drop_tt(udev);
-
-   kfree(sch_ep);
-   return -ENOSPC;
-   }
+   list_add_tail(_ep->endpoint, >bw_ep_list_new);
 
-   list_add_tail(_ep->endpoint, _bw->bw_ep_list);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
-   ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-   | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-   ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-   | EP_BREPEAT(sch_ep->repeat));
+static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+struct mu3h_sch_ep_info *sch_ep)
+{
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
+   int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+   struct mu3h_sch_bw_info *sch_bw = >sch_array[bw_index];
 
-   xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-   sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-   sch_ep->offset, sch_ep->repeat);
+   update_bus_bw(sch_bw, sch_ep, 0);
+   list_del(_ep->endpoint);
 
-   return 0;
+   if (sch_ep->sch_tt) {
+   list_del(_ep->tt_endpoint);
+   drop_tt(udev);
+   }
+   kfree(sch_ep);
 }
-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
 void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
@@ -675,7 +668,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_virt_device *virt_dev;
struct mu3h_sch_bw_info *sch_array;
struct mu3h_sch_bw_info *sch_bw;
-   struct mu3h_sch_ep_info *sch_ep;
+

Re: [PATCH v2 0/3] Release allocated periodic bandwidth data from reset_bandwidth()

2020-12-10 Thread Ikjoon Jang
On Fri, Dec 11, 2020 at 9:53 AM Chunfeng Yun  wrote:
>
> On Thu, 2020-12-10 at 18:47 +0800, Ikjoon Jang wrote:
> > xhci-mtk releases allocated TT bandwidth data only when whole
> > endpoints of a device are dropped as there're only {add|drop}_endpoint()
> > hooks are defined. This patchset adds more hooks and releases all
> > bandwidth data from reset_bandwidth() path, not drop_endpoint().
> >
> >
> > Changes in v2:
> > - fix a 0-day warning from unused variable
> > - split one big patch into three patches
> > - bugfix in hw flags
> >
> > Ikjoon Jang (3):
> >   usb: xhci-mtk: code cleanups in getting bandwidth table
> >   usb: xhci-mtk: delay association of tt and ep
> >   usb: xhci-mtk: fix unreleased bandwidth data
> >
> >  drivers/usb/host/xhci-mtk-sch.c | 180 
> >  drivers/usb/host/xhci-mtk.h |  13 +++
> >  drivers/usb/host/xhci.c |   9 ++
> >  3 files changed, 133 insertions(+), 69 deletions(-)
> Thanks for your patch, I'll test it and check it with our DE

Thanks, I will upload v3.
But I don't expect any logic changes from v2.
Can you please give me feedback on v2 if you find anything?

>
> >
>


Re: [PATCH v2 3/3] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-10 Thread Ikjoon Jang
On Thu, Dec 10, 2020 at 6:57 PM Greg Kroah-Hartman
 wrote:
>
> On Thu, Dec 10, 2020 at 06:47:47PM +0800, Ikjoon Jang wrote:
> > xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
> > to handle its own sw bandwidth managements and stores bandwidth data
> > into internal table every time add_endpoint() is called,
> > so when bandwidth allocation fails at one endpoint, all earlier
> > allocation from the same interface could still remain at the table.
> >
> > This patch adds two more hooks from check_bandwidth() and
> > reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > from reset_bandwidth().
> >
> > Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
> > Signed-off-by: Ikjoon Jang 
>
> Shouldn't this be the first patch in the series?  You don't want a fix
> to be dependent on code style changes, otherwise it is really really
> hard to backport it to older kernels that might need this fix, right?

yes, you're right.

This patchset also requires
"4b0f7a77fb3c usb: xhci-mtk: supports bandwidth scheduling with multi-TT",
which doesn't have a Fixes tag.

I think I can change Fixes to point to that commit (4b0f7a77fb3c),
as this unreleased bandwidth data is much more impactful to
TT bandwidth.

Thanks!

>
> Can you re-order these patches please?
>
> thanks,
>
> greg k-h


[PATCH v2 1/3] usb: xhci-mtk: code cleanups in getting bandwidth table

2020-12-10 Thread Ikjoon Jang
Simplifies the codes for getting internal bandwidth data,
No functional changes.

Signed-off-by: Ikjoon Jang 
---

 drivers/usb/host/xhci-mtk-sch.c | 20 +++-
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..c334b6d76479 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -49,9 +49,11 @@ static int is_fs_or_ls(enum usb_device_speed speed)
 * so the bandwidth domain array is organized as follow for simplification:
 * SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
 */
-static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
-   struct usb_host_endpoint *ep)
+static struct mu3h_sch_bw_info *get_bw_info(struct xhci_hcd_mtk *mtk,
+struct usb_device *udev,
+struct usb_host_endpoint *ep)
 {
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
struct xhci_virt_device *virt_dev;
int bw_index;
 
@@ -67,7 +69,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct 
usb_device *udev,
bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
}
 
-   return bw_index;
+   return >sch_array[bw_index];
 }
 
 static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
@@ -603,9 +605,7 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_virt_device *virt_dev;
struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_bw_info *sch_array;
unsigned int ep_index;
-   int bw_index;
int ret = 0;
 
xhci = hcd_to_xhci(hcd);
@@ -613,7 +613,6 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -632,8 +631,7 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
return 0;
}
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
+   sch_bw = get_bw_info(mtk, udev, ep);
 
sch_ep = create_sch_ep(udev, ep, ep_ctx);
if (IS_ERR_OR_NULL(sch_ep))
@@ -673,15 +671,12 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct xhci_hcd *xhci;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
-   struct mu3h_sch_bw_info *sch_array;
struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
-   int bw_index;
 
xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
-   sch_array = mtk->sch_array;
 
xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
__func__, usb_endpoint_type(>desc), udev->speed,
@@ -691,8 +686,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
return;
 
-   bw_index = get_bw_index(xhci, udev, ep);
-   sch_bw = _array[bw_index];
+   sch_bw = get_bw_info(mtk, udev, ep);
 
list_for_each_entry(sch_ep, _bw->bw_ep_list, endpoint) {
if (sch_ep->ep == ep) {
-- 
2.29.2.576.ga3fc446d84-goog



[PATCH v2 2/3] usb: xhci-mtk: delay association of tt and ep

2020-12-10 Thread Ikjoon Jang
xhci-mtk creates internal data structures for representing the
relationship between endpoint and TT.

This patch simply delays its association between endpoint and TT
when it's really loaded onto internal bandwidth table.

This is a preparation step for fixing unreleased periodic
TT bandwidth data, no functional changes.

Signed-off-by: Ikjoon Jang 
---

 drivers/usb/host/xhci-mtk-sch.c | 40 -
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index c334b6d76479..439391f1dc78 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -174,7 +174,6 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
 {
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_tt *tt = NULL;
u32 len_bw_budget_table;
size_t mem_size;
 
@@ -192,15 +191,6 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
if (!sch_ep)
return ERR_PTR(-ENOMEM);
 
-   if (is_fs_or_ls(udev->speed)) {
-   tt = find_tt(udev);
-   if (IS_ERR(tt)) {
-   kfree(sch_ep);
-   return ERR_PTR(-ENOMEM);
-   }
-   }
-
-   sch_ep->sch_tt = tt;
sch_ep->ep = ep;
 
return sch_ep;
@@ -377,10 +367,10 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
}
 }
 
-static int check_sch_tt(struct usb_device *udev,
-   struct mu3h_sch_ep_info *sch_ep, u32 offset)
+static int check_sch_tt(struct mu3h_sch_tt *tt,
+   struct mu3h_sch_ep_info *sch_ep,
+   u32 offset)
 {
-   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
u32 fs_budget_start;
u32 start_ss, last_ss;
@@ -450,10 +440,9 @@ static int check_sch_tt(struct usb_device *udev,
return 0;
 }
 
-static void update_sch_tt(struct usb_device *udev,
-   struct mu3h_sch_ep_info *sch_ep)
+static void update_sch_tt(struct mu3h_sch_tt *tt,
+ struct mu3h_sch_ep_info *sch_ep)
 {
-   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 base, num_esit;
int i, j;
 
@@ -465,10 +454,12 @@ static void update_sch_tt(struct usb_device *udev,
}
 
list_add_tail(_ep->tt_endpoint, >ep_list);
+   sch_ep->sch_tt = tt;
 }
 
 static int check_sch_bw(struct usb_device *udev,
-   struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
+   struct mu3h_sch_bw_info *sch_bw,
+   struct mu3h_sch_ep_info *sch_ep)
 {
u32 offset;
u32 esit;
@@ -480,8 +471,14 @@ static int check_sch_bw(struct usb_device *udev,
u32 min_cs_count;
bool tt_offset_ok = false;
int ret;
+   struct mu3h_sch_tt *tt = NULL;
 
esit = sch_ep->esit;
+   if (is_fs_or_ls(udev->speed)) {
+   tt = find_tt(udev);
+   if (IS_ERR(tt))
+   return -ENOMEM;
+   }
 
/*
 * Search through all possible schedule microframes.
@@ -493,7 +490,7 @@ static int check_sch_bw(struct usb_device *udev,
min_num_budget = sch_ep->num_budget_microframes;
for (offset = 0; offset < esit; offset++) {
if (is_fs_or_ls(udev->speed)) {
-   ret = check_sch_tt(udev, sch_ep, offset);
+   ret = check_sch_tt(tt, sch_ep, offset);
if (ret)
continue;
else
@@ -531,10 +528,11 @@ static int check_sch_bw(struct usb_device *udev,
 
if (is_fs_or_ls(udev->speed)) {
/* all offset for tt is not ok*/
-   if (!tt_offset_ok)
+   if (!tt_offset_ok) {
+   drop_tt(udev);
return -ERANGE;
-
-   update_sch_tt(udev, sch_ep);
+   }
+   update_sch_tt(tt, sch_ep);
}
 
/* update bus bandwidth info */
-- 
2.29.2.576.ga3fc446d84-goog



[PATCH v2 3/3] usb: xhci-mtk: fix unreleased bandwidth data

2020-12-10 Thread Ikjoon Jang
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
from reset_bandwidth().

Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
Signed-off-by: Ikjoon Jang 

---

Changes in v2:
- fix wrong offset in mediatek hw flags
- fix 0-day warnings

 drivers/usb/host/xhci-mtk-sch.c | 120 ++--
 drivers/usb/host/xhci-mtk.h |  13 
 drivers/usb/host/xhci.c |   9 +++
 3 files changed, 107 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 439391f1dc78..102d8e0a50f1 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -583,6 +583,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
mtk->sch_array = sch_array;
 
+   INIT_LIST_HEAD(>bw_ep_list_new);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -597,16 +599,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
struct usb_host_endpoint *ep)
 {
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
-   struct xhci_hcd *xhci;
+   struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep;
unsigned int ep_index;
-   int ret = 0;
 
-   xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(>desc);
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
@@ -637,42 +637,37 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
 
setup_sch_info(udev, ep_ctx, sch_ep);
 
-   ret = check_sch_bw(udev, sch_bw, sch_ep);
-   if (ret) {
-   xhci_err(xhci, "Not enough bandwidth!\n");
-   if (is_fs_or_ls(udev->speed))
-   drop_tt(udev);
-
-   kfree(sch_ep);
-   return -ENOSPC;
-   }
+   list_add_tail(_ep->endpoint, >bw_ep_list_new);
 
-   list_add_tail(_ep->endpoint, _bw->bw_ep_list);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
-   ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
-   | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
-   ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
-   | EP_BREPEAT(sch_ep->repeat));
+static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+struct mu3h_sch_ep_info *sch_ep)
+{
+   struct mu3h_sch_bw_info *sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
 
-   xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
-   sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
-   sch_ep->offset, sch_ep->repeat);
+   update_bus_bw(sch_bw, sch_ep, 0);
+   list_del(_ep->endpoint);
 
-   return 0;
+   if (sch_ep->sch_tt) {
+   list_del(_ep->tt_endpoint);
+   drop_tt(udev);
+   }
+   kfree(sch_ep);
 }
-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
 
 void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
-   struct usb_host_endpoint *ep)
+   struct usb_host_endpoint *ep)
 {
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
-   struct xhci_hcd *xhci;
-   struct xhci_slot_ctx *slot_ctx;
+   struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_virt_device *virt_dev;
+   struct xhci_slot_ctx *slot_ctx;
struct mu3h_sch_bw_info *sch_bw;
-   struct mu3h_sch_ep_info *sch_ep;
+   struct mu3h_sch_ep_info *sch_ep, *tmp;
 
-   xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
 
@@ -686,17 +681,72 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct 
usb_device *udev,
 
sch_bw = get_bw_info(mtk, udev, ep);
 
-   list_for_each_entry(sch_ep, _bw->bw_ep_list, endpoint) {
+   list_for_each_entry_safe(sch_ep, tmp, _bw->bw_ep_list, endpoint) {
if (sch_ep->ep == ep) {
-   update_bus_bw(sch_bw, sch_ep, 0);
-   list_del(_ep->endpoint);
-   if (is_fs_or_ls(udev->speed)) {
-   li

[PATCH v2 0/3] Release allocated periodic bandwidth data from reset_bandwidth()

2020-12-10 Thread Ikjoon Jang


xhci-mtk releases allocated TT bandwidth data only when whole
endpoints of a device are dropped as there're only {add|drop}_endpoint()
hooks are defined. This patchset adds more hooks and releases all
bandwidth data from reset_bandwidth() path, not drop_endpoint().


Changes in v2:
- fix a 0-day warning from unused variable
- split one big patch into three patches
- bugfix in hw flags

Ikjoon Jang (3):
  usb: xhci-mtk: code cleanups in getting bandwidth table
  usb: xhci-mtk: delay association of tt and ep
  usb: xhci-mtk: fix unreleased bandwidth data

 drivers/usb/host/xhci-mtk-sch.c | 180 
 drivers/usb/host/xhci-mtk.h |  13 +++
 drivers/usb/host/xhci.c |   9 ++
 3 files changed, 133 insertions(+), 69 deletions(-)

-- 
2.29.2.576.ga3fc446d84-goog



Re: [v6, 3/3] reset-controller: ti: force the write operation when assert or deassert

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

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

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



> > >
> > >  /**
> > > @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct 
> > > reset_controller_dev *rcdev,
> > > mask = BIT(control->deassert_bit);
> > > value = (control->flags & DEASSERT_SET) ? mask : 0x0;
> > >
> > > -   return regmap_update_bits(data->regmap, control->deassert_offset, 
> > > mask, value);
> > > +   return regmap_write_bits(data->regmap, control->deassert_offset, 
> > > mask, value);
> > >  }
> > >
> > >  /**
>


Re: [v6, 3/3] reset-controller: ti: force the write operation when assert or deassert

2020-11-30 Thread Ikjoon Jang
On Wed, Sep 30, 2020 at 10:21:59AM +0800, Crystal Guo wrote:
> Force the write operation in case the read already happens
> to return the correct value.
> 
> Signed-off-by: Crystal Guo 
> ---
>  drivers/reset/reset-ti-syscon.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
> index 5d1f8306cd4f..c34394f1e9e2 100644
> --- a/drivers/reset/reset-ti-syscon.c
> +++ b/drivers/reset/reset-ti-syscon.c
> @@ -97,7 +97,7 @@ static int ti_syscon_reset_assert(struct 
> reset_controller_dev *rcdev,
>   mask = BIT(control->assert_bit);
>   value = (control->flags & ASSERT_SET) ? mask : 0x0;
>  
> - return regmap_update_bits(data->regmap, control->assert_offset, mask, 
> value);
> + return regmap_write_bits(data->regmap, control->assert_offset, mask, 
> value);
>  }

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

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

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

>  
>  /**
> @@ -128,7 +128,7 @@ static int ti_syscon_reset_deassert(struct 
> reset_controller_dev *rcdev,
>   mask = BIT(control->deassert_bit);
>   value = (control->flags & DEASSERT_SET) ? mask : 0x0;
>  
> - return regmap_update_bits(data->regmap, control->deassert_offset, mask, 
> value);
> + return regmap_write_bits(data->regmap, control->deassert_offset, mask, 
> value);
>  }
>  
>  /**


Re: [v6,2/3] reset-controller: ti: introduce a new reset handler

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

Reviewed-by: Ikjoon Jang 

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

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

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

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


[PATCH] usb: xhci-mtk: fix unreleased bandwidth data

2020-11-29 Thread Ikjoon Jang
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when one endpoint's bandwidth allocation fails, all earlier
endpoints from same interface still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), so mtk-xhci can releases all remaining
allocations in reset_bandwidth().

Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
Signed-off-by: Ikjoon Jang 
---

 drivers/usb/host/xhci-mtk-sch.c | 163 
 drivers/usb/host/xhci-mtk.h |  13 +++
 drivers/usb/host/xhci.c |   9 ++
 3 files changed, 123 insertions(+), 62 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..6fdc7be29420 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -49,9 +49,11 @@ static int is_fs_or_ls(enum usb_device_speed speed)
 * so the bandwidth domain array is organized as follow for simplification:
 * SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
 */
-static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
-   struct usb_host_endpoint *ep)
+static struct mu3h_sch_bw_info *get_bw_info(struct xhci_hcd_mtk *mtk,
+struct usb_device *udev,
+struct usb_host_endpoint *ep)
 {
+   struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
struct xhci_virt_device *virt_dev;
int bw_index;
 
@@ -67,7 +69,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct 
usb_device *udev,
bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
}
 
-   return bw_index;
+   return >sch_array[bw_index];
 }
 
 static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
@@ -172,7 +174,6 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
 {
struct mu3h_sch_ep_info *sch_ep;
-   struct mu3h_sch_tt *tt = NULL;
u32 len_bw_budget_table;
size_t mem_size;
 
@@ -190,15 +191,6 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct 
usb_device *udev,
if (!sch_ep)
return ERR_PTR(-ENOMEM);
 
-   if (is_fs_or_ls(udev->speed)) {
-   tt = find_tt(udev);
-   if (IS_ERR(tt)) {
-   kfree(sch_ep);
-   return ERR_PTR(-ENOMEM);
-   }
-   }
-
-   sch_ep->sch_tt = tt;
sch_ep->ep = ep;
 
return sch_ep;
@@ -375,10 +367,10 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
}
 }
 
-static int check_sch_tt(struct usb_device *udev,
-   struct mu3h_sch_ep_info *sch_ep, u32 offset)
+static int check_sch_tt(struct mu3h_sch_tt *tt,
+   struct mu3h_sch_ep_info *sch_ep,
+   u32 offset)
 {
-   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
u32 fs_budget_start;
u32 start_ss, last_ss;
@@ -448,10 +440,9 @@ static int check_sch_tt(struct usb_device *udev,
return 0;
 }
 
-static void update_sch_tt(struct usb_device *udev,
-   struct mu3h_sch_ep_info *sch_ep)
+static void update_sch_tt(struct mu3h_sch_tt *tt,
+ struct mu3h_sch_ep_info *sch_ep)
 {
-   struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 base, num_esit;
int i, j;
 
@@ -463,6 +454,7 @@ static void update_sch_tt(struct usb_device *udev,
}
 
list_add_tail(_ep->tt_endpoint, >ep_list);
+   sch_ep->sch_tt = tt;
 }
 
 static int check_sch_bw(struct usb_device *udev,
@@ -476,22 +468,28 @@ static int check_sch_bw(struct usb_device *udev,
u32 bw_boundary;
u32 min_num_budget;
u32 min_cs_count;
+   struct mu3h_sch_tt *tt = NULL;
bool tt_offset_ok = false;
int ret;
 
-   esit = sch_ep->esit;
+   if (is_fs_or_ls(udev->speed)) {
+   tt = find_tt(udev);
+   if (IS_ERR(tt))
+   return -ENOMEM;
+   }
 
/*
 * Search through all possible schedule microframes.
 * and find a microframe where its worst bandwidth is minimum.
 */
+   esit = sch_ep->esit;
min_bw = ~0;
min_index = 0;
min_cs_count = sch_ep->cs_count;
min_num_budget = sch_ep->num_budget_microframes;
for (offset = 0; offset < esit; offset++) {
if (is_fs_or_ls(udev->speed)) {
-   ret = check_sch_tt(udev, sch_ep, offset);
+   ret = check_sch_tt(tt, sch_ep, offset);
if (ret)
continue;
else
@@

Re: [PATCH v5 23/24] arm64: dts: mediatek: Add mt8192 clock controllers

2020-11-22 Thread Ikjoon Jang
On Mon, Nov 09, 2020 at 10:03:48AM +0800, Weiyi Lu wrote:
> Add clock controller nodes for SoC mt8192
> 
> Signed-off-by: Weiyi Lu 
> ---
>  arch/arm64/boot/dts/mediatek/mt8192.dtsi | 163 
> +++
>  1 file changed, 163 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi 
> b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
> index e12e024..92dcfbd 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi
> @@ -5,6 +5,7 @@
>   */
>  
>  /dts-v1/;
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -213,6 +214,24 @@
>   };
>   };
>  
> + topckgen: syscon@1000 {
> + compatible = "mediatek,mt8192-topckgen", "syscon";
> + reg = <0 0x1000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
> + infracfg: syscon@10001000 {
> + compatible = "mediatek,mt8192-infracfg", "syscon";
> + reg = <0 0x10001000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
> + pericfg: syscon@10003000 {
> + compatible = "mediatek,mt8192-pericfg", "syscon";
> + reg = <0 0x10003000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +

There are 26 new bindings for mt8192 clock providers, "mediatek,mt8192-*'.
I guess the one reason of doing this is that those mmio blocks are
just scattered all around over different memory regions.

I wonder if there could be a simpler way of merging them into one
binding of "mediatek,mt8192-clocks" and converting all new bindings
into generic syscon:

mt8192-clocks: mt8192_clocks {
compatible = "mediatek,mt8192-clocks";
#clock-cells = <1>;

infracfg: clk_infracfg {
syscon = <_infracfg>;
};
pericfg: clk_pericfg {
syscon = <_pericfg>:
};
};

syscon_pericfg: syscon@10003000 {
compatible = "syscon";
reg = <0 0x10003000 0 0x1000>;
};

...

>   pio: pinctrl@10005000 {
>   compatible = "mediatek,mt8192-pinctrl";
>   reg = <0 0x10005000 0 0x1000>,
> @@ -238,6 +257,12 @@
>   #interrupt-cells = <2>;
>   };
>  
> + apmixedsys: syscon@1000c000 {
> + compatible = "mediatek,mt8192-apmixedsys", "syscon";
> + reg = <0 0x1000c000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
>   systimer: timer@10017000 {
>   compatible = "mediatek,mt8192-timer",
>"mediatek,mt6765-timer";
> @@ -247,6 +272,12 @@
>   clock-names = "clk13m";
>   };
>  
> + scp_adsp: syscon@1072 {
> + compatible = "mediatek,mt8192-scp_adsp", "syscon";
> + reg = <0 0x1072 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
>   uart0: serial@11002000 {
>   compatible = "mediatek,mt8192-uart",
>"mediatek,mt6577-uart";
> @@ -267,6 +298,12 @@
>   status = "disabled";
>   };
>  
> + imp_iic_wrap_c: syscon@11007000 {
> + compatible = "mediatek,mt8192-imp_iic_wrap_c", "syscon";
> + reg = <0 0x11007000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
>   spi0: spi@1100a000 {
>   compatible = "mediatek,mt8192-spi",
>"mediatek,mt6765-spi";
> @@ -379,6 +416,12 @@
>   status = "disabled";
>   };
>  
> + audsys: syscon@1121 {
> + compatible = "mediatek,mt8192-audsys", "syscon";
> + reg = <0 0x1121 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
>   i2c3: i2c3@11cb {
>   compatible = "mediatek,mt8192-i2c";
>   reg = <0 0x11cb 0 0x1000>,
> @@ -392,6 +435,12 @@
>   status = "disabled";
>   };
>  
> + imp_iic_wrap_e: syscon@11cb1000 {
> + compatible = "mediatek,mt8192-imp_iic_wrap_e", "syscon";
> + reg = <0 0x11cb1000 0 0x1000>;
> + #clock-cells = <1>;
> + };
> +
>   i2c7: i2c7@11d0 {
>   compatible = "mediatek,mt8192-i2c";
>   reg = <0 0x11d0 0 0x1000>,
> @@ -431,6 +480,12 @@
>   status = "disabled";
>   };
>  
> + 

Re: [PATCH v5 07/24] clk: mediatek: Fix asymmetrical PLL enable and disable control

2020-11-17 Thread Ikjoon Jang
On Mon, Nov 09, 2020 at 10:03:32AM +0800, Weiyi Lu wrote:
> In fact, the en_mask is a combination of divider enable mask
> and pll enable bit(bit0).
> Before this patch, we enabled both divider mask and bit0 in prepare(),
> but only cleared the bit0 in unprepare().
> In the future, we hope en_mask will only be used as divider enable mask.
> The enable register(CON0) will be set in 2 steps:
> first is divider mask, and then bit0 during prepare(), and vice versa.
> But considering backward compatibility, at this stage we allow en_mask
> to be a combination or a pure divider enable mask.
> And then we will make en_mask a pure divider enable mask in another
> following patch series.

I have a question on this: Are there any possible problems on controlling
divider_en and bit0 at the same time? Or is this only for cleanups?

If mtk_pll_data::en_mask is not allowed to control with bit0 together,
I guess register_pll() also needs to check en_mask::bit0 is cleared?

> 
> Signed-off-by: Weiyi Lu 
> ---
>  drivers/clk/mediatek/clk-pll.c | 20 
>  1 file changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
> index f440f2cd..11ed5d1 100644
> --- a/drivers/clk/mediatek/clk-pll.c
> +++ b/drivers/clk/mediatek/clk-pll.c
> @@ -238,6 +238,7 @@ static int mtk_pll_prepare(struct clk_hw *hw)
>  {
>   struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
>   u32 r;
> + u32 div_en_mask;
>  
>   r = readl(pll->pwr_addr) | CON0_PWR_ON;
>   writel(r, pll->pwr_addr);
> @@ -247,10 +248,15 @@ static int mtk_pll_prepare(struct clk_hw *hw)
>   writel(r, pll->pwr_addr);
>   udelay(1);
>  
> - r = readl(pll->base_addr + REG_CON0);
> - r |= pll->data->en_mask;
> + r = readl(pll->base_addr + REG_CON0) | CON0_BASE_EN;
>   writel(r, pll->base_addr + REG_CON0);
>  
> + div_en_mask = pll->data->en_mask & ~CON0_BASE_EN;
> + if (div_en_mask) {
> + r = readl(pll->base_addr + REG_CON0) | div_en_mask;
> + writel(r, pll->base_addr + REG_CON0);
> + }
> +
>   __mtk_pll_tuner_enable(pll);
>  
>   udelay(20);
> @@ -268,6 +274,7 @@ static void mtk_pll_unprepare(struct clk_hw *hw)
>  {
>   struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
>   u32 r;
> + u32 div_en_mask;
>  
>   if (pll->data->flags & HAVE_RST_BAR) {
>   r = readl(pll->base_addr + REG_CON0);
> @@ -277,8 +284,13 @@ static void mtk_pll_unprepare(struct clk_hw *hw)
>  
>   __mtk_pll_tuner_disable(pll);
>  
> - r = readl(pll->base_addr + REG_CON0);
> - r &= ~CON0_BASE_EN;
> + div_en_mask = pll->data->en_mask & ~CON0_BASE_EN;
> + if (div_en_mask) {
> + r = readl(pll->base_addr + REG_CON0) & ~div_en_mask;
> + writel(r, pll->base_addr + REG_CON0);
> + }
> +
> + r = readl(pll->base_addr + REG_CON0) & ~CON0_BASE_EN;
>   writel(r, pll->base_addr + REG_CON0);
>  
>   r = readl(pll->pwr_addr) | CON0_ISO_EN;
> -- 
> 1.8.1.1.dirty
> ___
> linux-arm-kernel mailing list
> linux-arm-ker...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


Re: [PATCH v1] spi: spi-mtk-nor: add axi clock control for MT8192 spi-nor

2020-11-16 Thread Ikjoon Jang
On Wed, Nov 11, 2020 at 4:55 PM Bayi Cheng  wrote:
>
> From: bayi cheng 
>
> MT8192 spi-nor is an independent sub system, we need extra control axi
> bus clock for it. Add support for the additional axi clock to allow it
> to be configured appropriately.
>
> Signed-off-by: bayi cheng 

Tested-by: Ikjoon Jang 

> ---
>  drivers/spi/spi-mtk-nor.c | 16 +++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> index b97f26a..bf2d0f9 100644
> --- a/drivers/spi/spi-mtk-nor.c
> +++ b/drivers/spi/spi-mtk-nor.c
> @@ -103,6 +103,7 @@ struct mtk_nor {
> dma_addr_t buffer_dma;
> struct clk *spi_clk;
> struct clk *ctlr_clk;
> +   struct clk *axi_clk;
> unsigned int spi_freq;
> bool wbuf_en;
> bool has_irq;
> @@ -672,6 +673,7 @@ static void mtk_nor_disable_clk(struct mtk_nor *sp)
>  {
> clk_disable_unprepare(sp->spi_clk);
> clk_disable_unprepare(sp->ctlr_clk);
> +   clk_disable_unprepare(sp->axi_clk);
>  }
>
>  static int mtk_nor_enable_clk(struct mtk_nor *sp)
> @@ -688,6 +690,13 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
> return ret;
> }
>
> +   ret = clk_prepare_enable(sp->axi_clk);
> +   if (ret) {
> +   clk_disable_unprepare(sp->spi_clk);
> +   clk_disable_unprepare(sp->ctlr_clk);
> +   return ret;
> +   }
> +
> return 0;
>  }
>
> @@ -746,7 +755,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
> struct spi_controller *ctlr;
> struct mtk_nor *sp;
> void __iomem *base;
> -   struct clk *spi_clk, *ctlr_clk;
> +   struct clk *spi_clk, *ctlr_clk, *axi_clk;
> int ret, irq;
> unsigned long dma_bits;
>
> @@ -762,6 +771,10 @@ static int mtk_nor_probe(struct platform_device *pdev)
> if (IS_ERR(ctlr_clk))
> return PTR_ERR(ctlr_clk);
>
> +   axi_clk = devm_clk_get_optional(>dev, "axi");
> +   if (IS_ERR(axi_clk))
> +   return PTR_ERR(axi_clk);
> +
> dma_bits = (unsigned long)of_device_get_match_data(>dev);
> if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
> dev_err(>dev, "failed to set dma mask(%lu)\n", 
> dma_bits);
> @@ -794,6 +807,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
> sp->dev = >dev;
> sp->spi_clk = spi_clk;
> sp->ctlr_clk = ctlr_clk;
> +   sp->axi_clk = axi_clk;
> sp->high_dma = (dma_bits > 32);
> sp->buffer = dmam_alloc_coherent(>dev,
> MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
> --
> 1.9.1
>


[PATCH v5 0/4] spi: spi-mtk-nor: Add mt8192 support.

2020-10-06 Thread Ikjoon Jang
This patchset adds 36bit dma address and power management
supports for mt8192-nor.

Changes in v5:
- Rebase from merge conflict

Changes in v4:
- Drop two patches from a list, addressed by an another series
- Fix 0-day ci 'shift-count-overflow' warning

Changes in v3:
- Fix a bugfix of v2 in checking spi memory operation.
- split read_dma function into two (normal/bounce)
- Support 7bytes generic spi xfer

Changes in v2:
- Add power management support
- Fix bugs in checking spi memory operation.
- use dma_alloc_coherent for allocating bounce buffer
- code cleanups

Ikjoon Jang (4):
  dt-bindings: spi: add mt8192-nor compatible string
  spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer
  spi: spi-mtk-nor: support 36bit dma addressing
  spi: spi-mtk-nor: Add power management support

 .../bindings/spi/mediatek,spi-mtk-nor.yaml|   1 +
 drivers/spi/spi-mtk-nor.c | 211 --
 2 files changed, 148 insertions(+), 64 deletions(-)

-- 
2.28.0.806.g8561365e88-goog



[PATCH v5 3/4] spi: spi-mtk-nor: support 36bit dma addressing

2020-10-06 Thread Ikjoon Jang
This patch enables 36bit dma address support to spi-mtk-nor.
Currently this is enabled only for mt8192-nor.

Signed-off-by: Ikjoon Jang 
---
 drivers/spi/spi-mtk-nor.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index c11bed28b952..e46d5c93d742 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -79,6 +79,8 @@
 #define MTK_NOR_REG_DMA_FADR   0x71c
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
+#define MTK_NOR_REG_DMA_DADR_HB0x738
+#define MTK_NOR_REG_DMA_END_DADR_HB0x73c
 
 #define MTK_NOR_PRG_MAX_SIZE   6
 // Reading DMA src/dst addresses have to be 16-byte aligned
@@ -103,6 +105,7 @@ struct mtk_nor {
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
+   bool high_dma;
struct completion op_done;
 };
 
@@ -343,6 +346,13 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, 
unsigned int length,
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
 
+   if (sp->high_dma) {
+   writel(upper_32_bits(dma_addr),
+  sp->base + MTK_NOR_REG_DMA_DADR_HB);
+   writel(upper_32_bits(dma_addr + length),
+  sp->base + MTK_NOR_REG_DMA_END_DADR_HB);
+   }
+
if (sp->has_irq) {
reinit_completion(>op_done);
mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
@@ -731,7 +741,8 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops 
= {
 };
 
 static const struct of_device_id mtk_nor_match[] = {
-   { .compatible = "mediatek,mt8173-nor" },
+   { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
+   { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_nor_match);
@@ -743,6 +754,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
void __iomem *base;
struct clk *spi_clk, *ctlr_clk;
int ret, irq;
+   unsigned long dma_bits;
 
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -756,6 +768,12 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (IS_ERR(ctlr_clk))
return PTR_ERR(ctlr_clk);
 
+   dma_bits = (unsigned long)of_device_get_match_data(>dev);
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
+   dev_err(>dev, "failed to set dma mask(%lu)\n", dma_bits);
+   return -EINVAL;
+   }
+
ctlr = spi_alloc_master(>dev, sizeof(*sp));
if (!ctlr) {
dev_err(>dev, "failed to allocate spi controller\n");
@@ -781,6 +799,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->dev = >dev;
sp->spi_clk = spi_clk;
sp->ctlr_clk = ctlr_clk;
+   sp->high_dma = (dma_bits > 32);
sp->buffer = dmam_alloc_coherent(>dev,
MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
>buffer_dma, GFP_KERNEL);
-- 
2.28.0.806.g8561365e88-goog



[PATCH v5 1/4] dt-bindings: spi: add mt8192-nor compatible string

2020-10-06 Thread Ikjoon Jang
Add MT8192 spi-nor controller support.

Signed-off-by: Ikjoon Jang 
Acked-by: Rob Herring 

---
 Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
index 42c9205ac991..55c239446a5b 100644
--- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -30,6 +30,7 @@ properties:
   - mediatek,mt7622-nor
   - mediatek,mt7623-nor
   - mediatek,mt7629-nor
+  - mediatek,mt8192-nor
   - enum:
   - mediatek,mt8173-nor
   - items:
-- 
2.28.0.806.g8561365e88-goog



[PATCH v5 4/4] spi: spi-mtk-nor: Add power management support

2020-10-06 Thread Ikjoon Jang
This patch adds dev_pm_ops to mtk-nor to support suspend/resume,
auto suspend delay is set to -1 by default.

Accessing registers are only permitted after its clock is enabled
to deal with unknown state of operating clk at probe time.

Signed-off-by: Ikjoon Jang 
---
 drivers/spi/spi-mtk-nor.c | 98 ++-
 1 file changed, 76 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index e46d5c93d742..b97f26a60cbe 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -690,22 +691,15 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
return 0;
 }
 
-static int mtk_nor_init(struct mtk_nor *sp)
+static void mtk_nor_init(struct mtk_nor *sp)
 {
-   int ret;
-
-   ret = mtk_nor_enable_clk(sp);
-   if (ret)
-   return ret;
-
-   sp->spi_freq = clk_get_rate(sp->spi_clk);
+   writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
+   writel(MTK_NOR_IRQ_MASK, sp->base + MTK_NOR_REG_IRQ_STAT);
 
writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
-
-   return ret;
 }
 
 static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
@@ -788,6 +782,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
ctlr->num_chipselect = 1;
ctlr->setup = mtk_nor_setup;
ctlr->transfer_one_message = mtk_nor_transfer_one_message;
+   ctlr->auto_runtime_pm = true;
 
dev_set_drvdata(>dev, ctlr);
 
@@ -811,12 +806,19 @@ static int mtk_nor_probe(struct platform_device *pdev)
return -ENOMEM;
}
 
+   ret = mtk_nor_enable_clk(sp);
+   if (ret < 0)
+   return ret;
+
+   sp->spi_freq = clk_get_rate(sp->spi_clk);
+
+   mtk_nor_init(sp);
+
irq = platform_get_irq_optional(pdev, 0);
+
if (irq < 0) {
dev_warn(sp->dev, "IRQ not available.");
} else {
-   writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
-   writel(0, base + MTK_NOR_REG_IRQ_EN);
ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
   pdev->name, sp);
if (ret < 0) {
@@ -827,34 +829,86 @@ static int mtk_nor_probe(struct platform_device *pdev)
}
}
 
-   ret = mtk_nor_init(sp);
-   if (ret < 0) {
-   kfree(ctlr);
-   return ret;
-   }
+   pm_runtime_set_autosuspend_delay(>dev, -1);
+   pm_runtime_use_autosuspend(>dev);
+   pm_runtime_set_active(>dev);
+   pm_runtime_enable(>dev);
+   pm_runtime_get_noresume(>dev);
+
+   ret = devm_spi_register_controller(>dev, ctlr);
+   if (ret < 0)
+   goto err_probe;
+
+   pm_runtime_mark_last_busy(>dev);
+   pm_runtime_put_autosuspend(>dev);
 
dev_info(>dev, "spi frequency: %d Hz\n", sp->spi_freq);
 
-   return devm_spi_register_controller(>dev, ctlr);
+   return 0;
+
+err_probe:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return ret;
 }
 
 static int mtk_nor_remove(struct platform_device *pdev)
 {
-   struct spi_controller *ctlr;
-   struct mtk_nor *sp;
+   struct spi_controller *ctlr = dev_get_drvdata(>dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
-   ctlr = dev_get_drvdata(>dev);
-   sp = spi_controller_get_devdata(ctlr);
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_nor_runtime_suspend(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
mtk_nor_disable_clk(sp);
 
return 0;
 }
 
+static int __maybe_unused mtk_nor_runtime_resume(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
+
+   return mtk_nor_enable_clk(sp);
+}
+
+static int __maybe_unused mtk_nor_suspend(struct device *dev)
+{
+   return pm_runtime_force_suspend(dev);
+}
+
+static int __maybe_unused mtk_nor_resume(struct device *dev)
+{
+   return pm_runtime_force_resume(dev);
+}
+
+static const struct dev_pm_ops mtk_nor_pm_ops = {
+   SET_RUNTIME_PM_OPS(mtk_nor_runtime_suspend,
+  mtk_nor_runtime_resume, NULL)

[PATCH v5 2/4] spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer

2020-10-06 Thread Ikjoon Jang
Use dma_alloc_coherent() for bounce buffer instead of kmalloc() to
make sure the bounce buffer to be allocated within its DMAable range.

Signed-off-by: Ikjoon Jang 

---
 drivers/spi/spi-mtk-nor.c | 94 ++-
 1 file changed, 52 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index ea39736de291..c11bed28b952 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -97,6 +97,7 @@ struct mtk_nor {
struct device *dev;
void __iomem *base;
u8 *buffer;
+   dma_addr_t buffer_dma;
struct clk *spi_clk;
struct clk *ctlr_clk;
unsigned int spi_freq;
@@ -145,6 +146,11 @@ static void mtk_nor_set_addr(struct mtk_nor *sp, const 
struct spi_mem_op *op)
}
 }
 
+static bool need_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   return ((uintptr_t)op->data.buf.in & MTK_NOR_DMA_ALIGN_MASK);
+}
+
 static bool mtk_nor_match_read(const struct spi_mem_op *op)
 {
int dummy = 0;
@@ -238,6 +244,8 @@ static void mtk_nor_adj_prg_size(struct spi_mem_op *op)
 
 static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 {
+   struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
+
if (!op->data.nbytes)
return 0;
 
@@ -251,8 +259,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
struct spi_mem_op *op)
if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
(op->data.nbytes < MTK_NOR_DMA_ALIGN))
op->data.nbytes = 1;
-   else if (!((ulong)(op->data.buf.in) &
-  MTK_NOR_DMA_ALIGN_MASK))
+   else if (!need_bounce(sp, op))
op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
@@ -325,19 +332,12 @@ static void mtk_nor_setup_bus(struct mtk_nor *sp, const 
struct spi_mem_op *op)
mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
 }
 
-static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
-   u8 *buffer)
+static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, unsigned int length,
+   dma_addr_t dma_addr)
 {
int ret = 0;
ulong delay;
u32 reg;
-   dma_addr_t dma_addr;
-
-   dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
-   if (dma_mapping_error(sp->dev, dma_addr)) {
-   dev_err(sp->dev, "failed to map dma buffer.\n");
-   return -EINVAL;
-   }
 
writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
@@ -362,30 +362,49 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, 
unsigned int length,
 (delay + 1) * 100);
}
 
-   dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
if (ret < 0)
dev_err(sp->dev, "dma read timeout.\n");
 
return ret;
 }
 
-static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
-  unsigned int length, u8 *buffer)
+static int mtk_nor_read_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
 {
unsigned int rdlen;
int ret;
 
-   if (length & MTK_NOR_DMA_ALIGN_MASK)
-   rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
+   if (op->data.nbytes & MTK_NOR_DMA_ALIGN_MASK)
+   rdlen = (op->data.nbytes + MTK_NOR_DMA_ALIGN) & 
~MTK_NOR_DMA_ALIGN_MASK;
else
-   rdlen = length;
+   rdlen = op->data.nbytes;
 
-   ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
-   if (ret)
-   return ret;
+   ret = mtk_nor_dma_exec(sp, op->addr.val, rdlen, sp->buffer_dma);
 
-   memcpy(buffer, sp->buffer, length);
-   return 0;
+   if (!ret)
+   memcpy(op->data.buf.in, sp->buffer, op->data.nbytes);
+
+   return ret;
+}
+
+static int mtk_nor_read_dma(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   int ret;
+   dma_addr_t dma_addr;
+
+   if (need_bounce(sp, op))
+   return mtk_nor_read_bounce(sp, op);
+
+   dma_addr = dma_map_single(sp->dev, op->data.buf.in,
+ op->data.nbytes, DMA_FROM_DEVICE);
+
+   if (dma_mapping_error(sp->dev, dma_addr))
+   return -EINVAL;
+
+   ret = mtk_nor_dma_exec(sp, op->addr.val, op->data.nbytes, dma_addr);
+
+   dma_unmap_single(sp->dev, dma_addr, op->data.nbytes, DMA_FROM_DEVICE);
+
+

Re: linux-next: Fixes tag needs some work in the battery tree

2020-10-05 Thread Ikjoon Jang
On Tue, Oct 6, 2020 at 11:57 AM Ikjoon Jang  wrote:
>
> On Mon, Oct 5, 2020 at 7:50 PM Stephen Rothwell  wrote:
> >
> > Hi all,
> >
> > In commit
> >
> >   f9d293364b45 ("power: supply: sbs-battery: keep error code when 
> > get_property() fails")
> >
> > Fixes tag
> >
> >   Fixes: c4f382930145 (power: supply: sbs-battery: don't assume i2c errors 
> > as battery disconnect)
> >
> > has these problem(s):
> >
> >   - Target SHA1 does not exist
> >
> > Maybe you meant
> >
> > Fixes: 395a7251dc2b ("power: supply: sbs-battery: don't assume i2c errors 
> > as battery disconnect")
> >
>
> Yes, you're right. I guess I made a mistake here.
> I'll send a v2 patch.

Oh I'm sorry, it's from linux-next!

I found d6e24aa0bf15 ("power: supply: sbs-battery: keep error code
when get_property() fails") on sre/for-next branch
with a valid Fixes tag:

power: supply: sbs-battery: keep error code when get_property() fails

Commit c4f382930145 (power: supply: sbs-battery: don't assume
i2c errors as battery disconnect) overwrites the original error code
returned from internal functions. On such a sporadic i2c error,
    a user will get a wrong value without errors.

Fixes: 395a7251dc2b (power: supply: sbs-battery: don't assume i2c
errors as battery disconnect)

Signed-off-by: Ikjoon Jang 
Signed-off-by: Sebastian Reichel 

but there is still a wrong sha-1 hash in the commit message,
Sebastian, can you please amend the commit message before merge?


>
> Thank you!
>
> > --
> > Cheers,
> > Stephen Rothwell


Re: linux-next: Fixes tag needs some work in the battery tree

2020-10-05 Thread Ikjoon Jang
On Mon, Oct 5, 2020 at 7:50 PM Stephen Rothwell  wrote:
>
> Hi all,
>
> In commit
>
>   f9d293364b45 ("power: supply: sbs-battery: keep error code when 
> get_property() fails")
>
> Fixes tag
>
>   Fixes: c4f382930145 (power: supply: sbs-battery: don't assume i2c errors as 
> battery disconnect)
>
> has these problem(s):
>
>   - Target SHA1 does not exist
>
> Maybe you meant
>
> Fixes: 395a7251dc2b ("power: supply: sbs-battery: don't assume i2c errors as 
> battery disconnect")
>

Yes, you're right. I guess I made a mistake here.
I'll send a v2 patch.

Thank you!

> --
> Cheers,
> Stephen Rothwell


[PATCH v4 3/4] spi: spi-mtk-nor: support 36bit dma addressing

2020-09-29 Thread Ikjoon Jang
This patch enables 36bit dma address support to spi-mtk-nor.
Currently this is enabled only for mt8192-nor.

Signed-off-by: Ikjoon Jang 
---

Changes in v4:
- Fix 0-day ci warning from shifting 32bit value
- Fix missing initialization of internal flags, 'high_dma'

 drivers/spi/spi-mtk-nor.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index cfb9a2450962..eac613b3930d 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -78,6 +78,8 @@
 #define MTK_NOR_REG_DMA_FADR   0x71c
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
+#define MTK_NOR_REG_DMA_DADR_HB0x738
+#define MTK_NOR_REG_DMA_END_DADR_HB0x73c
 
 #define MTK_NOR_PRG_MAX_SIZE   6
 // Reading DMA src/dst addresses have to be 16-byte aligned
@@ -102,6 +104,7 @@ struct mtk_nor {
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
+   bool high_dma;
struct completion op_done;
 };
 
@@ -278,6 +281,13 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, 
unsigned int length,
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
 
+   if (sp->high_dma) {
+   writel(upper_32_bits(dma_addr),
+  sp->base + MTK_NOR_REG_DMA_DADR_HB);
+   writel(upper_32_bits(dma_addr + length),
+  sp->base + MTK_NOR_REG_DMA_END_DADR_HB);
+   }
+
if (sp->has_irq) {
reinit_completion(>op_done);
mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
@@ -589,7 +599,8 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops 
= {
 };
 
 static const struct of_device_id mtk_nor_match[] = {
-   { .compatible = "mediatek,mt8173-nor" },
+   { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
+   { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_nor_match);
@@ -601,6 +612,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
void __iomem *base;
struct clk *spi_clk, *ctlr_clk;
int ret, irq;
+   unsigned long dma_bits;
 
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -614,6 +626,12 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (IS_ERR(ctlr_clk))
return PTR_ERR(ctlr_clk);
 
+   dma_bits = (unsigned long)of_device_get_match_data(>dev);
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
+   dev_err(>dev, "failed to set dma mask(%lu)\n", dma_bits);
+   return -EINVAL;
+   }
+
ctlr = spi_alloc_master(>dev, sizeof(*sp));
if (!ctlr) {
dev_err(>dev, "failed to allocate spi controller\n");
@@ -639,6 +657,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->dev = >dev;
sp->spi_clk = spi_clk;
sp->ctlr_clk = ctlr_clk;
+   sp->high_dma = (dma_bits > 32);
sp->buffer = dmam_alloc_coherent(>dev,
MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
>buffer_dma, GFP_KERNEL);
-- 
2.28.0.709.gb0816b6eb0-goog



[PATCH v4 2/4] spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer

2020-09-29 Thread Ikjoon Jang
Use dma_alloc_coherent() for bounce buffer instead of kmalloc() to
make sure the bounce buffer to be allocated within its DMAable range.

Additionally, add an internal helper need_bounce() function checking
whether op's data buffer is DMAable.

Reviewed-by: Chuanhong Guo 
Signed-off-by: Ikjoon Jang 

---

Changes in v4:
- No changes since v3

Changes in v3:
- simplify function names
- restore back padding bytes to bounce buffer omitted in v2

 drivers/spi/spi-mtk-nor.c | 93 +--
 1 file changed, 51 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 6e6ca2b8e6c8..cfb9a2450962 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -96,6 +96,7 @@ struct mtk_nor {
struct device *dev;
void __iomem *base;
u8 *buffer;
+   dma_addr_t buffer_dma;
struct clk *spi_clk;
struct clk *ctlr_clk;
unsigned int spi_freq;
@@ -144,6 +145,11 @@ static void mtk_nor_set_addr(struct mtk_nor *sp, const 
struct spi_mem_op *op)
}
 }
 
+static bool need_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   return ((uintptr_t)op->data.buf.in & MTK_NOR_DMA_ALIGN_MASK);
+}
+
 static bool mtk_nor_match_read(const struct spi_mem_op *op)
 {
int dummy = 0;
@@ -169,6 +175,7 @@ static bool mtk_nor_match_read(const struct spi_mem_op *op)
 
 static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 {
+   struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
size_t len;
 
if (!op->data.nbytes)
@@ -180,8 +187,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
struct spi_mem_op *op)
if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
(op->data.nbytes < MTK_NOR_DMA_ALIGN))
op->data.nbytes = 1;
-   else if (!((ulong)(op->data.buf.in) &
-  MTK_NOR_DMA_ALIGN_MASK))
+   else if (!need_bounce(sp, op))
op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
@@ -261,19 +267,12 @@ static void mtk_nor_setup_bus(struct mtk_nor *sp, const 
struct spi_mem_op *op)
mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
 }
 
-static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
-   u8 *buffer)
+static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, unsigned int length,
+   dma_addr_t dma_addr)
 {
int ret = 0;
ulong delay;
u32 reg;
-   dma_addr_t dma_addr;
-
-   dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
-   if (dma_mapping_error(sp->dev, dma_addr)) {
-   dev_err(sp->dev, "failed to map dma buffer.\n");
-   return -EINVAL;
-   }
 
writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
@@ -298,30 +297,49 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, 
unsigned int length,
 (delay + 1) * 100);
}
 
-   dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
if (ret < 0)
dev_err(sp->dev, "dma read timeout.\n");
 
return ret;
 }
 
-static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
-  unsigned int length, u8 *buffer)
+static int mtk_nor_read_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
 {
unsigned int rdlen;
int ret;
 
-   if (length & MTK_NOR_DMA_ALIGN_MASK)
-   rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
+   if (op->data.nbytes & MTK_NOR_DMA_ALIGN_MASK)
+   rdlen = (op->data.nbytes + MTK_NOR_DMA_ALIGN) & 
~MTK_NOR_DMA_ALIGN_MASK;
else
-   rdlen = length;
+   rdlen = op->data.nbytes;
 
-   ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
-   if (ret)
-   return ret;
+   ret = mtk_nor_dma_exec(sp, op->addr.val, rdlen, sp->buffer_dma);
 
-   memcpy(buffer, sp->buffer, length);
-   return 0;
+   if (!ret)
+   memcpy(op->data.buf.in, sp->buffer, op->data.nbytes);
+
+   return ret;
+}
+
+static int mtk_nor_read_dma(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   int ret;
+   dma_addr_t dma_addr;
+
+   if (need_bounce(sp, op))
+   return mtk_nor_read_bounce(sp, op);
+
+   dma_addr = dma_map_single(sp->dev, op->data.buf.in,
+ op->data.nbytes, D

[PATCH v4 4/4] spi: spi-mtk-nor: Add power management support

2020-09-29 Thread Ikjoon Jang
This patch adds dev_pm_ops to mtk-nor to support suspend/resume,
auto suspend delay is set to -1 by default.

Accessing registers are only permitted after its clock is enabled
to deal with unknown state of operating clk at probe time,

Signed-off-by: Ikjoon Jang 
---
Changes in v4:
- No changes

Changes in v3:
- Remove unrelated changes of dma_set_mask_coherent()

 drivers/spi/spi-mtk-nor.c | 98 ++-
 1 file changed, 76 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index eac613b3930d..6179eb163cd6 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -548,22 +549,15 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
return 0;
 }
 
-static int mtk_nor_init(struct mtk_nor *sp)
+static void mtk_nor_init(struct mtk_nor *sp)
 {
-   int ret;
-
-   ret = mtk_nor_enable_clk(sp);
-   if (ret)
-   return ret;
-
-   sp->spi_freq = clk_get_rate(sp->spi_clk);
+   writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
+   writel(MTK_NOR_IRQ_MASK, sp->base + MTK_NOR_REG_IRQ_STAT);
 
writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
-
-   return ret;
 }
 
 static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
@@ -646,6 +640,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
ctlr->num_chipselect = 1;
ctlr->setup = mtk_nor_setup;
ctlr->transfer_one_message = mtk_nor_transfer_one_message;
+   ctlr->auto_runtime_pm = true;
 
dev_set_drvdata(>dev, ctlr);
 
@@ -669,12 +664,19 @@ static int mtk_nor_probe(struct platform_device *pdev)
return -ENOMEM;
}
 
+   ret = mtk_nor_enable_clk(sp);
+   if (ret < 0)
+   return ret;
+
+   sp->spi_freq = clk_get_rate(sp->spi_clk);
+
+   mtk_nor_init(sp);
+
irq = platform_get_irq_optional(pdev, 0);
+
if (irq < 0) {
dev_warn(sp->dev, "IRQ not available.");
} else {
-   writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
-   writel(0, base + MTK_NOR_REG_IRQ_EN);
ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
   pdev->name, sp);
if (ret < 0) {
@@ -685,34 +687,86 @@ static int mtk_nor_probe(struct platform_device *pdev)
}
}
 
-   ret = mtk_nor_init(sp);
-   if (ret < 0) {
-   kfree(ctlr);
-   return ret;
-   }
+   pm_runtime_set_autosuspend_delay(>dev, -1);
+   pm_runtime_use_autosuspend(>dev);
+   pm_runtime_set_active(>dev);
+   pm_runtime_enable(>dev);
+   pm_runtime_get_noresume(>dev);
+
+   ret = devm_spi_register_controller(>dev, ctlr);
+   if (ret < 0)
+   goto err_probe;
+
+   pm_runtime_mark_last_busy(>dev);
+   pm_runtime_put_autosuspend(>dev);
 
dev_info(>dev, "spi frequency: %d Hz\n", sp->spi_freq);
 
-   return devm_spi_register_controller(>dev, ctlr);
+   return 0;
+
+err_probe:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return ret;
 }
 
 static int mtk_nor_remove(struct platform_device *pdev)
 {
-   struct spi_controller *ctlr;
-   struct mtk_nor *sp;
+   struct spi_controller *ctlr = dev_get_drvdata(>dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
-   ctlr = dev_get_drvdata(>dev);
-   sp = spi_controller_get_devdata(ctlr);
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_nor_runtime_suspend(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
mtk_nor_disable_clk(sp);
 
return 0;
 }
 
+static int __maybe_unused mtk_nor_runtime_resume(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
+
+   return mtk_nor_enable_clk(sp);
+}
+
+static int __maybe_unused mtk_nor_suspend(struct device *dev)
+{
+   return pm_runtime_force_suspend(dev);
+}
+
+static int __maybe_unused mtk_nor_resume(struct device *dev)
+{
+   return pm_runtime_force_resume(dev);
+}
+
+static const struct dev_pm_ops mtk_nor_pm_ops = {
+  

[PATCH v4 1/4] dt-bindings: spi: add mt8192-nor compatible string

2020-09-29 Thread Ikjoon Jang
Add MT8192 spi-nor controller support.

Signed-off-by: Ikjoon Jang 
Acked-by: Rob Herring 

---

(no changes since v1)

 Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
index 42c9205ac991..55c239446a5b 100644
--- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -30,6 +30,7 @@ properties:
   - mediatek,mt7622-nor
   - mediatek,mt7623-nor
   - mediatek,mt7629-nor
+  - mediatek,mt8192-nor
   - enum:
   - mediatek,mt8173-nor
   - items:
-- 
2.28.0.709.gb0816b6eb0-goog



[PATCH v4 0/4] spi: spi-mtk-nor: Add mt8192 support.

2020-09-29 Thread Ikjoon Jang


This patchset adds 36bit dma address and power management
supports for mt8192-nor. Additionally, use dma_alloc_coherent()
instead of kmalloc() for internal bounce buffer for platforms
of only supporting 32bit addresses.

Changes in v4:
- Drop two patches from a list which already addressed by
  an another series and not directly related with mt8192 support
- Fix 0-day ci 'shift-count-overflow' warning
- Fix missing 'high_dma' initialization for 36bit address

Changes in v3:
- Fix a bugfix of v2 in checking spi memory operation.
- split read_dma function into two (normal/bounce)
- Support 7bytes generic spi xfer

Changes in v2:
- Add power management support
- Fix bugs in checking spi memory operation.
- use dma_alloc_coherent for allocating bounce buffer
- code cleanups

Ikjoon Jang (4):
  dt-bindings: spi: add mt8192-nor compatible string
  spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer
  spi: spi-mtk-nor: support 36bit dma addressing
  spi: spi-mtk-nor: Add power management support

 .../bindings/spi/mediatek,spi-mtk-nor.yaml|   1 +
 drivers/spi/spi-mtk-nor.c | 210 --
 2 files changed, 147 insertions(+), 64 deletions(-)

-- 
2.28.0.709.gb0816b6eb0-goog



[RESEND PATCH v4] mtd: spi-nor: winbond: Add support for w25q64jwm

2020-09-28 Thread Ikjoon Jang
Add support Winbond w25q{64,128,256}jwm which are identical to existing
w25q32jwm except for their sizes.

This was tested with w25q64jwm, basic erase/write/readback and
lock/unlock both lower/upper blocks were okay.

Signed-off-by: i...@chromium.org 
Signed-off-by: Xingyu Wu 
Signed-off-by: ST Lin 
Tested-by: Nicolas Boichat 

Signed-off-by: Ikjoon Jang 
---

Changes in v4:
- drops package type code from name

Changes in v3:
- fix commit message formats

Changes in v2:
- remove duplicated flash ID (w25q32jwm)

 drivers/mtd/spi-nor/winbond.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c
index 6dcde15fb1aa..e5dfa786f190 100644
--- a/drivers/mtd/spi-nor/winbond.c
+++ b/drivers/mtd/spi-nor/winbond.c
@@ -63,6 +63,15 @@ static const struct flash_info winbond_parts[] = {
{ "w25q32jwm", INFO(0xef8016, 0, 64 * 1024,  64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q64jwm", INFO(0xef8017, 0, 64 * 1024, 128,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q128jwm", INFO(0xef8018, 0, 64 * 1024, 256,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q256jwm", INFO(0xef8019, 0, 64 * 1024, 512,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128,
 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-- 
2.28.0.681.g6f77f65b4e-goog



Re: [PATCH v3 5/6] spi: spi-mtk-nor: support 36bit dma addressing

2020-09-27 Thread Ikjoon Jang
On Sun, Sep 27, 2020 at 4:30 PM Yingjoe Chen  wrote:
>
> On Fri, 2020-09-25 at 14:54 +0800, Ikjoon Jang wrote:
> > This patch enables 36bit dma address support to spi-mtk-nor.
> > Currently this is enabled only for mt8192-nor.
> >
> > Signed-off-by: Ikjoon Jang 
> > ---
> >
> > (no changes since v1)
> >
> >  drivers/spi/spi-mtk-nor.c | 18 +-
> >  1 file changed, 17 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> > index 8dbafee7f431..35205635ed42 100644
> > --- a/drivers/spi/spi-mtk-nor.c
> > +++ b/drivers/spi/spi-mtk-nor.c
> > @@ -78,6 +78,8 @@
> >  #define MTK_NOR_REG_DMA_FADR 0x71c
> >  #define MTK_NOR_REG_DMA_DADR 0x720
> >  #define MTK_NOR_REG_DMA_END_DADR 0x724
> > +#define MTK_NOR_REG_DMA_DADR_HB  0x738
> > +#define MTK_NOR_REG_DMA_END_DADR_HB  0x73c
> >
> >  /* maximum bytes of TX in PRG mode */
> >  #define MTK_NOR_PRG_MAX_SIZE 6
> > @@ -106,6 +108,7 @@ struct mtk_nor {
> >   unsigned int spi_freq;
> >   bool wbuf_en;
> >   bool has_irq;
> > + bool high_dma;
> >   struct completion op_done;
> >  };
> >
> > @@ -305,6 +308,11 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 
> > from, unsigned int length,
> >   writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
> >   writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
> >
> > + if (sp->high_dma) {
> > + writel(dma_addr >> 32, sp->base + MTK_NOR_REG_DMA_DADR_HB);
> > + writel((dma_addr + length) >> 32, sp->base + 
> > MTK_NOR_REG_DMA_END_DADR_HB);
> > + }
> > +
>
> Maybe use upper_32_bits() ?

Thanks, good to know that!

>
>
> >   if (sp->has_irq) {
> >   reinit_completion(>op_done);
> >   mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
> > @@ -635,7 +643,8 @@ static const struct spi_controller_mem_ops 
> > mtk_nor_mem_ops = {
> >  };
> >
> >  static const struct of_device_id mtk_nor_match[] = {
> > - { .compatible = "mediatek,mt8173-nor" },
> > + { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
> > + { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
> >   { /* sentinel */ }
> >  };
> >  MODULE_DEVICE_TABLE(of, mtk_nor_match);
> > @@ -647,6 +656,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
> >   void __iomem *base;
> >   struct clk *spi_clk, *ctlr_clk;
> >   int ret, irq;
> > + unsigned long dma_bits;
> >
> >   base = devm_platform_ioremap_resource(pdev, 0);
> >   if (IS_ERR(base))
> > @@ -660,6 +670,12 @@ static int mtk_nor_probe(struct platform_device *pdev)
> >   if (IS_ERR(ctlr_clk))
> >   return PTR_ERR(ctlr_clk);
> >
> > + dma_bits = (unsigned long)of_device_get_match_data(>dev);
> > + if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
> > + dev_err(>dev, "failed to set dma mask(%lu)\n", 
> > dma_bits);
> > + return -EINVAL;
> > + }
> > +
>
> As said in previous version. I don't see any place enable high_dma, so I
> think this patch won't set >32bits for anychip. We need something like:
>
> sp->hidh_dma = dma_bits > 32;
>
> Am I missing anything?

Yeah, you're right, that line disappeared between v2 ~ v3 (by mistake).

>
> Joe.C
>


Re: [PATCH v3 2/6] spi: spi-mtk-nor: fix mishandled logics in checking SPI memory operation

2020-09-25 Thread Ikjoon Jang
On Fri, Sep 25, 2020 at 2:54 PM Ikjoon Jang  wrote:
>
> Fix a bug which limits its protocol availability in supports_op().
>
> Fixes: a59b2c7c56bf ("spi: spi-mtk-nor: support standard spi properties")
> Signed-off-by: Ikjoon Jang 
> ---

This is also duplicated work of https://patchwork.kernel.org/patch/11797723/,
I'm going to drop this patch in v4.

>
> (no changes since v1)
>
>  drivers/spi/spi-mtk-nor.c | 26 +++---
>  1 file changed, 11 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> index 6e6ca2b8e6c8..0f7d4ec68730 100644
> --- a/drivers/spi/spi-mtk-nor.c
> +++ b/drivers/spi/spi-mtk-nor.c
> @@ -211,28 +211,24 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
> if (op->cmd.buswidth != 1)
> return false;
>
> +   if (!spi_mem_default_supports_op(mem, op))
> +   return false;
> +
> if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
> -   switch(op->data.dir) {
> -   case SPI_MEM_DATA_IN:
> -   if (!mtk_nor_match_read(op))
> -   return false;
> -   break;
> -   case SPI_MEM_DATA_OUT:
> -   if ((op->addr.buswidth != 1) ||
> -   (op->dummy.nbytes != 0) ||
> -   (op->data.buswidth != 1))
> -   return false;
> -   break;
> -   default:
> -   break;
> -   }
> +   if ((op->data.dir == SPI_MEM_DATA_IN) && 
> mtk_nor_match_read(op))
> +   return true;
> +   else if (op->data.dir == SPI_MEM_DATA_OUT)
> +   return (op->addr.buswidth == 1) &&
> +  (op->dummy.nbytes == 0) &&
> +  (op->data.buswidth == 1);
> }
> +
> len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
> if ((len > MTK_NOR_PRG_MAX_SIZE) ||
> ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
> return false;
>
> -   return spi_mem_default_supports_op(mem, op);
> +   return true;
>  }
>
>  static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op 
> *op)
> --
> 2.28.0.681.g6f77f65b4e-goog
>


Re: [PATCH v3 3/6] spi: spi-mtk-nor: support 7 bytes transfer of generic spi

2020-09-25 Thread Ikjoon Jang
On Fri, Sep 25, 2020 at 3:47 PM Chuanhong Guo  wrote:
>
> Hi!
>
> On Fri, Sep 25, 2020 at 2:55 PM Ikjoon Jang  wrote:
> >
> > When mtk-nor fallbacks to generic spi transfers, it can actually
> > transfer up to 7 bytes.
>
> generic transfer_one_message should support full-duplex transfers,
> not transfers with special format requirements. (e.g. here the last
> byte is rx only.) These transfers with format requirements should
> be implemented with spi-mem interface instead.

yep, that's correct.

>
> >
> > This patch fixes adjust_op_size() and supports_op() to explicitly
> > check 7 bytes range and also fixes possible under/overflow conditions
> > in register offsets calculation.
> >
> > Signed-off-by: Ikjoon Jang 
>
> I was notified by Bayi about your discussion and sent some
> patches yesterday for the same purpose. Whoops...
> As transfer_one_message isn't the proper place to implement
> this, maybe we could work on my version instead?
>

I didn't noticed that before,
Sure, please go ahead, I'll follow up with your patch in v4.

> > ---
> >
> > (no changes since v1)
>
> This should be "new patch" not "no changes" :P

oops, it seems my script did something wrong.

>
>
> >
> >  drivers/spi/spi-mtk-nor.c | 102 --
> >  1 file changed, 76 insertions(+), 26 deletions(-)
> >
> > diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> > index 0f7d4ec68730..e7719d249095 100644
> > --- a/drivers/spi/spi-mtk-nor.c
> > +++ b/drivers/spi/spi-mtk-nor.c
> > @@ -79,7 +79,11 @@
> >  #define MTK_NOR_REG_DMA_DADR   0x720
> >  #define MTK_NOR_REG_DMA_END_DADR   0x724
> >
> > +/* maximum bytes of TX in PRG mode */
> >  #define MTK_NOR_PRG_MAX_SIZE   6
> > +/* maximum bytes of TX + RX is 7, last 1 byte is always being sent as zero 
> > */
> > +#define MTK_NOR_PRG_MAX_CYCLES 7
> > +
> >  // Reading DMA src/dst addresses have to be 16-byte aligned
> >  #define MTK_NOR_DMA_ALIGN  16
> >  #define MTK_NOR_DMA_ALIGN_MASK (MTK_NOR_DMA_ALIGN - 1)
> > @@ -167,6 +171,24 @@ static bool mtk_nor_match_read(const struct spi_mem_op 
> > *op)
> > return false;
> >  }
> >
> > +static bool mtk_nor_check_prg(const struct spi_mem_op *op)
> > +{
> > +   size_t len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
> > +
> > +   if (len > MTK_NOR_PRG_MAX_SIZE)
> > +   return false;
> > +
> > +   if (!op->data.nbytes)
> > +   return true;
> > +
> > +   if (op->data.dir == SPI_MEM_DATA_OUT)
> > +   return ((len + op->data.nbytes) <= MTK_NOR_PRG_MAX_SIZE);
> > +   else if (op->data.dir == SPI_MEM_DATA_IN)
> > +   return ((len + op->data.nbytes) <= MTK_NOR_PRG_MAX_CYCLES);
> > +   else
> > +   return true;
> > +}
> > +
> >  static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op 
> > *op)
> >  {
> > size_t len;
> > @@ -195,10 +217,22 @@ static int mtk_nor_adjust_op_size(struct spi_mem 
> > *mem, struct spi_mem_op *op)
> > }
> > }
> >
> > -   len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -
> > - op->dummy.nbytes;
> > -   if (op->data.nbytes > len)
> > -   op->data.nbytes = len;
> > +   if (mtk_nor_check_prg(op))
> > +   return 0;
> > +
> > +   len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
> > +
> > +   if (op->data.dir == SPI_MEM_DATA_OUT) {
> > +   if (len == MTK_NOR_PRG_MAX_SIZE)
> > +   return -EINVAL;
> > +   op->data.nbytes = min_t(unsigned int, op->data.nbytes,
> > +   MTK_NOR_PRG_MAX_SIZE - len);
> > +   } else  {
> > +   if (len == MTK_NOR_PRG_MAX_CYCLES)
> > +   return -EINVAL;
> > +   op->data.nbytes = min_t(unsigned int, op->data.nbytes,
> > +   MTK_NOR_PRG_MAX_CYCLES - len);
> > +   }
> >
> > return 0;
> >  }
> > @@ -206,8 +240,6 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
> > struct spi_mem_op *op)
> >  static bool mtk_nor_supports_op(struct spi_mem *mem,
> > const struct spi_mem_op *op)
> >  {
>

Re: [PATCH v3 5/6] spi: spi-mtk-nor: support 36bit dma addressing

2020-09-25 Thread Ikjoon Jang
On Fri, Sep 25, 2020 at 4:27 PM Chuanhong Guo  wrote:
>

[snip]

> > +   if (sp->high_dma) {
> > +   writel(dma_addr >> 32, sp->base + MTK_NOR_REG_DMA_DADR_HB);
> > +   writel((dma_addr + length) >> 32, sp->base + 
> > MTK_NOR_REG_DMA_END_DADR_HB);
> > +   }
>
> I remembered kbuild test robot reported a warning on this on 32-bit platforms
> in your v1. [0]
> I don't know what's the fix for this though :(
>
> [0] https://marc.info/?l=linux-spi=159982425706940=2

yeah, I'm not sure how to handle this properly,

"warning: shift count >= width of type",
(sp->high_dma) is always false on 32bit arm kernel.
I think adding size check on here is unnecessary, should I fix for this warning?

> --
> Regards,
> Chuanhong Guo

Sorry for resending, Chuanhong.


[PATCH v3 3/6] spi: spi-mtk-nor: support 7 bytes transfer of generic spi

2020-09-25 Thread Ikjoon Jang
When mtk-nor fallbacks to generic spi transfers, it can actually
transfer up to 7 bytes.

This patch fixes adjust_op_size() and supports_op() to explicitly
check 7 bytes range and also fixes possible under/overflow conditions
in register offsets calculation.

Signed-off-by: Ikjoon Jang 
---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 102 --
 1 file changed, 76 insertions(+), 26 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 0f7d4ec68730..e7719d249095 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -79,7 +79,11 @@
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
 
+/* maximum bytes of TX in PRG mode */
 #define MTK_NOR_PRG_MAX_SIZE   6
+/* maximum bytes of TX + RX is 7, last 1 byte is always being sent as zero */
+#define MTK_NOR_PRG_MAX_CYCLES 7
+
 // Reading DMA src/dst addresses have to be 16-byte aligned
 #define MTK_NOR_DMA_ALIGN  16
 #define MTK_NOR_DMA_ALIGN_MASK (MTK_NOR_DMA_ALIGN - 1)
@@ -167,6 +171,24 @@ static bool mtk_nor_match_read(const struct spi_mem_op *op)
return false;
 }
 
+static bool mtk_nor_check_prg(const struct spi_mem_op *op)
+{
+   size_t len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+   if (len > MTK_NOR_PRG_MAX_SIZE)
+   return false;
+
+   if (!op->data.nbytes)
+   return true;
+
+   if (op->data.dir == SPI_MEM_DATA_OUT)
+   return ((len + op->data.nbytes) <= MTK_NOR_PRG_MAX_SIZE);
+   else if (op->data.dir == SPI_MEM_DATA_IN)
+   return ((len + op->data.nbytes) <= MTK_NOR_PRG_MAX_CYCLES);
+   else
+   return true;
+}
+
 static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 {
size_t len;
@@ -195,10 +217,22 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
struct spi_mem_op *op)
}
}
 
-   len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -
- op->dummy.nbytes;
-   if (op->data.nbytes > len)
-   op->data.nbytes = len;
+   if (mtk_nor_check_prg(op))
+   return 0;
+
+   len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+   if (op->data.dir == SPI_MEM_DATA_OUT) {
+   if (len == MTK_NOR_PRG_MAX_SIZE)
+   return -EINVAL;
+   op->data.nbytes = min_t(unsigned int, op->data.nbytes,
+   MTK_NOR_PRG_MAX_SIZE - len);
+   } else  {
+   if (len == MTK_NOR_PRG_MAX_CYCLES)
+   return -EINVAL;
+   op->data.nbytes = min_t(unsigned int, op->data.nbytes,
+   MTK_NOR_PRG_MAX_CYCLES - len);
+   }
 
return 0;
 }
@@ -206,8 +240,6 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
struct spi_mem_op *op)
 static bool mtk_nor_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
 {
-   size_t len;
-
if (op->cmd.buswidth != 1)
return false;
 
@@ -223,12 +255,11 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
   (op->data.buswidth == 1);
}
 
-   len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
-   if ((len > MTK_NOR_PRG_MAX_SIZE) ||
-   ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
+   /* fallback to generic spi xfer */
+   if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 || op->data.buswidth 
> 1)
return false;
 
-   return true;
+   return mtk_nor_check_prg(op);
 }
 
 static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op)
@@ -459,22 +490,36 @@ static int mtk_nor_transfer_one_message(struct 
spi_controller *master,
int stat = 0;
int reg_offset = MTK_NOR_REG_PRGDATA_MAX;
void __iomem *reg;
-   const u8 *txbuf;
-   u8 *rxbuf;
-   int i;
+   int i, tx_len = 0, rx_len = 0;
 
list_for_each_entry(t, >transfers, transfer_list) {
-   txbuf = t->tx_buf;
-   for (i = 0; i < t->len; i++, reg_offset--) {
+   const u8 *txbuf = t->tx_buf;
+
+   if (!txbuf) {
+   rx_len += t->len;
+   continue;
+   }
+
+   if (rx_len) {
+   stat = -EPROTO;
+   goto msg_done;
+   }
+
+   for (i = 0; i < t->len && reg_offset >= 0; i++, reg_offset--) {
reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset);
-   if (txbuf)
-   writeb(txbuf[i], reg);
-   else
- 

[PATCH v3 2/6] spi: spi-mtk-nor: fix mishandled logics in checking SPI memory operation

2020-09-25 Thread Ikjoon Jang
Fix a bug which limits its protocol availability in supports_op().

Fixes: a59b2c7c56bf ("spi: spi-mtk-nor: support standard spi properties")
Signed-off-by: Ikjoon Jang 
---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 26 +++---
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 6e6ca2b8e6c8..0f7d4ec68730 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -211,28 +211,24 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
if (op->cmd.buswidth != 1)
return false;
 
+   if (!spi_mem_default_supports_op(mem, op))
+   return false;
+
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
-   switch(op->data.dir) {
-   case SPI_MEM_DATA_IN:
-   if (!mtk_nor_match_read(op))
-   return false;
-   break;
-   case SPI_MEM_DATA_OUT:
-   if ((op->addr.buswidth != 1) ||
-   (op->dummy.nbytes != 0) ||
-   (op->data.buswidth != 1))
-   return false;
-   break;
-   default:
-   break;
-   }
+   if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
+   return true;
+   else if (op->data.dir == SPI_MEM_DATA_OUT)
+   return (op->addr.buswidth == 1) &&
+  (op->dummy.nbytes == 0) &&
+  (op->data.buswidth == 1);
}
+
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if ((len > MTK_NOR_PRG_MAX_SIZE) ||
((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
return false;
 
-   return spi_mem_default_supports_op(mem, op);
+   return true;
 }
 
 static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op)
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v3 6/6] spi: spi-mtk-nor: Add power management support

2020-09-25 Thread Ikjoon Jang
This patch adds dev_pm_ops to mtk-nor to support suspend/resume,
auto suspend delay is set to -1 by default.

Accessing registers are only permitted after its clock is enabled
to deal with unknown state of operating clk at probe time,

Signed-off-by: Ikjoon Jang 
---

Changes in v3:
- Fix a bugfix of v2 in checking spi memory operation.
- split read_dma function into two (normal/bounce)
- Support 7bytes generic spi xfer

Changes in v2:
- Add power management support
- Fix bugs in checking spi memory operation.
- use dma_alloc_coherent for allocating bounce buffer
- code cleanups

 drivers/spi/spi-mtk-nor.c | 98 ++-
 1 file changed, 76 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 35205635ed42..bde4c846ce65 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -592,22 +593,15 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
return 0;
 }
 
-static int mtk_nor_init(struct mtk_nor *sp)
+static void mtk_nor_init(struct mtk_nor *sp)
 {
-   int ret;
-
-   ret = mtk_nor_enable_clk(sp);
-   if (ret)
-   return ret;
-
-   sp->spi_freq = clk_get_rate(sp->spi_clk);
+   writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
+   writel(MTK_NOR_IRQ_MASK, sp->base + MTK_NOR_REG_IRQ_STAT);
 
writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
-
-   return ret;
 }
 
 static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
@@ -690,6 +684,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
ctlr->num_chipselect = 1;
ctlr->setup = mtk_nor_setup;
ctlr->transfer_one_message = mtk_nor_transfer_one_message;
+   ctlr->auto_runtime_pm = true;
 
dev_set_drvdata(>dev, ctlr);
 
@@ -712,12 +707,19 @@ static int mtk_nor_probe(struct platform_device *pdev)
return -ENOMEM;
}
 
+   ret = mtk_nor_enable_clk(sp);
+   if (ret < 0)
+   return ret;
+
+   sp->spi_freq = clk_get_rate(sp->spi_clk);
+
+   mtk_nor_init(sp);
+
irq = platform_get_irq_optional(pdev, 0);
+
if (irq < 0) {
dev_warn(sp->dev, "IRQ not available.");
} else {
-   writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
-   writel(0, base + MTK_NOR_REG_IRQ_EN);
ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
   pdev->name, sp);
if (ret < 0) {
@@ -728,34 +730,86 @@ static int mtk_nor_probe(struct platform_device *pdev)
}
}
 
-   ret = mtk_nor_init(sp);
-   if (ret < 0) {
-   kfree(ctlr);
-   return ret;
-   }
+   pm_runtime_set_autosuspend_delay(>dev, -1);
+   pm_runtime_use_autosuspend(>dev);
+   pm_runtime_set_active(>dev);
+   pm_runtime_enable(>dev);
+   pm_runtime_get_noresume(>dev);
+
+   ret = devm_spi_register_controller(>dev, ctlr);
+   if (ret < 0)
+   goto err_probe;
+
+   pm_runtime_mark_last_busy(>dev);
+   pm_runtime_put_autosuspend(>dev);
 
dev_info(>dev, "spi frequency: %d Hz\n", sp->spi_freq);
 
-   return devm_spi_register_controller(>dev, ctlr);
+   return 0;
+
+err_probe:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return ret;
 }
 
 static int mtk_nor_remove(struct platform_device *pdev)
 {
-   struct spi_controller *ctlr;
-   struct mtk_nor *sp;
+   struct spi_controller *ctlr = dev_get_drvdata(>dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
-   ctlr = dev_get_drvdata(>dev);
-   sp = spi_controller_get_devdata(ctlr);
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_nor_runtime_suspend(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
mtk_nor_disable_clk(sp);
 
return 0;
 }
 
+static int __maybe_unused mtk_nor_runtime_resume(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
+
+   return mtk_nor_enable_clk(sp);
+}
+
+static int __maybe_unused mtk_nor_suspend(struct device *d

[PATCH v3 1/6] dt-bindings: spi: add mt8192-nor compatible string

2020-09-25 Thread Ikjoon Jang
Add MT8192 spi-nor controller support.

Signed-off-by: Ikjoon Jang 
Acked-by: Rob Herring 
---

(no changes since v1)

 Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
index 42c9205ac991..55c239446a5b 100644
--- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -30,6 +30,7 @@ properties:
   - mediatek,mt7622-nor
   - mediatek,mt7623-nor
   - mediatek,mt7629-nor
+  - mediatek,mt8192-nor
   - enum:
   - mediatek,mt8173-nor
   - items:
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v3 0/6] spi: spi-mtk-nor: Add mt8192 support

2020-09-25 Thread Ikjoon Jang
This patchset adds 36bit dma address and power management
supports for mt8192-nor.

Changes in v3:
- Fix a bugfix of v2 in checking spi memory operation.
- split read_dma function into two (normal/bounce)
- Support 7bytes generic spi xfer

Changes in v2:
- Add power management support
- Fix bugs in checking spi memory operation.
- use dma_alloc_coherent for allocating bounce buffer
- code cleanups

Ikjoon Jang (6):
  dt-bindings: spi: add mt8192-nor compatible string
  spi: spi-mtk-nor: fix mishandled logics in checking SPI memory
operation
  spi: spi-mtk-nor: support 7 bytes transfer of generic spi
  spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer
  spi: spi-mtk-nor: support 36bit dma addressing
  spi: spi-mtk-nor: Add power management support

 .../bindings/spi/mediatek,spi-mtk-nor.yaml|   1 +
 drivers/spi/spi-mtk-nor.c | 333 --
 2 files changed, 230 insertions(+), 104 deletions(-)

-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v3 5/6] spi: spi-mtk-nor: support 36bit dma addressing

2020-09-25 Thread Ikjoon Jang
This patch enables 36bit dma address support to spi-mtk-nor.
Currently this is enabled only for mt8192-nor.

Signed-off-by: Ikjoon Jang 
---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 8dbafee7f431..35205635ed42 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -78,6 +78,8 @@
 #define MTK_NOR_REG_DMA_FADR   0x71c
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
+#define MTK_NOR_REG_DMA_DADR_HB0x738
+#define MTK_NOR_REG_DMA_END_DADR_HB0x73c
 
 /* maximum bytes of TX in PRG mode */
 #define MTK_NOR_PRG_MAX_SIZE   6
@@ -106,6 +108,7 @@ struct mtk_nor {
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
+   bool high_dma;
struct completion op_done;
 };
 
@@ -305,6 +308,11 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, 
unsigned int length,
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
 
+   if (sp->high_dma) {
+   writel(dma_addr >> 32, sp->base + MTK_NOR_REG_DMA_DADR_HB);
+   writel((dma_addr + length) >> 32, sp->base + 
MTK_NOR_REG_DMA_END_DADR_HB);
+   }
+
if (sp->has_irq) {
reinit_completion(>op_done);
mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
@@ -635,7 +643,8 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops 
= {
 };
 
 static const struct of_device_id mtk_nor_match[] = {
-   { .compatible = "mediatek,mt8173-nor" },
+   { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
+   { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_nor_match);
@@ -647,6 +656,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
void __iomem *base;
struct clk *spi_clk, *ctlr_clk;
int ret, irq;
+   unsigned long dma_bits;
 
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -660,6 +670,12 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (IS_ERR(ctlr_clk))
return PTR_ERR(ctlr_clk);
 
+   dma_bits = (unsigned long)of_device_get_match_data(>dev);
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
+   dev_err(>dev, "failed to set dma mask(%lu)\n", dma_bits);
+   return -EINVAL;
+   }
+
ctlr = spi_alloc_master(>dev, sizeof(*sp));
if (!ctlr) {
dev_err(>dev, "failed to allocate spi controller\n");
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v3 4/6] spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer

2020-09-25 Thread Ikjoon Jang
Use dma_alloc_coherent() for bounce buffer instead of kmalloc() to
make sure the bounce buffer to be allocated within its DMAable range.

Signed-off-by: Ikjoon Jang 

---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 93 +--
 1 file changed, 51 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index e7719d249095..8dbafee7f431 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -100,6 +100,7 @@ struct mtk_nor {
struct device *dev;
void __iomem *base;
u8 *buffer;
+   dma_addr_t buffer_dma;
struct clk *spi_clk;
struct clk *ctlr_clk;
unsigned int spi_freq;
@@ -148,6 +149,11 @@ static void mtk_nor_set_addr(struct mtk_nor *sp, const 
struct spi_mem_op *op)
}
 }
 
+static bool need_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   return ((uintptr_t)op->data.buf.in & MTK_NOR_DMA_ALIGN_MASK);
+}
+
 static bool mtk_nor_match_read(const struct spi_mem_op *op)
 {
int dummy = 0;
@@ -191,6 +197,7 @@ static bool mtk_nor_check_prg(const struct spi_mem_op *op)
 
 static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 {
+   struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
size_t len;
 
if (!op->data.nbytes)
@@ -202,8 +209,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, 
struct spi_mem_op *op)
if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
(op->data.nbytes < MTK_NOR_DMA_ALIGN))
op->data.nbytes = 1;
-   else if (!((ulong)(op->data.buf.in) &
-  MTK_NOR_DMA_ALIGN_MASK))
+   else if (!need_bounce(sp, op))
op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
@@ -288,19 +294,12 @@ static void mtk_nor_setup_bus(struct mtk_nor *sp, const 
struct spi_mem_op *op)
mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
 }
 
-static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
-   u8 *buffer)
+static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, unsigned int length,
+   dma_addr_t dma_addr)
 {
int ret = 0;
ulong delay;
u32 reg;
-   dma_addr_t dma_addr;
-
-   dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
-   if (dma_mapping_error(sp->dev, dma_addr)) {
-   dev_err(sp->dev, "failed to map dma buffer.\n");
-   return -EINVAL;
-   }
 
writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
@@ -325,30 +324,49 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, 
unsigned int length,
 (delay + 1) * 100);
}
 
-   dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
if (ret < 0)
dev_err(sp->dev, "dma read timeout.\n");
 
return ret;
 }
 
-static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
-  unsigned int length, u8 *buffer)
+static int mtk_nor_read_bounce(struct mtk_nor *sp, const struct spi_mem_op *op)
 {
unsigned int rdlen;
int ret;
 
-   if (length & MTK_NOR_DMA_ALIGN_MASK)
-   rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
+   if (op->data.nbytes & MTK_NOR_DMA_ALIGN_MASK)
+   rdlen = (op->data.nbytes + MTK_NOR_DMA_ALIGN) & 
~MTK_NOR_DMA_ALIGN_MASK;
else
-   rdlen = length;
+   rdlen = op->data.nbytes;
 
-   ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
-   if (ret)
-   return ret;
+   ret = mtk_nor_dma_exec(sp, op->addr.val, rdlen, sp->buffer_dma);
 
-   memcpy(buffer, sp->buffer, length);
-   return 0;
+   if (!ret)
+   memcpy(op->data.buf.in, sp->buffer, op->data.nbytes);
+
+   return ret;
+}
+
+static int mtk_nor_read_dma(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+   int ret;
+   dma_addr_t dma_addr;
+
+   if (need_bounce(sp, op))
+   return mtk_nor_read_bounce(sp, op);
+
+   dma_addr = dma_map_single(sp->dev, op->data.buf.in,
+ op->data.nbytes, DMA_FROM_DEVICE);
+
+   if (dma_mapping_error(sp->dev, dma_addr))
+   return -EINVAL;
+
+   ret = mtk_nor_dma_exec(sp, op->addr.val, op->data.nbytes, dma_addr);
+
+   dma_unmap_single(sp->dev, dma_addr, op-&g

Re: [PATCH v2 4/5] spi: spi-mtk-nor: support 36bit dma addressing to mediatek

2020-09-21 Thread Ikjoon Jang
On Sat, Sep 19, 2020 at 11:26 PM Yingjoe Chen  wrote:
>
> On Fri, 2020-09-18 at 16:31 +0800, Ikjoon Jang wrote:
> > This patch enables 36bit dma address support to spi-mtk-nor.
> > Currently 36bit dma addressing is enabled only for mt8192-nor.
[snip]
>
> Do we need to set sp->high_dma when we have >32bits DMA?
>

Yes, to do so, you need to add new compatible strings if there are
more SoCs support >32bit other than mt8192
or just ust mt8192-nor for binding.

> Joe.C


Re: [PATCH v2 3/5] spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer

2020-09-21 Thread Ikjoon Jang
On Fri, Sep 18, 2020 at 9:25 PM Chuanhong Guo  wrote:
>
> Hi!
>
> On Fri, Sep 18, 2020 at 4:35 PM Ikjoon Jang  wrote:
> >
> > Use dma_alloc_coherent() for bounce buffer instead of kmalloc.
>
> The commit message should explain why such a change is
> needed. (i.e. why using dma_alloc_coherent here is better
> than kmalloc.) And if there's no benefit for this change I'd prefer
> leaving it untouched.
> I remembered reading somewhere that stream DMA api is
> prefered over dma_alloc_coherent for this kind of single-direction
> DMA operation.
>

I will add more description on why I changed it to dma_alloc_coherent():
- to explictly support devices like mt8173-nor which only supports
32bit addressing for dma.

And it also reminded me an another problem, (I won't address this
issue for now in v3):
as this device is using dma range as [start, end) format
where 'end' can be zero in that corner case of {start = 0xffff_f000; end = 0; }

> >
> > Signed-off-by: Ikjoon Jang 
> >
> > ---
> >
> > (no changes since v1)
> >
> >  drivers/spi/spi-mtk-nor.c | 60 +++
> >  1 file changed, 35 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> > index 54b2c0fde95b..e14798a6e7d0 100644
> > --- a/drivers/spi/spi-mtk-nor.c
> > +++ b/drivers/spi/spi-mtk-nor.c
> > @@ -96,6 +96,7 @@ struct mtk_nor {
> > struct device *dev;
> > void __iomem *base;
> > u8 *buffer;
> > +   dma_addr_t buffer_dma;
> > struct clk *spi_clk;
> > struct clk *ctlr_clk;
> > unsigned int spi_freq;
> > @@ -275,19 +276,16 @@ static void mtk_nor_setup_bus(struct mtk_nor *sp, 
> > const struct spi_mem_op *op)
> > mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
> >  }
> >
> > -static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int 
> > length,
> > -   u8 *buffer)
> > +static int read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
>
> This name is a bit confusing considering there's a mtk_nor_read_dma
> below.
> As this function now only executes dma readings and wait it to finish,
> what about mtk_nor_dma_exec instead?

yeah, good idea.

>
> > +   dma_addr_t dma_addr)
> >  {
> > int ret = 0;
> > ulong delay;
> > u32 reg;
> > -   dma_addr_t dma_addr;
> >
> > -   dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
> > -   if (dma_mapping_error(sp->dev, dma_addr)) {
> > -   dev_err(sp->dev, "failed to map dma buffer.\n");
> > +   if (WARN_ON((length & MTK_NOR_DMA_ALIGN_MASK) ||
> > +   (dma_addr & MTK_NOR_DMA_ALIGN_MASK)))
>
> These alignment is guaranteed by callers of this function if all
> my comments below are addressed. This check isn't needed.

ACK.

>
> > return -EINVAL;
> > -   }
> >
> > writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
> > writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
> > @@ -312,30 +310,39 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 
> > from, unsigned int length,
> >  (delay + 1) * 100);
> > }
> >
> > -   dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
> > if (ret < 0)
> > dev_err(sp->dev, "dma read timeout.\n");
> >
> > return ret;
> >  }
> >
> > -static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
> > -  unsigned int length, u8 *buffer)
> > +static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from,
> > +   unsigned int length, u8 *buffer)
> >  {
> > -   unsigned int rdlen;
> > int ret;
> > +   dma_addr_t dma_addr;
> > +   bool bounce = need_bounce(buffer, length);
> >
> > -   if (length & MTK_NOR_DMA_ALIGN_MASK)
> > -   rdlen = (length + MTK_NOR_DMA_ALIGN) & 
> > ~MTK_NOR_DMA_ALIGN_MASK;
>
> The intention of this rdlen alignment is explained in 2/5.
> Please make sure this rdlen alignment logic is present
> only for PIO reading.

okay, I'll use padding again in v3.

>
> > -   else
> > -   rdlen = length;
> > +   if (!bounce) {
> > +   dma_addr = dma_map_single(sp->dev, buffer, length,
> > + DMA_FROM_DE

Re: [PATCH v2 2/5] spi: spi-mtk-nor: fix mishandled logics in checking SPI memory operation

2020-09-21 Thread Ikjoon Jang
On Fri, Sep 18, 2020 at 9:09 PM Chuanhong Guo  wrote:
>
> Hi!
>
> On Fri, Sep 18, 2020 at 4:34 PM Ikjoon Jang  wrote:
> >
> > Fix a simple bug which can limits its transfer size,
> > and add a simple helper function for code cleanups.
> >
> > Fixes: a59b2c7c56bf ("spi: spi-mtk-nor: support standard spi properties")
> > Signed-off-by: Ikjoon Jang 
> >
> > ---
> >
> > (no changes since v1)
> >
> >  drivers/spi/spi-mtk-nor.c | 62 ---
> >  1 file changed, 38 insertions(+), 24 deletions(-)
> >
> > diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
> > index 6e6ca2b8e6c8..54b2c0fde95b 100644
> > --- a/drivers/spi/spi-mtk-nor.c
> > +++ b/drivers/spi/spi-mtk-nor.c
> > @@ -167,52 +167,63 @@ static bool mtk_nor_match_read(const struct 
> > spi_mem_op *op)
> > return false;
> >  }
> >
> > -static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op 
> > *op)
> > +static bool need_bounce(void *cpu_addr, unsigned long len)
> >  {
> > -   size_t len;
> > +   return !!(((uintptr_t)cpu_addr) & MTK_NOR_DMA_ALIGN_MASK);
> > +}
>
> parameter 'len' isn't used in this function.

ACK.

>
> >
> > +static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op 
> > *op)
> > +{
> > if (!op->data.nbytes)
> > return 0;
> >
> > if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
> > -   if ((op->data.dir == SPI_MEM_DATA_IN) &&
> > -   mtk_nor_match_read(op)) {
>
> I think replacing a if/else if with a two-case switch is more
> of a personal code preference rather than code cleanup.
> I'd prefer only adding need_bounce to replace alignment
> check using a separated commit and leave other stuff
> untouched because:
> 1. This "cleanup" made unintended logic changes (see below)
> 2. The "cleanup" itself actually becomes the major part of
> this patch, while the actual fix mentioned in commit
> message is the minor part.
> 3. A fix commit should contain the fix itself. It shouldn't
> mix with these code changes.

Got it, v3 will only include the fix itself.

>
> > +   switch (op->data.dir) {
> > +   case SPI_MEM_DATA_IN:
> > +   if (!mtk_nor_match_read(op))
> > +   return -EINVAL;
>
> You are changing the code logic here.
> mtk_nor_match_read checks if the operation can be executed
> using controller PIO/DMA reading. Even if it's not supported,
> we can still use PRG mode to execute the operation.
> One example of such an operation is SPI NOR SFDP reading.
> Your change breaks that which then breaks 1_2_2 and 1_4_4
> reading capability because spi-nor driver parses these op formats
> from SFDP table.

As you already noticed it, this is a bug from the last patch I made
and v2 isn't fixing this problem. This should be restored & fixed in v3.
And will not include other changes in a same patch.

>
> > +   /* check if it's DMAable */
> > if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
> > -   (op->data.nbytes < MTK_NOR_DMA_ALIGN))
> > +   (op->data.nbytes < MTK_NOR_DMA_ALIGN)) {
> > op->data.nbytes = 1;
> > -   else if (!((ulong)(op->data.buf.in) &
> > -  MTK_NOR_DMA_ALIGN_MASK))
> > +   } else {
> > +   if (need_bounce(op->data.buf.in, 
> > op->data.nbytes) &&
> > +   (op->data.nbytes > 
> > MTK_NOR_BOUNCE_BUF_SIZE))
> > +   op->data.nbytes = 
> > MTK_NOR_BOUNCE_BUF_SIZE;
> > op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
> > -   else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
> > -   op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
>
> data length alignment is intentionally done only for DMA reading
> without the bounce buffer.
> My intention here:
> If we use the bounce buffer, we can read more data than needed to.
> Say we want 25 bytes of data, reading 32 bytes using DMA and
> bounce buffer should be faster than reading 16 bytes with DMA
> and another 9 bytes with PIO, because for every single byte of PIO
> reading, adjust_op_size and exec_

[PATCH v2 1/5] dt-bindings: spi: add mt8192-nor compatible string

2020-09-18 Thread Ikjoon Jang
Add compatible string for mt8192 SoC.

Signed-off-by: Ikjoon Jang 
---

(no changes since v1)

 Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
index 42c9205ac991..55c239446a5b 100644
--- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -30,6 +30,7 @@ properties:
   - mediatek,mt7622-nor
   - mediatek,mt7623-nor
   - mediatek,mt7629-nor
+  - mediatek,mt8192-nor
   - enum:
   - mediatek,mt8173-nor
   - items:
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v2 3/5] spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer

2020-09-18 Thread Ikjoon Jang
Use dma_alloc_coherent() for bounce buffer instead of kmalloc.

Signed-off-by: Ikjoon Jang 

---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 60 +++
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 54b2c0fde95b..e14798a6e7d0 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -96,6 +96,7 @@ struct mtk_nor {
struct device *dev;
void __iomem *base;
u8 *buffer;
+   dma_addr_t buffer_dma;
struct clk *spi_clk;
struct clk *ctlr_clk;
unsigned int spi_freq;
@@ -275,19 +276,16 @@ static void mtk_nor_setup_bus(struct mtk_nor *sp, const 
struct spi_mem_op *op)
mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
 }
 
-static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
-   u8 *buffer)
+static int read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
+   dma_addr_t dma_addr)
 {
int ret = 0;
ulong delay;
u32 reg;
-   dma_addr_t dma_addr;
 
-   dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
-   if (dma_mapping_error(sp->dev, dma_addr)) {
-   dev_err(sp->dev, "failed to map dma buffer.\n");
+   if (WARN_ON((length & MTK_NOR_DMA_ALIGN_MASK) ||
+   (dma_addr & MTK_NOR_DMA_ALIGN_MASK)))
return -EINVAL;
-   }
 
writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
@@ -312,30 +310,39 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, 
unsigned int length,
 (delay + 1) * 100);
}
 
-   dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
if (ret < 0)
dev_err(sp->dev, "dma read timeout.\n");
 
return ret;
 }
 
-static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
-  unsigned int length, u8 *buffer)
+static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from,
+   unsigned int length, u8 *buffer)
 {
-   unsigned int rdlen;
int ret;
+   dma_addr_t dma_addr;
+   bool bounce = need_bounce(buffer, length);
 
-   if (length & MTK_NOR_DMA_ALIGN_MASK)
-   rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
-   else
-   rdlen = length;
+   if (!bounce) {
+   dma_addr = dma_map_single(sp->dev, buffer, length,
+ DMA_FROM_DEVICE);
+   if (dma_mapping_error(sp->dev, dma_addr)) {
+   dev_err(sp->dev, "failed to map dma buffer.\n");
+   return -EINVAL;
+   }
+   } else {
+   dma_addr = sp->buffer_dma;
+   }
 
-   ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
-   if (ret)
-   return ret;
+   ret = read_dma(sp, from, length, dma_addr);
 
-   memcpy(buffer, sp->buffer, length);
-   return 0;
+   if (!bounce)
+   dma_unmap_single(sp->dev, dma_addr, length,
+DMA_FROM_DEVICE);
+   else
+   memcpy(buffer, sp->buffer, length);
+
+   return ret;
 }
 
 static int mtk_nor_read_pio(struct mtk_nor *sp, const struct spi_mem_op *op)
@@ -439,11 +446,6 @@ static int mtk_nor_exec_op(struct spi_mem *mem, const 
struct spi_mem_op *op)
if (op->data.nbytes == 1) {
mtk_nor_set_addr(sp, op);
return mtk_nor_read_pio(sp, op);
-   } else if (((ulong)(op->data.buf.in) &
-   MTK_NOR_DMA_ALIGN_MASK)) {
-   return mtk_nor_read_bounce(sp, op->addr.val,
-  op->data.nbytes,
-  op->data.buf.in);
} else {
return mtk_nor_read_dma(sp, op->addr.val,
op->data.nbytes,
@@ -654,6 +656,10 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->dev = >dev;
sp->spi_clk = spi_clk;
sp->ctlr_clk = ctlr_clk;
+   sp->buffer = dma_alloc_coherent(>dev, MTK_NOR_BOUNCE_BUF_SIZE,
+   >buffer_dma, GFP_KERNEL);
+   if (!sp->buffer)
+   return -ENOMEM;
 
irq = platform_get_irq_optional(pdev, 0);
if (irq < 0) {
@@ -674,6 +680,8 @@ static int mtk_nor_probe(struct platform_device *pdev)
ret = mtk_nor_init(sp);
if (ret < 0) {
kfree(ctlr);
+   dma_free_coherent(>dev, MTK_NOR_BOUNCE_BUF_SIZE,
+  

[PATCH v2 5/5] spi: spi-mtk-nor: Add power management support

2020-09-18 Thread Ikjoon Jang
This patch adds dev_pm_ops to mtk-nor to support suspend/resume,
auto suspend delay is set to -1 by default.

Accessing registers are delayed after enabling clocks
to deal with unknown state of clocks at probe time,

Signed-off-by: Ikjoon Jang 
---

 drivers/spi/spi-mtk-nor.c | 105 +-
 1 file changed, 80 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 99dd5dca744e..5dcd575998d9 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -551,22 +552,15 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
return 0;
 }
 
-static int mtk_nor_init(struct mtk_nor *sp)
+static void mtk_nor_init(struct mtk_nor *sp)
 {
-   int ret;
-
-   ret = mtk_nor_enable_clk(sp);
-   if (ret)
-   return ret;
-
-   sp->spi_freq = clk_get_rate(sp->spi_clk);
+   writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
+   writel(MTK_NOR_IRQ_MASK, sp->base + MTK_NOR_REG_IRQ_STAT);
 
writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
-
-   return ret;
 }
 
 static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
@@ -630,6 +624,11 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (IS_ERR(ctlr_clk))
return PTR_ERR(ctlr_clk);
 
+   irq = platform_get_irq_optional(pdev, 0);
+
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(36)))
+   dev_warn(>dev, "failed to set dma mask(36)\n");
+
buffer = devm_kmalloc(>dev,
  MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
  GFP_KERNEL);
@@ -661,6 +660,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
ctlr->num_chipselect = 1;
ctlr->setup = mtk_nor_setup;
ctlr->transfer_one_message = mtk_nor_transfer_one_message;
+   ctlr->auto_runtime_pm = true;
 
dev_set_drvdata(>dev, ctlr);
 
@@ -678,12 +678,17 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (!sp->buffer)
return -ENOMEM;
 
-   irq = platform_get_irq_optional(pdev, 0);
+   ret = mtk_nor_enable_clk(sp);
+   if (ret < 0)
+   return ret;
+
+   sp->spi_freq = clk_get_rate(sp->spi_clk);
+
+   mtk_nor_init(sp);
+
if (irq < 0) {
dev_warn(sp->dev, "IRQ not available.");
} else {
-   writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
-   writel(0, base + MTK_NOR_REG_IRQ_EN);
ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
   pdev->name, sp);
if (ret < 0) {
@@ -694,26 +699,41 @@ static int mtk_nor_probe(struct platform_device *pdev)
}
}
 
-   ret = mtk_nor_init(sp);
-   if (ret < 0) {
-   kfree(ctlr);
-   dma_free_coherent(>dev, MTK_NOR_BOUNCE_BUF_SIZE,
- sp->buffer, sp->buffer_dma);
-   return ret;
-   }
+   pm_runtime_set_autosuspend_delay(>dev, -1);
+   pm_runtime_use_autosuspend(>dev);
+   pm_runtime_set_active(>dev);
+   pm_runtime_enable(>dev);
+   pm_runtime_get_noresume(>dev);
+
+   ret = devm_spi_register_controller(>dev, ctlr);
+   if (ret < 0)
+   goto err_probe;
+
+   pm_runtime_mark_last_busy(>dev);
+   pm_runtime_put_autosuspend(>dev);
 
dev_info(>dev, "spi frequency: %d Hz\n", sp->spi_freq);
 
-   return devm_spi_register_controller(>dev, ctlr);
+   return 0;
+
+err_probe:
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
+
+   mtk_nor_disable_clk(sp);
+
+   return ret;
 }
 
 static int mtk_nor_remove(struct platform_device *pdev)
 {
-   struct spi_controller *ctlr;
-   struct mtk_nor *sp;
+   struct spi_controller *ctlr = dev_get_drvdata(>dev);
+   struct mtk_nor *sp = spi_controller_get_devdata(ctlr);
 
-   ctlr = dev_get_drvdata(>dev);
-   sp = spi_controller_get_devdata(ctlr);
+   pm_runtime_disable(>dev);
+   pm_runtime_set_suspended(>dev);
+   pm_runtime_dont_use_autosuspend(>dev);
 
mtk_nor_disable_clk(sp);
 
@@ -722,10 +742,45 @@ static int mtk_nor_remove(struct platform_device *pdev)
return 0;
 }
 
+static int __maybe_unused mtk_nor_runtime_suspend(struct device *dev)
+{
+   struct spi_controller *ctlr = dev_get_drvdata(dev);
+   struct mtk_nor *sp = spi_controlle

[PATCH v2 0/5] spi: spi-mtk-nor: Add mt8192 support.

2020-09-18 Thread Ikjoon Jang
This patchset adds 36bit dma address and power management
supports for mt8192-nor.

Changes in v2:
- Add power management support
- Fix bugs in checking spi memory operation.
- use dma_alloc_coherent for allocating bounce buffer
- code cleanups

Ikjoon Jang (5):
  dt-bindings: spi: add mt8192-nor compatible string
  spi: spi-mtk-nor: fix mishandled logics in checking SPI memory
operation
  spi: spi-mtk-nor: use dma_alloc_coherent() for bounce buffer
  spi: spi-mtk-nor: support 36bit dma addressing to mediatek
  spi: spi-mtk-nor: Add power management support

 .../bindings/spi/mediatek,spi-mtk-nor.yaml|   1 +
 drivers/spi/spi-mtk-nor.c | 242 --
 2 files changed, 170 insertions(+), 73 deletions(-)

-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v2 4/5] spi: spi-mtk-nor: support 36bit dma addressing to mediatek

2020-09-18 Thread Ikjoon Jang
This patch enables 36bit dma address support to spi-mtk-nor.
Currently 36bit dma addressing is enabled only for mt8192-nor.

Signed-off-by: Ikjoon Jang 
---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index e14798a6e7d0..99dd5dca744e 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -78,6 +78,8 @@
 #define MTK_NOR_REG_DMA_FADR   0x71c
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
+#define MTK_NOR_REG_DMA_DADR_HB0x738
+#define MTK_NOR_REG_DMA_END_DADR_HB0x73c
 
 #define MTK_NOR_PRG_MAX_SIZE   6
 // Reading DMA src/dst addresses have to be 16-byte aligned
@@ -102,6 +104,7 @@ struct mtk_nor {
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
+   bool high_dma;
struct completion op_done;
 };
 
@@ -291,6 +294,11 @@ static int read_dma(struct mtk_nor *sp, u32 from, unsigned 
int length,
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
 
+   if (sp->high_dma) {
+   writel(dma_addr >> 32, sp->base + MTK_NOR_REG_DMA_DADR_HB);
+   writel((dma_addr + length) >> 32, sp->base + 
MTK_NOR_REG_DMA_END_DADR_HB);
+   }
+
if (sp->has_irq) {
reinit_completion(>op_done);
mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
@@ -594,7 +602,8 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops 
= {
 };
 
 static const struct of_device_id mtk_nor_match[] = {
-   { .compatible = "mediatek,mt8173-nor" },
+   { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
+   { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_nor_match);
@@ -607,6 +616,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
u8 *buffer;
struct clk *spi_clk, *ctlr_clk;
int ret, irq;
+   unsigned long dma_bits;
 
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -623,6 +633,13 @@ static int mtk_nor_probe(struct platform_device *pdev)
buffer = devm_kmalloc(>dev,
  MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
  GFP_KERNEL);
+
+   dma_bits = (unsigned long)of_device_get_match_data(>dev);
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
+   dev_err(>dev, "failed to set dma mask(%lu)\n", dma_bits);
+   return -EINVAL;
+   }
+
if (!buffer)
return -ENOMEM;
 
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v2 2/5] spi: spi-mtk-nor: fix mishandled logics in checking SPI memory operation

2020-09-18 Thread Ikjoon Jang
Fix a simple bug which can limits its transfer size,
and add a simple helper function for code cleanups.

Fixes: a59b2c7c56bf ("spi: spi-mtk-nor: support standard spi properties")
Signed-off-by: Ikjoon Jang 

---

(no changes since v1)

 drivers/spi/spi-mtk-nor.c | 62 ---
 1 file changed, 38 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 6e6ca2b8e6c8..54b2c0fde95b 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -167,52 +167,63 @@ static bool mtk_nor_match_read(const struct spi_mem_op 
*op)
return false;
 }
 
-static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+static bool need_bounce(void *cpu_addr, unsigned long len)
 {
-   size_t len;
+   return !!(((uintptr_t)cpu_addr) & MTK_NOR_DMA_ALIGN_MASK);
+}
 
+static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
if (!op->data.nbytes)
return 0;
 
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
-   if ((op->data.dir == SPI_MEM_DATA_IN) &&
-   mtk_nor_match_read(op)) {
+   switch (op->data.dir) {
+   case SPI_MEM_DATA_IN:
+   if (!mtk_nor_match_read(op))
+   return -EINVAL;
+   /* check if it's DMAable */
if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
-   (op->data.nbytes < MTK_NOR_DMA_ALIGN))
+   (op->data.nbytes < MTK_NOR_DMA_ALIGN)) {
op->data.nbytes = 1;
-   else if (!((ulong)(op->data.buf.in) &
-  MTK_NOR_DMA_ALIGN_MASK))
+   } else {
+   if (need_bounce(op->data.buf.in, 
op->data.nbytes) &&
+   (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE))
+   op->data.nbytes = 
MTK_NOR_BOUNCE_BUF_SIZE;
op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
-   else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
-   op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
-   return 0;
-   } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+   }
+   break;
+   case SPI_MEM_DATA_OUT:
if (op->data.nbytes >= MTK_NOR_PP_SIZE)
op->data.nbytes = MTK_NOR_PP_SIZE;
else
op->data.nbytes = 1;
-   return 0;
+   break;
+   default:
+   break;
}
+   } else {
+   u8 len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+   if (len > MTK_NOR_PRG_MAX_SIZE)
+   return -EINVAL;
+   if (op->data.nbytes && !(MTK_NOR_PRG_MAX_SIZE - len))
+   return -EINVAL;
+   if (op->data.nbytes > (MTK_NOR_PRG_MAX_SIZE - len))
+   op->data.nbytes = MTK_NOR_PRG_MAX_SIZE - len;
}
 
-   len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -
- op->dummy.nbytes;
-   if (op->data.nbytes > len)
-   op->data.nbytes = len;
-
return 0;
 }
 
 static bool mtk_nor_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
 {
-   size_t len;
-
if (op->cmd.buswidth != 1)
return false;
 
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
-   switch(op->data.dir) {
+   switch (op->data.dir) {
case SPI_MEM_DATA_IN:
if (!mtk_nor_match_read(op))
return false;
@@ -226,11 +237,14 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
default:
break;
}
+   } else {
+   u8 len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+
+   if (len > MTK_NOR_PRG_MAX_SIZE)
+   return false;
+   if (op->data.nbytes && !(MTK_NOR_PRG_MAX_SIZE - len))
+   return false;
}
-   len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
-   if ((len > MTK_NOR_PRG_MAX_SIZE) ||
-   ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
-   return false;
 
return spi_mem_default_supports_op(mem, op);
 }
-- 
2.28.0.681.g6f77f65b4e-goog



[PATCH v4] mtd: spi-nor: winbond: Add support for w25q64jwm

2020-09-14 Thread Ikjoon Jang
Add support Winbond w25q{64,128,256}jwm which are identical to existing
w25q32jwm except for their sizes.

This was tested with w25q64jwm, basic erase/write/readback and
lock/unlock top and bottom blocks were okay.

Signed-off-by: Ikjoon Jang 
Signed-off-by: Xingyu Wu 
Signed-off-by: ST Lin 
---

Changes in v4:
- drops package type code from name

Changes in v3:
- fix commit message formats

Changes in v2:
- remove duplicated flash ID (w25q32jwm)

 drivers/mtd/spi-nor/winbond.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c
index 6dcde15fb1aa..e5dfa786f190 100644
--- a/drivers/mtd/spi-nor/winbond.c
+++ b/drivers/mtd/spi-nor/winbond.c
@@ -63,6 +63,15 @@ static const struct flash_info winbond_parts[] = {
{ "w25q32jwm", INFO(0xef8016, 0, 64 * 1024,  64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q64jwm", INFO(0xef8017, 0, 64 * 1024, 128,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q128jwm", INFO(0xef8018, 0, 64 * 1024, 256,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
+   { "w25q256jwm", INFO(0xef8019, 0, 64 * 1024, 512,
+   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128,
 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-- 
2.28.0.618.gf4bc123cb7-goog



[PATCH 2/2] spi: spi-mtk-nor: support 36bit dma addressing to mediatek spi-nor

2020-09-09 Thread Ikjoon Jang
This patch enables direct mappings over 32bit range to spi-mtk-nor.

Signed-off-by: Ikjoon Jang 

---

 drivers/spi/spi-mtk-nor.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 6e6ca2b8e6c8..eb93ae34e670 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -78,6 +78,8 @@
 #define MTK_NOR_REG_DMA_FADR   0x71c
 #define MTK_NOR_REG_DMA_DADR   0x720
 #define MTK_NOR_REG_DMA_END_DADR   0x724
+#define MTK_NOR_REG_DMA_DADR_HB0x738
+#define MTK_NOR_REG_DMA_END_DADR_HB0x73c
 
 #define MTK_NOR_PRG_MAX_SIZE   6
 // Reading DMA src/dst addresses have to be 16-byte aligned
@@ -101,6 +103,7 @@ struct mtk_nor {
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
+   bool high_dma;
struct completion op_done;
 };
 
@@ -279,6 +282,11 @@ static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, 
unsigned int length,
writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
 
+   if (sp->high_dma) {
+   writel(dma_addr >> 32, sp->base + MTK_NOR_REG_DMA_DADR_HB);
+   writel((dma_addr + length) >> 32, sp->base + 
MTK_NOR_REG_DMA_END_DADR_HB);
+   }
+
if (sp->has_irq) {
reinit_completion(>op_done);
mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
@@ -578,7 +586,8 @@ static const struct spi_controller_mem_ops mtk_nor_mem_ops 
= {
 };
 
 static const struct of_device_id mtk_nor_match[] = {
-   { .compatible = "mediatek,mt8173-nor" },
+   { .compatible = "mediatek,mt8192-nor", .data = (void *)36 },
+   { .compatible = "mediatek,mt8173-nor", .data = (void *)32 },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_nor_match);
@@ -591,6 +600,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
u8 *buffer;
struct clk *spi_clk, *ctlr_clk;
int ret, irq;
+   unsigned long dma_bits;
 
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -614,6 +624,12 @@ static int mtk_nor_probe(struct platform_device *pdev)
buffer = (u8 *)(((ulong)buffer + MTK_NOR_DMA_ALIGN) &
~MTK_NOR_DMA_ALIGN_MASK);
 
+   dma_bits = (unsigned long)of_device_get_match_data(>dev);
+   if (dma_set_mask_and_coherent(>dev, DMA_BIT_MASK(dma_bits))) {
+   dev_err(>dev, "failed to set dma mask(%lu)\n", dma_bits);
+   return -EINVAL;
+   }
+
ctlr = spi_alloc_master(>dev, sizeof(*sp));
if (!ctlr) {
dev_err(>dev, "failed to allocate spi controller\n");
@@ -640,6 +656,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->dev = >dev;
sp->spi_clk = spi_clk;
sp->ctlr_clk = ctlr_clk;
+   sp->high_dma = (dma_bits > 32);
 
irq = platform_get_irq_optional(pdev, 0);
if (irq < 0) {
-- 
2.28.0.526.ge36021eeef-goog



[PATCH 1/2] dt-bindings: spi: add mt8192-nor compatible string

2020-09-09 Thread Ikjoon Jang
Add MT8192 spi-nor controller binding.

Signed-off-by: Ikjoon Jang 
---

 Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
index 42c9205ac991..55c239446a5b 100644
--- a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -30,6 +30,7 @@ properties:
   - mediatek,mt7622-nor
   - mediatek,mt7623-nor
   - mediatek,mt7629-nor
+  - mediatek,mt8192-nor
   - enum:
   - mediatek,mt8173-nor
   - items:
-- 
2.28.0.526.ge36021eeef-goog



[PATCH 0/2] Add 36bit dma support to mediatek spi-nor controller.

2020-09-09 Thread Ikjoon Jang
mt8192-nor has 36bit addressing support, this patch adds 36bit address
handlings to spi-mtk-nor.

Ikjoon Jang (2):
  dt-bindings: spi: add mt8192-nor compatible string
  spi: spi-mtk-nor: support 36bit dma addressing to mediatek spi-nor

 .../bindings/spi/mediatek,spi-mtk-nor.yaml|  1 +
 drivers/spi/spi-mtk-nor.c | 19 ++-
 2 files changed, 19 insertions(+), 1 deletion(-)

-- 
2.28.0.526.ge36021eeef-goog



[PATCH] power: supply: sbs-battery: keep error code when get_property() fails

2020-09-02 Thread Ikjoon Jang
Commit c4f382930145 (power: supply: sbs-battery: don't assume
i2c errors as battery disconnect) overwrites the original error code
returned from internal functions. On such a sporadic i2c error,
a user will get a wrong value without errors.

Fixes: c4f382930145 (power: supply: sbs-battery: don't assume i2c errors as 
battery disconnect)

Signed-off-by: Ikjoon Jang 
---
Sorry, I missed an case with present state unchanged.
Sebastian, if you're okay with this patch,
I think this could be squashed into original commit c4f382930145 in your
branch.
---
 drivers/power/supply/sbs-battery.c | 24 +---
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index dacc4bc1c013..13192cbcce71 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -962,11 +962,10 @@ static int sbs_get_property(struct power_supply *psy,
if (!chip->gpio_detect && chip->is_present != (ret >= 0)) {
bool old_present = chip->is_present;
union power_supply_propval val;
-
-   ret = sbs_get_battery_presence_and_health(
+   int err = sbs_get_battery_presence_and_health(
client, POWER_SUPPLY_PROP_PRESENT, );
 
-   sbs_update_presence(chip, !ret && val.intval);
+   sbs_update_presence(chip, !err && val.intval);
 
if (old_present != chip->is_present)
power_supply_changed(chip->power_supply);
@@ -976,19 +975,14 @@ static int sbs_get_property(struct power_supply *psy,
if (!ret) {
/* Convert units to match requirements for power supply class */
sbs_unit_adjustment(client, psp, val);
+   dev_dbg(>dev,
+   "%s: property = %d, value = %x\n", __func__,
+   psp, val->intval);
+   } else if (!chip->is_present)  {
+   /* battery not present, so return NODATA for properties */
+   ret = -ENODATA;
}
-
-   dev_dbg(>dev,
-   "%s: property = %d, value = %x\n", __func__, psp, val->intval);
-
-   if (ret && chip->is_present)
-   return ret;
-
-   /* battery not present, so return NODATA for properties */
-   if (ret)
-   return -ENODATA;
-
-   return 0;
+   return ret;
 }
 
 static void sbs_supply_changed(struct sbs_info *chip)
-- 
2.28.0.402.g5ffc5be6b7-goog



[PATCH v4] power: supply: sbs-battery: don't assume i2c errors as battery disconnect

2020-08-27 Thread Ikjoon Jang
Current sbs-battery considers all smbus errors as disconnection events
when battery-detect pin isn't supplied, and restored to present state back
when any successful transaction is made.

This can lead to unwanted state changes between present and !present
when there's one i2c error and other following commands were successful.

This patch provides a unified way of checking presence by calling
sbs_get_battery_presence_and_health() when detect pin is not used.

Signed-off-by: Ikjoon Jang 
---
v4: rebase from merge conflict, amend commit messages
v3: check return value of get_presence_and_health()
v2: combine get_presence_and_health functions to reuse
---

 drivers/power/supply/sbs-battery.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index 6273211cd673..dacc4bc1c013 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -959,10 +959,17 @@ static int sbs_get_property(struct power_supply *psy,
return -EINVAL;
}
 
-   if (!chip->gpio_detect &&
-   chip->is_present != (ret >= 0)) {
-   sbs_update_presence(chip, (ret >= 0));
-   power_supply_changed(chip->power_supply);
+   if (!chip->gpio_detect && chip->is_present != (ret >= 0)) {
+   bool old_present = chip->is_present;
+   union power_supply_propval val;
+
+   ret = sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+
+   sbs_update_presence(chip, !ret && val.intval);
+
+   if (old_present != chip->is_present)
+   power_supply_changed(chip->power_supply);
}
 
 done:
@@ -1147,11 +1154,13 @@ static int sbs_probe(struct i2c_client *client)
 * to the battery.
 */
if (!(force_load || chip->gpio_detect)) {
-   rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
+   union power_supply_propval val;
 
-   if (rc < 0) {
-   dev_err(>dev, "%s: Failed to get device 
status\n",
-   __func__);
+   rc = sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+   if (rc < 0 || !val.intval) {
+   dev_err(>dev, "Failed to get present status\n");
+   rc = -ENODEV;
goto exit_psupply;
}
}
-- 
2.28.0.402.g5ffc5be6b7-goog



[PATCH] spi: spi-mtk-nor: support standard spi properties

2020-08-26 Thread Ikjoon Jang
Use default supports_op() to support spi-[rt]x-bus-width properties.
And check dummy op's byte length instead of its bus width for output.

Signed-off-by: Ikjoon Jang 
---
 drivers/spi/spi-mtk-nor.c | 29 -
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index b08d8e9a8ee9..6e6ca2b8e6c8 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -211,25 +211,28 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
if (op->cmd.buswidth != 1)
return false;
 
-   /* DTR ops not supported. */
-   if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
-   return false;
-   if (op->cmd.nbytes != 1)
-   return false;
-
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
-   if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
-   return true;
-   else if (op->data.dir == SPI_MEM_DATA_OUT)
-   return (op->addr.buswidth == 1) &&
-  (op->dummy.buswidth == 0) &&
-  (op->data.buswidth == 1);
+   switch(op->data.dir) {
+   case SPI_MEM_DATA_IN:
+   if (!mtk_nor_match_read(op))
+   return false;
+   break;
+   case SPI_MEM_DATA_OUT:
+   if ((op->addr.buswidth != 1) ||
+   (op->dummy.nbytes != 0) ||
+   (op->data.buswidth != 1))
+   return false;
+   break;
+   default:
+   break;
+   }
}
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if ((len > MTK_NOR_PRG_MAX_SIZE) ||
((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
return false;
-   return true;
+
+   return spi_mem_default_supports_op(mem, op);
 }
 
 static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op)
-- 
2.28.0.297.g1956fa8f8d-goog



[PATCH v2] dt-bindings: spi: Convert spi-mtk-nor to json-schema

2020-08-26 Thread Ikjoon Jang
Convert Mediatek ARM SOC's serial NOR flash controller binding
to json-schema format.

Signed-off-by: Ikjoon Jang 
---
v2: remove unnecessary quotes, set interrupts as required,
add unevaluatedProperties:false
---
 .../bindings/spi/mediatek,spi-mtk-nor.yaml| 85 +++
 .../devicetree/bindings/spi/spi-mtk-nor.txt   | 47 --
 2 files changed, 85 insertions(+), 47 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
 delete mode 100644 Documentation/devicetree/bindings/spi/spi-mtk-nor.txt

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
new file mode 100644
index ..42c9205ac991
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/mediatek,spi-mtk-nor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Serial NOR flash controller for MediaTek ARM SoCs
+
+maintainers:
+  - Bayi Cheng 
+  - Chuanhong Guo 
+
+description: |
+  This spi controller support single, dual, or quad mode transfer for
+  SPI NOR flash. There should be only one spi slave device following
+  generic spi bindings. It's not recommended to use this controller
+  for devices other than SPI NOR flash due to limited transfer
+  capability of this controller.
+
+allOf:
+  - $ref: /spi/spi-controller.yaml#
+
+properties:
+  compatible:
+oneOf:
+  - items:
+  - enum:
+  - mediatek,mt2701-nor
+  - mediatek,mt2712-nor
+  - mediatek,mt7622-nor
+  - mediatek,mt7623-nor
+  - mediatek,mt7629-nor
+  - enum:
+  - mediatek,mt8173-nor
+  - items:
+  - const: mediatek,mt8173-nor
+  reg:
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  clocks:
+items:
+  - description: clock used for spi bus
+  - description: clock used for controller
+
+  clock-names:
+items:
+  - const: spi
+  - const: sf
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+#include 
+
+soc {
+  #address-cells = <2>;
+  #size-cells = <2>;
+
+  nor_flash: spi@1100d000 {
+compatible = "mediatek,mt8173-nor";
+reg = <0 0x1100d000 0 0xe0>;
+interrupts = <_flash_irq>;
+clocks = < CLK_PERI_SPI>, < CLK_TOP_SPINFI_IFR_SEL>;
+clock-names = "spi", "sf";
+#address-cells = <1>;
+#size-cells = <0>;
+
+flash@0 {
+  compatible = "jedec,spi-nor";
+  reg = <0>;
+};
+  };
+};
+
diff --git a/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt 
b/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt
deleted file mode 100644
index 984ae7fd4f94..
--- a/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-* Serial NOR flash controller for MediaTek ARM SoCs
-
-Required properties:
-- compatible:For mt8173, compatible should be "mediatek,mt8173-nor",
- and it's the fallback compatible for other Soc.
- For every other SoC, should contain both the SoC-specific 
compatible
- string and "mediatek,mt8173-nor".
- The possible values are:
- "mediatek,mt2701-nor", "mediatek,mt8173-nor"
- "mediatek,mt2712-nor", "mediatek,mt8173-nor"
- "mediatek,mt7622-nor", "mediatek,mt8173-nor"
- "mediatek,mt7623-nor", "mediatek,mt8173-nor"
- "mediatek,mt7629-nor", "mediatek,mt8173-nor"
- "mediatek,mt8173-nor"
-- reg:   physical base address and length of the controller's 
register
-- interrupts:Interrupt number used by the controller.
-- clocks:the phandle of the clocks needed by the nor controller
-- clock-names:   the names of the clocks
- the clocks should be named "spi" and "sf". "spi" is used for 
spi bus,
- and "sf" is used for controller, these are the clocks witch
- hardware needs to enabling nor flash and nor flash controller.
- See 
Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
-- #address-cells: should be <1>
-- #size-cells:   should be <0>
-
-There should be only one spi slave device following generic spi bindings.
-It's not recommended to use this controller for devices other than SPI NOR
-flash due to limited transfer capability of th

[PATCH] dt-bindings: spi: Convert spi-mtk-nor to json-schema

2020-08-19 Thread Ikjoon Jang
Convert Mediatek ARM SOC's serial NOR flash controller binding
to json-schema format.

Signed-off-by: Ikjoon Jang 
---
 .../bindings/spi/mediatek,spi-mtk-nor.yaml| 82 +++
 .../devicetree/bindings/spi/spi-mtk-nor.txt   | 47 ---
 2 files changed, 82 insertions(+), 47 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
 delete mode 100644 Documentation/devicetree/bindings/spi/spi-mtk-nor.txt

diff --git a/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml 
b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
new file mode 100644
index ..1e4bcf691539
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/mediatek,spi-mtk-nor.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/mediatek,spi-mtk-nor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Serial NOR flash controller for MediaTek ARM SoCs
+
+maintainers:
+  - Bayi Cheng 
+  - Chuanhong Guo 
+
+description: |
+  This spi controller support single, dual, or quad mode transfer for
+  SPI NOR flash. There should be only one spi slave device following
+  generic spi bindings. It's not recommended to use this controller
+  for devices other than SPI NOR flash due to limited transfer
+  capability of this controller.
+
+allOf:
+  - $ref: /spi/spi-controller.yaml#
+
+properties:
+  compatible:
+oneOf:
+  - items:
+  - enum:
+  - mediatek,mt2701-nor
+  - mediatek,mt2712-nor
+  - mediatek,mt7622-nor
+  - mediatek,mt7623-nor
+  - mediatek,mt7629-nor
+  - enum:
+  - mediatek,mt8173-nor
+  - items:
+  - const: mediatek,mt8173-nor
+  reg:
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  clocks:
+items:
+  - description: clock used for spi bus
+  - description: clock used for controller
+
+  clock-names:
+items:
+  - const: "spi"
+  - const: "sf"
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+examples:
+  - |
+#include 
+
+soc {
+  #address-cells = <2>;
+  #size-cells = <2>;
+
+  nor_flash: spi@1100d000 {
+compatible = "mediatek,mt8173-nor";
+reg = <0 0x1100d000 0 0xe0>;
+interrupts = <_flash_irq>;
+clocks = < CLK_PERI_SPI>, < CLK_TOP_SPINFI_IFR_SEL>;
+clock-names = "spi", "sf";
+#address-cells = <1>;
+#size-cells = <0>;
+
+flash@0 {
+  compatible = "jedec,spi-nor";
+  reg = <0>;
+};
+  };
+};
+
diff --git a/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt 
b/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt
deleted file mode 100644
index 984ae7fd4f94..
--- a/Documentation/devicetree/bindings/spi/spi-mtk-nor.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-* Serial NOR flash controller for MediaTek ARM SoCs
-
-Required properties:
-- compatible:For mt8173, compatible should be "mediatek,mt8173-nor",
- and it's the fallback compatible for other Soc.
- For every other SoC, should contain both the SoC-specific 
compatible
- string and "mediatek,mt8173-nor".
- The possible values are:
- "mediatek,mt2701-nor", "mediatek,mt8173-nor"
- "mediatek,mt2712-nor", "mediatek,mt8173-nor"
- "mediatek,mt7622-nor", "mediatek,mt8173-nor"
- "mediatek,mt7623-nor", "mediatek,mt8173-nor"
- "mediatek,mt7629-nor", "mediatek,mt8173-nor"
- "mediatek,mt8173-nor"
-- reg:   physical base address and length of the controller's 
register
-- interrupts:Interrupt number used by the controller.
-- clocks:the phandle of the clocks needed by the nor controller
-- clock-names:   the names of the clocks
- the clocks should be named "spi" and "sf". "spi" is used for 
spi bus,
- and "sf" is used for controller, these are the clocks witch
- hardware needs to enabling nor flash and nor flash controller.
- See 
Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
-- #address-cells: should be <1>
-- #size-cells:   should be <0>
-
-There should be only one spi slave device following generic spi bindings.
-It's not recommended to use this controller for devices other than SPI NOR
-flash due to limited transfer capability of this controller.
-
-Example:
-
-nor_flash: spi@1100d000 {
-   compatible = "mediatek,mt8173-nor";

[PATCH v3 1/2] power: supply: sbs-battery: combine get_presence_and_health

2020-08-12 Thread Ikjoon Jang
This patch enables calling sbs_get_battery_presence_and_health()
without checking its chip type. No functional changes.

Signed-off-by: Ikjoon Jang 
---
 drivers/power/supply/sbs-battery.c | 73 +++---
 1 file changed, 36 insertions(+), 37 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index 83b9924033bd..6acb4ea25d2a 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -389,37 +389,6 @@ static bool sbs_bat_needs_calibration(struct i2c_client 
*client)
return !!(ret & BIT(7));
 }
 
-static int sbs_get_battery_presence_and_health(
-   struct i2c_client *client, enum power_supply_property psp,
-   union power_supply_propval *val)
-{
-   int ret;
-
-   /* Dummy command; if it succeeds, battery is present. */
-   ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
-
-   if (ret < 0) { /* battery not present*/
-   if (psp == POWER_SUPPLY_PROP_PRESENT) {
-   val->intval = 0;
-   return 0;
-   }
-   return ret;
-   }
-
-   if (psp == POWER_SUPPLY_PROP_PRESENT)
-   val->intval = 1; /* battery present */
-   else { /* POWER_SUPPLY_PROP_HEALTH */
-   if (sbs_bat_needs_calibration(client)) {
-   val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
-   } else {
-   /* SBS spec doesn't have a general health command. */
-   val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
-   }
-   }
-
-   return 0;
-}
-
 static int sbs_get_ti_battery_presence_and_health(
struct i2c_client *client, enum power_supply_property psp,
union power_supply_propval *val)
@@ -478,6 +447,41 @@ static int sbs_get_ti_battery_presence_and_health(
return 0;
 }
 
+static int sbs_get_battery_presence_and_health(
+   struct i2c_client *client, enum power_supply_property psp,
+   union power_supply_propval *val)
+{
+   struct sbs_info *chip = i2c_get_clientdata(client);
+   int ret;
+
+   if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
+   return sbs_get_ti_battery_presence_and_health(client, psp, val);
+
+   /* Dummy command; if it succeeds, battery is present. */
+   ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
+
+   if (ret < 0) { /* battery not present*/
+   if (psp == POWER_SUPPLY_PROP_PRESENT) {
+   val->intval = 0;
+   return 0;
+   }
+   return ret;
+   }
+
+   if (psp == POWER_SUPPLY_PROP_PRESENT)
+   val->intval = 1; /* battery present */
+   else { /* POWER_SUPPLY_PROP_HEALTH */
+   if (sbs_bat_needs_calibration(client)) {
+   val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
+   } else {
+   /* SBS spec doesn't have a general health command. */
+   val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+   }
+   }
+
+   return 0;
+}
+
 static int sbs_get_battery_property(struct i2c_client *client,
int reg_offset, enum power_supply_property psp,
union power_supply_propval *val)
@@ -780,12 +784,7 @@ static int sbs_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_HEALTH:
-   if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
-   ret = sbs_get_ti_battery_presence_and_health(client,
-psp, val);
-   else
-   ret = sbs_get_battery_presence_and_health(client, psp,
- val);
+   ret = sbs_get_battery_presence_and_health(client, psp, val);
 
/* this can only be true if no gpio is used */
if (psp == POWER_SUPPLY_PROP_PRESENT)
-- 
2.28.0.236.gb10cc79966-goog



[PATCH v3 2/2] power: supply: sbs-battery: don't assume i2c errors as battery disconnect

2020-08-12 Thread Ikjoon Jang
Current sbs-battery considers all smbus errors as disconnection events
when battery-detect pin isn't supplied, and restored to present state back
when any successful transaction is made.

This can lead to unlimited state changes between present and !present
when one unsupported command was requested and other following commands
were successful, e.g. udev rules tries to read multiple properties.

This patch checks battery presence by reading known good command to
check battery existence.

Signed-off-by: Ikjoon Jang 
---
 drivers/power/supply/sbs-battery.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index 6acb4ea25d2a..2e32fde04628 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -878,10 +878,17 @@ static int sbs_get_property(struct power_supply *psy,
if (!chip->enable_detection)
goto done;
 
-   if (!chip->gpio_detect &&
-   chip->is_present != (ret >= 0)) {
-   sbs_update_presence(chip, (ret >= 0));
-   power_supply_changed(chip->power_supply);
+   if (!chip->gpio_detect && chip->is_present != (ret >= 0)) {
+   bool old_present = chip->is_present;
+   union power_supply_propval val;
+
+   ret = sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+
+   sbs_update_presence(chip, !ret && val.intval);
+
+   if (old_present != chip->is_present)
+   power_supply_changed(chip->power_supply);
}
 
 done:
@@ -1067,11 +1074,13 @@ static int sbs_probe(struct i2c_client *client)
 * to the battery.
 */
if (!(force_load || chip->gpio_detect)) {
-   rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
+   union power_supply_propval val;
 
-   if (rc < 0) {
-   dev_err(>dev, "%s: Failed to get device 
status\n",
-   __func__);
+   rc = sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+   if (rc < 0 || !val.intval) {
+   dev_err(>dev, "Failed to get present status\n");
+   rc = -ENODEV;
goto exit_psupply;
}
}
-- 
2.28.0.236.gb10cc79966-goog



[PATCH v3 0/2] power: supply: sbs-battery: fix presence check

2020-08-12 Thread Ikjoon Jang
When gpio detection is not supplied, presence state transitions depend
on every smbus transfer result from get_property(). This patch tries to
check battery presence again with well supported command before
state transition.

Changes:
v3: check return value of get_presence_and_health()
v2: combine get_presence_and_health functions to reuse

Ikjoon Jang (2):
  power: supply: sbs-battery: combine get_presence_and_health
  power: supply: sbs-battery: don't assume i2c errors as battery
disconnect

 drivers/power/supply/sbs-battery.c | 98 --
 1 file changed, 53 insertions(+), 45 deletions(-)

-- 
2.28.0.236.gb10cc79966-goog



[PATCH v2 2/2] power: supply: sbs-battery: don't assume every i2c errors as battery disconnect

2020-08-11 Thread Ikjoon Jang
Current sbs-battery considers all smbus errors as diconnection events
when battery-detect pin isn't supplied, and restored to present state back
on any successful transaction were made.

This can leads to unlimited state changes between present and !present
when one unsupported command was requested and other following commands
were successful, e.g. udev rules tries to read multiple properties.

This patch checks battery presence by reading known good command to
check battery existence.

Signed-off-by: Ikjoon Jang 
---
v2: fix return value checking of sbs_get_battery_presence_and_health()
---
 drivers/power/supply/sbs-battery.c | 26 +-
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index 6acb4ea25d2a..db964a470ebc 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -878,10 +878,17 @@ static int sbs_get_property(struct power_supply *psy,
if (!chip->enable_detection)
goto done;
 
-   if (!chip->gpio_detect &&
-   chip->is_present != (ret >= 0)) {
-   sbs_update_presence(chip, (ret >= 0));
-   power_supply_changed(chip->power_supply);
+   if (!chip->gpio_detect && chip->is_present != (ret >=0)) {
+   bool old_present = chip->is_present;
+   union power_supply_propval val;
+
+   sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+
+   sbs_update_presence(chip, val.intval);
+
+   if (old_present != chip->is_present)
+   power_supply_changed(chip->power_supply);
}
 
 done:
@@ -1067,11 +1074,12 @@ static int sbs_probe(struct i2c_client *client)
 * to the battery.
 */
if (!(force_load || chip->gpio_detect)) {
-   rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
-
-   if (rc < 0) {
-   dev_err(>dev, "%s: Failed to get device 
status\n",
-   __func__);
+   union power_supply_propval val;
+   sbs_get_battery_presence_and_health(
+   client, POWER_SUPPLY_PROP_PRESENT, );
+   if (!val.intval) {
+   dev_err(>dev, "Failed to get present status\n");
+   rc = -ENODEV;
goto exit_psupply;
}
}
-- 
2.28.0.236.gb10cc79966-goog



[PATCH v2 1/2] power: supply: sbs-battery: combine get_presence_and_health

2020-08-11 Thread Ikjoon Jang
This patch combines two different sbs_get_battery_presence_and_health()
for reuse in the future. No functional changes.

Signed-off-by: Ikjoon Jang 
---
 drivers/power/supply/sbs-battery.c | 73 +++---
 1 file changed, 36 insertions(+), 37 deletions(-)

diff --git a/drivers/power/supply/sbs-battery.c 
b/drivers/power/supply/sbs-battery.c
index 83b9924033bd..6acb4ea25d2a 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -389,37 +389,6 @@ static bool sbs_bat_needs_calibration(struct i2c_client 
*client)
return !!(ret & BIT(7));
 }
 
-static int sbs_get_battery_presence_and_health(
-   struct i2c_client *client, enum power_supply_property psp,
-   union power_supply_propval *val)
-{
-   int ret;
-
-   /* Dummy command; if it succeeds, battery is present. */
-   ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
-
-   if (ret < 0) { /* battery not present*/
-   if (psp == POWER_SUPPLY_PROP_PRESENT) {
-   val->intval = 0;
-   return 0;
-   }
-   return ret;
-   }
-
-   if (psp == POWER_SUPPLY_PROP_PRESENT)
-   val->intval = 1; /* battery present */
-   else { /* POWER_SUPPLY_PROP_HEALTH */
-   if (sbs_bat_needs_calibration(client)) {
-   val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
-   } else {
-   /* SBS spec doesn't have a general health command. */
-   val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
-   }
-   }
-
-   return 0;
-}
-
 static int sbs_get_ti_battery_presence_and_health(
struct i2c_client *client, enum power_supply_property psp,
union power_supply_propval *val)
@@ -478,6 +447,41 @@ static int sbs_get_ti_battery_presence_and_health(
return 0;
 }
 
+static int sbs_get_battery_presence_and_health(
+   struct i2c_client *client, enum power_supply_property psp,
+   union power_supply_propval *val)
+{
+   struct sbs_info *chip = i2c_get_clientdata(client);
+   int ret;
+
+   if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
+   return sbs_get_ti_battery_presence_and_health(client, psp, val);
+
+   /* Dummy command; if it succeeds, battery is present. */
+   ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
+
+   if (ret < 0) { /* battery not present*/
+   if (psp == POWER_SUPPLY_PROP_PRESENT) {
+   val->intval = 0;
+   return 0;
+   }
+   return ret;
+   }
+
+   if (psp == POWER_SUPPLY_PROP_PRESENT)
+   val->intval = 1; /* battery present */
+   else { /* POWER_SUPPLY_PROP_HEALTH */
+   if (sbs_bat_needs_calibration(client)) {
+   val->intval = POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED;
+   } else {
+   /* SBS spec doesn't have a general health command. */
+   val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+   }
+   }
+
+   return 0;
+}
+
 static int sbs_get_battery_property(struct i2c_client *client,
int reg_offset, enum power_supply_property psp,
union power_supply_propval *val)
@@ -780,12 +784,7 @@ static int sbs_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_HEALTH:
-   if (chip->flags & SBS_FLAGS_TI_BQ20ZX5)
-   ret = sbs_get_ti_battery_presence_and_health(client,
-psp, val);
-   else
-   ret = sbs_get_battery_presence_and_health(client, psp,
- val);
+   ret = sbs_get_battery_presence_and_health(client, psp, val);
 
/* this can only be true if no gpio is used */
if (psp == POWER_SUPPLY_PROP_PRESENT)
-- 
2.28.0.236.gb10cc79966-goog



  1   2   >