Implements a new uio driver for freescale 85xx platforms to access
the Cache-Sram form user level. It is extremely helpful for the user
space applications that require high performance memory accesses.

Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Cc: Christophe Leroy <christophe.le...@c-s.fr>
Cc: Scott Wood <o...@buserror.net>
Cc: Michael Ellerman <m...@ellerman.id.au>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Wang Wenhu <wenhu.w...@vivo.com>
---
 drivers/uio/Kconfig                   |   8 +
 drivers/uio/Makefile                  |   1 +
 drivers/uio/uio_fsl_85xx_cache_sram.c | 407 ++++++++++++++++++++++++++
 3 files changed, 416 insertions(+)
 create mode 100644 drivers/uio/uio_fsl_85xx_cache_sram.c

diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 202ee81cfc2b..f6e6ec0089c0 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -105,6 +105,14 @@ config UIO_NETX
          To compile this driver as a module, choose M here; the module
          will be called uio_netx.
 
+config UIO_FSL_85XX_CACHE_SRAM
+       tristate "Freescale MPC85xx Cache-Sram driver"
+       depends on FSL_SOC_BOOKE && PPC32 && !FSL_85XX_CACHE_SRAM
+       help
+         Generic driver for accessing the Cache-Sram form user level. This
+         is extremely helpful for some user-space applications that require
+         high performance memory accesses.
+
 config UIO_FSL_ELBC_GPCM
        tristate "eLBC/GPCM driver"
        depends on FSL_LBC
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index c285dd2a4539..be2056cffc21 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -10,4 +10,5 @@ obj-$(CONFIG_UIO_NETX)        += uio_netx.o
 obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
 obj-$(CONFIG_UIO_MF624)         += uio_mf624.o
 obj-$(CONFIG_UIO_FSL_ELBC_GPCM)        += uio_fsl_elbc_gpcm.o
+obj-$(CONFIG_UIO_FSL_85XX_CACHE_SRAM)  += uio_fsl_85xx_cache_sram.o
 obj-$(CONFIG_UIO_HV_GENERIC)   += uio_hv_generic.o
diff --git a/drivers/uio/uio_fsl_85xx_cache_sram.c 
b/drivers/uio/uio_fsl_85xx_cache_sram.c
new file mode 100644
index 000000000000..312ca38e93e1
--- /dev/null
+++ b/drivers/uio/uio_fsl_85xx_cache_sram.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+ * Copyright (C) 2020 Wang Wenhu <wenhu.w...@vivo.com>
+ * All rights reserved.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+
+#define DRIVER_NAME    "uio_fsl_85xx_cache_sram"
+#define UIO_INFO_VER   "devicetree,pseudo"
+
+#define MAX_SRAM_UIO_INFOS     5
+
+#define L2CR_L2FI              0x40000000      /* L2 flash invalidate */
+#define L2CR_SRAM_FULL         0x00010000      /* L2SRAM full size */
+#define L2CR_SRAM_HALF         0x00020000      /* L2SRAM half size */
+#define L2CR_SRAM_QUART                0x00040000      /* L2SRAM one quarter 
size */
+#define L2CR_SRAM_EIGHTH       0x00060000      /* L2SRAM one eighth size */
+
+#define L2SRAM_BAR_MSK_LO18    0xFFFFC000      /* Lower 18 bits */
+#define L2SRAM_BARE_MSK_HI4    0x0000000F      /* Upper 4 bits */
+
+enum cache_sram_lock_ways {
+       LOCK_WAYS_ZERO,
+       LOCK_WAYS_EIGHTH,
+       LOCK_WAYS_TWO_EIGHTH,
+       LOCK_WAYS_HALF = 4,
+       LOCK_WAYS_FULL = 8,
+};
+
+struct mpc85xx_l2ctlr {
+       u32     ctl;            /* 0x000 - L2 control */
+       u8      res1[0xC];
+       u32     ewar0;          /* 0x010 - External write address 0 */
+       u32     ewarea0;        /* 0x014 - External write address extended 0 */
+       u32     ewcr0;          /* 0x018 - External write ctrl */
+       u8      res2[4];
+       u32     ewar1;          /* 0x020 - External write address 1 */
+       u32     ewarea1;        /* 0x024 - External write address extended 1 */
+       u32     ewcr1;          /* 0x028 - External write ctrl 1 */
+       u8      res3[4];
+       u32     ewar2;          /* 0x030 - External write address 2 */
+       u32     ewarea2;        /* 0x034 - External write address extended 2 */
+       u32     ewcr2;          /* 0x038 - External write ctrl 2 */
+       u8      res4[4];
+       u32     ewar3;          /* 0x040 - External write address 3 */
+       u32     ewarea3;        /* 0x044 - External write address extended 3 */
+       u32     ewcr3;          /* 0x048 - External write ctrl 3 */
+       u8      res5[0xB4];
+       u32     srbar0;         /* 0x100 - SRAM base address 0 */
+       u32     srbarea0;       /* 0x104 - SRAM base addr reg ext address 0 */
+       u32     srbar1;         /* 0x108 - SRAM base address 1 */
+       u32     srbarea1;       /* 0x10C - SRAM base addr reg ext address 1 */
+       u8      res6[0xCF0];
+       u32     errinjhi;       /* 0xE00 - Error injection mask high */
+       u32     errinjlo;       /* 0xE04 - Error injection mask low */
+       u32     errinjctl;      /* 0xE08 - Error injection tag/ecc control */
+       u8      res7[0x14];
+       u32     captdatahi;     /* 0xE20 - Error data high capture */
+       u32     captdatalo;     /* 0xE24 - Error data low capture */
+       u32     captecc;        /* 0xE28 - Error syndrome */
+       u8      res8[0x14];
+       u32     errdet;         /* 0xE40 - Error detect */
+       u32     errdis;         /* 0xE44 - Error disable */
+       u32     errinten;       /* 0xE48 - Error interrupt enable */
+       u32     errattr;        /* 0xE4c - Error attribute capture */
+       u32     erradrrl;       /* 0xE50 - Error address capture low */
+       u32     erradrrh;       /* 0xE54 - Error address capture high */
+       u32     errctl;         /* 0xE58 - Error control */
+       u8      res9[0x1A4];
+};
+
+/**
+ * struct uio_cache_sram - controller for cache-sram and uio devices
+ *
+ * @base_phys: physical address of cache-sram
+ * @base_virt: mapped virtual address of cache-sram
+ * @size:      size of the sram could be used by user
+ * @alloced:   size of the sram allocated while initiating uio_infos
+ * @l2cache_size: total size of the cache-sram
+ * @l2ctlr:    address of the l2-controller
+ * @info_count:        count of the uio devices(info) for the cache-sram
+ * @uio_infos: address array of the uio devices(info)
+ */
+struct uio_cache_sram {
+       phys_addr_t base_phys;
+       void *base_virt;
+       unsigned int size;
+       unsigned int alloced;
+
+       unsigned int l2cache_size;
+
+       struct mpc85xx_l2ctlr __iomem *l2ctlr;
+
+       unsigned int info_count;
+       struct uio_info *uio_infos[MAX_SRAM_UIO_INFOS];
+};
+
+static int of_init_cache_sram(struct device_node *node,
+                             struct uio_cache_sram *cache_sram)
+{
+       const __be32 *cell;
+
+       if (of_property_read_u32(node, "cache-size",
+                               &cache_sram->l2cache_size)) {
+               pr_err("%pOF: missing cache-size property\n", node);
+               return -EINVAL;
+       }
+
+       cell = of_get_property(node, "sram-range", NULL);
+       if (!cell) {
+               pr_err("%pOF: missing sram-range property\n", node);
+               return -EINVAL;
+       }
+
+       cache_sram->base_phys = of_read_number(cell, of_n_addr_cells(node));
+       cache_sram->size = of_read_number(cell + of_n_addr_cells(node),
+                                         of_n_size_cells(node));
+
+       return 0;
+}
+
+static void l2ctrl_init(struct uio_cache_sram *cache_sram)
+{
+       struct mpc85xx_l2ctlr *l2ctlr = cache_sram->l2ctlr;
+
+       /* Write bits[0-17] to srbar0 */
+       out_be32(&l2ctlr->srbar0,
+                lower_32_bits(cache_sram->base_phys) & L2SRAM_BAR_MSK_LO18);
+
+       /* Write bits[18-21] to srbare0 */
+#ifdef CONFIG_PHYS_64BIT
+       out_be32(&l2ctlr->srbarea0,
+                upper_32_bits(cache_sram->base_phys) & L2SRAM_BARE_MSK_HI4);
+#endif
+
+       clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
+
+       switch (LOCK_WAYS_FULL * cache_sram->size / cache_sram->l2cache_size) {
+       case LOCK_WAYS_EIGHTH:
+               setbits32(&l2ctlr->ctl,
+                         L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
+               break;
+
+       case LOCK_WAYS_TWO_EIGHTH:
+               setbits32(&l2ctlr->ctl,
+                         L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
+               break;
+
+       case LOCK_WAYS_HALF:
+               setbits32(&l2ctlr->ctl,
+                         L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
+               break;
+
+       case LOCK_WAYS_FULL:
+       default:
+               setbits32(&l2ctlr->ctl,
+                         L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
+               break;
+       }
+       eieio();
+}
+
+static int uio_cache_sram_init(struct platform_device *pdev,
+                              struct uio_cache_sram *cache_sram)
+{
+       struct device_node *node = pdev->dev.of_node;
+       unsigned int rem;
+       unsigned char ways;
+       int ret;
+
+       ret = of_init_cache_sram(node, cache_sram);
+       if (ret)
+               return ret;
+
+       rem = cache_sram->l2cache_size % cache_sram->size;
+       ways = LOCK_WAYS_FULL * cache_sram->size / cache_sram->l2cache_size;
+       if (rem || (ways & (ways - 1))) {
+               dev_err(&pdev->dev, "Illegal cache-size in command line\n");
+               return -EINVAL;
+       }
+
+       cache_sram->l2ctlr = of_iomap(pdev->dev.of_node, 0);
+       if (!cache_sram->l2ctlr) {
+               dev_err(&pdev->dev, "error can't map l2-controller\n");
+               return -EINVAL;
+       }
+
+       l2ctrl_init(cache_sram);
+
+       if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+                               "fsl_85xx_cache_sram")) {
+               dev_err(&pdev->dev, "%pOF: request memory failed\n",
+                               pdev->dev.of_node);
+               ret = -ENXIO;
+               goto out_unmap;
+       }
+
+       cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys,
+                                                cache_sram->size);
+       if (!cache_sram->base_virt) {
+               dev_err(&pdev->dev, "%pOF: ioremap_coherent failed\n",
+                       pdev->dev.of_node);
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       return 0;
+out_release:
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+out_unmap:
+       iounmap(cache_sram->l2ctlr);
+       return ret;
+}
+
+static int uio_cache_sram_destroy(struct uio_cache_sram *cache_sram)
+{
+       iounmap(cache_sram->l2ctlr);
+       iounmap(cache_sram->base_virt);
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+       return 0;
+}
+
+static void uio_info_free_internal(struct uio_info *info)
+{
+       int i;
+
+       for (i = 0; i < MAX_UIO_MAPS; i++) {
+               struct uio_mem *uiomem = &info->mem[i];
+
+               if (uiomem->internal_addr)
+                       memset(uiomem, 0, sizeof(*uiomem));
+       }
+}
+
+void uio_infos_unregister(struct uio_cache_sram *cache_sram)
+{
+       int i;
+
+       for (i = 0; i < cache_sram->info_count; i++) {
+               uio_unregister_device(cache_sram->uio_infos[i]);
+               uio_info_free_internal(cache_sram->uio_infos[i]);
+               cache_sram->uio_infos[i] = NULL;
+       }
+
+       cache_sram->info_count = 0;
+}
+
+static int uio_fsl_85xx_cache_sram_probe(struct platform_device *pdev)
+{
+       struct device_node *parent = pdev->dev.of_node;
+       struct device_node *node = NULL;
+       struct uio_cache_sram *cache_sram;
+       struct uio_info *info;
+       struct uio_mem *uiomem;
+       const unsigned int *p;
+       struct property *prop;
+       const char *dt_name;
+       u32 size;
+       int ret;
+
+       cache_sram = devm_kzalloc(&pdev->dev, sizeof(*cache_sram), GFP_KERNEL);
+       if (!cache_sram)
+               return -ENOMEM;
+
+       ret = uio_cache_sram_init(pdev, cache_sram);
+       if (ret)
+               return ret;
+
+       for_each_child_of_node(parent, node) {
+               char buf[24];
+               int map_idx = 0;
+
+               /* alloc uio_info for one uio device */
+               info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+               if (!info)
+                       return -ENOMEM;
+
+               /* get optional uio name */
+               if (of_property_read_string(parent, "uio_name", &dt_name)) {
+                       sprintf(buf, "uio-sram%d", cache_sram->info_count);
+                       dt_name = buf;
+               }
+
+               info->name = devm_kstrdup(&pdev->dev, dt_name, GFP_KERNEL);
+               if (!info->name)
+                       return -ENOMEM;
+
+               of_property_for_each_u32(node, "uiomaps", prop, p, size) {
+                       char name[10];
+
+                       /* size should not be less than 2 */
+                       if (size < 2) {
+                               pr_err("size %x less than 2\n", size);
+                               return -EINVAL;
+                       }
+
+                       /* size should be 2^n aligned */
+                       if (size != roundup_pow_of_two(size)) {
+                               pr_err("size %x is not 2^n algiend\n", size);
+                               return -EINVAL;
+                       }
+
+                       if (cache_sram->alloced + size > cache_sram->size) {
+                               pr_err("size %x too big\n", size);
+                               return -EINVAL;
+                       }
+
+                       uiomem = &info->mem[map_idx];
+                       uiomem->addr = cache_sram->base_phys +
+                                      cache_sram->alloced;
+                       uiomem->internal_addr = cache_sram->base_virt +
+                                               cache_sram->alloced;
+                       uiomem->size = size;
+                       uiomem->memtype = UIO_MEM_PHYS;
+
+                       cache_sram->alloced += size;
+
+                       sprintf(name, "mem%d", map_idx);
+                       uiomem->name = devm_kstrdup(&pdev->dev, name,
+                                                   GFP_KERNEL);
+
+                       map_idx++;
+                       if (map_idx >= MAX_UIO_MAPS) {
+                               dev_warn(&pdev->dev, "more than %d uio-maps for 
device.\n",
+                                        MAX_UIO_MAPS);
+                               break;
+                       }
+               }
+
+               if (map_idx == 0) {
+                       dev_err(&pdev->dev, "error no valid uio-map 
configuration found\n");
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               info->version = UIO_INFO_VER;
+
+               /* register uio device */
+               if (uio_register_device(&pdev->dev, info)) {
+                       dev_err(&pdev->dev, "error uio,cache-sram registration 
failed\n");
+                       ret = -ENODEV;
+                       goto err_out;
+               }
+
+               cache_sram->uio_infos[cache_sram->info_count] = info;
+               cache_sram->info_count++;
+
+               if (cache_sram->info_count >= MAX_SRAM_UIO_INFOS) {
+                       dev_warn(&pdev->dev, "more than %d uio_info devices.\n",
+                                MAX_SRAM_UIO_INFOS);
+                       break;
+               }
+       }
+
+       platform_set_drvdata(pdev, cache_sram);
+
+       return 0;
+err_out:
+       uio_infos_unregister(cache_sram);
+       return ret;
+}
+
+static int uio_fsl_85xx_cache_sram_remove(struct platform_device *pdev)
+{
+       struct uio_cache_sram *cache_sram = platform_get_drvdata(pdev);
+
+       uio_infos_unregister(cache_sram);
+
+       uio_cache_sram_destroy(cache_sram);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id uio_fsl_85xx_cache_sram_of_match[] = {
+       { /* This is filled with module_parm */ },
+       { /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, uio_fsl_85xx_cache_sram_of_match);
+
+module_param_string(of_id, uio_fsl_85xx_cache_sram_of_match[0].compatible,
+                   sizeof(uio_fsl_85xx_cache_sram_of_match[0].compatible), 0);
+MODULE_PARM_DESC(of_id, "platform device id to be handled by cache-sram-uio");
+#endif
+
+static struct platform_driver uio_fsl_85xx_cache_sram = {
+       .probe = uio_fsl_85xx_cache_sram_probe,
+       .remove = uio_fsl_85xx_cache_sram_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = 
of_match_ptr(uio_fsl_85xx_cache_sram_of_match),
+       },
+};
+
+module_platform_driver(uio_fsl_85xx_cache_sram);
+
+MODULE_AUTHOR("Wang Wenhu <wenhu.w...@vivo.com>");
+MODULE_DESCRIPTION("Freescale MPC85xx Cache-Sram UIO Platform Driver");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_LICENSE("GPL v2");
-- 
2.17.1

Reply via email to