mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
Allwinner driver changes for 7.2
Mostly changes to the SRAM driver to allow for one SRAM region to be "claimed" by multiple changes. When a region is "claimed" it is removed or disconnected from the CPU's view. This is needed on the H6 and H616, which have one alias region seemingly shared between the video codec engine and the display engine. One minor fix for the RSB driver is also included. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE2nN1m/hhnkhOWjtHOJpUIZwPJDAFAmod2AsQHHdlbnNAa2Vy bmVsLm9yZwAKCRA4mlQhnA8kMCUND/4h+xocrSMz4T+gHAvffsGItDQrtyLreXem GNIdY7whCRo+6KgipnTgXtvqRCzBhiQx9PYM3BTLNLUCURdM0NAcooE/f1kidVOI BHOTvfX1cy9eoGVJpZnfMAdMT/MlIw6LC7C1n1y8H14q1ERWkAOeO+k1VE9lMbIj jI9YWCFPvq29F+gEZAlCZXZnMWkgrJiLixnVYyi32P1k/u3ykqoNx7TKHWPsWaj5 /lS22YJUkcf0ARAJhcTElxYLytuhUCE68KKYVD7cN8uojebbcTAJLSkO7INtEdD/ USkY5sdq1cmDQ42ejgSPkcaL3etwBAha1NceKFLEAYVto6GUziOmXaGw8TLJVMD7 8ILjzOVj28iUADqy43tvwkqzDNDgn1xy+wmZSiSb6b9N+htDNKHh37R8NeJd0EwY 8YC/r5H5JqwBFQ0PWXHnjeFNlp6lBZ3G/QWU9ztnsCaDKp8P4jtl8wCF843lACtj BKPFCQ/+dkAlxExClaUo1JewJqhjyghpLmoWRMy/azbkdx7B100hH3DabAicN7JH 1lJ+rvIgTmmlwmGYceQ6sdg//M1b+3emTQ2kX3cgPCra8srKnp5ZkJzwtK0J9OHv XEFzB9rtvBPYvKt0dk/eaQAKAZIq82j9vdrtMzI1A5LeUF3VMEr7BxXxplBdwAH6 TSIElm0ktA== =n5X7 -----END PGP SIGNATURE----- Merge tag 'sunxi-drivers-for-7.2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into soc/drivers Allwinner driver changes for 7.2 Mostly changes to the SRAM driver to allow for one SRAM region to be "claimed" by multiple changes. When a region is "claimed" it is removed or disconnected from the CPU's view. This is needed on the H6 and H616, which have one alias region seemingly shared between the video codec engine and the display engine. One minor fix for the RSB driver is also included. * tag 'sunxi-drivers-for-7.2' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sunxi/linux: bus: sunxi-rsb: Always check register address validity soc: sunxi: sram: Add H616 SRAM regions soc: sunxi: sram: Support claiming multiple regions per device soc: sunxi: sram: Allow SRAM to be claimed multiple times soc: sunxi: sram: Const-ify sunxi_sram_func data and references dt-bindings: sram: sunxi-sram: Add H616 SRAM regions dt-bindings: sram: Document Allwinner H616 VE SRAM Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
This commit is contained in:
commit
a68c459ac6
|
|
@ -80,6 +80,7 @@ patternProperties:
|
|||
- const: allwinner,sun4i-a10-sram-c1
|
||||
- const: allwinner,sun4i-a10-sram-d
|
||||
- const: allwinner,sun50i-a64-sram-c
|
||||
- const: allwinner,sun50i-h616-ve-sram
|
||||
- items:
|
||||
- enum:
|
||||
- allwinner,sun5i-a13-sram-a3-a4
|
||||
|
|
@ -103,7 +104,9 @@ patternProperties:
|
|||
- allwinner,sun7i-a20-sram-d
|
||||
- const: allwinner,sun4i-a10-sram-d
|
||||
- items:
|
||||
- const: allwinner,sun50i-h6-sram-c
|
||||
- enum:
|
||||
- allwinner,sun50i-h6-sram-c
|
||||
- allwinner,sun50i-h616-sram-c
|
||||
- const: allwinner,sun50i-a64-sram-c
|
||||
|
||||
required:
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ patternProperties:
|
|||
- allwinner,sun4i-a10-sram-d
|
||||
- allwinner,sun9i-a80-smp-sram
|
||||
- allwinner,sun50i-a64-sram-c
|
||||
- allwinner,sun50i-h616-ve-sram
|
||||
- amlogic,meson8-ao-arc-sram
|
||||
- amlogic,meson8b-ao-arc-sram
|
||||
- amlogic,meson8-smp-sram
|
||||
|
|
|
|||
|
|
@ -445,6 +445,9 @@ static int regmap_sunxi_rsb_reg_write(void *context, unsigned int reg,
|
|||
struct sunxi_rsb_ctx *ctx = context;
|
||||
struct sunxi_rsb_device *rdev = ctx->rdev;
|
||||
|
||||
if (reg > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -29,16 +30,16 @@ struct sunxi_sram_func {
|
|||
};
|
||||
|
||||
struct sunxi_sram_data {
|
||||
char *name;
|
||||
u8 reg;
|
||||
u8 offset;
|
||||
u8 width;
|
||||
struct sunxi_sram_func *func;
|
||||
char *name;
|
||||
u8 reg;
|
||||
u8 offset;
|
||||
u8 width;
|
||||
const struct sunxi_sram_func *func;
|
||||
};
|
||||
|
||||
struct sunxi_sram_desc {
|
||||
struct sunxi_sram_data data;
|
||||
bool claimed;
|
||||
u8 claim_cnt;
|
||||
};
|
||||
|
||||
#define SUNXI_SRAM_MAP(_reg_val, _val, _func) \
|
||||
|
|
@ -54,7 +55,7 @@ struct sunxi_sram_desc {
|
|||
.reg = _reg, \
|
||||
.offset = _off, \
|
||||
.width = _width, \
|
||||
.func = (struct sunxi_sram_func[]){ \
|
||||
.func = (const struct sunxi_sram_func[]){ \
|
||||
__VA_ARGS__, { } }, \
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +83,12 @@ static struct sunxi_sram_desc sun50i_a64_sram_c = {
|
|||
SUNXI_SRAM_MAP(0, 1, "de2")),
|
||||
};
|
||||
|
||||
static struct sunxi_sram_desc sun50i_h616_ve_sram = {
|
||||
.data = SUNXI_SRAM_DATA("VE", 0x0, 0, 1,
|
||||
SUNXI_SRAM_MAP(1, 0, "cpu"),
|
||||
SUNXI_SRAM_MAP(0, 1, "ve")),
|
||||
};
|
||||
|
||||
static const struct of_device_id sunxi_sram_dt_ids[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun4i-a10-sram-a3-a4",
|
||||
|
|
@ -99,6 +106,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
|
|||
.compatible = "allwinner,sun50i-a64-sram-c",
|
||||
.data = &sun50i_a64_sram_c.data,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun50i-h616-ve-sram",
|
||||
.data = &sun50i_h616_ve_sram.data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -111,7 +122,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
|
|||
struct device_node *sram_node, *section_node;
|
||||
const struct sunxi_sram_data *sram_data;
|
||||
const struct of_device_id *match;
|
||||
struct sunxi_sram_func *func;
|
||||
const struct sunxi_sram_func *func;
|
||||
const __be32 *sram_addr_p, *section_addr_p;
|
||||
u32 val;
|
||||
|
||||
|
|
@ -164,69 +175,97 @@ static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data
|
|||
return container_of(data, struct sunxi_sram_desc, data);
|
||||
}
|
||||
|
||||
static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
|
||||
unsigned int *reg_value)
|
||||
static const struct sunxi_sram_data *sunxi_sram_get_match(struct device_node *np, u8 val,
|
||||
unsigned int *reg_value)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
const struct sunxi_sram_data *data;
|
||||
struct sunxi_sram_func *func;
|
||||
struct of_phandle_args args;
|
||||
u8 val;
|
||||
int ret;
|
||||
const struct sunxi_sram_func *func;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
|
||||
&args);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
if (!of_device_is_available(np))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (!of_device_is_available(args.np)) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
val = args.args[0];
|
||||
|
||||
match = of_match_node(sunxi_sram_dt_ids, args.np);
|
||||
if (!match) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
match = of_match_node(sunxi_sram_dt_ids, np);
|
||||
if (!match)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
data = match->data;
|
||||
if (!data) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (func = data->func; func->func; func++) {
|
||||
if (val == func->val) {
|
||||
if (reg_value)
|
||||
*reg_value = func->reg_val;
|
||||
if (!data)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
for (func = data->func; func->func; func++)
|
||||
if (val == func->val)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!func->func) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (!func->func)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
of_node_put(args.np);
|
||||
return match->data;
|
||||
if (reg_value)
|
||||
*reg_value = func->reg_val;
|
||||
|
||||
err:
|
||||
of_node_put(args.np);
|
||||
return ERR_PTR(ret);
|
||||
return data;
|
||||
}
|
||||
|
||||
int sunxi_sram_claim(struct device *dev)
|
||||
#define SUNXI_SRAM_PROP "allwinner,sram"
|
||||
#define SUNXI_SRAM_CELLS 1
|
||||
|
||||
static int sunxi_sram_claim_one(struct device_node *np, u8 arg)
|
||||
{
|
||||
const struct sunxi_sram_data *sram_data;
|
||||
struct sunxi_sram_desc *sram_desc;
|
||||
unsigned int device;
|
||||
u32 val, mask;
|
||||
|
||||
sram_data = sunxi_sram_get_match(np, arg, &device);
|
||||
if (IS_ERR(sram_data))
|
||||
return PTR_ERR(sram_data);
|
||||
|
||||
sram_desc = to_sram_desc(sram_data);
|
||||
|
||||
spin_lock(&sram_lock);
|
||||
|
||||
if (sram_desc->claim_cnt) {
|
||||
if (!WARN_ON(sram_desc->claim_cnt == U8_MAX))
|
||||
sram_desc->claim_cnt++;
|
||||
} else {
|
||||
mask = GENMASK(sram_data->offset + sram_data->width - 1,
|
||||
sram_data->offset);
|
||||
val = readl(base + sram_data->reg);
|
||||
val &= ~mask;
|
||||
writel(val | ((device << sram_data->offset) & mask),
|
||||
base + sram_data->reg);
|
||||
|
||||
sram_desc->claim_cnt++;
|
||||
}
|
||||
|
||||
spin_unlock(&sram_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sunxi_sram_release_one(struct device_node *np, u8 arg)
|
||||
{
|
||||
const struct sunxi_sram_data *sram_data;
|
||||
struct sunxi_sram_desc *sram_desc;
|
||||
|
||||
sram_data = sunxi_sram_get_match(np, arg, NULL);
|
||||
if (IS_ERR(sram_data))
|
||||
return;
|
||||
|
||||
sram_desc = to_sram_desc(sram_data);
|
||||
|
||||
spin_lock(&sram_lock);
|
||||
if (!WARN_ON(sram_desc->claim_cnt == 0))
|
||||
sram_desc->claim_cnt--;
|
||||
spin_unlock(&sram_lock);
|
||||
}
|
||||
|
||||
int sunxi_sram_claim(struct device *dev)
|
||||
{
|
||||
struct of_phandle_iterator it;
|
||||
int err;
|
||||
int count = 0;
|
||||
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
|
@ -236,50 +275,53 @@ int sunxi_sram_claim(struct device *dev)
|
|||
if (!dev || !dev->of_node)
|
||||
return -EINVAL;
|
||||
|
||||
sram_data = sunxi_sram_of_parse(dev->of_node, &device);
|
||||
if (IS_ERR(sram_data))
|
||||
return PTR_ERR(sram_data);
|
||||
of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
|
||||
NULL, SUNXI_SRAM_CELLS) {
|
||||
u32 args[SUNXI_SRAM_CELLS];
|
||||
|
||||
sram_desc = to_sram_desc(sram_data);
|
||||
of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
|
||||
|
||||
spin_lock(&sram_lock);
|
||||
err = sunxi_sram_claim_one(it.node, args[0]);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
if (sram_desc->claimed) {
|
||||
spin_unlock(&sram_lock);
|
||||
return -EBUSY;
|
||||
count++;
|
||||
}
|
||||
|
||||
mask = GENMASK(sram_data->offset + sram_data->width - 1,
|
||||
sram_data->offset);
|
||||
val = readl(base + sram_data->reg);
|
||||
val &= ~mask;
|
||||
writel(val | ((device << sram_data->offset) & mask),
|
||||
base + sram_data->reg);
|
||||
|
||||
sram_desc->claimed = true;
|
||||
spin_unlock(&sram_lock);
|
||||
if (count == 0)
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
while (count--) {
|
||||
struct of_phandle_args args;
|
||||
|
||||
of_parse_phandle_with_fixed_args(dev->of_node, SUNXI_SRAM_PROP,
|
||||
SUNXI_SRAM_CELLS, count, &args);
|
||||
sunxi_sram_release_one(args.np, args.args[0]);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(sunxi_sram_claim);
|
||||
|
||||
void sunxi_sram_release(struct device *dev)
|
||||
{
|
||||
const struct sunxi_sram_data *sram_data;
|
||||
struct sunxi_sram_desc *sram_desc;
|
||||
struct of_phandle_iterator it;
|
||||
int err;
|
||||
|
||||
if (!dev || !dev->of_node)
|
||||
return;
|
||||
|
||||
sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
|
||||
if (IS_ERR(sram_data))
|
||||
return;
|
||||
of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP,
|
||||
NULL, SUNXI_SRAM_CELLS) {
|
||||
u32 args[SUNXI_SRAM_CELLS];
|
||||
|
||||
sram_desc = to_sram_desc(sram_data);
|
||||
of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS);
|
||||
|
||||
spin_lock(&sram_lock);
|
||||
sram_desc->claimed = false;
|
||||
spin_unlock(&sram_lock);
|
||||
sunxi_sram_release_one(it.node, args[0]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(sunxi_sram_release);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user