Skip to content

Commit

Permalink
ASoC: SOF: Intel: hda-mlink: fixes and extensions
Browse files Browse the repository at this point in the history
Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

With additional testing with multiple links and multiple DAI types, we
found a couple of mistakes with refcounts, base address, missing
initialization.

A new helper was also added due to a change in the SoundWire
programming sequences, with the host driver in charge of setting up
the DMA channel mapping instead of the firmware.
  • Loading branch information
Mark Brown committed May 15, 2023
2 parents 1c0d023 + ccc2f0c commit 9be0b3a
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 9 deletions.
14 changes: 14 additions & 0 deletions include/sound/hda-mlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,17 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink);

int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num);

int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
int channel_mask, int stream_id, int dir);

void hda_bus_ml_put_all(struct hdac_bus *bus);
void hda_bus_ml_reset_losidv(struct hdac_bus *bus);
int hda_bus_ml_resume(struct hdac_bus *bus);
int hda_bus_ml_suspend(struct hdac_bus *bus);

struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus);

struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid);

Expand Down Expand Up @@ -144,6 +148,13 @@ hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return
static inline int
hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { return 0; }

static inline int
hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
int channel_mask, int stream_id, int dir)
{
return 0;
}

static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { }
static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { }
static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; }
Expand All @@ -155,6 +166,9 @@ hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; }
static inline struct hdac_ext_link *
hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus) { return NULL; }

static inline struct hdac_ext_link *
hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus) { return NULL; }

static inline struct mutex *
hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid) { return NULL; }

Expand Down
96 changes: 87 additions & 9 deletions sound/soc/sof/intel/hda-mlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)

/* worst-case number of sublinks is used for sublink refcount array allocation only */
#define HDAML_MAX_SUBLINKS (AZX_ML_LCTL_CPA_SHIFT - AZX_ML_LCTL_SPA_SHIFT)

/**
* struct hdac_ext2_link - HDAudio extended+alternate link
*
Expand All @@ -33,6 +36,7 @@
* @leptr: extended link pointer
* @eml_lock: mutual exclusion to access shared registers e.g. CPA/SPA bits
* in LCTL register
* @sublink_ref_count: array of refcounts, required to power-manage sublinks independently
* @base_ptr: pointer to shim/ip/shim_vs space
* @instance_offset: offset between each of @slcount instances managed by link
* @shim_offset: offset to SHIM register base
Expand All @@ -53,6 +57,7 @@ struct hdac_ext2_link {
u32 leptr;

struct mutex eml_lock; /* prevent concurrent access to e.g. CPA/SPA */
int sublink_ref_count[HDAML_MAX_SUBLINKS];

/* internal values computed from LCAP contents */
void __iomem *base_ptr;
Expand All @@ -68,6 +73,7 @@ struct hdac_ext2_link {
#define AZX_REG_SDW_SHIM_OFFSET 0x0
#define AZX_REG_SDW_IP_OFFSET 0x100
#define AZX_REG_SDW_VS_SHIM_OFFSET 0x6000
#define AZX_REG_SDW_SHIM_PCMSyCM(y) (0x16 + 0x4 * (y))

/* only one instance supported */
#define AZX_REG_INTEL_DMIC_SHIM_OFFSET 0x0
Expand All @@ -91,7 +97,7 @@ struct hdac_ext2_link {
*/

static int hdaml_lnk_enum(struct device *dev, struct hdac_ext2_link *h2link,
void __iomem *ml_addr, int link_idx)
void __iomem *remap_addr, void __iomem *ml_addr, int link_idx)
{
struct hdac_ext_link *hlink = &h2link->hext_link;
u32 base_offset;
Expand Down Expand Up @@ -126,15 +132,16 @@ static int hdaml_lnk_enum(struct device *dev, struct hdac_ext2_link *h2link,
link_idx, h2link->slcount);

/* find IP ID and offsets */
h2link->leptr = readl(hlink->ml_addr + AZX_REG_ML_LEPTR);
h2link->leptr = readl(ml_addr + AZX_REG_ML_LEPTR);

h2link->elid = FIELD_GET(AZX_REG_ML_LEPTR_ID, h2link->leptr);

base_offset = FIELD_GET(AZX_REG_ML_LEPTR_PTR, h2link->leptr);
h2link->base_ptr = hlink->ml_addr + base_offset;
h2link->base_ptr = remap_addr + base_offset;

switch (h2link->elid) {
case AZX_REG_ML_LEPTR_ID_SDW:
h2link->instance_offset = AZX_REG_SDW_INSTANCE_OFFSET;
h2link->shim_offset = AZX_REG_SDW_SHIM_OFFSET;
h2link->ip_offset = AZX_REG_SDW_IP_OFFSET;
h2link->shim_vs_offset = AZX_REG_SDW_VS_SHIM_OFFSET;
Expand All @@ -149,6 +156,7 @@ static int hdaml_lnk_enum(struct device *dev, struct hdac_ext2_link *h2link,
link_idx, base_offset);
break;
case AZX_REG_ML_LEPTR_ID_INTEL_SSP:
h2link->instance_offset = AZX_REG_INTEL_SSP_INSTANCE_OFFSET;
h2link->shim_offset = AZX_REG_INTEL_SSP_SHIM_OFFSET;
h2link->ip_offset = AZX_REG_INTEL_SSP_IP_OFFSET;
h2link->shim_vs_offset = AZX_REG_INTEL_SSP_VS_SHIM_OFFSET;
Expand Down Expand Up @@ -333,6 +341,21 @@ static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num)
writel(val, lsdiid);
}

static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
int stream_id, int dir)
{
u16 val;

val = readw(pcmsycm);

u16p_replace_bits(&val, lchan, GENMASK(3, 0));
u16p_replace_bits(&val, hchan, GENMASK(7, 4));
u16p_replace_bits(&val, stream_id, GENMASK(13, 8));
u16p_replace_bits(&val, dir, BIT(15));

writew(val, pcmsycm);
}

static void hdaml_lctl_offload_enable(u32 __iomem *lctl, bool enable)
{
u32 val = readl(lctl);
Expand Down Expand Up @@ -364,7 +387,7 @@ static int hda_ml_alloc_h2link(struct hdac_bus *bus, int index)
hlink->bus = bus;
hlink->ml_addr = bus->mlcap + AZX_ML_BASE + (AZX_ML_INTERVAL * index);

ret = hdaml_lnk_enum(bus->dev, h2link, hlink->ml_addr, index);
ret = hdaml_lnk_enum(bus->dev, h2link, bus->remap_addr, hlink->ml_addr, index);
if (ret < 0) {
kfree(h2link);
return ret;
Expand Down Expand Up @@ -641,8 +664,13 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
if (eml_lock)
mutex_lock(&h2link->eml_lock);

if (++hlink->ref_count > 1)
goto skip_init;
if (!alt) {
if (++hlink->ref_count > 1)
goto skip_init;
} else {
if (++h2link->sublink_ref_count[sublink] > 1)
goto skip_init;
}

ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);

Expand Down Expand Up @@ -684,9 +712,13 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
if (eml_lock)
mutex_lock(&h2link->eml_lock);

if (--hlink->ref_count > 0)
goto skip_shutdown;

if (!alt) {
if (--hlink->ref_count > 0)
goto skip_shutdown;
} else {
if (--h2link->sublink_ref_count[sublink] > 0)
goto skip_shutdown;
}
ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);

skip_shutdown:
Expand Down Expand Up @@ -740,6 +772,40 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, SND_SOC_SOF_HDA_MLINK);

/*
* the 'y' parameter comes from the PCMSyCM hardware register naming. 'y' refers to the
* PDI index, i.e. the FIFO used for RX or TX
*/
int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
int channel_mask, int stream_id, int dir)
{
struct hdac_ext2_link *h2link;
u16 __iomem *pcmsycm;
u16 val;

h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
if (!h2link)
return -ENODEV;

pcmsycm = h2link->base_ptr + h2link->shim_offset +
h2link->instance_offset * sublink +
AZX_REG_SDW_SHIM_PCMSyCM(y);

mutex_lock(&h2link->eml_lock);

hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask),
stream_id, dir);

mutex_unlock(&h2link->eml_lock);

val = readw(pcmsycm);

dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
channel_mask, stream_id, dir, val);

return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);

void hda_bus_ml_put_all(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
Expand Down Expand Up @@ -836,6 +902,18 @@ struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
}
EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, SND_SOC_SOF_HDA_MLINK);

struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
{
struct hdac_ext2_link *h2link;

h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
if (!h2link)
return NULL;

return &h2link->hext_link;
}
EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, SND_SOC_SOF_HDA_MLINK);

int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
struct hdac_ext2_link *h2link;
Expand Down

0 comments on commit 9be0b3a

Please sign in to comment.