Skip to content

Commit 5de15b6

Browse files
Sergei Shtylyovr-vignesh
authored andcommitted
mtd: hyperbus: add Renesas RPC-IF driver
Add the HyperFLash driver for the Renesas RPC-IF. It's the "front end" driver using the "back end" APIs in the main driver to talk to the real hardware. Signed-off-by: Sergei Shtylyov <[email protected]> Signed-off-by: Vignesh Raghavendra <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 00c9cf4 commit 5de15b6

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

drivers/mtd/hyperbus/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,11 @@ config HBMC_AM654
2222
This is the driver for HyperBus controller on TI's AM65x and
2323
other SoCs
2424

25+
config RPCIF_HYPERBUS
26+
tristate "Renesas RPC-IF HyperBus driver"
27+
depends on RENESAS_RPCIF || COMPILE_TEST
28+
depends on MTD_CFI_BE_BYTE_SWAP
29+
help
30+
This option includes Renesas RPC-IF HyperBus support.
31+
2532
endif # MTD_HYPERBUS

drivers/mtd/hyperbus/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
obj-$(CONFIG_MTD_HYPERBUS) += hyperbus-core.o
44
obj-$(CONFIG_HBMC_AM654) += hbmc-am654.o
5+
obj-$(CONFIG_RPCIF_HYPERBUS) += rpc-if.o

drivers/mtd/hyperbus/rpc-if.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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+
20+
struct rpcif_hyperbus {
21+
struct rpcif rpc;
22+
struct hyperbus_ctlr ctlr;
23+
struct hyperbus_device hbdev;
24+
};
25+
26+
static 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+
46+
static 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+
62+
static 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+
76+
static 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+
89+
static 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+
100+
static 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+
111+
static 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+
117+
static 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+
rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
128+
129+
platform_set_drvdata(pdev, hyperbus);
130+
131+
rpcif_enable_rpm(&hyperbus->rpc);
132+
133+
rpcif_hw_init(&hyperbus->rpc, true);
134+
135+
hyperbus->hbdev.map.size = hyperbus->rpc.size;
136+
hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
137+
138+
hyperbus->ctlr.dev = dev;
139+
hyperbus->ctlr.ops = &rpcif_hb_ops;
140+
hyperbus->hbdev.ctlr = &hyperbus->ctlr;
141+
hyperbus->hbdev.np = of_get_next_child(pdev->dev.parent->of_node, NULL);
142+
error = hyperbus_register_device(&hyperbus->hbdev);
143+
if (error)
144+
rpcif_disable_rpm(&hyperbus->rpc);
145+
146+
return error;
147+
}
148+
149+
static int rpcif_hb_remove(struct platform_device *pdev)
150+
{
151+
struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
152+
int error = hyperbus_unregister_device(&hyperbus->hbdev);
153+
struct rpcif *rpc = dev_get_drvdata(pdev->dev.parent);
154+
155+
rpcif_disable_rpm(rpc);
156+
return error;
157+
}
158+
159+
static struct platform_driver rpcif_platform_driver = {
160+
.probe = rpcif_hb_probe,
161+
.remove = rpcif_hb_remove,
162+
.driver = {
163+
.name = "rpc-if-hyperflash",
164+
},
165+
};
166+
167+
module_platform_driver(rpcif_platform_driver);
168+
169+
MODULE_DESCRIPTION("Renesas RPC-IF HyperFlash driver");
170+
MODULE_LICENSE("GPL v2");

include/linux/mtd/hyperbus.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88

99
#include <linux/mtd/map.h>
1010

11+
/* HyperBus command bits */
12+
#define HYPERBUS_RW 0x80 /* R/W# */
13+
#define HYPERBUS_RW_WRITE 0
14+
#define HYPERBUS_RW_READ 0x80
15+
#define HYPERBUS_AS 0x40 /* Address Space */
16+
#define HYPERBUS_AS_MEM 0
17+
#define HYPERBUS_AS_REG 0x40
18+
#define HYPERBUS_BT 0x20 /* Burst Type */
19+
#define HYPERBUS_BT_WRAPPED 0
20+
#define HYPERBUS_BT_LINEAR 0x20
21+
1122
enum hyperbus_memtype {
1223
HYPERFLASH,
1324
HYPERRAM,

0 commit comments

Comments
 (0)