Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Linux driver for RPC-IF HyperFlash
0004  *
0005  * Copyright (C) 2019-2020 Cogent Embedded, Inc.
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/mtd/hyperbus.h>
0012 #include <linux/mtd/mtd.h>
0013 #include <linux/mux/consumer.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/types.h>
0017 
0018 #include <memory/renesas-rpc-if.h>
0019 
0020 struct  rpcif_hyperbus {
0021     struct rpcif rpc;
0022     struct hyperbus_ctlr ctlr;
0023     struct hyperbus_device hbdev;
0024 };
0025 
0026 static const struct rpcif_op rpcif_op_tmpl = {
0027     .cmd = {
0028         .buswidth = 8,
0029         .ddr = true,
0030     },
0031     .ocmd = {
0032         .buswidth = 8,
0033         .ddr = true,
0034     },
0035     .addr = {
0036         .nbytes = 1,
0037         .buswidth = 8,
0038         .ddr = true,
0039     },
0040     .data = {
0041         .buswidth = 8,
0042         .ddr = true,
0043     },
0044 };
0045 
0046 static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
0047                   unsigned long from, ssize_t len)
0048 {
0049     struct rpcif_op op = rpcif_op_tmpl;
0050 
0051     op.cmd.opcode = HYPERBUS_RW_READ | HYPERBUS_AS_MEM;
0052     op.addr.val = from >> 1;
0053     op.dummy.buswidth = 1;
0054     op.dummy.ncycles = 15;
0055     op.data.dir = RPCIF_DATA_IN;
0056     op.data.nbytes = len;
0057     op.data.buf.in = to;
0058 
0059     rpcif_prepare(rpc, &op, NULL, NULL);
0060 }
0061 
0062 static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
0063                    void *from, ssize_t len)
0064 {
0065     struct rpcif_op op = rpcif_op_tmpl;
0066 
0067     op.cmd.opcode = HYPERBUS_RW_WRITE | HYPERBUS_AS_MEM;
0068     op.addr.val = to >> 1;
0069     op.data.dir = RPCIF_DATA_OUT;
0070     op.data.nbytes = len;
0071     op.data.buf.out = from;
0072 
0073     rpcif_prepare(rpc, &op, NULL, NULL);
0074 }
0075 
0076 static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
0077 {
0078     struct rpcif_hyperbus *hyperbus =
0079         container_of(hbdev, struct rpcif_hyperbus, hbdev);
0080     map_word data;
0081 
0082     rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
0083 
0084     rpcif_manual_xfer(&hyperbus->rpc);
0085 
0086     return data.x[0];
0087 }
0088 
0089 static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
0090                  u16 data)
0091 {
0092     struct rpcif_hyperbus *hyperbus =
0093         container_of(hbdev, struct rpcif_hyperbus, hbdev);
0094 
0095     rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
0096 
0097     rpcif_manual_xfer(&hyperbus->rpc);
0098 }
0099 
0100 static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
0101                    unsigned long from, ssize_t len)
0102 {
0103     struct rpcif_hyperbus *hyperbus =
0104         container_of(hbdev, struct rpcif_hyperbus, hbdev);
0105 
0106     rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
0107 
0108     rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
0109 }
0110 
0111 static const struct hyperbus_ops rpcif_hb_ops = {
0112     .read16 = rpcif_hb_read16,
0113     .write16 = rpcif_hb_write16,
0114     .copy_from = rpcif_hb_copy_from,
0115 };
0116 
0117 static int rpcif_hb_probe(struct platform_device *pdev)
0118 {
0119     struct device *dev = &pdev->dev;
0120     struct rpcif_hyperbus *hyperbus;
0121     int error;
0122 
0123     hyperbus = devm_kzalloc(dev, sizeof(*hyperbus), GFP_KERNEL);
0124     if (!hyperbus)
0125         return -ENOMEM;
0126 
0127     error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
0128     if (error)
0129         return error;
0130 
0131     platform_set_drvdata(pdev, hyperbus);
0132 
0133     rpcif_enable_rpm(&hyperbus->rpc);
0134 
0135     error = rpcif_hw_init(&hyperbus->rpc, true);
0136     if (error)
0137         goto out_disable_rpm;
0138 
0139     hyperbus->hbdev.map.size = hyperbus->rpc.size;
0140     hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
0141 
0142     hyperbus->ctlr.dev = dev;
0143     hyperbus->ctlr.ops = &rpcif_hb_ops;
0144     hyperbus->hbdev.ctlr = &hyperbus->ctlr;
0145     hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
0146     error = hyperbus_register_device(&hyperbus->hbdev);
0147     if (error)
0148         goto out_disable_rpm;
0149 
0150     return 0;
0151 
0152 out_disable_rpm:
0153     rpcif_disable_rpm(&hyperbus->rpc);
0154     return error;
0155 }
0156 
0157 static int rpcif_hb_remove(struct platform_device *pdev)
0158 {
0159     struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
0160 
0161     hyperbus_unregister_device(&hyperbus->hbdev);
0162 
0163     rpcif_disable_rpm(&hyperbus->rpc);
0164 
0165     return 0;
0166 }
0167 
0168 static struct platform_driver rpcif_platform_driver = {
0169     .probe  = rpcif_hb_probe,
0170     .remove = rpcif_hb_remove,
0171     .driver = {
0172         .name   = "rpc-if-hyperflash",
0173     },
0174 };
0175 
0176 module_platform_driver(rpcif_platform_driver);
0177 
0178 MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
0179 MODULE_LICENSE("GPL v2");