lkml.org 
[lkml]   [2021]   [Apr]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    SubjectRe [PATCH v2 21/21] ipmi: kcs_bmc_aspeed: Optionally apply status address
    Date
    On Fri, Mar 19, 2021 at 01:27:52AM CDT, Andrew Jeffery wrote:
    >Some Aspeed KCS devices can derive the status register address from the
    >address of the data register. As such, the address of the status
    >register can be implicit in the configuration if desired. On the other
    >hand, sometimes address schemes might be requested that are incompatible
    >with the default addressing scheme. Allow these requests where possible
    >if the devicetree specifies the status register address.
    >
    >Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
    >---
    > drivers/char/ipmi/kcs_bmc_aspeed.c | 113 +++++++++++++++++++++--------
    > 1 file changed, 81 insertions(+), 32 deletions(-)
    >
    >diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
    >index 7334b1f51dcc..98789b837690 100644
    >--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
    >+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
    >@@ -83,6 +83,8 @@
    > #define LPC_STR2 0x040
    > #define LPC_STR3 0x044
    > #define LPC_HICRB 0x100
    >+#define LPC_HICRB_EN16LADR2 BIT(5)
    >+#define LPC_HICRB_EN16LADR1 BIT(4)
    > #define LPC_HICRB_IBFIE4 BIT(1)
    > #define LPC_HICRB_LPC4E BIT(0)
    > #define LPC_HICRC 0x104
    >@@ -96,6 +98,11 @@
    > #define LPC_IDR4 0x114
    > #define LPC_ODR4 0x118
    > #define LPC_STR4 0x11C
    >+#define LPC_LSADR12 0x120
    >+#define LPC_LSADR12_LSADR2_MASK GENMASK(31, 16)
    >+#define LPC_LSADR12_LSADR2_SHIFT 16
    >+#define LPC_LSADR12_LSADR1_MASK GENMASK(15, 0)
    >+#define LPC_LSADR12_LSADR1_SHIFT 0
    >
    > #define OBE_POLL_PERIOD (HZ / 2)
    >
    >@@ -123,7 +130,7 @@ struct aspeed_kcs_bmc {
    >
    > struct aspeed_kcs_of_ops {
    > int (*get_channel)(struct platform_device *pdev);
    >- int (*get_io_address)(struct platform_device *pdev);
    >+ int (*get_io_address)(struct platform_device *pdev, u32 addrs[2]);
    > };
    >
    > static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc_device *kcs_bmc)
    >@@ -217,38 +224,64 @@ static void aspeed_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask,
    > * C. KCS4
    > * D / C : CA4h / CA5h
    > */
    >-static void aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u16 addr)
    >+static int aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u32 addrs[2], int nr_addrs)
    > {
    > struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
    >
    >- switch (kcs_bmc->channel) {
    >+ if (WARN_ON(nr_addrs < 1 || nr_addrs > 2))
    >+ return -EINVAL;
    >+
    >+ switch (priv->kcs_bmc.channel) {
    > case 1:
    >- regmap_update_bits(priv->map, LPC_HICR4,
    >- LPC_HICR4_LADR12AS, 0);
    >- regmap_write(priv->map, LPC_LADR12H, addr >> 8);
    >- regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
    >+ regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, 0);
    >+ regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8);
    >+ regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF);
    >+ if (nr_addrs == 2) {
    >+ regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR1_MASK,
    >+ addrs[1] << LPC_LSADR12_LSADR1_SHIFT);
    >+
    >+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR1,
    >+ LPC_HICRB_EN16LADR1);
    >+ }
    > break;
    >
    > case 2:
    >- regmap_update_bits(priv->map, LPC_HICR4,
    >- LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
    >- regmap_write(priv->map, LPC_LADR12H, addr >> 8);
    >- regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
    >+ regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
    >+ regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8);
    >+ regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF);
    >+ if (nr_addrs == 2) {
    >+ regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR2_MASK,
    >+ addrs[1] << LPC_LSADR12_LSADR2_SHIFT);
    >+
    >+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR2,
    >+ LPC_HICRB_EN16LADR2);
    >+ }
    > break;
    >
    > case 3:
    >- regmap_write(priv->map, LPC_LADR3H, addr >> 8);
    >- regmap_write(priv->map, LPC_LADR3L, addr & 0xFF);
    >+ if (nr_addrs == 2) {
    >+ dev_err(priv->kcs_bmc.dev,
    >+ "Channel 3 only supports inferred status IO address\n");
    >+ return -EINVAL;
    >+ }
    >+
    >+ regmap_write(priv->map, LPC_LADR3H, addrs[0] >> 8);
    >+ regmap_write(priv->map, LPC_LADR3L, addrs[0] & 0xFF);
    > break;
    >
    > case 4:
    >- regmap_write(priv->map, LPC_LADR4, ((addr + 1) << 16) |
    >- addr);
    >+ if (nr_addrs == 1)
    >+ regmap_write(priv->map, LPC_LADR4, ((addrs[0] + 1) << 16) | addrs[0]);
    >+ else
    >+ regmap_write(priv->map, LPC_LADR4, (addrs[1] << 16) | addrs[0]);
    >+
    > break;
    >
    > default:
    >- break;
    >+ return -EINVAL;
    > }
    >+
    >+ return 0;
    > }
    >
    > static inline int aspeed_kcs_map_serirq_type(u32 dt_type)
    >@@ -462,18 +495,18 @@ static int aspeed_kcs_of_v1_get_channel(struct platform_device *pdev)
    > return channel;
    > }
    >
    >-static int aspeed_kcs_of_v1_get_io_address(struct platform_device *pdev)
    >+static int
    >+aspeed_kcs_of_v1_get_io_address(struct platform_device *pdev, u32 addrs[2])
    > {
    >- u32 slave;
    > int rc;
    >
    >- rc = of_property_read_u32(pdev->dev.of_node, "kcs_addr", &slave);
    >- if (rc || slave > 0xffff) {
    >+ rc = of_property_read_u32(pdev->dev.of_node, "kcs_addr", addrs);
    >+ if (rc || addrs[0] > 0xffff) {
    > dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
    > return -EINVAL;
    > }
    >
    >- return slave;
    >+ return 1;
    > }
    >
    > static int aspeed_kcs_of_v2_get_channel(struct platform_device *pdev)
    >@@ -509,16 +542,27 @@ static int aspeed_kcs_of_v2_get_channel(struct platform_device *pdev)
    > return -EINVAL;
    > }
    >
    >-static int aspeed_kcs_of_v2_get_io_address(struct platform_device *pdev)
    >+static int
    >+aspeed_kcs_of_v2_get_io_address(struct platform_device *pdev, u32 addrs[2])
    > {
    >- uint32_t slave;
    > int rc;
    >
    >- rc = of_property_read_u32(pdev->dev.of_node, "aspeed,lpc-io-reg", &slave);
    >- if (rc || slave > 0xffff)
    >+ rc = of_property_read_variable_u32_array(pdev->dev.of_node,
    >+ "aspeed,lpc-io-reg",
    >+ addrs, 1, 2);
    >+ if (rc < 0)
    >+ return rc;
    >+
    >+ if (WARN_ON(rc == 0))
    >+ return -EINVAL;

    Is this check necessary? It looks like
    of_property_read_variable_u32_array() should fail in that case given
    sz_min==1, so this seems like it should be impossible to trigger.

    >+
    >+ if (addrs[0] > 0xffff)
    >+ return -EINVAL;
    >+
    >+ if (rc == 2 && addrs[1] > 0xffff)
    > return -EINVAL;
    >
    >- return slave;
    >+ return rc;
    > }
    >
    > static int aspeed_kcs_probe(struct platform_device *pdev)
    >@@ -527,9 +571,11 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
    > struct kcs_bmc_device *kcs_bmc;
    > struct aspeed_kcs_bmc *priv;
    > struct device_node *np;
    >- int rc, channel, addr;
    > bool have_upstream_irq;
    > u32 upstream_irq[2];
    >+ int rc, channel;
    >+ int nr_addrs;
    >+ u32 addrs[2];
    >
    > np = pdev->dev.of_node->parent;
    > if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") &&
    >@@ -547,9 +593,9 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
    > if (channel < 0)
    > return channel;
    >
    >- addr = ops->get_io_address(pdev);
    >- if (addr < 0)
    >- return addr;
    >+ nr_addrs = ops->get_io_address(pdev, addrs);
    >+ if (nr_addrs < 0)
    >+ return nr_addrs;
    >
    > np = pdev->dev.of_node;
    > rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", upstream_irq, 2);
    >@@ -578,7 +624,9 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
    > priv->obe.remove = false;
    > timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0);
    >
    >- aspeed_kcs_set_address(kcs_bmc, addr);
    >+ rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs);
    >+ if (rc)
    >+ return rc;
    >
    > /* Host to BMC IRQ */
    > rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev);
    >@@ -600,7 +648,8 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
    > if (rc < 0)
    > return rc;
    >
    >- dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n", kcs_bmc->channel, addr);
    >+ dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n",
    >+ kcs_bmc->channel, addrs[0]);
    >
    > return 0;
    > }
    >--
    >2.27.0
    >
    \
     
     \ /
      Last update: 2021-04-01 21:10    [W:4.595 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site