mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
dmaengine: ste_dma40: Fix V4B event group mapping
DMA40 physical resources are connected in pairs to event groups. The
mapping repeats after each complete set of groups.
D40_GROUP_SIZE and D40_PHYS_TO_GROUP() encode the four-group V4A layout.
On V4B, which has five groups, resources 8 and 9 are consequently offered
both to event groups 0 and 4. The GCC clock bookkeeping also treats these
resources as group 0 instead of group 4.
Derive the physical-resource stride and reverse mapping from the
variant-specific number of event groups. This preserves the V4A mapping
and gives V4B a ten-resource stride: resources 8 and 9 belong only to
group 4, while resources 10 and 11 repeat group 0.
Fixes: 3cb645dc85 ("dmaengine: ste_dma40: support more than 128 event lines")
Assisted-by: LLM
Signed-off-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260927-dma40-fixes-v7-21-89f595e8851d@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
e66a9dbe04
commit
b36f8fce73
|
|
@ -85,6 +85,7 @@ struct stedma40_platform_data {
|
|||
/* Number of event groups per hardware register layout */
|
||||
#define D40_EVENT_GROUPS_V4A 4
|
||||
#define D40_EVENT_GROUPS_V4B 5
|
||||
#define D40_PHYS_PER_EVENT_GROUP 2
|
||||
|
||||
/* Max number of logical channels per physical channel */
|
||||
#define D40_MAX_LOG_CHAN_PER_PHY 32
|
||||
|
|
@ -2022,6 +2023,12 @@ static bool d40_alloc_mask_free(struct d40_phy_res *phy, bool is_src,
|
|||
return is_free;
|
||||
}
|
||||
|
||||
static int d40_phy_to_group(struct d40_base *base, int phy)
|
||||
{
|
||||
return (phy / D40_PHYS_PER_EVENT_GROUP) %
|
||||
base->gen_dmac.num_event_groups;
|
||||
}
|
||||
|
||||
static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
|
||||
{
|
||||
int dev_type = d40c->dma_cfg.dev_type;
|
||||
|
|
@ -2032,11 +2039,14 @@ static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
|
|||
int j;
|
||||
int log_num;
|
||||
int num_phy_chans;
|
||||
int phy_group_stride;
|
||||
bool is_src;
|
||||
bool is_log = d40c->dma_cfg.mode == STEDMA40_MODE_LOGICAL;
|
||||
|
||||
phys = d40c->base->phy_res;
|
||||
num_phy_chans = d40c->base->num_phy_chans;
|
||||
phy_group_stride = D40_PHYS_PER_EVENT_GROUP *
|
||||
d40c->base->gen_dmac.num_event_groups;
|
||||
|
||||
if (d40c->dma_cfg.dir == DMA_DEV_TO_MEM) {
|
||||
log_num = 2 * dev_type;
|
||||
|
|
@ -2070,13 +2080,18 @@ static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
|
|||
}
|
||||
}
|
||||
} else
|
||||
for (j = 0; j < d40c->base->num_phy_chans;
|
||||
j += D40_GROUP_SIZE) {
|
||||
int phy_num = j + event_group * 2;
|
||||
if (phy_num + 1 >= num_phy_chans)
|
||||
for (j = 0; j < num_phy_chans;
|
||||
j += phy_group_stride) {
|
||||
int phy_num = j + event_group *
|
||||
D40_PHYS_PER_EVENT_GROUP;
|
||||
|
||||
if (phy_num + D40_PHYS_PER_EVENT_GROUP >
|
||||
num_phy_chans)
|
||||
break;
|
||||
|
||||
for (i = phy_num; i < phy_num + 2; i++) {
|
||||
for (i = phy_num;
|
||||
i < phy_num + D40_PHYS_PER_EVENT_GROUP;
|
||||
i++) {
|
||||
if (d40_alloc_mask_set(&phys[i],
|
||||
is_src,
|
||||
0,
|
||||
|
|
@ -2095,9 +2110,10 @@ static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
|
|||
return -EINVAL;
|
||||
|
||||
/* Find logical channel */
|
||||
for (j = 0; j < d40c->base->num_phy_chans; j += D40_GROUP_SIZE) {
|
||||
int phy_num = j + event_group * 2;
|
||||
if (phy_num + 1 >= num_phy_chans)
|
||||
for (j = 0; j < num_phy_chans; j += phy_group_stride) {
|
||||
int phy_num = j + event_group * D40_PHYS_PER_EVENT_GROUP;
|
||||
|
||||
if (phy_num + D40_PHYS_PER_EVENT_GROUP > num_phy_chans)
|
||||
break;
|
||||
|
||||
if (d40c->dma_cfg.use_fixed_channel) {
|
||||
|
|
@ -2124,14 +2140,17 @@ static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
|
|||
* channels.
|
||||
*/
|
||||
if (is_src) {
|
||||
for (i = phy_num; i < phy_num + 2; i++) {
|
||||
for (i = phy_num;
|
||||
i < phy_num + D40_PHYS_PER_EVENT_GROUP;
|
||||
i++) {
|
||||
if (d40_alloc_mask_set(&phys[i], is_src,
|
||||
event_line, is_log,
|
||||
first_phy_user))
|
||||
goto found_log;
|
||||
}
|
||||
} else {
|
||||
for (i = phy_num + 1; i >= phy_num; i--) {
|
||||
for (i = phy_num + D40_PHYS_PER_EVENT_GROUP - 1;
|
||||
i >= phy_num; i--) {
|
||||
if (d40_alloc_mask_set(&phys[i], is_src,
|
||||
event_line, is_log,
|
||||
first_phy_user))
|
||||
|
|
@ -3302,9 +3321,9 @@ static int __init d40_phy_res_init(struct d40_base *base)
|
|||
base->phy_res[i].allocated_src = D40_ALLOC_PHY;
|
||||
base->phy_res[i].allocated_dst = D40_ALLOC_PHY;
|
||||
base->phy_res[i].reserved = true;
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(d40_phy_to_group(base, i),
|
||||
D40_DREG_GCC_SRC);
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(d40_phy_to_group(base, i),
|
||||
D40_DREG_GCC_DST);
|
||||
|
||||
|
||||
|
|
@ -3324,9 +3343,9 @@ static int __init d40_phy_res_init(struct d40_base *base)
|
|||
base->phy_res[chan].allocated_src = D40_ALLOC_PHY;
|
||||
base->phy_res[chan].allocated_dst = D40_ALLOC_PHY;
|
||||
base->phy_res[chan].reserved = true;
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan),
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(d40_phy_to_group(base, chan),
|
||||
D40_DREG_GCC_SRC);
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan),
|
||||
gcc |= D40_DREG_GCC_EVTGRP_ENA(d40_phy_to_group(base, chan),
|
||||
D40_DREG_GCC_DST);
|
||||
num_phy_chans_avail--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
#define D40_TYPE_TO_GROUP(type) (type / 16)
|
||||
#define D40_TYPE_TO_EVENT(type) (type % 16)
|
||||
#define D40_GROUP_SIZE 8
|
||||
#define D40_PHYS_TO_GROUP(phys) ((phys & (D40_GROUP_SIZE - 1)) / 2)
|
||||
|
||||
/* Most bits of the CFG register are the same in log as in phy mode */
|
||||
#define D40_SREG_CFG_MST_POS 15
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user