diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index aec455a3628b..14a0defeb97d 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "bolero-cdc.h" #include "internal.h" @@ -37,6 +38,41 @@ static u16 bolero_mclk_mux_tbl[MAX_MACRO][MCLK_MUX_MAX] = { {TX_MACRO, VA_MACRO}, }; +static bool bolero_is_valid_codec_dev(struct device *dev); + +int bolero_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + struct bolero_priv *priv = NULL; + struct swr_mstr_port_map *map = NULL; + u16 idx; + + if (!component || (size == 0) || !data) + return -EINVAL; + + priv = snd_soc_component_get_drvdata(component); + if (!priv) + return -EINVAL; + + if (!bolero_is_valid_codec_dev(priv->dev)) { + dev_err(priv->dev, "%s: invalid codec\n", __func__); + return -EINVAL; + } + map = (struct swr_mstr_port_map *)data; + + for (idx = 0; idx < size; idx++) { + if (priv->macro_params[map->id].set_port_map) + priv->macro_params[map->id].set_port_map(component, + map->uc, + SWR_MSTR_PORT_LEN, + map->swr_port_params); + map += 1; + } + + return 0; +} +EXPORT_SYMBOL(bolero_set_port_map); + static void bolero_ahb_write_device(char __iomem *io_base, u16 reg, u8 value) { @@ -350,6 +386,7 @@ int bolero_register_macro(struct device *dev, u16 macro_id, priv->macro_params[macro_id].dai_ptr = ops->dai_ptr; priv->macro_params[macro_id].mclk_fn = ops->mclk_fn; priv->macro_params[macro_id].event_handler = ops->event_handler; + priv->macro_params[macro_id].set_port_map = ops->set_port_map; priv->macro_params[macro_id].dev = dev; priv->current_mclk_mux_macro[macro_id] = bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index 488ccf7eb506..524225e795dd 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -51,6 +51,8 @@ struct macro_ops { int (*event_handler)(struct snd_soc_component *component, u16 event, u32 data); int (*reg_wake_irq)(struct snd_soc_component *component, u32 data); + int (*set_port_map)(struct snd_soc_component *component, u32 uc, + u32 size, void *data); char __iomem *io_base; }; @@ -69,6 +71,7 @@ int bolero_register_wake_irq(struct snd_soc_component *component, u32 data); void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n); int bolero_runtime_resume(struct device *dev); int bolero_runtime_suspend(struct device *dev); +int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data); #else static inline int bolero_register_macro(struct device *dev, u16 macro_id, @@ -107,13 +110,24 @@ static inline void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n) static inline int bolero_register_wake_irq(struct snd_soc_component *component, u32 data) +{ + return 0; +} + static inline int bolero_runtime_resume(struct device *dev) { return 0; } + static int bolero_runtime_suspend(struct device *dev) { return 0; } + +static inline int bolero_set_port_map(struct snd_soc_component *component, + u32 size, void *data) +{ + return 0; +} #endif /* CONFIG_SND_SOC_BOLERO */ #endif /* BOLERO_CDC_H */ diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index ff8684f7170b..db01461ead69 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "bolero-cdc.h" @@ -701,6 +702,29 @@ static bool rx_macro_get_data(struct snd_soc_component *component, return true; } +static int rx_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *rx_dev = NULL; + struct rx_macro_priv *rx_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + ret = swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3366,6 +3390,7 @@ static void rx_macro_init_ops(struct macro_ops *ops, char __iomem *rx_io_base) ops->num_dais = ARRAY_SIZE(rx_macro_dai); ops->mclk_fn = rx_macro_mclk_ctrl; ops->event_handler = rx_macro_event_handler; + ops->set_port_map = rx_macro_set_port_map; } static int rx_macro_probe(struct platform_device *pdev) diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index c33a857acbaa..2cb0714ef9d2 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "bolero-cdc.h" #include "bolero-cdc-registers.h" @@ -1709,6 +1710,29 @@ err: return; } +static int tx_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + ret = swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + static void tx_macro_init_ops(struct macro_ops *ops, char __iomem *tx_io_base) { @@ -1721,6 +1745,7 @@ static void tx_macro_init_ops(struct macro_ops *ops, ops->mclk_fn = tx_macro_mclk_ctrl; ops->event_handler = tx_macro_event_handler; ops->reg_wake_irq = tx_macro_reg_wake_irq; + ops->set_port_map = tx_macro_set_port_map; } static int tx_macro_probe(struct platform_device *pdev) diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index 48a42ac46531..d9facd823080 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "bolero-cdc.h" @@ -452,6 +453,29 @@ static bool wsa_macro_get_data(struct snd_soc_component *component, return true; } +static int wsa_macro_set_port_map(struct snd_soc_component *component, + u32 usecase, u32 size, void *data) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + struct swrm_port_config port_cfg; + int ret = 0; + + if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + memset(&port_cfg, 0, sizeof(port_cfg)); + port_cfg.uc = usecase; + port_cfg.size = size; + port_cfg.params = data; + + ret = swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_SET_PORT_MAP, &port_cfg); + + return ret; +} + /** * wsa_macro_set_spkr_gain_offset - offset the speaker path * gain with the given offset value. @@ -2770,6 +2794,7 @@ static void wsa_macro_init_ops(struct macro_ops *ops, ops->num_dais = ARRAY_SIZE(wsa_macro_dai); ops->mclk_fn = wsa_macro_mclk_ctrl; ops->event_handler = wsa_macro_event_handler; + ops->set_port_map = wsa_macro_set_port_map; } static int wsa_macro_probe(struct platform_device *pdev) diff --git a/asoc/sm8250-port-config.h b/asoc/sm8250-port-config.h new file mode 100644 index 000000000000..0f8c3c1b0722 --- /dev/null +++ b/asoc/sm8250-port-config.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _SM8250_PORT_CONFIG +#define _SM8250_PORT_CONFIG + +#include + +#define WSA_MSTR_PORT_MASK 0xFF +/* + * Add port configuration in the format + *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl} + */ + +static struct port_params wsa_frame_params_default[SWR_MSTR_PORT_LEN] = { + {7, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {31, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {63, 12, 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {7, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {31, 18, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {63, 13, 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {15, 7, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + {15, 10, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, +}; + +static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0}, + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, +}; + +static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0}, + {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0}, +}; + +/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ +static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { + {1, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX1 */ + {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX2 */ + {3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */ +}; + +static struct swr_mstr_port_map sm_port_map[] = { + {TX_MACRO, SWR_UC0, tx_frame_params_default}, + {RX_MACRO, SWR_UC0, rx_frame_params_default}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, + {WSA_MACRO, SWR_UC0, wsa_frame_params_default}, +}; + +#endif /* _SM8250_PORT_CONFIG */ diff --git a/include/soc/swr-common.h b/include/soc/swr-common.h new file mode 100644 index 000000000000..92b79c79a9fb --- /dev/null +++ b/include/soc/swr-common.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved. + */ + +#ifndef _LINUX_SWR_COMMON_H +#define _LINUX_SWR_COMMON_H +#include +#include +#include +#include + +enum { + SWR_UC0 = 0, + SWR_UC1, + SWR_UC_MAX, +}; + +struct port_params { + u8 si; + u8 off1; + u8 off2; + u8 hstart;/* head start */ + u8 hstop; /* head stop */ + u8 wd_len;/* word length */ + u8 bp_mode; /* block pack mode */ + u8 bgp_ctrl;/* block group control */ + u8 lane_ctrl;/* lane to be used */ +}; + +struct swrm_port_config { + u32 size; + u32 uc; + void *params; +}; + +struct swr_mstr_port_map { + u32 id; + u32 uc; + struct port_params *swr_port_params; +}; + +#define SWR_MSTR_PORT_LEN 8 /* Number of master ports */ + +#endif /* _LINUX_SWR_COMMON_H */ diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h index 0f1762545e73..ad129c832700 100644 --- a/include/soc/swr-wcd.h +++ b/include/soc/swr-wcd.h @@ -20,6 +20,7 @@ enum { SWR_DEVICE_SSR_DOWN, SWR_DEVICE_SSR_UP, SWR_REGISTER_WAKE_IRQ, + SWR_SET_PORT_MAP, }; struct swr_mstr_port { diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 26433539ea5c..fd77cf59dffa 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -19,15 +19,17 @@ #include #include #include -#include +#include #include #include #include "swrm_registers.h" #include "swr-mstr-ctrl.h" -#include "swrm_port_config.h" #define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700 #define SWRM_SYS_SUSPEND_WAIT 1 + +#define SWRM_DSD_PARAMS_PORT 4 + #define SWR_BROADCAST_CMD_ID 0x0F #define SWR_AUTO_SUSPEND_DELAY 3 /* delay in sec */ #define SWR_DEV_ID_MASK 0xFFFFFFFFFFFF @@ -377,27 +379,16 @@ static void copy_port_tables(struct swr_mstr_ctrl *swrm, static int swrm_get_port_config(struct swr_mstr_ctrl *swrm) { struct port_params *params; + u32 usecase = 0; - switch (swrm->master_id) { - case MASTER_ID_WSA: - params = wsa_frame_superset; - break; - case MASTER_ID_RX: - /* Two RX tables for dsd and without dsd enabled */ - if (swrm->mport_cfg[4].port_en) - params = rx_frame_params_dsd; - else - params = rx_frame_params; - break; - case MASTER_ID_TX: - params = tx_frame_params_superset; - break; - default: /* MASTER_GENERIC*/ - /* computer generic frame parameters */ - return -EINVAL; - } + /* TODO - Send usecase information to avoid checking for master_id */ + if (swrm->mport_cfg[SWRM_DSD_PARAMS_PORT].port_en && + (swrm->master_id == MASTER_ID_RX)) + usecase = 1; + params = swrm->port_param[usecase]; copy_port_tables(swrm, params); + return 0; } @@ -2187,6 +2178,53 @@ int swrm_register_wake_irq(struct swr_mstr_ctrl *swrm) return ret; } +static int swrm_alloc_port_mem(struct device *dev, struct swr_mstr_ctrl *swrm, + u32 uc, u32 size) +{ + if (!swrm->port_param) { + swrm->port_param = devm_kzalloc(dev, + sizeof(swrm->port_param) * SWR_UC_MAX, + GFP_KERNEL); + if (!swrm->port_param) + return -ENOMEM; + } + if (!swrm->port_param[uc]) { + swrm->port_param[uc] = devm_kcalloc(dev, size, + sizeof(struct port_params), + GFP_KERNEL); + if (!swrm->port_param[uc]) + return -ENOMEM; + } else { + dev_err_ratelimited(swrm->dev, "%s: called more than once\n", + __func__); + } + + return 0; +} + +static int swrm_copy_port_config(struct swr_mstr_ctrl *swrm, + struct swrm_port_config *port_cfg, + u32 size) +{ + int idx; + struct port_params *params; + int uc = port_cfg->uc; + int ret = 0; + + for (idx = 0; idx < size; idx++) { + params = &((struct port_params *)port_cfg->params)[idx]; + if (!params) { + dev_err(swrm->dev, "%s: Invalid params\n", __func__); + ret = -EINVAL; + break; + } + memcpy(&swrm->port_param[uc][idx], params, + sizeof(struct port_params)); + } + + return ret; +} + /** * swrm_wcd_notify - parent device can notify to soundwire master through * this function @@ -2200,6 +2238,7 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) int ret = 0; struct swr_master *mstr; struct swr_device *swr_dev; + struct swrm_port_config *port_cfg; if (!pdev) { pr_err("%s: pdev is NULL\n", __func__); @@ -2327,6 +2366,27 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) mutex_unlock(&swrm->mlock); } break; + case SWR_SET_PORT_MAP: + if (!data) { + dev_err(swrm->dev, "%s: data is NULL for id=%d\n", + __func__, id); + ret = -EINVAL; + } else { + mutex_lock(&swrm->mlock); + port_cfg = (struct swrm_port_config *)data; + if (!port_cfg->size) { + ret = -EINVAL; + goto done; + } + ret = swrm_alloc_port_mem(&pdev->dev, swrm, + port_cfg->uc, port_cfg->size); + if (!ret) + swrm_copy_port_config(swrm, port_cfg, + port_cfg->size); +done: + mutex_unlock(&swrm->mlock); + } + break; default: dev_err(swrm->dev, "%s: swr master unknown id %d\n", __func__, id); diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index 8582c51ea96c..afbbe4682932 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -9,6 +9,7 @@ #include #include #include +#include #define SWR_ROW_48 0 #define SWR_ROW_50 1 @@ -61,18 +62,6 @@ struct usecase { u32 chrate; }; -struct port_params { - u8 si; - u8 off1; - u8 off2; - u8 hstart;/* head start */ - u8 hstop; /* head stop */ - u8 wd_len;/* word length */ - u8 bp_mode; /* block pack mode */ - u8 bgp_ctrl;/* block group control */ - u8 lane_ctrl;/* lane to be used */ -}; - struct swrm_mports { struct list_head port_req_list; bool port_en; @@ -163,6 +152,8 @@ struct swr_mstr_ctrl { wait_queue_head_t pm_wq; int wlock_holders; u32 intr_mask; + struct port_params **port_param; + u8 num_usecase; }; #endif /* _SWR_WCD_CTRL_H */ diff --git a/soc/swrm_port_config.h b/soc/swrm_port_config.h deleted file mode 100644 index 0458696380eb..000000000000 --- a/soc/swrm_port_config.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2018 The Linux Foundation. All rights reserved. - */ - -#ifndef _SWRM_PORT_CONFIG -#define _SWRM_PORT_CONFIG - -#define WSA_MSTR_PORT_MASK 0xFF - - -/* - * Add port configuration in the format - *{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl} - */ - -struct port_params wsa_frame_superset[SWR_MSTR_PORT_LEN] = { - {7, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {31, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {63, 12, 31, 0xFF, 0xFF, 0xFF, 0x1, 0xFF, 0xFF}, - {7, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {31, 18, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {63, 13, 31, 0xFF, 0xFF, 0xFF, 0x1, 0xFF, 0xFF}, - {15, 7, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, - {15, 10, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, -}; - -struct port_params rx_frame_params[SWR_MSTR_PORT_LEN] = { - {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, - {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, - {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, - {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0}, - {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, -}; - -struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = { - {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, - {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, - {31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0}, - {7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0}, - {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0}, -}; - -struct port_params tx_frame_params_superset[SWR_MSTR_PORT_LEN] = { - {1, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, - {1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, - {3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, - {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, -}; - -#endif /* _SWRM_REGISTERS_H */