Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ properties:
- qcom,sm8450-lpass-rx-macro
- qcom,sm8550-lpass-rx-macro
- qcom,sc8280xp-lpass-rx-macro
- qcom,shikra-lpass-rx-macro
- items:
- enum:
- qcom,kaanapali-lpass-rx-macro
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ properties:
- qcom,sm8450-lpass-va-macro
- qcom,sm8550-lpass-va-macro
- qcom,sc8280xp-lpass-va-macro
- qcom,shikra-lpass-va-macro
- items:
- enum:
- qcom,glymur-lpass-va-macro
Expand Down
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ properties:
- qcom,sdm845-sndcard
- qcom,sm8250-sndcard
- qcom,sm8450-sndcard
- qcom,shikra-sndcard
- qcom,x1e80100-sndcard

audio-routing:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ properties:
maximum: 4
- const: 0xff

qcom,swr-master-ee-val:
$ref: /schemas/types.yaml#/definitions/uint8-array
description:
Execution-environment value used to route SoundWire master
interrupts to CPU0 or CPU1.

label:
maxItems: 1

Expand Down
103 changes: 77 additions & 26 deletions drivers/soundwire/qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define SWRM_COMP_STATUS 0x014
#define SWRM_LINK_MANAGER_EE 0x018
#define SWRM_EE_CPU 1
#define SWRM_MAX_EE 1
#define SWRM_FRM_GEN_ENABLED BIT(0)
#define SWRM_VERSION_1_3_0 0x01030000
#define SWRM_VERSION_1_5_1 0x01050001
Expand Down Expand Up @@ -118,6 +119,7 @@
#define SWRM_V2_0_CLK_CTRL 0x5060
#define SWRM_V2_0_CLK_CTRL_CLK_START BIT(0)
#define SWRM_V2_0_LINK_STATUS 0x5064
#define SWRM_V2_REG_EE_STRIDE 0x1000

#define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
#define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
Expand Down Expand Up @@ -202,6 +204,7 @@ struct qcom_swrm_ctrl {
struct mutex port_lock;
struct clk *hclk;
int irq;
u32 ee;
unsigned int version;
int wake_irq;
int num_din_ports;
Expand All @@ -222,6 +225,7 @@ struct qcom_swrm_ctrl {
u32 slave_status;
u32 wr_fifo_depth;
bool clock_stop_not_supported;
unsigned int reg_layout_local[SWRM_OFFSET_DP_SAMPLECTRL2_BANK + 1];
};

struct qcom_swrm_data {
Expand Down Expand Up @@ -328,6 +332,36 @@ static const struct qcom_swrm_data swrm_v3_0_data = {
};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)

static void qcom_swrm_set_ee_register_layout(struct qcom_swrm_ctrl *ctrl,
const struct qcom_swrm_data *data)
{
int ee_offset;

memcpy(ctrl->reg_layout_local, data->reg_layout,
sizeof(ctrl->reg_layout_local));
ctrl->reg_layout = ctrl->reg_layout_local;

if (ctrl->version < SWRM_VERSION_2_0_0)
return;

/*
* Current register constants map EE1. For EE0, use the EE register
* window stride to access status/IRQ/FIFO registers.
*/
ee_offset = ((int)ctrl->ee - SWRM_EE_CPU) * SWRM_V2_REG_EE_STRIDE;
if (!ee_offset)
return;

ctrl->reg_layout_local[SWRM_REG_FRAME_GEN_ENABLED] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_INTERRUPT_STATUS] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_INTERRUPT_CLEAR] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_INTERRUPT_CPU_EN] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_CMD_FIFO_WR_CMD] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_CMD_FIFO_RD_CMD] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_CMD_FIFO_STATUS] += ee_offset;
ctrl->reg_layout_local[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] += ee_offset;
}

static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
u32 *val)
{
Expand Down Expand Up @@ -904,12 +938,13 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);

if (ctrl->version == SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, ctrl->ee);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU);
SWRM_MCP_BUS_CLK_START << ctrl->ee);
} else if (ctrl->version >= SWRM_VERSION_2_0_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_V2_0_CLK_CTRL,
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, ctrl->ee);
ctrl->reg_write(ctrl, SWRM_V2_0_CLK_CTRL +
((int)ctrl->ee - SWRM_EE_CPU) * SWRM_V2_REG_EE_STRIDE,
SWRM_V2_0_CLK_CTRL_CLK_START);
} else {
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
Expand All @@ -935,11 +970,9 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, ctrl->reg_layout[SWRM_REG_INTERRUPT_CLEAR],
0xFFFFFFFF);

/* enable CPU IRQs */
if (ctrl->mmio) {
ctrl->reg_write(ctrl, ctrl->reg_layout[SWRM_REG_INTERRUPT_CPU_EN],
SWRM_INTERRUPT_STATUS_RMSK);
}
/* enable CPU IRQs for the selected EE window */
ctrl->reg_write(ctrl, ctrl->reg_layout[SWRM_REG_INTERRUPT_CPU_EN],
SWRM_INTERRUPT_STATUS_RMSK);

/* Set IRQ to PULSE */
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
Expand Down Expand Up @@ -1545,7 +1578,22 @@ static int qcom_swrm_probe(struct platform_device *pdev)
return -ENOMEM;

data = of_device_get_match_data(dev);
ctrl->ee = SWRM_EE_CPU;
ret = of_property_read_u32(dev->of_node, "qcom,swr-master-ee-val", &ctrl->ee);
if (ret)
ret = of_property_read_u32(dev->of_node, "qcom,ee", &ctrl->ee);
if (ret)
ctrl->ee = SWRM_EE_CPU;
if (ctrl->ee > SWRM_MAX_EE) {
dev_warn(dev, "invalid SoundWire EE %u, using EE%u\n",
ctrl->ee, SWRM_EE_CPU);
ctrl->ee = SWRM_EE_CPU;
}
ctrl->max_reg = data->max_reg;
/*
* Defer EE register window selection until HW version is known.
* For v2.0+ the IRQ/FIFO window is EE-banked.
*/
ctrl->reg_layout = data->reg_layout;
ctrl->rows_index = sdw_find_row_index(data->default_rows);
ctrl->cols_index = sdw_find_col_index(data->default_cols);
Expand Down Expand Up @@ -1623,6 +1671,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
prop->default_row = data->default_rows;

ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
qcom_swrm_set_ee_register_layout(ctrl, data);

ret = devm_request_threaded_irq(dev, ctrl->irq, NULL,
qcom_swrm_irq_handler,
Expand Down Expand Up @@ -1724,24 +1773,26 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev)
if (!swrm_wait_for_frame_gen_enabled(ctrl))
dev_err(ctrl->dev, "link failed to connect\n");

/* wait for hw enumeration to complete */
wait_for_completion_timeout(&ctrl->enumeration,
msecs_to_jiffies(TIMEOUT_MS));
qcom_swrm_get_device_status(ctrl);
sdw_handle_slave_status(&ctrl->bus, ctrl->status);
} else {
reset_control_reset(ctrl->audio_cgcr);

if (ctrl->version == SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU);
} else if (ctrl->version >= SWRM_VERSION_2_0_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_V2_0_CLK_CTRL,
SWRM_V2_0_CLK_CTRL_CLK_START);
/* wait for hw enumeration to complete */
wait_for_completion_timeout(&ctrl->enumeration,
msecs_to_jiffies(TIMEOUT_MS));
qcom_swrm_get_device_status(ctrl);
sdw_handle_slave_status(&ctrl->bus, ctrl->status);
} else {
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
reset_control_reset(ctrl->audio_cgcr);

if (ctrl->version == SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, ctrl->ee);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
SWRM_MCP_BUS_CLK_START << ctrl->ee);
} else if (ctrl->version >= SWRM_VERSION_2_0_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, ctrl->ee);
ctrl->reg_write(ctrl, SWRM_V2_0_CLK_CTRL +
((int)ctrl->ee - SWRM_EE_CPU) *
SWRM_V2_REG_EE_STRIDE,
SWRM_V2_0_CLK_CTRL_CLK_START);
} else {
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
}
ctrl->reg_write(ctrl, ctrl->reg_layout[SWRM_REG_INTERRUPT_CLEAR],
SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET);
Expand Down
2 changes: 2 additions & 0 deletions include/dt-bindings/sound/qcom,lpass.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#define LPASS_CDC_DMA_VA_TX7 32
#define LPASS_CDC_DMA_VA_TX8 33

#define MI2S_SENARY 34

#define LPASS_MCLK0 0

#endif /* __DT_QCOM_LPASS_H */
5 changes: 5 additions & 0 deletions sound/soc/codecs/lpass-macro-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#define LPASS_MACRO_FLAG_HAS_NPL_CLOCK BIT(0)
/* The soundwire block should be internally reset at probe */
#define LPASS_MACRO_FLAG_RESET_SWR BIT(1)
/* FS counter control bit[7] must be toggled (Shikra / v4.0) */
#define LPASS_MACRO_FLAG_BYPASS_FS_CONTROL BIT(2)

enum lpass_version {
LPASS_VER_9_0_0,
Expand All @@ -30,6 +32,7 @@ enum lpass_codec_version {
LPASS_CODEC_VERSION_2_7,
LPASS_CODEC_VERSION_2_8,
LPASS_CODEC_VERSION_2_9,
LPASS_CODEC_VERSION_4_0,
};

struct lpass_macro {
Expand Down Expand Up @@ -68,6 +71,8 @@ static inline const char *lpass_macro_get_codec_version_string(int version)
return "v2.7";
case LPASS_CODEC_VERSION_2_8:
return "v2.8";
case LPASS_CODEC_VERSION_4_0:
return "v4.0";
default:
break;
}
Expand Down
14 changes: 14 additions & 0 deletions sound/soc/codecs/lpass-rx-macro.c
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ struct rx_macro {
int clsh_users;
int rx_mclk_cnt;
enum lpass_codec_version codec_version;
bool bypass_fs_control;
int rxn_reg_stride;
int rxn_reg_stride2;
bool is_ear_mode_on;
Expand Down Expand Up @@ -1612,6 +1613,7 @@ static bool rx_is_rw_register(struct device *dev, unsigned int reg)
case LPASS_CODEC_VERSION_2_6:
case LPASS_CODEC_VERSION_2_7:
case LPASS_CODEC_VERSION_2_8:
case LPASS_CODEC_VERSION_4_0:
return rx_2_5_is_rw_register(dev, reg);
default:
break;
Expand Down Expand Up @@ -2043,6 +2045,11 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_CLK_MCLK2_ENABLE);
regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
CDC_RX_FS_MCLK_CNT_CLR_MASK, 0x00);

if (rx->bypass_fs_control)
regmap_update_bits(regmap,
CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
0x80, 0x80);
regmap_update_bits(regmap, CDC_RX_CLK_RST_CTRL_FS_CNT_CONTROL,
CDC_RX_FS_MCLK_CNT_EN_MASK,
CDC_RX_FS_MCLK_CNT_ENABLE);
Expand Down Expand Up @@ -3648,6 +3655,7 @@ static int rx_macro_component_probe(struct snd_soc_component *component)
case LPASS_CODEC_VERSION_2_6:
case LPASS_CODEC_VERSION_2_7:
case LPASS_CODEC_VERSION_2_8:
case LPASS_CODEC_VERSION_4_0:
controls = rx_macro_2_5_snd_controls;
num_controls = ARRAY_SIZE(rx_macro_2_5_snd_controls);
widgets = rx_macro_2_5_dapm_widgets;
Expand Down Expand Up @@ -3809,6 +3817,7 @@ static int rx_macro_probe(struct platform_device *pdev)
return PTR_ERR(base);

rx->codec_version = lpass_macro_get_codec_version();
rx->bypass_fs_control = !!(flags & LPASS_MACRO_FLAG_BYPASS_FS_CONTROL);
struct reg_default *reg_defaults __free(kfree) = NULL;

switch (rx->codec_version) {
Expand All @@ -3831,6 +3840,7 @@ static int rx_macro_probe(struct platform_device *pdev)
case LPASS_CODEC_VERSION_2_6:
case LPASS_CODEC_VERSION_2_7:
case LPASS_CODEC_VERSION_2_8:
case LPASS_CODEC_VERSION_4_0:
rx->rxn_reg_stride = 0xc0;
rx->rxn_reg_stride2 = 0x0;
def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults);
Expand Down Expand Up @@ -3961,6 +3971,10 @@ static const struct of_device_id rx_macro_dt_match[] = {
}, {
.compatible = "qcom,sc8280xp-lpass-rx-macro",
.data = (void *)LPASS_MACRO_FLAG_HAS_NPL_CLOCK,
}, {
.compatible = "qcom,shikra-lpass-rx-macro",
.data = (void *)(LPASS_MACRO_FLAG_HAS_NPL_CLOCK |
LPASS_MACRO_FLAG_BYPASS_FS_CONTROL),
},
{ }
};
Expand Down
Loading