]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - drivers/memory/renesas-rpc-if.c
PCI: hv: Propagate coherence from VMbus device to PCI device
[mirror_ubuntu-jammy-kernel.git] / drivers / memory / renesas-rpc-if.c
index 45eed659b0c6de5f14266e2e9242b76f4e38bff4..86187022330021bf315d155f7ce73eda5b73247e 100644 (file)
@@ -160,10 +160,62 @@ static const struct regmap_access_table rpcif_volatile_table = {
        .n_yes_ranges   = ARRAY_SIZE(rpcif_volatile_ranges),
 };
 
+
+/*
+ * Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed
+ * with proper width. Requires SMENR_SPIDE to be correctly set before!
+ */
+static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct rpcif *rpc = context;
+
+       if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
+               u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
+
+               if (spide == 0x8) {
+                       *val = readb(rpc->base + reg);
+                       return 0;
+               } else if (spide == 0xC) {
+                       *val = readw(rpc->base + reg);
+                       return 0;
+               } else if (spide != 0xF) {
+                       return -EILSEQ;
+               }
+       }
+
+       *val = readl(rpc->base + reg);
+       return 0;
+
+}
+
+static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct rpcif *rpc = context;
+
+       if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
+               u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
+
+               if (spide == 0x8) {
+                       writeb(val, rpc->base + reg);
+                       return 0;
+               } else if (spide == 0xC) {
+                       writew(val, rpc->base + reg);
+                       return 0;
+               } else if (spide != 0xF) {
+                       return -EILSEQ;
+               }
+       }
+
+       writel(val, rpc->base + reg);
+       return 0;
+}
+
 static const struct regmap_config rpcif_regmap_config = {
        .reg_bits       = 32,
        .val_bits       = 32,
        .reg_stride     = 4,
+       .reg_read       = rpcif_reg_read,
+       .reg_write      = rpcif_reg_write,
        .fast_io        = true,
        .max_register   = RPCIF_PHYINT,
        .volatile_table = &rpcif_volatile_table,
@@ -173,17 +225,15 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *res;
-       void __iomem *base;
 
        rpc->dev = dev;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       rpc->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(rpc->base))
+               return PTR_ERR(rpc->base);
 
-       rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-                                           &rpcif_regmap_config);
+       rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
        if (IS_ERR(rpc->regmap)) {
                dev_err(&pdev->dev,
                        "failed to init regmap for rpcif, error %ld\n",
@@ -194,7 +244,7 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
        rpc->dirmap = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(rpc->dirmap))
-               rpc->dirmap = NULL;
+               return PTR_ERR(rpc->dirmap);
        rpc->size = resource_size(res);
 
        rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
@@ -354,20 +404,16 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
                        nbytes = op->data.nbytes;
                rpc->xferlen = nbytes;
 
-               rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) |
-                       RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
+               rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
        }
 }
 EXPORT_SYMBOL(rpcif_prepare);
 
 int rpcif_manual_xfer(struct rpcif *rpc)
 {
-       u32 smenr, smcr, pos = 0, max = 4;
+       u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
        int ret = 0;
 
-       if (rpc->bus_size == 2)
-               max = 8;
-
        pm_runtime_get_sync(rpc->dev);
 
        regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
@@ -378,37 +424,36 @@ int rpcif_manual_xfer(struct rpcif *rpc)
        regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option);
        regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
        regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
+       regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr);
        smenr = rpc->enable;
 
        switch (rpc->dir) {
        case RPCIF_DATA_OUT:
                while (pos < rpc->xferlen) {
-                       u32 nbytes = rpc->xferlen - pos;
-                       u32 data[2];
+                       u32 bytes_left = rpc->xferlen - pos;
+                       u32 nbytes, data[2];
 
                        smcr = rpc->smcr | RPCIF_SMCR_SPIE;
-                       if (nbytes > max) {
-                               nbytes = max;
+
+                       /* nbytes may only be 1, 2, 4, or 8 */
+                       nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
+                       if (bytes_left > nbytes)
                                smcr |= RPCIF_SMCR_SSLKP;
-                       }
+
+                       smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
+                       regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
 
                        memcpy(data, rpc->buffer + pos, nbytes);
-                       if (nbytes > 4) {
+                       if (nbytes == 8) {
                                regmap_write(rpc->regmap, RPCIF_SMWDR1,
                                             data[0]);
                                regmap_write(rpc->regmap, RPCIF_SMWDR0,
                                             data[1]);
-                       } else if (nbytes > 2) {
+                       } else {
                                regmap_write(rpc->regmap, RPCIF_SMWDR0,
                                             data[0]);
-                       } else  {
-                               regmap_write(rpc->regmap, RPCIF_SMWDR0,
-                                            data[0] << 16);
                        }
 
-                       regmap_write(rpc->regmap, RPCIF_SMADR,
-                                    rpc->smadr + pos);
-                       regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
                        regmap_write(rpc->regmap, RPCIF_SMCR, smcr);
                        ret = wait_msg_xfer_end(rpc);
                        if (ret)
@@ -448,14 +493,16 @@ int rpcif_manual_xfer(struct rpcif *rpc)
                        break;
                }
                while (pos < rpc->xferlen) {
-                       u32 nbytes = rpc->xferlen - pos;
-                       u32 data[2];
+                       u32 bytes_left = rpc->xferlen - pos;
+                       u32 nbytes, data[2];
 
-                       if (nbytes > max)
-                               nbytes = max;
+                       /* nbytes may only be 1, 2, 4, or 8 */
+                       nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
 
                        regmap_write(rpc->regmap, RPCIF_SMADR,
                                     rpc->smadr + pos);
+                       smenr &= ~RPCIF_SMENR_SPIDE(0xF);
+                       smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
                        regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
                        regmap_write(rpc->regmap, RPCIF_SMCR,
                                     rpc->smcr | RPCIF_SMCR_SPIE);
@@ -463,18 +510,14 @@ int rpcif_manual_xfer(struct rpcif *rpc)
                        if (ret)
                                goto err_out;
 
-                       if (nbytes > 4) {
+                       if (nbytes == 8) {
                                regmap_read(rpc->regmap, RPCIF_SMRDR1,
                                            &data[0]);
                                regmap_read(rpc->regmap, RPCIF_SMRDR0,
                                            &data[1]);
-                       } else if (nbytes > 2) {
-                               regmap_read(rpc->regmap, RPCIF_SMRDR0,
-                                           &data[0]);
-                       } else  {
+                       } else {
                                regmap_read(rpc->regmap, RPCIF_SMRDR0,
                                            &data[0]);
-                               data[0] >>= 16;
                        }
                        memcpy(rpc->buffer + pos, data, nbytes);