memory: renesas-rpc-if: Split-off private data from struct rpcif
The rpcif structure is used as a common data structure, shared by the
RPC-IF core driver and by the HyperBus and SPI child drivers.
This poses several problems:
- Most structure members describe private core driver state, which
should not be accessible by the child drivers,
- The structure's lifetime is controlled by the child drivers,
complicating use by the core driver.
Fix this by moving the private core driver state to its own structure,
managed by the RPC-IF core driver, and store it in the core driver's
private data field. This requires absorbing the child's platform
device, as that was stored in the driver's private data field before.
Fixes: ca7d8b980b
("memory: add Renesas RPC-IF driver")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/r/09fbb6fa67d5a8cd48a08808c9afa2f6a499aa42.1669213027.git.geert+renesas@glider.be
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
This commit is contained in:
parent
1b929c02af
commit
51de3fc9a8
@ -163,14 +163,36 @@ static const struct regmap_access_table rpcif_volatile_table = {
|
|||||||
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
|
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
enum rpcif_type type;
|
||||||
|
enum rpcif_data_dir dir;
|
||||||
|
u8 bus_size;
|
||||||
|
u8 xfer_size;
|
||||||
|
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
|
* Custom accessor functions to ensure SM[RW]DR[01] are always accessed with
|
||||||
* proper width. Requires rpcif.xfer_size to be correctly set before!
|
* 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)
|
static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||||
{
|
{
|
||||||
struct rpcif *rpc = context;
|
struct rpcif_priv *rpc = context;
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case RPCIF_SMRDR0:
|
case RPCIF_SMRDR0:
|
||||||
@ -206,7 +228,7 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
|
|||||||
|
|
||||||
static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
|
static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||||
{
|
{
|
||||||
struct rpcif *rpc = context;
|
struct rpcif_priv *rpc = context;
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case RPCIF_SMWDR0:
|
case RPCIF_SMWDR0:
|
||||||
@ -253,13 +275,12 @@ static const struct regmap_config rpcif_regmap_config = {
|
|||||||
.volatile_table = &rpcif_volatile_table,
|
.volatile_table = &rpcif_volatile_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
int rpcif_sw_init(struct rpcif *rpcif, struct device *dev)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct rpcif_priv *rpc = dev_get_drvdata(dev);
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
|
||||||
rpc->dev = dev;
|
|
||||||
|
|
||||||
rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs");
|
rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs");
|
||||||
if (IS_ERR(rpc->base))
|
if (IS_ERR(rpc->base))
|
||||||
return PTR_ERR(rpc->base);
|
return PTR_ERR(rpc->base);
|
||||||
@ -280,12 +301,17 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
|||||||
|
|
||||||
rpc->type = (uintptr_t)of_device_get_match_data(dev);
|
rpc->type = (uintptr_t)of_device_get_match_data(dev);
|
||||||
rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(rpc->rstc))
|
||||||
|
return PTR_ERR(rpc->rstc);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(rpc->rstc);
|
rpcif->dev = dev;
|
||||||
|
rpcif->dirmap = rpc->dirmap;
|
||||||
|
rpcif->size = rpc->size;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_sw_init);
|
EXPORT_SYMBOL(rpcif_sw_init);
|
||||||
|
|
||||||
static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
|
static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc)
|
||||||
{
|
{
|
||||||
regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000);
|
regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000);
|
||||||
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000);
|
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000);
|
||||||
@ -299,8 +325,9 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
|
|||||||
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032);
|
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
|
int rpcif_hw_init(struct rpcif *rpcif, bool hyperflash)
|
||||||
{
|
{
|
||||||
|
struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev);
|
||||||
u32 dummy;
|
u32 dummy;
|
||||||
|
|
||||||
pm_runtime_get_sync(rpc->dev);
|
pm_runtime_get_sync(rpc->dev);
|
||||||
@ -364,7 +391,7 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_hw_init);
|
EXPORT_SYMBOL(rpcif_hw_init);
|
||||||
|
|
||||||
static int wait_msg_xfer_end(struct rpcif *rpc)
|
static int wait_msg_xfer_end(struct rpcif_priv *rpc)
|
||||||
{
|
{
|
||||||
u32 sts;
|
u32 sts;
|
||||||
|
|
||||||
@ -373,7 +400,7 @@ static int wait_msg_xfer_end(struct rpcif *rpc)
|
|||||||
USEC_PER_SEC);
|
USEC_PER_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 rpcif_bits_set(struct rpcif *rpc, u32 nbytes)
|
static u8 rpcif_bits_set(struct rpcif_priv *rpc, u32 nbytes)
|
||||||
{
|
{
|
||||||
if (rpc->bus_size == 2)
|
if (rpc->bus_size == 2)
|
||||||
nbytes /= 2;
|
nbytes /= 2;
|
||||||
@ -386,9 +413,11 @@ static u8 rpcif_bit_size(u8 buswidth)
|
|||||||
return buswidth > 4 ? 2 : ilog2(buswidth);
|
return buswidth > 4 ? 2 : ilog2(buswidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
|
void rpcif_prepare(struct rpcif *rpcif, const struct rpcif_op *op, u64 *offs,
|
||||||
size_t *len)
|
size_t *len)
|
||||||
{
|
{
|
||||||
|
struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev);
|
||||||
|
|
||||||
rpc->smcr = 0;
|
rpc->smcr = 0;
|
||||||
rpc->smadr = 0;
|
rpc->smadr = 0;
|
||||||
rpc->enable = 0;
|
rpc->enable = 0;
|
||||||
@ -472,8 +501,9 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_prepare);
|
EXPORT_SYMBOL(rpcif_prepare);
|
||||||
|
|
||||||
int rpcif_manual_xfer(struct rpcif *rpc)
|
int rpcif_manual_xfer(struct rpcif *rpcif)
|
||||||
{
|
{
|
||||||
|
struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev);
|
||||||
u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
|
u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -593,7 +623,7 @@ exit:
|
|||||||
err_out:
|
err_out:
|
||||||
if (reset_control_reset(rpc->rstc))
|
if (reset_control_reset(rpc->rstc))
|
||||||
dev_err(rpc->dev, "Failed to reset HW\n");
|
dev_err(rpc->dev, "Failed to reset HW\n");
|
||||||
rpcif_hw_init(rpc, rpc->bus_size == 2);
|
rpcif_hw_init(rpcif, rpc->bus_size == 2);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_manual_xfer);
|
EXPORT_SYMBOL(rpcif_manual_xfer);
|
||||||
@ -640,8 +670,9 @@ static void memcpy_fromio_readw(void *to,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf)
|
||||||
{
|
{
|
||||||
|
struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev);
|
||||||
loff_t from = offs & (rpc->size - 1);
|
loff_t from = offs & (rpc->size - 1);
|
||||||
size_t size = rpc->size - from;
|
size_t size = rpc->size - from;
|
||||||
|
|
||||||
@ -676,6 +707,7 @@ static int rpcif_probe(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct platform_device *vdev;
|
struct platform_device *vdev;
|
||||||
struct device_node *flash;
|
struct device_node *flash;
|
||||||
|
struct rpcif_priv *rpc;
|
||||||
const char *name;
|
const char *name;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -696,11 +728,18 @@ static int rpcif_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
of_node_put(flash);
|
of_node_put(flash);
|
||||||
|
|
||||||
|
rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL);
|
||||||
|
if (!rpc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
vdev = platform_device_alloc(name, pdev->id);
|
vdev = platform_device_alloc(name, pdev->id);
|
||||||
if (!vdev)
|
if (!vdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
vdev->dev.parent = &pdev->dev;
|
vdev->dev.parent = &pdev->dev;
|
||||||
platform_set_drvdata(pdev, vdev);
|
|
||||||
|
rpc->dev = &pdev->dev;
|
||||||
|
rpc->vdev = vdev;
|
||||||
|
platform_set_drvdata(pdev, rpc);
|
||||||
|
|
||||||
ret = platform_device_add(vdev);
|
ret = platform_device_add(vdev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -713,9 +752,9 @@ static int rpcif_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
static int rpcif_remove(struct platform_device *pdev)
|
static int rpcif_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct platform_device *vdev = platform_get_drvdata(pdev);
|
struct rpcif_priv *rpc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
platform_device_unregister(vdev);
|
platform_device_unregister(rpc->vdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -65,24 +65,8 @@ enum rpcif_type {
|
|||||||
|
|
||||||
struct rpcif {
|
struct rpcif {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
|
||||||
void __iomem *dirmap;
|
void __iomem *dirmap;
|
||||||
struct regmap *regmap;
|
|
||||||
struct reset_control *rstc;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
enum rpcif_type type;
|
|
||||||
enum rpcif_data_dir dir;
|
|
||||||
u8 bus_size;
|
|
||||||
u8 xfer_size;
|
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int rpcif_sw_init(struct rpcif *rpc, struct device *dev);
|
int rpcif_sw_init(struct rpcif *rpc, struct device *dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user