cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rpc-if.c (3958B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Linux driver for RPC-IF HyperFlash
      4 *
      5 * Copyright (C) 2019-2020 Cogent Embedded, Inc.
      6 */
      7
      8#include <linux/err.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/mtd/hyperbus.h>
     12#include <linux/mtd/mtd.h>
     13#include <linux/mux/consumer.h>
     14#include <linux/of.h>
     15#include <linux/platform_device.h>
     16#include <linux/types.h>
     17
     18#include <memory/renesas-rpc-if.h>
     19
     20struct	rpcif_hyperbus {
     21	struct rpcif rpc;
     22	struct hyperbus_ctlr ctlr;
     23	struct hyperbus_device hbdev;
     24};
     25
     26static const struct rpcif_op rpcif_op_tmpl = {
     27	.cmd = {
     28		.buswidth = 8,
     29		.ddr = true,
     30	},
     31	.ocmd = {
     32		.buswidth = 8,
     33		.ddr = true,
     34	},
     35	.addr = {
     36		.nbytes = 1,
     37		.buswidth = 8,
     38		.ddr = true,
     39	},
     40	.data = {
     41		.buswidth = 8,
     42		.ddr = true,
     43	},
     44};
     45
     46static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
     47				  unsigned long from, ssize_t len)
     48{
     49	struct rpcif_op op = rpcif_op_tmpl;
     50
     51	op.cmd.opcode = HYPERBUS_RW_READ | HYPERBUS_AS_MEM;
     52	op.addr.val = from >> 1;
     53	op.dummy.buswidth = 1;
     54	op.dummy.ncycles = 15;
     55	op.data.dir = RPCIF_DATA_IN;
     56	op.data.nbytes = len;
     57	op.data.buf.in = to;
     58
     59	rpcif_prepare(rpc, &op, NULL, NULL);
     60}
     61
     62static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
     63				   void *from, ssize_t len)
     64{
     65	struct rpcif_op op = rpcif_op_tmpl;
     66
     67	op.cmd.opcode = HYPERBUS_RW_WRITE | HYPERBUS_AS_MEM;
     68	op.addr.val = to >> 1;
     69	op.data.dir = RPCIF_DATA_OUT;
     70	op.data.nbytes = len;
     71	op.data.buf.out = from;
     72
     73	rpcif_prepare(rpc, &op, NULL, NULL);
     74}
     75
     76static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
     77{
     78	struct rpcif_hyperbus *hyperbus =
     79		container_of(hbdev, struct rpcif_hyperbus, hbdev);
     80	map_word data;
     81
     82	rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
     83
     84	rpcif_manual_xfer(&hyperbus->rpc);
     85
     86	return data.x[0];
     87}
     88
     89static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
     90			     u16 data)
     91{
     92	struct rpcif_hyperbus *hyperbus =
     93		container_of(hbdev, struct rpcif_hyperbus, hbdev);
     94
     95	rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
     96
     97	rpcif_manual_xfer(&hyperbus->rpc);
     98}
     99
    100static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
    101			       unsigned long from, ssize_t len)
    102{
    103	struct rpcif_hyperbus *hyperbus =
    104		container_of(hbdev, struct rpcif_hyperbus, hbdev);
    105
    106	rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
    107
    108	rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
    109}
    110
    111static const struct hyperbus_ops rpcif_hb_ops = {
    112	.read16 = rpcif_hb_read16,
    113	.write16 = rpcif_hb_write16,
    114	.copy_from = rpcif_hb_copy_from,
    115};
    116
    117static int rpcif_hb_probe(struct platform_device *pdev)
    118{
    119	struct device *dev = &pdev->dev;
    120	struct rpcif_hyperbus *hyperbus;
    121	int error;
    122
    123	hyperbus = devm_kzalloc(dev, sizeof(*hyperbus), GFP_KERNEL);
    124	if (!hyperbus)
    125		return -ENOMEM;
    126
    127	error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
    128	if (error)
    129		return error;
    130
    131	platform_set_drvdata(pdev, hyperbus);
    132
    133	rpcif_enable_rpm(&hyperbus->rpc);
    134
    135	error = rpcif_hw_init(&hyperbus->rpc, true);
    136	if (error)
    137		return error;
    138
    139	hyperbus->hbdev.map.size = hyperbus->rpc.size;
    140	hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
    141
    142	hyperbus->ctlr.dev = dev;
    143	hyperbus->ctlr.ops = &rpcif_hb_ops;
    144	hyperbus->hbdev.ctlr = &hyperbus->ctlr;
    145	hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
    146	error = hyperbus_register_device(&hyperbus->hbdev);
    147	if (error)
    148		rpcif_disable_rpm(&hyperbus->rpc);
    149
    150	return error;
    151}
    152
    153static int rpcif_hb_remove(struct platform_device *pdev)
    154{
    155	struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
    156	int error = hyperbus_unregister_device(&hyperbus->hbdev);
    157
    158	rpcif_disable_rpm(&hyperbus->rpc);
    159
    160	return error;
    161}
    162
    163static struct platform_driver rpcif_platform_driver = {
    164	.probe	= rpcif_hb_probe,
    165	.remove	= rpcif_hb_remove,
    166	.driver	= {
    167		.name	= "rpc-if-hyperflash",
    168	},
    169};
    170
    171module_platform_driver(rpcif_platform_driver);
    172
    173MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
    174MODULE_LICENSE("GPL v2");