// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RPC-IF core driver
*
* Copyright (C) 2018-2019 Renesas Solutions Corp.
* Copyright (C) 2019 Macronix International Co., Ltd.
* Copyright (C) 2019-2020 Cogent Embedded, Inc.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <memory/renesas-rpc-if.h>
#include "renesas-rpc-if-regs.h"
#include "renesas-xspi-if-regs.h"
static const struct regmap_range rpcif_volatile_ranges[] = {
regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1),
regmap_reg_range(RPCIF_SMWDR0, RPCIF_SMWDR1),
regmap_reg_range(RPCIF_CMNSR, RPCIF_CMNSR),
};
static const struct regmap_access_table rpcif_volatile_table = {
.yes_ranges = rpcif_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
};
static const struct regmap_range xspi_volatile_ranges[] = {
regmap_reg_range(XSPI_CDD0BUF0, XSPI_CDD0BUF0),
};
static const struct regmap_access_table xspi_volatile_table = {
.yes_ranges = xspi_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(xspi_volatile_ranges),
};
struct rpcif_priv;
struct rpcif_impl {
int (*hw_init)(struct rpcif_priv *rpc, bool hyperflash);
void (*prepare)(struct rpcif_priv *rpc, const struct rpcif_op *op,
u64 *offs, size_t *len);
int (*manual_xfer)(struct rpcif_priv *rpc);
size_t (*dirmap_read)(struct rpcif_priv *rpc, u64 offs, size_t len,
void *buf);
u32 status_reg;
u32 status_mask;
};
struct rpcif_info {
const struct regmap_config *regmap_config;
const struct rpcif_impl *impl;
enum rpcif_type type;
u8 strtim;
};
struct rpcif_priv {
struct device *dev;
void __iomem *base;
void __iomem *dirmap;
struct regmap *regmap;
struct reset_control *rstc;
struct platform_device *vdev;
size_t size;
const struct rpcif_info *info;
enum rpcif_data_dir dir;
u8 bus_size;
u8 xfer_size;
u8 addr_nbytes; /* Specified for xSPI */
u32 proto; /* Specified for xSPI */
void *buffer;
u32 xferlen;
u32 smcr;
u32 smadr;
u32 command; /* DRCMR or SMCMR */
u32 option; /* DROPR or SMOPR */
u32 enable; /* DRENR or SMENR */
u32 dummy; /* DRDMCR or SMDMCR */
u32 ddr; /* DRDRENR or SMDRENR */
};
/*
* Custom accessor functions to ensure SM[RW]DR[01] are always accessed with
* proper width. Requires rpcif_priv.xfer_size to be correctly set before!
*/
static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct rpcif_priv *rpc = context;
switch (reg) {
case RPCIF_SMRDR0:
case RPCIF_SMWDR0:
switch (rpc->xfer_size) {
case 1:
*val = readb(rpc->base + reg);
return 0;
case 2:
*val = readw(rpc->base + reg);
return 0;
case 4:
case