* [PATCH 1/4] dt-bindings: i3c: Add AST2600 i3c controller
  2023-02-16  7:41 [PATCH 0/4] i3c: Add support for ast2600 i3c controller Jeremy Kerr
@ 2023-02-16  7:41 ` Jeremy Kerr
  2023-02-16  8:24   ` Krzysztof Kozlowski
  2023-02-16 13:58   ` Rob Herring
  2023-02-16  7:41 ` [PATCH 2/4] i3c: dw: Add platform operations Jeremy Kerr
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 10+ messages in thread
From: Jeremy Kerr @ 2023-02-16  7:41 UTC (permalink / raw)
  To: linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
Add a devicetree binding for the ast2600 i3c controller hardware. This
is heavily based on the designware i3c core, plus a reset facility
and two platform-specific properties:
 - sda-pullup-ohms: to specify the value of the configurable pullup
   resistors on the SDA line
 - aspeed,global-regs: to reference the (ast2600-specific) i3c global
   register block, and the device index to use within it.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
changes from RFC:
 - add vendor prefix to global-regs properties
 - add item description on global-regs property
 - drop global reg node from example
---
 .../bindings/i3c/aspeed,ast2600-i3c.yaml      | 73 +++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
diff --git a/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
new file mode 100644
index 000000000000..920428f243b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i3c/aspeed,ast2600-i3c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2600 i3c controller
+
+maintainers:
+  - Jeremy Kerr <jk@codeconstruct.com.au>
+
+allOf:
+  - $ref: i3c.yaml#
+
+properties:
+  compatible:
+    const: aspeed,ast2600-i3c
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  sda-pullup-ohms:
+    enum: [545, 750, 2000]
+    default: 2000
+    description: |
+      Value to configure SDA pullup resistor, in Ohms.
+
+  aspeed,global-regs:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: phandle to i3c global register syscon node
+          - description: index of this i3c controller in the global register set
+    description: |
+      A (phandle, controller index) reference to the i3c global register set
+      used for this device.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+  - aspeed,global-regs
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/ast2600-clock.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    i3c-master@2000 {
+        compatible = "aspeed,ast2600-i3c";
+        reg = <0x2000 0x1000>;
+        #address-cells = <3>;
+        #size-cells = <0>;
+        clocks = <&syscon ASPEED_CLK_GATE_I3C0CLK>;
+        resets = <&syscon ASPEED_RESET_I3C0>;
+        aspeed,global-regs = <&i3c_global 0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_i3c1_default>;
+        interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+    };
+...
-- 
2.39.1
^ permalink raw reply related	[flat|nested] 10+ messages in thread* Re: [PATCH 1/4] dt-bindings: i3c: Add AST2600 i3c controller
  2023-02-16  7:41 ` [PATCH 1/4] dt-bindings: i3c: Add AST2600 " Jeremy Kerr
@ 2023-02-16  8:24   ` Krzysztof Kozlowski
  2023-02-16 13:58   ` Rob Herring
  1 sibling, 0 replies; 10+ messages in thread
From: Krzysztof Kozlowski @ 2023-02-16  8:24 UTC (permalink / raw)
  To: Jeremy Kerr, linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
On 16/02/2023 08:41, Jeremy Kerr wrote:
> Add a devicetree binding for the ast2600 i3c controller hardware. This
> is heavily based on the designware i3c core, plus a reset facility
> and two platform-specific properties:
> 
>  - sda-pullup-ohms: to specify the value of the configurable pullup
>    resistors on the SDA line
> 
>  - aspeed,global-regs: to reference the (ast2600-specific) i3c global
>    register block, and the device index to use within it.
> 
> Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
> 
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Best regards,
Krzysztof
^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] dt-bindings: i3c: Add AST2600 i3c controller
  2023-02-16  7:41 ` [PATCH 1/4] dt-bindings: i3c: Add AST2600 " Jeremy Kerr
  2023-02-16  8:24   ` Krzysztof Kozlowski
@ 2023-02-16 13:58   ` Rob Herring
  1 sibling, 0 replies; 10+ messages in thread
From: Rob Herring @ 2023-02-16 13:58 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: Alexandre Belloni, Krzysztof Kozlowski, linux-i3c, Joel Stanley,
	devicetree, Rob Herring, Vitor Soares, Dylan Hung, linux-aspeed,
	Andrew Jeffery
On Thu, 16 Feb 2023 15:41:52 +0800, Jeremy Kerr wrote:
> Add a devicetree binding for the ast2600 i3c controller hardware. This
> is heavily based on the designware i3c core, plus a reset facility
> and two platform-specific properties:
> 
>  - sda-pullup-ohms: to specify the value of the configurable pullup
>    resistors on the SDA line
> 
>  - aspeed,global-regs: to reference the (ast2600-specific) i3c global
>    register block, and the device index to use within it.
> 
> Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
> 
> ---
> changes from RFC:
>  - add vendor prefix to global-regs properties
>  - add item description on global-regs property
>  - drop global reg node from example
> ---
>  .../bindings/i3c/aspeed,ast2600-i3c.yaml      | 73 +++++++++++++++++++
>  1 file changed, 73 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
> 
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.example.dts:30.31-32 syntax error
FATAL ERROR: Unable to parse input tree
make[1]: *** [scripts/Makefile.lib:434: Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.example.dtb] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1508: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/82d750f53df622d8986e9a07053c7ee27dee61a2.1676532146.git.jk@codeconstruct.com.au
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH 2/4] i3c: dw: Add platform operations
  2023-02-16  7:41 [PATCH 0/4] i3c: Add support for ast2600 i3c controller Jeremy Kerr
  2023-02-16  7:41 ` [PATCH 1/4] dt-bindings: i3c: Add AST2600 " Jeremy Kerr
@ 2023-02-16  7:41 ` Jeremy Kerr
  2023-02-16 15:04   ` Ben Dooks
  2023-02-16  7:41 ` [PATCH 3/4] i3c: dw: Add AST2600 platform ops Jeremy Kerr
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Jeremy Kerr @ 2023-02-16  7:41 UTC (permalink / raw)
  To: linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
The dw i3c core can be integrated into various SoC devices. Platforms
that use this core may need a little configuration that is specific to
that platform.
Add a little infrastructure to allow platform-specific behaviour: a bit
of data on struct dw_i3c_master, and two hooks to the probe and init
calls to enable this.
A future change will add new platform support that uses these hooks.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
 drivers/i3c/master/dw-i3c-master.c | 42 +++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index d73d57362b3b..49b891449222 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -241,6 +241,17 @@ struct dw_i3c_master {
 	char version[5];
 	char type[5];
 	u8 addrs[MAX_DEVS];
+
+	/* platform-specific data */
+	const struct dw_i3c_platform_ops *platform_ops;
+	union {
+	} pdata;
+
+};
+
+struct dw_i3c_platform_ops {
+	int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
+	int (*init)(struct dw_i3c_master *i3c);
 };
 
 struct dw_i3c_i2c_dev_data {
@@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 	u32 thld_ctrl;
 	int ret;
 
+	if (master->platform_ops && master->platform_ops->init) {
+		ret = master->platform_ops->init(master);
+		if (ret)
+			return ret;
+	}
+
 	switch (bus->mode) {
 	case I3C_BUS_MODE_MIXED_FAST:
 	case I3C_BUS_MODE_MIXED_LIMITED:
@@ -1128,8 +1145,15 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.i2c_xfers = dw_i3c_master_i2c_xfers,
 };
 
+static const struct of_device_id dw_i3c_master_of_match[] = {
+	{ .compatible = "snps,dw-i3c-master-1.00a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
+
 static int dw_i3c_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
 	struct dw_i3c_master *master;
 	int ret, irq;
 
@@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
 	master->maxdevs = ret >> 16;
 	master->free_pos = GENMASK(master->maxdevs - 1, 0);
 
+	/* match any platform-specific ops */
+	match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node);
+	if (match && match->data)
+		master->platform_ops = match->data;
+
+	/* platform-specific probe */
+	if (master->platform_ops && master->platform_ops->probe) {
+		ret = master->platform_ops->probe(master, pdev);
+		if (ret)
+			goto err_assert_rst;
+	}
+
 	ret = i3c_master_register(&master->base, &pdev->dev,
 				  &dw_mipi_i3c_ops, false);
 	if (ret)
@@ -1213,12 +1249,6 @@ static int dw_i3c_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id dw_i3c_master_of_match[] = {
-	{ .compatible = "snps,dw-i3c-master-1.00a", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
-
 static struct platform_driver dw_i3c_driver = {
 	.probe = dw_i3c_probe,
 	.remove = dw_i3c_remove,
-- 
2.39.1
^ permalink raw reply related	[flat|nested] 10+ messages in thread* Re: [PATCH 2/4] i3c: dw: Add platform operations
  2023-02-16  7:41 ` [PATCH 2/4] i3c: dw: Add platform operations Jeremy Kerr
@ 2023-02-16 15:04   ` Ben Dooks
  2023-02-17  9:43     ` Jeremy Kerr
  0 siblings, 1 reply; 10+ messages in thread
From: Ben Dooks @ 2023-02-16 15:04 UTC (permalink / raw)
  To: Jeremy Kerr, linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
On 16/02/2023 07:41, Jeremy Kerr wrote:
> The dw i3c core can be integrated into various SoC devices. Platforms
> that use this core may need a little configuration that is specific to
> that platform.
> 
> Add a little infrastructure to allow platform-specific behaviour: a bit
> of data on struct dw_i3c_master, and two hooks to the probe and init
> calls to enable this.
> 
> A future change will add new platform support that uses these hooks.
> 
> Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
> ---
>   drivers/i3c/master/dw-i3c-master.c | 42 +++++++++++++++++++++++++-----
>   1 file changed, 36 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
> index d73d57362b3b..49b891449222 100644
> --- a/drivers/i3c/master/dw-i3c-master.c
> +++ b/drivers/i3c/master/dw-i3c-master.c
> @@ -241,6 +241,17 @@ struct dw_i3c_master {
>   	char version[5];
>   	char type[5];
>   	u8 addrs[MAX_DEVS];
> +
> +	/* platform-specific data */
> +	const struct dw_i3c_platform_ops *platform_ops;
> +	union {
> +	} pdata;
> +
> +};
> +
> +struct dw_i3c_platform_ops {
> +	int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
> +	int (*init)(struct dw_i3c_master *i3c);
>   };
Given the comment below having this and the main probe defined in a 
header so users can just call in and we don't have to change the
main code here every time someone comes up with their own
special way of handing this?
>   struct dw_i3c_i2c_dev_data {
> @@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
>   	u32 thld_ctrl;
>   	int ret;
>   
> +	if (master->platform_ops && master->platform_ops->init) {
> +		ret = master->platform_ops->init(master);
> +		if (ret)
> +			return ret;
> +	}
I'd rather have a "default" set of ops than have all this checking for
NULL pointers all over the place.
> +
>   	switch (bus->mode) {
>   	case I3C_BUS_MODE_MIXED_FAST:
>   	case I3C_BUS_MODE_MIXED_LIMITED:
> @@ -1128,8 +1145,15 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
>   	.i2c_xfers = dw_i3c_master_i2c_xfers,
>   };
>   
> +static const struct of_device_id dw_i3c_master_of_match[] = {
> +	{ .compatible = "snps,dw-i3c-master-1.00a", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
> +
>   static int dw_i3c_probe(struct platform_device *pdev)
>   {
> +	const struct of_device_id *match;
>   	struct dw_i3c_master *master;
>   	int ret, irq;
>   
> @@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
>   	master->maxdevs = ret >> 16;
>   	master->free_pos = GENMASK(master->maxdevs - 1, 0);
>   
> +	/* match any platform-specific ops */
> +	match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node);
> +	if (match && match->data)
> +		master->platform_ops = match->data;
I'm sure there's a of_device_get_match_data() which would have
both removed hte need to move the match table around and the
call to of_match_node().
> +
> +	/* platform-specific probe */
> +	if (master->platform_ops && master->platform_ops->probe) {
> +		ret = master->platform_ops->probe(master, pdev);
> +		if (ret)
> +			goto err_assert_rst;
> +	}
> +
>   	ret = i3c_master_register(&master->base, &pdev->dev,
>   				  &dw_mipi_i3c_ops, false);
>   	if (ret)
> @@ -1213,12 +1249,6 @@ static int dw_i3c_remove(struct platform_device *pdev)
>   	return 0;
>   }
>   
> -static const struct of_device_id dw_i3c_master_of_match[] = {
> -	{ .compatible = "snps,dw-i3c-master-1.00a", },
> -	{},
> -};
> -MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
> -
>   static struct platform_driver dw_i3c_driver = {
>   	.probe = dw_i3c_probe,
>   	.remove = dw_i3c_remove,
^ permalink raw reply	[flat|nested] 10+ messages in thread* Re: [PATCH 2/4] i3c: dw: Add platform operations
  2023-02-16 15:04   ` Ben Dooks
@ 2023-02-17  9:43     ` Jeremy Kerr
  0 siblings, 0 replies; 10+ messages in thread
From: Jeremy Kerr @ 2023-02-17  9:43 UTC (permalink / raw)
  To: Ben Dooks, linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
Hi Ben,
Thanks for taking a look at the patch. My responses inline (just
re-ordered, simple stuff first)
> >   struct dw_i3c_i2c_dev_data {
> > @@ -612,6 +623,12 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
> >         u32 thld_ctrl;
> >         int ret;
> >   
> > +       if (master->platform_ops && master->platform_ops->init) {
> > +               ret = master->platform_ops->init(master);
> > +               if (ret)
> > +                       return ret;
> > +       }
> 
> I'd rather have a "default" set of ops than have all this checking for
> NULL pointers all over the place.
Yep, that's a better structure, changed for v2.
> > @@ -1181,6 +1205,18 @@ static int dw_i3c_probe(struct platform_device *pdev)
> >         master->maxdevs = ret >> 16;
> >         master->free_pos = GENMASK(master->maxdevs - 1, 0);
> >   
> > +       /* match any platform-specific ops */
> > +       match = of_match_node(dw_i3c_master_of_match, pdev->dev.of_node);
> > +       if (match && match->data)
> > +               master->platform_ops = match->data;
> 
> I'm sure there's a of_device_get_match_data() which would have
> both removed hte need to move the match table around and the
> call to of_match_node().
That's the one I was looking for! Thanks for the pointer, I have updated
in v2.
> > @@ -241,6 +241,17 @@ struct dw_i3c_master {
> >         char version[5];
> >         char type[5];
> >         u8 addrs[MAX_DEVS];
> > +
> > +       /* platform-specific data */
> > +       const struct dw_i3c_platform_ops *platform_ops;
> > +       union {
> > +       } pdata;
> > +
> > +};
> > +
> > +struct dw_i3c_platform_ops {
> > +       int (*probe)(struct dw_i3c_master *i3c, struct platform_device *pdev);
> > +       int (*init)(struct dw_i3c_master *i3c);
> >   };
> 
> Given the comment below having this and the main probe defined in a 
> header so users can just call in and we don't have to change the
> main code here every time someone comes up with their own
> special way of handing this?
I'm not sure I 100% understand the intention here - is it that we'd
split the platform-specific code into entirely new drivers, and have
those call into dw_i3c_probe() (presumably doing a bit of custom init
either before or after that call)?
If so: I think the platform support should stay fairly minimal, so I'm
not sure that warrants a new driver for each instance. In the ast2600
case it's just a couple of extra reg writes in the i3c init path. I'd be
reluctant to split that out completely at this stage - but if this does
grow, we can certainly reconsider.
Also, I'd like to allow for the case where the platform-specific parts
may access the fields of struct dw_i3c_master; with this approach we
don't need to expose that struct outside of the single driver.
Cheers,
Jeremy
^ permalink raw reply	[flat|nested] 10+ messages in thread
* [PATCH 3/4] i3c: dw: Add AST2600 platform ops
  2023-02-16  7:41 [PATCH 0/4] i3c: Add support for ast2600 i3c controller Jeremy Kerr
  2023-02-16  7:41 ` [PATCH 1/4] dt-bindings: i3c: Add AST2600 " Jeremy Kerr
  2023-02-16  7:41 ` [PATCH 2/4] i3c: dw: Add platform operations Jeremy Kerr
@ 2023-02-16  7:41 ` Jeremy Kerr
  2023-02-16  7:41 ` [PATCH 4/4] i3c: dw: Add compatible string for ASPEED AST2600 BMC platform Jeremy Kerr
  2023-03-01  1:04 ` [PATCH 0/4] i3c: Add support for ast2600 i3c controller Joel Stanley
  4 siblings, 0 replies; 10+ messages in thread
From: Jeremy Kerr @ 2023-02-16  7:41 UTC (permalink / raw)
  To: linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
Now that we have platform-specific hooks for the dw i3c driver, add
platform support for the ASPEED AST2600 SoC.
The AST2600 has a small set of "i3c global" registers, providing
platform-level i3c configuration outside of the i3c core.
For the ast2600, we need a couple of extra setup operations:
 - on probe: find the i3c global register set and parse the SDA pullup
   resistor values
 - on init: set the pullups accordingly, and set the i3c instance IDs
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
 drivers/i3c/master/dw-i3c-master.c | 122 +++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 49b891449222..9be3348cba0e 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -16,8 +16,10 @@
 #include <linux/iopoll.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 
@@ -201,6 +203,28 @@
 
 #define XFER_TIMEOUT (msecs_to_jiffies(1000))
 
+/* AST2600-specific global register set */
+#define AST2600_I3CG_REG0(idx)	(((idx) * 4 * 4) + 0x10)
+#define AST2600_I3CG_REG1(idx)	(((idx) * 4 * 4) + 0x14)
+
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_MASK	GENMASK(29, 28)
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_2K	(0x0 << 28)
+#define AST2600_I3CG_REG0_SDA_PULLUP_EN_750	(0x2 << 28)
+
+#define AST2600_I3CG_REG1_I2C_MODE		BIT(0)
+#define AST2600_I3CG_REG1_TEST_MODE		BIT(1)
+#define AST2600_I3CG_REG1_ACT_MODE_MASK		GENMASK(3, 2)
+#define AST2600_I3CG_REG1_ACT_MODE(x)		(((x) << 2) & AST2600_I3CG_REG1_ACT_MODE_MASK)
+#define AST2600_I3CG_REG1_PENDING_INT_MASK	GENMASK(7, 4)
+#define AST2600_I3CG_REG1_PENDING_INT(x)	(((x) << 4) & AST2600_I3CG_REG1_PENDING_INT_MASK)
+#define AST2600_I3CG_REG1_SA_MASK		GENMASK(14, 8)
+#define AST2600_I3CG_REG1_SA(x)			(((x) << 8) & AST2600_I3CG_REG1_SA_MASK)
+#define AST2600_I3CG_REG1_SA_EN			BIT(15)
+#define AST2600_I3CG_REG1_INST_ID_MASK		GENMASK(19, 16)
+#define AST2600_I3CG_REG1_INST_ID(x)		(((x) << 16) & AST2600_I3CG_REG1_INST_ID_MASK)
+
+#define AST2600_DEFAULT_SDA_PULLUP_OHMS		2000
+
 struct dw_i3c_master_caps {
 	u8 cmdfifodepth;
 	u8 datafifodepth;
@@ -224,6 +248,12 @@ struct dw_i3c_xfer {
 	struct dw_i3c_cmd cmds[];
 };
 
+struct pdata_ast2600 {
+	struct regmap *global_regs;
+	unsigned int global_idx;
+	unsigned int sda_pullup;
+};
+
 struct dw_i3c_master {
 	struct i3c_master_controller base;
 	u16 maxdevs;
@@ -245,6 +275,7 @@ struct dw_i3c_master {
 	/* platform-specific data */
 	const struct dw_i3c_platform_ops *platform_ops;
 	union {
+		struct pdata_ast2600 ast2600;
 	} pdata;
 
 };
@@ -1145,6 +1176,97 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.i2c_xfers = dw_i3c_master_i2c_xfers,
 };
 
+/* hardware-specific ops */
+
+static int ast2600_i3c_pullup_to_reg(unsigned int ohms, u32 *regp)
+{
+	u32 reg;
+
+	switch (ohms) {
+	case 2000:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_2K;
+		break;
+	case 750:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_750;
+		break;
+	case 545:
+		reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_2K |
+			AST2600_I3CG_REG0_SDA_PULLUP_EN_750;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (regp)
+		*regp = reg;
+
+	return 0;
+}
+
+static int ast2600_i3c_probe(struct dw_i3c_master *master,
+			     struct platform_device *pdev)
+{
+	struct pdata_ast2600 *pdata = &master->pdata.ast2600;
+	struct device_node *np = pdev->dev.of_node;
+	struct of_phandle_args gspec;
+	int rc;
+
+	rc = of_parse_phandle_with_fixed_args(np, "aspeed,global-regs", 1, 0,
+					      &gspec);
+	if (rc)
+		return -ENODEV;
+
+	pdata->global_regs = syscon_node_to_regmap(gspec.np);
+	of_node_put(gspec.np);
+
+	if (IS_ERR(pdata->global_regs))
+		return PTR_ERR(pdata->global_regs);
+
+	pdata->global_idx = gspec.args[0];
+
+	rc = of_property_read_u32(np, "sda-pullup-ohms", &pdata->sda_pullup);
+	if (rc)
+		pdata->sda_pullup = AST2600_DEFAULT_SDA_PULLUP_OHMS;
+
+	rc = ast2600_i3c_pullup_to_reg(pdata->sda_pullup, NULL);
+	if (rc)
+		dev_err(&master->base.dev, "invalid sda-pullup value %d\n",
+			pdata->sda_pullup);
+
+	return rc;
+}
+
+static int ast2600_i3c_init(struct dw_i3c_master *master)
+{
+	struct pdata_ast2600 *pdata = &master->pdata.ast2600;
+	u32 reg = 0;
+	int rc;
+
+	/* reg0: set SDA pullup values */
+	rc = ast2600_i3c_pullup_to_reg(pdata->sda_pullup, ®);
+	if (rc)
+		return rc;
+
+	rc = regmap_write(pdata->global_regs,
+			  AST2600_I3CG_REG0(pdata->global_idx), reg);
+	if (rc)
+		return rc;
+
+	/* reg1: set up the instance id, but leave everything else disabled,
+	 * as it's all for client mode
+	 */
+	reg = AST2600_I3CG_REG1_INST_ID(pdata->global_idx);
+	rc = regmap_write(pdata->global_regs,
+			  AST2600_I3CG_REG1(pdata->global_idx), reg);
+
+	return rc;
+}
+
+static const struct dw_i3c_platform_ops ast2600_platform_ops = {
+	.probe = ast2600_i3c_probe,
+	.init = ast2600_i3c_init,
+};
+
 static const struct of_device_id dw_i3c_master_of_match[] = {
 	{ .compatible = "snps,dw-i3c-master-1.00a", },
 	{},
-- 
2.39.1
^ permalink raw reply related	[flat|nested] 10+ messages in thread* [PATCH 4/4] i3c: dw: Add compatible string for ASPEED AST2600 BMC platform
  2023-02-16  7:41 [PATCH 0/4] i3c: Add support for ast2600 i3c controller Jeremy Kerr
                   ` (2 preceding siblings ...)
  2023-02-16  7:41 ` [PATCH 3/4] i3c: dw: Add AST2600 platform ops Jeremy Kerr
@ 2023-02-16  7:41 ` Jeremy Kerr
  2023-03-01  1:04 ` [PATCH 0/4] i3c: Add support for ast2600 i3c controller Joel Stanley
  4 siblings, 0 replies; 10+ messages in thread
From: Jeremy Kerr @ 2023-02-16  7:41 UTC (permalink / raw)
  To: linux-i3c
  Cc: Alexandre Belloni, Vitor Soares, linux-aspeed, devicetree,
	Rob Herring, Krzysztof Kozlowski, Dylan Hung, Joel Stanley,
	Andrew Jeffery
Now that we have platform-specific code for the ast2600, enable it
through a new compatible string.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
 drivers/i3c/master/dw-i3c-master.c | 1 +
 1 file changed, 1 insertion(+)
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 9be3348cba0e..5ac226e0c558 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -1269,6 +1269,7 @@ static const struct dw_i3c_platform_ops ast2600_platform_ops = {
 
 static const struct of_device_id dw_i3c_master_of_match[] = {
 	{ .compatible = "snps,dw-i3c-master-1.00a", },
+	{ .compatible = "aspeed,ast2600-i3c", .data = &ast2600_platform_ops },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
-- 
2.39.1
^ permalink raw reply related	[flat|nested] 10+ messages in thread* Re: [PATCH 0/4] i3c: Add support for ast2600 i3c controller
  2023-02-16  7:41 [PATCH 0/4] i3c: Add support for ast2600 i3c controller Jeremy Kerr
                   ` (3 preceding siblings ...)
  2023-02-16  7:41 ` [PATCH 4/4] i3c: dw: Add compatible string for ASPEED AST2600 BMC platform Jeremy Kerr
@ 2023-03-01  1:04 ` Joel Stanley
  4 siblings, 0 replies; 10+ messages in thread
From: Joel Stanley @ 2023-03-01  1:04 UTC (permalink / raw)
  To: Jeremy Kerr
  Cc: linux-i3c, Alexandre Belloni, Vitor Soares, linux-aspeed,
	devicetree, Rob Herring, Krzysztof Kozlowski, Dylan Hung,
	Andrew Jeffery
On Thu, 16 Feb 2023 at 07:42, Jeremy Kerr <jk@codeconstruct.com.au> wrote:
>
> The AST2600 SoC hardware includes a set of i3c controllers, based on the
> designware i3c core, plus some global registers for SoC integration.
>
> This series adds support for these i3c controllers, through the existing
> dw i3c master controller driver, by adding a set of platform-specific
> hooks to handle the global register configuration. This also gives us a
> way to add any future hardware-specific behaviours.
>
> We also need a DT binding to describe the ast2600-specific hardware.
> Since this involves new (mandatory) properties, I have added this as a
> separate binding rather than add a new compat string to the dw binding.
>
> The dt-binding example depends on a prior submission to the dt binding
> headers:
>
>   https://lore.kernel.org/linux-devicetree/cover.1676294433.git.jk@codeconstruct.com.au/
>
> Full support for the global regmap will land with this queued mfd change:
>
>   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git/commit/?id=cf2271843de835839e91c5c036492a87085af756
>
> Of course, any queries/comments/etc are most welcome.
Reviewed-by: Joel Stanley <joel@jms.id.au>
>
> Cheers,
>
>
> Jeremy
>
> Jeremy Kerr (4):
>   dt-bindings: i3c: Add AST2600 i3c controller
>   i3c: dw: Add platform operations
>   i3c: dw: Add AST2600 platform ops
>   i3c: dw: Add compatible string for ASPEED AST2600 BMC platform
>
>  .../bindings/i3c/aspeed,ast2600-i3c.yaml      |  73 ++++++++
>  drivers/i3c/master/dw-i3c-master.c            | 165 +++++++++++++++++-
>  2 files changed, 232 insertions(+), 6 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml
>
> --
> 2.39.1
>
^ permalink raw reply	[flat|nested] 10+ messages in thread