soundwire updates for 6.13

- structure optimization of few bus structures and header updates
  - support for 2.0 disco spec
  - amd driver updates for acp revision, refactoring code and support for
    acp6.3
  - soft reset support for cadence driver
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmdEgiMACgkQfBQHDyUj
 g0dVBA/+MWwHs+Sl7LMSmkpGsfAsmSbD2il+v+9WcVnaQpl/dgv8EXPGbafBBgK/
 AlVUvLCNdbwY93wCb/2xdGPOJS699D7AtdJnUEppcL2VsMtEbgQxyG0OSekRVH0c
 NxVLNPVLQFQnZayh7MNflQNVrXJyEqUJg8n0G9G1KT7jTeMavejYhqmhN7TKNtLD
 vJzF79QFC2n7+f7jK9+d2pJlhW5V3XUyQCRF6FipftKbuZN+ciVh9kjnAf1GjPsi
 qpv7kRZ3ttZiYW+/8FjJxqChnT10b/ahRDwJTXE+uGhqxHD9Cjo/GYrzUtQQbDR2
 uvZ6+o0UxhN3HR5Dq09FJYPluHpt8S/s/wZ0dj+dXlvPR82qT6LA9LP16BFwYj3S
 36/DpGwJBYg3tsmwECKbY08t3aI1d8nXNKG0tXbkEU3RUWVeOJOLAyXbwYQ9DRGN
 k3RbTTEZiw223FlgAk9dzCI6mMuekdh20UWVH7iZwUl8ZvJhWNdWiZOV4uaUcGZS
 fmJ6JE7cM1ntv5rXjKIhhnTnoL5Z+3es3PjLxj8PE7VNC8Dlln67FF1NuoDd0uF0
 jWA13iNUOKgytsx2jxAxWnU8S3SAPjB1+GD65ovMxH+b9xtgwhtmCcpySJaG4/Pn
 P7F7dx1+bK8gbmc5xJf8ZddYeDF/Nb/493trk+Sf+zZSs+hevRY=
 =3Ob7
 -----END PGP SIGNATURE-----

Merge tag 'soundwire-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire

Pull soundwire updates from Vinod Koul:

 - structure optimization of few bus structures and header updates

 - support for 2.0 disco spec

 - amd driver updates for acp revision, refactoring code and support for
   acp6.3

 - soft reset support for cadence driver

* tag 'soundwire-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (24 commits)
  soundwire: Minor formatting fixups in sdw.h header
  soundwire: Update the includes on the sdw.h header
  soundwire: cadence: clear MCP BLOCK_WAKEUP in init
  soundwire: cadence: add soft-reset on startup
  soundwire: intel_auxdevice: add kernel parameter for mclk divider
  soundwire: mipi-disco: add support for DP0/DPn 'lane-list' property
  soundwire: mipi-disco: add new properties from 2.0 spec
  soundwire: mipi-disco: add comment on DP0-supported property
  soundwire: mipi-disco: add support for peripheral channelprepare timeout
  soundwire: mipi_disco: add support for clock-scales property
  soundwire: mipi-disco: add error handling for property array read
  soundwire: mipi-disco: remove DPn audio-modes
  soundwire: optimize sdw_dpn_prop
  soundwire: optimize sdw_dp0_prop
  soundwire: optimize sdw_slave_prop
  soundwire: optimize sdw_bus structure
  soundwire: optimize sdw_master_prop
  soundwire: optimize sdw_stream_runtime memory layout
  soundwire: mipi_disco: add MIPI-specific property_read_bool() helpers
  soundwire: Correct some typos in comments
  ...
This commit is contained in:
Linus Torvalds 2024-11-27 13:38:09 -08:00
commit 9ad55a67a7
18 changed files with 368 additions and 208 deletions

View File

@ -174,6 +174,7 @@ is applicable::
SCSI Appropriate SCSI support is enabled. SCSI Appropriate SCSI support is enabled.
A lot of drivers have their options described inside A lot of drivers have their options described inside
the Documentation/scsi/ sub-directory. the Documentation/scsi/ sub-directory.
SDW SoundWire support is enabled.
SECURITY Different security models are enabled. SECURITY Different security models are enabled.
SELINUX SELinux support is enabled. SELINUX SELinux support is enabled.
SERIAL Serial support is enabled. SERIAL Serial support is enabled.

View File

@ -6075,6 +6075,10 @@
non-zero "wait" parameter. See weight_single non-zero "wait" parameter. See weight_single
and weight_many. and weight_many.
sdw_mclk_divider=[SDW]
Specify the MCLK divider for Intel SoundWire buses in
case the BIOS does not provide the clock rate properly.
skew_tick= [KNL,EARLY] Offset the periodic timer tick per cpu to mitigate skew_tick= [KNL,EARLY] Offset the periodic timer tick per cpu to mitigate
xtime_lock contention on larger systems, and/or RCU lock xtime_lock contention on larger systems, and/or RCU lock
contention on all systems with CONFIG_MAXSMP set. contention on all systems with CONFIG_MAXSMP set.

View File

@ -121,6 +121,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
sdw_pdata[index].instance = index; sdw_pdata[index].instance = index;
sdw_pdata[index].acp_sdw_lock = res->acp_lock; sdw_pdata[index].acp_sdw_lock = res->acp_lock;
sdw_pdata[index].acp_rev = res->acp_rev;
pdevinfo[index].name = "amd_sdw_manager"; pdevinfo[index].name = "amd_sdw_manager";
pdevinfo[index].id = index; pdevinfo[index].id = index;
pdevinfo[index].parent = res->parent; pdevinfo[index].parent = res->parent;

View File

@ -433,12 +433,18 @@ static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_pa
u32 frame_fmt_reg, dpn_frame_fmt; u32 frame_fmt_reg, dpn_frame_fmt;
dev_dbg(amd_manager->dev, "p_params->num:0x%x\n", p_params->num); dev_dbg(amd_manager->dev, "p_params->num:0x%x\n", p_params->num);
switch (amd_manager->instance) { switch (amd_manager->acp_rev) {
case ACP_SDW0: case ACP63_PCI_REV_ID:
frame_fmt_reg = sdw0_manager_dp_reg[p_params->num].frame_fmt_reg; switch (amd_manager->instance) {
break; case ACP_SDW0:
case ACP_SDW1: frame_fmt_reg = acp63_sdw0_dp_reg[p_params->num].frame_fmt_reg;
frame_fmt_reg = sdw1_manager_dp_reg[p_params->num].frame_fmt_reg; break;
case ACP_SDW1:
frame_fmt_reg = acp63_sdw1_dp_reg[p_params->num].frame_fmt_reg;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -465,20 +471,28 @@ static int amd_sdw_transport_params(struct sdw_bus *bus,
u32 frame_fmt_reg, sample_int_reg, hctrl_dp0_reg; u32 frame_fmt_reg, sample_int_reg, hctrl_dp0_reg;
u32 offset_reg, lane_ctrl_ch_en_reg; u32 offset_reg, lane_ctrl_ch_en_reg;
switch (amd_manager->instance) { switch (amd_manager->acp_rev) {
case ACP_SDW0: case ACP63_PCI_REV_ID:
frame_fmt_reg = sdw0_manager_dp_reg[params->port_num].frame_fmt_reg; switch (amd_manager->instance) {
sample_int_reg = sdw0_manager_dp_reg[params->port_num].sample_int_reg; case ACP_SDW0:
hctrl_dp0_reg = sdw0_manager_dp_reg[params->port_num].hctrl_dp0_reg; frame_fmt_reg = acp63_sdw0_dp_reg[params->port_num].frame_fmt_reg;
offset_reg = sdw0_manager_dp_reg[params->port_num].offset_reg; sample_int_reg = acp63_sdw0_dp_reg[params->port_num].sample_int_reg;
lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg; hctrl_dp0_reg = acp63_sdw0_dp_reg[params->port_num].hctrl_dp0_reg;
break; offset_reg = acp63_sdw0_dp_reg[params->port_num].offset_reg;
case ACP_SDW1: lane_ctrl_ch_en_reg =
frame_fmt_reg = sdw1_manager_dp_reg[params->port_num].frame_fmt_reg; acp63_sdw0_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
sample_int_reg = sdw1_manager_dp_reg[params->port_num].sample_int_reg; break;
hctrl_dp0_reg = sdw1_manager_dp_reg[params->port_num].hctrl_dp0_reg; case ACP_SDW1:
offset_reg = sdw1_manager_dp_reg[params->port_num].offset_reg; frame_fmt_reg = acp63_sdw1_dp_reg[params->port_num].frame_fmt_reg;
lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg; sample_int_reg = acp63_sdw1_dp_reg[params->port_num].sample_int_reg;
hctrl_dp0_reg = acp63_sdw1_dp_reg[params->port_num].hctrl_dp0_reg;
offset_reg = acp63_sdw1_dp_reg[params->port_num].offset_reg;
lane_ctrl_ch_en_reg =
acp63_sdw1_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -520,12 +534,20 @@ static int amd_sdw_port_enable(struct sdw_bus *bus,
u32 dpn_ch_enable; u32 dpn_ch_enable;
u32 lane_ctrl_ch_en_reg; u32 lane_ctrl_ch_en_reg;
switch (amd_manager->instance) { switch (amd_manager->acp_rev) {
case ACP_SDW0: case ACP63_PCI_REV_ID:
lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; switch (amd_manager->instance) {
break; case ACP_SDW0:
case ACP_SDW1: lane_ctrl_ch_en_reg =
lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; acp63_sdw0_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
break;
case ACP_SDW1:
lane_ctrl_ch_en_reg =
acp63_sdw1_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -910,6 +932,7 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
amd_manager->mmio = amd_manager->acp_mmio + amd_manager->mmio = amd_manager->acp_mmio +
(amd_manager->instance * SDW_MANAGER_REG_OFFSET); (amd_manager->instance * SDW_MANAGER_REG_OFFSET);
amd_manager->acp_sdw_lock = pdata->acp_sdw_lock; amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
amd_manager->acp_rev = pdata->acp_rev;
amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS); amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS); amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
amd_manager->dev = dev; amd_manager->dev = dev;
@ -926,15 +949,21 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
* information. * information.
*/ */
amd_manager->bus.controller_id = 0; amd_manager->bus.controller_id = 0;
dev_dbg(dev, "acp_rev:0x%x\n", amd_manager->acp_rev);
switch (amd_manager->instance) { switch (amd_manager->acp_rev) {
case ACP_SDW0: case ACP63_PCI_REV_ID:
amd_manager->num_dout_ports = AMD_SDW0_MAX_TX_PORTS; switch (amd_manager->instance) {
amd_manager->num_din_ports = AMD_SDW0_MAX_RX_PORTS; case ACP_SDW0:
break; amd_manager->num_dout_ports = AMD_ACP63_SDW0_MAX_TX_PORTS;
case ACP_SDW1: amd_manager->num_din_ports = AMD_ACP63_SDW0_MAX_RX_PORTS;
amd_manager->num_dout_ports = AMD_SDW1_MAX_TX_PORTS; break;
amd_manager->num_din_ports = AMD_SDW1_MAX_RX_PORTS; case ACP_SDW1:
amd_manager->num_dout_ports = AMD_ACP63_SDW1_MAX_TX_PORTS;
amd_manager->num_din_ports = AMD_ACP63_SDW1_MAX_RX_PORTS;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;

View File

@ -155,12 +155,12 @@
#define AMD_SDW_IRQ_MASK_8TO11 0x000c7777 #define AMD_SDW_IRQ_MASK_8TO11 0x000c7777
#define AMD_SDW_IRQ_ERROR_MASK 0xff #define AMD_SDW_IRQ_ERROR_MASK 0xff
#define AMD_SDW_MAX_FREQ_NUM 1 #define AMD_SDW_MAX_FREQ_NUM 1
#define AMD_SDW0_MAX_TX_PORTS 3 #define AMD_ACP63_SDW0_MAX_TX_PORTS 3
#define AMD_SDW0_MAX_RX_PORTS 3 #define AMD_ACP63_SDW0_MAX_RX_PORTS 3
#define AMD_SDW1_MAX_TX_PORTS 1 #define AMD_ACP63_SDW1_MAX_TX_PORTS 1
#define AMD_SDW1_MAX_RX_PORTS 1 #define AMD_ACP63_SDW1_MAX_RX_PORTS 1
#define AMD_SDW0_MAX_DAI 6 #define AMD_ACP63_SDW0_MAX_DAI 6
#define AMD_SDW1_MAX_DAI 2 #define AMD_ACP63_SDW1_MAX_DAI 2
#define AMD_SDW_SLAVE_0_ATTACHED 5 #define AMD_SDW_SLAVE_0_ATTACHED 5
#define AMD_SDW_SSP_COUNTER_VAL 3 #define AMD_SDW_SSP_COUNTER_VAL 3
@ -222,7 +222,7 @@ struct sdw_manager_dp_reg {
* in SoundWire DMA driver. * in SoundWire DMA driver.
*/ */
static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = { static struct sdw_manager_dp_reg acp63_sdw0_dp_reg[AMD_ACP63_SDW0_MAX_DAI] = {
{ACP_SW_AUDIO0_TX_FRAME_FORMAT, ACP_SW_AUDIO0_TX_SAMPLEINTERVAL, ACP_SW_AUDIO0_TX_HCTRL_DP0, {ACP_SW_AUDIO0_TX_FRAME_FORMAT, ACP_SW_AUDIO0_TX_SAMPLEINTERVAL, ACP_SW_AUDIO0_TX_HCTRL_DP0,
ACP_SW_AUDIO0_TX_OFFSET_DP0, ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0}, ACP_SW_AUDIO0_TX_OFFSET_DP0, ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0},
{ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL, {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
@ -237,7 +237,7 @@ static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = {
ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0}, ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0},
}; };
static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = { static struct sdw_manager_dp_reg acp63_sdw1_dp_reg[AMD_ACP63_SDW1_MAX_DAI] = {
{ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL, {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0}, ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0},
{ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL, {ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL,

View File

@ -112,7 +112,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
/* Set higher order bits */ /* Set higher order bits */
*bus->assigned = ~GENMASK(SDW_BROADCAST_DEV_NUM, SDW_ENUM_DEV_NUM); *bus->assigned = ~GENMASK(SDW_BROADCAST_DEV_NUM, SDW_ENUM_DEV_NUM);
/* Set enumuration device number and broadcast device number */ /* Set enumeration device number and broadcast device number */
set_bit(SDW_ENUM_DEV_NUM, bus->assigned); set_bit(SDW_ENUM_DEV_NUM, bus->assigned);
set_bit(SDW_BROADCAST_DEV_NUM, bus->assigned); set_bit(SDW_BROADCAST_DEV_NUM, bus->assigned);

View File

@ -1377,6 +1377,31 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval); cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);
} }
/**
* sdw_cdns_soft_reset() - Cadence soft-reset
* @cdns: Cadence instance
*/
int sdw_cdns_soft_reset(struct sdw_cdns *cdns)
{
int ret;
cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST,
CDNS_MCP_CONTROL_SOFT_RST);
ret = cdns_config_update(cdns);
if (ret < 0) {
dev_err(cdns->dev, "%s: config update failed\n", __func__);
return ret;
}
ret = cdns_set_wait(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST, 0);
if (ret < 0)
dev_err(cdns->dev, "%s: Soft Reset timed out\n", __func__);
return ret;
}
EXPORT_SYMBOL(sdw_cdns_soft_reset);
/** /**
* sdw_cdns_init() - Cadence initialization * sdw_cdns_init() - Cadence initialization
* @cdns: Cadence instance * @cdns: Cadence instance
@ -1400,6 +1425,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
CDNS_IP_MCP_CONTROL_CMD_ACCEPT); CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
/* disable wakeup */
cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP,
0);
/* Configure mcp config */ /* Configure mcp config */
val = cdns_readl(cdns, CDNS_MCP_CONFIG); val = cdns_readl(cdns, CDNS_MCP_CONFIG);

View File

@ -168,6 +168,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns);
irqreturn_t sdw_cdns_irq(int irq, void *dev_id); irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id); irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
int sdw_cdns_soft_reset(struct sdw_cdns *cdns);
int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_init(struct sdw_cdns *cdns);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns, int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config); struct sdw_cdns_stream_config config);

View File

@ -41,6 +41,10 @@ static int md_flags;
module_param_named(sdw_md_flags, md_flags, int, 0444); module_param_named(sdw_md_flags, md_flags, int, 0444);
MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)"); MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)");
static int mclk_divider;
module_param_named(sdw_mclk_divider, mclk_divider, int, 0444);
MODULE_PARM_DESC(sdw_mclk_divider, "SoundWire Intel mclk divider");
struct wake_capable_part { struct wake_capable_part {
const u16 mfg_id; const u16 mfg_id;
const u16 part_id; const u16 part_id;
@ -142,8 +146,12 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
"intel-sdw-ip-clock", "intel-sdw-ip-clock",
&prop->mclk_freq); &prop->mclk_freq);
/* the values reported by BIOS are the 2x clock, not the bus clock */ if (mclk_divider)
prop->mclk_freq /= 2; /* use kernel parameter for BIOS or board work-arounds */
prop->mclk_freq /= mclk_divider;
else
/* the values reported by BIOS are the 2x clock, not the bus clock */
prop->mclk_freq /= 2;
fwnode_property_read_u32(link, fwnode_property_read_u32(link,
"intel-quirk-mask", "intel-quirk-mask",

View File

@ -16,6 +16,12 @@ int intel_start_bus(struct sdw_intel *sdw)
struct sdw_bus *bus = &cdns->bus; struct sdw_bus *bus = &cdns->bus;
int ret; int ret;
ret = sdw_cdns_soft_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to soft-reset Cadence IP: %d\n", __func__, ret);
return ret;
}
/* /*
* follow recommended programming flows to avoid timeouts when * follow recommended programming flows to avoid timeouts when
* gsync is enabled * gsync is enabled

View File

@ -23,6 +23,26 @@
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
#include "bus.h" #include "bus.h"
static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode,
const char *propname)
{
int ret;
u8 val;
if (!fwnode_property_present(fwnode, propname))
return false;
ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1);
if (ret < 0)
return false;
return !!val;
}
static bool mipi_device_property_read_bool(const struct device *dev,
const char *propname)
{
return mipi_fwnode_property_read_bool(dev_fwnode(dev), propname);
}
/** /**
* sdw_master_read_prop() - Read Master properties * sdw_master_read_prop() - Read Master properties
* @bus: SDW bus instance * @bus: SDW bus instance
@ -31,8 +51,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
{ {
struct sdw_master_prop *prop = &bus->prop; struct sdw_master_prop *prop = &bus->prop;
struct fwnode_handle *link; struct fwnode_handle *link;
const char *scales_prop;
char name[32]; char name[32];
int nval, i; int nval;
int ret;
int i;
device_property_read_u32(bus->dev, device_property_read_u32(bus->dev,
"mipi-sdw-sw-interface-revision", "mipi-sdw-sw-interface-revision",
@ -48,11 +71,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
return -EIO; return -EIO;
} }
if (fwnode_property_read_bool(link, if (mipi_fwnode_property_read_bool(link,
"mipi-sdw-clock-stop-mode0-supported")) "mipi-sdw-clock-stop-mode0-supported"))
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0); prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0);
if (fwnode_property_read_bool(link, if (mipi_fwnode_property_read_bool(link,
"mipi-sdw-clock-stop-mode1-supported")) "mipi-sdw-clock-stop-mode1-supported"))
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1); prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1);
@ -71,9 +94,11 @@ int sdw_master_read_prop(struct sdw_bus *bus)
return -ENOMEM; return -ENOMEM;
} }
fwnode_property_read_u32_array(link, ret = fwnode_property_read_u32_array(link,
"mipi-sdw-clock-frequencies-supported", "mipi-sdw-clock-frequencies-supported",
prop->clk_freq, prop->num_clk_freq); prop->clk_freq, prop->num_clk_freq);
if (ret < 0)
return ret;
} }
/* /*
@ -88,7 +113,12 @@ int sdw_master_read_prop(struct sdw_bus *bus)
} }
} }
nval = fwnode_property_count_u32(link, "mipi-sdw-supported-clock-gears"); scales_prop = "mipi-sdw-supported-clock-scales";
nval = fwnode_property_count_u32(link, scales_prop);
if (nval == 0) {
scales_prop = "mipi-sdw-supported-clock-gears";
nval = fwnode_property_count_u32(link, scales_prop);
}
if (nval > 0) { if (nval > 0) {
prop->num_clk_gears = nval; prop->num_clk_gears = nval;
prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears, prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears,
@ -99,10 +129,12 @@ int sdw_master_read_prop(struct sdw_bus *bus)
return -ENOMEM; return -ENOMEM;
} }
fwnode_property_read_u32_array(link, ret = fwnode_property_read_u32_array(link,
"mipi-sdw-supported-clock-gears", scales_prop,
prop->clk_gears, prop->clk_gears,
prop->num_clk_gears); prop->num_clk_gears);
if (ret < 0)
return ret;
} }
fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate",
@ -114,7 +146,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size",
&prop->default_col); &prop->default_col);
prop->dynamic_frame = fwnode_property_read_bool(link, prop->dynamic_frame = mipi_fwnode_property_read_bool(link,
"mipi-sdw-dynamic-frame-shape"); "mipi-sdw-dynamic-frame-shape");
fwnode_property_read_u32(link, "mipi-sdw-command-error-threshold", fwnode_property_read_u32(link, "mipi-sdw-command-error-threshold",
@ -131,6 +163,7 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
struct sdw_dp0_prop *dp0) struct sdw_dp0_prop *dp0)
{ {
int nval; int nval;
int ret;
fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength", fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength",
&dp0->max_word); &dp0->max_word);
@ -148,20 +181,38 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
if (!dp0->words) if (!dp0->words)
return -ENOMEM; return -ENOMEM;
fwnode_property_read_u32_array(port, ret = fwnode_property_read_u32_array(port,
"mipi-sdw-port-wordlength-configs", "mipi-sdw-port-wordlength-configs",
dp0->words, dp0->num_words); dp0->words, dp0->num_words);
if (ret < 0)
return ret;
} }
dp0->BRA_flow_controlled = fwnode_property_read_bool(port, dp0->BRA_flow_controlled = mipi_fwnode_property_read_bool(port,
"mipi-sdw-bra-flow-controlled"); "mipi-sdw-bra-flow-controlled");
dp0->simple_ch_prep_sm = fwnode_property_read_bool(port, dp0->simple_ch_prep_sm = mipi_fwnode_property_read_bool(port,
"mipi-sdw-simplified-channel-prepare-sm"); "mipi-sdw-simplified-channel-prepare-sm");
dp0->imp_def_interrupts = fwnode_property_read_bool(port, dp0->imp_def_interrupts = mipi_fwnode_property_read_bool(port,
"mipi-sdw-imp-def-dp0-interrupts-supported"); "mipi-sdw-imp-def-dp0-interrupts-supported");
nval = fwnode_property_count_u32(port, "mipi-sdw-lane-list");
if (nval > 0) {
dp0->num_lanes = nval;
dp0->lane_list = devm_kcalloc(&slave->dev,
dp0->num_lanes, sizeof(*dp0->lane_list),
GFP_KERNEL);
if (!dp0->lane_list)
return -ENOMEM;
ret = fwnode_property_read_u32_array(port,
"mipi-sdw-lane-list",
dp0->lane_list, dp0->num_lanes);
if (ret < 0)
return ret;
}
return 0; return 0;
} }
@ -171,9 +222,10 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
{ {
struct fwnode_handle *node; struct fwnode_handle *node;
u32 bit, i = 0; u32 bit, i = 0;
int nval;
unsigned long addr; unsigned long addr;
char name[40]; char name[40];
int nval;
int ret;
addr = ports; addr = ports;
/* valid ports are 1 to 14 so apply mask */ /* valid ports are 1 to 14 so apply mask */
@ -208,9 +260,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
return -ENOMEM; return -ENOMEM;
} }
fwnode_property_read_u32_array(node, ret = fwnode_property_read_u32_array(node,
"mipi-sdw-port-wordlength-configs", "mipi-sdw-port-wordlength-configs",
dpn[i].words, dpn[i].num_words); dpn[i].words, dpn[i].num_words);
if (ret < 0)
return ret;
} }
fwnode_property_read_u32(node, "mipi-sdw-data-port-type", fwnode_property_read_u32(node, "mipi-sdw-data-port-type",
@ -220,7 +274,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
"mipi-sdw-max-grouping-supported", "mipi-sdw-max-grouping-supported",
&dpn[i].max_grouping); &dpn[i].max_grouping);
dpn[i].simple_ch_prep_sm = fwnode_property_read_bool(node, dpn[i].simple_ch_prep_sm = mipi_fwnode_property_read_bool(node,
"mipi-sdw-simplified-channelprepare-sm"); "mipi-sdw-simplified-channelprepare-sm");
fwnode_property_read_u32(node, fwnode_property_read_u32(node,
@ -249,9 +303,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
return -ENOMEM; return -ENOMEM;
} }
fwnode_property_read_u32_array(node, ret = fwnode_property_read_u32_array(node,
"mipi-sdw-channel-number-list", "mipi-sdw-channel-number-list",
dpn[i].channels, dpn[i].num_channels); dpn[i].channels, dpn[i].num_channels);
if (ret < 0)
return ret;
} }
nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list"); nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list");
@ -266,10 +322,12 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
return -ENOMEM; return -ENOMEM;
} }
fwnode_property_read_u32_array(node, ret = fwnode_property_read_u32_array(node,
"mipi-sdw-channel-combination-list", "mipi-sdw-channel-combination-list",
dpn[i].ch_combinations, dpn[i].ch_combinations,
dpn[i].num_ch_combinations); dpn[i].num_ch_combinations);
if (ret < 0)
return ret;
} }
fwnode_property_read_u32(node, fwnode_property_read_u32(node,
@ -278,13 +336,27 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
fwnode_property_read_u32(node, "mipi-sdw-max-async-buffer", fwnode_property_read_u32(node, "mipi-sdw-max-async-buffer",
&dpn[i].max_async_buffer); &dpn[i].max_async_buffer);
dpn[i].block_pack_mode = fwnode_property_read_bool(node, dpn[i].block_pack_mode = mipi_fwnode_property_read_bool(node,
"mipi-sdw-block-packing-mode"); "mipi-sdw-block-packing-mode");
fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type", fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type",
&dpn[i].port_encoding); &dpn[i].port_encoding);
/* TODO: Read audio mode */ nval = fwnode_property_count_u32(node, "mipi-sdw-lane-list");
if (nval > 0) {
dpn[i].num_lanes = nval;
dpn[i].lane_list = devm_kcalloc(&slave->dev,
dpn[i].num_lanes, sizeof(*dpn[i].lane_list),
GFP_KERNEL);
if (!dpn[i].lane_list)
return -ENOMEM;
ret = fwnode_property_read_u32_array(node,
"mipi-sdw-lane-list",
dpn[i].lane_list, dpn[i].num_lanes);
if (ret < 0)
return ret;
}
fwnode_handle_put(node); fwnode_handle_put(node);
@ -304,42 +376,46 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
struct device *dev = &slave->dev; struct device *dev = &slave->dev;
struct fwnode_handle *port; struct fwnode_handle *port;
int nval; int nval;
int ret;
device_property_read_u32(dev, "mipi-sdw-sw-interface-revision", device_property_read_u32(dev, "mipi-sdw-sw-interface-revision",
&prop->mipi_revision); &prop->mipi_revision);
prop->wake_capable = device_property_read_bool(dev, prop->wake_capable = mipi_device_property_read_bool(dev,
"mipi-sdw-wake-up-unavailable"); "mipi-sdw-wake-up-unavailable");
prop->wake_capable = !prop->wake_capable; prop->wake_capable = !prop->wake_capable;
prop->test_mode_capable = device_property_read_bool(dev, prop->test_mode_capable = mipi_device_property_read_bool(dev,
"mipi-sdw-test-mode-supported"); "mipi-sdw-test-mode-supported");
prop->clk_stop_mode1 = false; prop->clk_stop_mode1 = false;
if (device_property_read_bool(dev, if (mipi_device_property_read_bool(dev,
"mipi-sdw-clock-stop-mode1-supported")) "mipi-sdw-clock-stop-mode1-supported"))
prop->clk_stop_mode1 = true; prop->clk_stop_mode1 = true;
prop->simple_clk_stop_capable = device_property_read_bool(dev, prop->simple_clk_stop_capable = mipi_device_property_read_bool(dev,
"mipi-sdw-simplified-clockstopprepare-sm-supported"); "mipi-sdw-simplified-clockstopprepare-sm-supported");
device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout", device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout",
&prop->clk_stop_timeout); &prop->clk_stop_timeout);
device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout", ret = device_property_read_u32(dev, "mipi-sdw-peripheral-channelprepare-timeout",
&prop->ch_prep_timeout); &prop->ch_prep_timeout);
if (ret < 0)
device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout",
&prop->ch_prep_timeout);
device_property_read_u32(dev, device_property_read_u32(dev,
"mipi-sdw-clockstopprepare-hard-reset-behavior", "mipi-sdw-clockstopprepare-hard-reset-behavior",
&prop->reset_behave); &prop->reset_behave);
prop->high_PHY_capable = device_property_read_bool(dev, prop->high_PHY_capable = mipi_device_property_read_bool(dev,
"mipi-sdw-highPHY-capable"); "mipi-sdw-highPHY-capable");
prop->paging_support = device_property_read_bool(dev, prop->paging_support = mipi_device_property_read_bool(dev,
"mipi-sdw-paging-support"); "mipi-sdw-paging-support");
prop->bank_delay_support = device_property_read_bool(dev, prop->bank_delay_support = mipi_device_property_read_bool(dev,
"mipi-sdw-bank-delay-support"); "mipi-sdw-bank-delay-support");
device_property_read_u32(dev, device_property_read_u32(dev,
@ -354,7 +430,17 @@ int sdw_slave_read_prop(struct sdw_slave *slave)
device_property_read_u32(dev, "mipi-sdw-sink-port-list", device_property_read_u32(dev, "mipi-sdw-sink-port-list",
&prop->sink_ports); &prop->sink_ports);
/* Read dp0 properties */ device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list",
&prop->sdca_interrupt_register_list);
prop->commit_register_supported = mipi_device_property_read_bool(dev,
"mipi-sdw-commit-register-supported");
/*
* Read dp0 properties - we don't rely on the 'mipi-sdw-dp-0-supported'
* property since the 'mipi-sdw-dp0-subproperties' property is logically
* equivalent.
*/
port = device_get_named_child_node(dev, "mipi-sdw-dp-0-subproperties"); port = device_get_named_child_node(dev, "mipi-sdw-dp-0-subproperties");
if (!port) { if (!port) {
dev_dbg(dev, "DP0 node not found!!\n"); dev_dbg(dev, "DP0 node not found!!\n");

View File

@ -1173,7 +1173,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
else else
sconfig.direction = SDW_DATA_DIR_RX; sconfig.direction = SDW_DATA_DIR_RX;
/* hw parameters wil be ignored as we only support PDM */ /* hw parameters will be ignored as we only support PDM */
sconfig.ch_count = 1; sconfig.ch_count = 1;
sconfig.frame_rate = params_rate(params); sconfig.frame_rate = params_rate(params);
sconfig.type = stream->type; sconfig.type = stream->type;

View File

@ -215,7 +215,7 @@ const struct attribute_group *sdw_attr_groups[] = {
/* /*
* the status is shown in capital letters for UNATTACHED and RESERVED * the status is shown in capital letters for UNATTACHED and RESERVED
* on purpose, to highligh users to the fact that these status values * on purpose, to highlight users to the fact that these status values
* are not expected. * are not expected.
*/ */
static const char *const slave_status[] = { static const char *const slave_status[] = {

View File

@ -4,14 +4,21 @@
#ifndef __SOUNDWIRE_H #ifndef __SOUNDWIRE_H
#define __SOUNDWIRE_H #define __SOUNDWIRE_H
#include <linux/bitfield.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/lockdep_types.h> #include <linux/completion.h>
#include <linux/device.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/lockdep_types.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/bitfield.h> #include <linux/mutex.h>
#include <linux/types.h>
#include <sound/sdca.h> #include <sound/sdca.h>
struct dentry;
struct fwnode_handle;
struct sdw_bus; struct sdw_bus;
struct sdw_slave; struct sdw_slave;
@ -227,64 +234,36 @@ enum sdw_clk_stop_mode {
/** /**
* struct sdw_dp0_prop - DP0 properties * struct sdw_dp0_prop - DP0 properties
* @words: wordlengths supported
* @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64 * @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64
* (inclusive) * (inclusive)
* @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64 * @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64
* (inclusive) * (inclusive)
* @num_words: number of wordlengths supported * @num_words: number of wordlengths supported
* @words: wordlengths supported * @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady * @BRA_flow_controlled: Slave implementation results in an OK_NotReady
* response * response
* @simple_ch_prep_sm: If channel prepare sequence is required * @simple_ch_prep_sm: If channel prepare sequence is required
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @imp_def_interrupts: If set, each bit corresponds to support for * @imp_def_interrupts: If set, each bit corresponds to support for
* implementation-defined interrupts * implementation-defined interrupts
* @num_lanes: array size of @lane_list
* @lane_list: indicates which Lanes can be used by DP0
* *
* The wordlengths are specified by Spec as max, min AND number of * The wordlengths are specified by Spec as max, min AND number of
* discrete values, implementation can define based on the wordlengths they * discrete values, implementation can define based on the wordlengths they
* support * support
*/ */
struct sdw_dp0_prop { struct sdw_dp0_prop {
u32 *words;
u32 max_word; u32 max_word;
u32 min_word; u32 min_word;
u32 num_words; u32 num_words;
u32 *words; u32 ch_prep_timeout;
bool BRA_flow_controlled; bool BRA_flow_controlled;
bool simple_ch_prep_sm; bool simple_ch_prep_sm;
u32 ch_prep_timeout;
bool imp_def_interrupts; bool imp_def_interrupts;
}; int num_lanes;
u32 *lane_list;
/**
* struct sdw_dpn_audio_mode - Audio mode properties for DPn
* @bus_min_freq: Minimum bus frequency, in Hz
* @bus_max_freq: Maximum bus frequency, in Hz
* @bus_num_freq: Number of discrete frequencies supported
* @bus_freq: Discrete bus frequencies, in Hz
* @min_freq: Minimum sampling frequency, in Hz
* @max_freq: Maximum sampling bus frequency, in Hz
* @num_freq: Number of discrete sampling frequency supported
* @freq: Discrete sampling frequencies, in Hz
* @prep_ch_behave: Specifies the dependencies between Channel Prepare
* sequence and bus clock configuration
* If 0, Channel Prepare can happen at any Bus clock rate
* If 1, Channel Prepare sequence shall happen only after Bus clock is
* changed to a frequency supported by this mode or compatible modes
* described by the next field
* @glitchless: Bitmap describing possible glitchless transitions from this
* Audio Mode to other Audio Modes
*/
struct sdw_dpn_audio_mode {
u32 bus_min_freq;
u32 bus_max_freq;
u32 bus_num_freq;
u32 *bus_freq;
u32 max_freq;
u32 min_freq;
u32 num_freq;
u32 *freq;
u32 prep_ch_behave;
u32 glitchless;
}; };
/** /**
@ -299,24 +278,25 @@ struct sdw_dpn_audio_mode {
* @type: Data port type. Full, Simplified or Reduced * @type: Data port type. Full, Simplified or Reduced
* @max_grouping: Maximum number of samples that can be grouped together for * @max_grouping: Maximum number of samples that can be grouped together for
* a full data port * a full data port
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
* machine
* @ch_prep_timeout: Port-specific timeout value, in milliseconds * @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @imp_def_interrupts: If set, each bit corresponds to support for * @imp_def_interrupts: If set, each bit corresponds to support for
* implementation-defined interrupts * implementation-defined interrupts
* @max_ch: Maximum channels supported * @max_ch: Maximum channels supported
* @min_ch: Minimum channels supported * @min_ch: Minimum channels supported
* @num_channels: Number of discrete channels supported * @num_channels: Number of discrete channels supported
* @channels: Discrete channels supported
* @num_ch_combinations: Number of channel combinations supported * @num_ch_combinations: Number of channel combinations supported
* @channels: Discrete channels supported
* @ch_combinations: Channel combinations supported * @ch_combinations: Channel combinations supported
* @lane_list: indicates which Lanes can be used by DPn
* @num_lanes: array size of @lane_list
* @modes: SDW mode supported * @modes: SDW mode supported
* @max_async_buffer: Number of samples that this port can buffer in * @max_async_buffer: Number of samples that this port can buffer in
* asynchronous modes * asynchronous modes
* @port_encoding: Payload Channel Sample encoding schemes supported
* @block_pack_mode: Type of block port mode supported * @block_pack_mode: Type of block port mode supported
* @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register * @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register
* @port_encoding: Payload Channel Sample encoding schemes supported * @simple_ch_prep_sm: If the port supports simplified channel prepare state
* @audio_modes: Audio modes supported * machine
*/ */
struct sdw_dpn_prop { struct sdw_dpn_prop {
u32 num; u32 num;
@ -326,25 +306,29 @@ struct sdw_dpn_prop {
u32 *words; u32 *words;
enum sdw_dpn_type type; enum sdw_dpn_type type;
u32 max_grouping; u32 max_grouping;
bool simple_ch_prep_sm;
u32 ch_prep_timeout; u32 ch_prep_timeout;
u32 imp_def_interrupts; u32 imp_def_interrupts;
u32 max_ch; u32 max_ch;
u32 min_ch; u32 min_ch;
u32 num_channels; u32 num_channels;
u32 *channels;
u32 num_ch_combinations; u32 num_ch_combinations;
u32 *channels;
u32 *ch_combinations; u32 *ch_combinations;
u32 *lane_list;
int num_lanes;
u32 modes; u32 modes;
u32 max_async_buffer; u32 max_async_buffer;
u32 port_encoding;
bool block_pack_mode; bool block_pack_mode;
bool read_only_wordlength; bool read_only_wordlength;
u32 port_encoding; bool simple_ch_prep_sm;
struct sdw_dpn_audio_mode *audio_modes;
}; };
/** /**
* struct sdw_slave_prop - SoundWire Slave properties * struct sdw_slave_prop - SoundWire Slave properties
* @dp0_prop: Data Port 0 properties
* @src_dpn_prop: Source Data Port N properties
* @sink_dpn_prop: Sink Data Port N properties
* @mipi_revision: Spec version of the implementation * @mipi_revision: Spec version of the implementation
* @wake_capable: Wake-up events are supported * @wake_capable: Wake-up events are supported
* @test_mode_capable: If test mode is supported * @test_mode_capable: If test mode is supported
@ -361,23 +345,26 @@ struct sdw_dpn_prop {
* SCP_AddrPage2 * SCP_AddrPage2
* @bank_delay_support: Slave implements bank delay/bridge support registers * @bank_delay_support: Slave implements bank delay/bridge support registers
* SCP_BankDelay and SCP_NextFrame * SCP_BankDelay and SCP_NextFrame
* @lane_control_support: Slave supports lane control
* @p15_behave: Slave behavior when the Master attempts a read to the Port15 * @p15_behave: Slave behavior when the Master attempts a read to the Port15
* alias * alias
* @lane_control_support: Slave supports lane control
* @master_count: Number of Masters present on this Slave * @master_count: Number of Masters present on this Slave
* @source_ports: Bitmap identifying source ports * @source_ports: Bitmap identifying source ports
* @sink_ports: Bitmap identifying sink ports * @sink_ports: Bitmap identifying sink ports
* @dp0_prop: Data Port 0 properties
* @src_dpn_prop: Source Data Port N properties
* @sink_dpn_prop: Sink Data Port N properties
* @scp_int1_mask: SCP_INT1_MASK desired settings
* @quirks: bitmask identifying deltas from the MIPI specification * @quirks: bitmask identifying deltas from the MIPI specification
* @sdca_interrupt_register_list: indicates which sets of SDCA interrupt status
* and masks are supported
* @commit_register_supported: is PCP_Commit register supported
* @scp_int1_mask: SCP_INT1_MASK desired settings
* @clock_reg_supported: the Peripheral implements the clock base and scale * @clock_reg_supported: the Peripheral implements the clock base and scale
* registers introduced with the SoundWire 1.2 specification. SDCA devices * registers introduced with the SoundWire 1.2 specification. SDCA devices
* do not need to set this boolean property as the registers are required. * do not need to set this boolean property as the registers are required.
* @use_domain_irq: call actual IRQ handler on slave, as well as callback * @use_domain_irq: call actual IRQ handler on slave, as well as callback
*/ */
struct sdw_slave_prop { struct sdw_slave_prop {
struct sdw_dp0_prop *dp0_prop;
struct sdw_dpn_prop *src_dpn_prop;
struct sdw_dpn_prop *sink_dpn_prop;
u32 mipi_revision; u32 mipi_revision;
bool wake_capable; bool wake_capable;
bool test_mode_capable; bool test_mode_capable;
@ -389,16 +376,15 @@ struct sdw_slave_prop {
bool high_PHY_capable; bool high_PHY_capable;
bool paging_support; bool paging_support;
bool bank_delay_support; bool bank_delay_support;
enum sdw_p15_behave p15_behave;
bool lane_control_support; bool lane_control_support;
enum sdw_p15_behave p15_behave;
u32 master_count; u32 master_count;
u32 source_ports; u32 source_ports;
u32 sink_ports; u32 sink_ports;
struct sdw_dp0_prop *dp0_prop;
struct sdw_dpn_prop *src_dpn_prop;
struct sdw_dpn_prop *sink_dpn_prop;
u8 scp_int1_mask;
u32 quirks; u32 quirks;
u32 sdca_interrupt_register_list;
u8 commit_register_supported;
u8 scp_int1_mask;
bool clock_reg_supported; bool clock_reg_supported;
bool use_domain_irq; bool use_domain_irq;
}; };
@ -407,13 +393,14 @@ struct sdw_slave_prop {
/** /**
* struct sdw_master_prop - Master properties * struct sdw_master_prop - Master properties
* @clk_gears: Clock gears supported
* @clk_freq: Clock frequencies supported, in Hz
* @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
* @revision: MIPI spec version of the implementation * @revision: MIPI spec version of the implementation
* @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported * @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
* @max_clk_freq: Maximum Bus clock frequency, in Hz * @max_clk_freq: Maximum Bus clock frequency, in Hz
* @num_clk_gears: Number of clock gears supported * @num_clk_gears: Number of clock gears supported
* @clk_gears: Clock gears supported
* @num_clk_freq: Number of clock frequencies supported, in Hz * @num_clk_freq: Number of clock frequencies supported, in Hz
* @clk_freq: Clock frequencies supported, in Hz
* @default_frame_rate: Controller default Frame rate, in Hz * @default_frame_rate: Controller default Frame rate, in Hz
* @default_row: Number of rows * @default_row: Number of rows
* @default_col: Number of columns * @default_col: Number of columns
@ -422,24 +409,23 @@ struct sdw_slave_prop {
* command * command
* @mclk_freq: clock reference passed to SoundWire Master, in Hz. * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux * @hw_disabled: if true, the Master is not functional, typically due to pin-mux
* @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
*/ */
struct sdw_master_prop { struct sdw_master_prop {
u32 *clk_gears;
u32 *clk_freq;
u64 quirks;
u32 revision; u32 revision;
u32 clk_stop_modes; u32 clk_stop_modes;
u32 max_clk_freq; u32 max_clk_freq;
u32 num_clk_gears; u32 num_clk_gears;
u32 *clk_gears;
u32 num_clk_freq; u32 num_clk_freq;
u32 *clk_freq;
u32 default_frame_rate; u32 default_frame_rate;
u32 default_row; u32 default_row;
u32 default_col; u32 default_col;
bool dynamic_frame;
u32 err_threshold; u32 err_threshold;
u32 mclk_freq; u32 mclk_freq;
bool dynamic_frame;
bool hw_disabled; bool hw_disabled;
u64 quirks;
}; };
/* Definitions for Master quirks */ /* Definitions for Master quirks */
@ -631,7 +617,6 @@ struct sdw_slave_ops {
int (*clk_stop)(struct sdw_slave *slave, int (*clk_stop)(struct sdw_slave *slave,
enum sdw_clk_stop_mode mode, enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type); enum sdw_clk_stop_type type);
}; };
/** /**
@ -707,8 +692,7 @@ struct sdw_master_device {
container_of(d, struct sdw_master_device, dev) container_of(d, struct sdw_master_device, dev)
struct sdw_driver { struct sdw_driver {
int (*probe)(struct sdw_slave *sdw, int (*probe)(struct sdw_slave *sdw, const struct sdw_device_id *id);
const struct sdw_device_id *id);
int (*remove)(struct sdw_slave *sdw); int (*remove)(struct sdw_slave *sdw);
void (*shutdown)(struct sdw_slave *sdw); void (*shutdown)(struct sdw_slave *sdw);
@ -727,7 +711,7 @@ struct sdw_driver {
SDW_SLAVE_ENTRY_EXT((_mfg_id), (_part_id), 0, 0, (_drv_data)) SDW_SLAVE_ENTRY_EXT((_mfg_id), (_part_id), 0, 0, (_drv_data))
int sdw_handle_slave_status(struct sdw_bus *bus, int sdw_handle_slave_status(struct sdw_bus *bus,
enum sdw_slave_status status[]); enum sdw_slave_status status[]);
/* /*
* SDW master structures and APIs * SDW master structures and APIs
@ -809,29 +793,28 @@ struct sdw_enable_ch {
*/ */
struct sdw_master_port_ops { struct sdw_master_port_ops {
int (*dpn_set_port_params)(struct sdw_bus *bus, int (*dpn_set_port_params)(struct sdw_bus *bus,
struct sdw_port_params *port_params, struct sdw_port_params *port_params,
unsigned int bank); unsigned int bank);
int (*dpn_set_port_transport_params)(struct sdw_bus *bus, int (*dpn_set_port_transport_params)(struct sdw_bus *bus,
struct sdw_transport_params *transport_params, struct sdw_transport_params *transport_params,
enum sdw_reg_bank bank); enum sdw_reg_bank bank);
int (*dpn_port_prep)(struct sdw_bus *bus, int (*dpn_port_prep)(struct sdw_bus *bus, struct sdw_prepare_ch *prepare_ch);
struct sdw_prepare_ch *prepare_ch);
int (*dpn_port_enable_ch)(struct sdw_bus *bus, int (*dpn_port_enable_ch)(struct sdw_bus *bus,
struct sdw_enable_ch *enable_ch, unsigned int bank); struct sdw_enable_ch *enable_ch, unsigned int bank);
}; };
struct sdw_msg; struct sdw_msg;
/** /**
* struct sdw_defer - SDW deffered message * struct sdw_defer - SDW deferred message
* @length: message length
* @complete: message completion * @complete: message completion
* @msg: SDW message * @msg: SDW message
* @length: message length
*/ */
struct sdw_defer { struct sdw_defer {
struct sdw_msg *msg;
int length; int length;
struct completion complete; struct completion complete;
struct sdw_msg *msg;
}; };
/** /**
@ -852,14 +835,11 @@ struct sdw_defer {
*/ */
struct sdw_master_ops { struct sdw_master_ops {
int (*read_prop)(struct sdw_bus *bus); int (*read_prop)(struct sdw_bus *bus);
u64 (*override_adr) u64 (*override_adr)(struct sdw_bus *bus, u64 addr);
(struct sdw_bus *bus, u64 addr); enum sdw_command_response (*xfer_msg)(struct sdw_bus *bus, struct sdw_msg *msg);
enum sdw_command_response (*xfer_msg) enum sdw_command_response (*xfer_msg_defer)(struct sdw_bus *bus);
(struct sdw_bus *bus, struct sdw_msg *msg);
enum sdw_command_response (*xfer_msg_defer)
(struct sdw_bus *bus);
int (*set_bus_conf)(struct sdw_bus *bus, int (*set_bus_conf)(struct sdw_bus *bus,
struct sdw_bus_params *params); struct sdw_bus_params *params);
int (*pre_bank_switch)(struct sdw_bus *bus); int (*pre_bank_switch)(struct sdw_bus *bus);
int (*post_bank_switch)(struct sdw_bus *bus); int (*post_bank_switch)(struct sdw_bus *bus);
u32 (*read_ping_status)(struct sdw_bus *bus); u32 (*read_ping_status)(struct sdw_bus *bus);
@ -874,68 +854,71 @@ struct sdw_master_ops {
* struct sdw_bus - SoundWire bus * struct sdw_bus - SoundWire bus
* @dev: Shortcut to &bus->md->dev to avoid changing the entire code. * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
* @md: Master device * @md: Master device
* @controller_id: system-unique controller ID. If set to -1, the bus @id will be used. * @bus_lock_key: bus lock key associated to @bus_lock
* @link_id: Link id number, can be 0 to N, unique for each Controller
* @id: bus system-wide unique id
* @slaves: list of Slaves on this bus
* @assigned: Bitmap for Slave device numbers.
* Bit set implies used number, bit clear implies unused number.
* @bus_lock: bus lock * @bus_lock: bus lock
* @slaves: list of Slaves on this bus
* @msg_lock_key: message lock key associated to @msg_lock
* @msg_lock: message lock * @msg_lock: message lock
* @compute_params: points to Bus resource management implementation
* @ops: Master callback ops
* @port_ops: Master port callback ops
* @params: Current bus parameters
* @prop: Master properties
* @vendor_specific_prop: pointer to non-standard properties
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This * @m_rt_list: List of Master instance of all stream(s) running on Bus. This
* is used to compute and program bus bandwidth, clock, frame shape, * is used to compute and program bus bandwidth, clock, frame shape,
* transport and port parameters * transport and port parameters
* @debugfs: Bus debugfs
* @domain: IRQ domain
* @defer_msg: Defer message * @defer_msg: Defer message
* @clk_stop_timeout: Clock stop timeout computed * @params: Current bus parameters
* @bank_switch_timeout: Bank switch timeout computed * @stream_refcount: number of streams currently using this bus
* @multi_link: Store bus property that indicates if multi links * @ops: Master callback ops
* are supported. This flag is populated by drivers after reading * @port_ops: Master port callback ops
* appropriate firmware (ACPI/DT). * @prop: Master properties
* @vendor_specific_prop: pointer to non-standard properties
* @hw_sync_min_links: Number of links used by a stream above which * @hw_sync_min_links: Number of links used by a stream above which
* hardware-based synchronization is required. This value is only * hardware-based synchronization is required. This value is only
* meaningful if multi_link is set. If set to 1, hardware-based * meaningful if multi_link is set. If set to 1, hardware-based
* synchronization will be used even if a stream only uses a single * synchronization will be used even if a stream only uses a single
* SoundWire segment. * SoundWire segment.
* @stream_refcount: number of streams currently using this bus * @controller_id: system-unique controller ID. If set to -1, the bus @id will be used.
* @link_id: Link id number, can be 0 to N, unique for each Controller
* @id: bus system-wide unique id
* @compute_params: points to Bus resource management implementation
* @assigned: Bitmap for Slave device numbers.
* Bit set implies used number, bit clear implies unused number.
* @clk_stop_timeout: Clock stop timeout computed
* @bank_switch_timeout: Bank switch timeout computed
* @domain: IRQ domain
* @irq_chip: IRQ chip
* @debugfs: Bus debugfs (optional)
* @multi_link: Store bus property that indicates if multi links
* are supported. This flag is populated by drivers after reading
* appropriate firmware (ACPI/DT).
*/ */
struct sdw_bus { struct sdw_bus {
struct device *dev; struct device *dev;
struct sdw_master_device *md; struct sdw_master_device *md;
struct lock_class_key bus_lock_key;
struct mutex bus_lock;
struct list_head slaves;
struct lock_class_key msg_lock_key;
struct mutex msg_lock;
struct list_head m_rt_list;
struct sdw_defer defer_msg;
struct sdw_bus_params params;
int stream_refcount;
const struct sdw_master_ops *ops;
const struct sdw_master_port_ops *port_ops;
struct sdw_master_prop prop;
void *vendor_specific_prop;
int hw_sync_min_links;
int controller_id; int controller_id;
unsigned int link_id; unsigned int link_id;
int id; int id;
struct list_head slaves;
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
struct mutex bus_lock;
struct lock_class_key bus_lock_key;
struct mutex msg_lock;
struct lock_class_key msg_lock_key;
int (*compute_params)(struct sdw_bus *bus); int (*compute_params)(struct sdw_bus *bus);
const struct sdw_master_ops *ops; DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
const struct sdw_master_port_ops *port_ops; unsigned int clk_stop_timeout;
struct sdw_bus_params params; u32 bank_switch_timeout;
struct sdw_master_prop prop; struct irq_chip irq_chip;
void *vendor_specific_prop; struct irq_domain *domain;
struct list_head m_rt_list;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
#endif #endif
struct irq_chip irq_chip;
struct irq_domain *domain;
struct sdw_defer defer_msg;
unsigned int clk_stop_timeout;
u32 bank_switch_timeout;
bool multi_link; bool multi_link;
int hw_sync_min_links;
int stream_refcount;
}; };
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
@ -1013,18 +996,18 @@ struct sdw_stream_params {
* @params: Stream parameters * @params: Stream parameters
* @state: Current state of the stream * @state: Current state of the stream
* @type: Stream type PCM or PDM * @type: Stream type PCM or PDM
* @m_rt_count: Count of Master runtime(s) in this stream
* @master_list: List of Master runtime(s) in this stream. * @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance * master_list can contain only one m_rt per Master instance
* for a stream * for a stream
* @m_rt_count: Count of Master runtime(s) in this stream
*/ */
struct sdw_stream_runtime { struct sdw_stream_runtime {
const char *name; const char *name;
struct sdw_stream_params params; struct sdw_stream_params params;
enum sdw_stream_state state; enum sdw_stream_state state;
enum sdw_stream_type type; enum sdw_stream_type type;
struct list_head master_list;
int m_rt_count; int m_rt_count;
struct list_head master_list;
}; };
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name); struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
@ -1033,12 +1016,12 @@ void sdw_release_stream(struct sdw_stream_runtime *stream);
int sdw_compute_params(struct sdw_bus *bus); int sdw_compute_params(struct sdw_bus *bus);
int sdw_stream_add_master(struct sdw_bus *bus, int sdw_stream_add_master(struct sdw_bus *bus,
struct sdw_stream_config *stream_config, struct sdw_stream_config *stream_config,
const struct sdw_port_config *port_config, const struct sdw_port_config *port_config,
unsigned int num_ports, unsigned int num_ports,
struct sdw_stream_runtime *stream); struct sdw_stream_runtime *stream);
int sdw_stream_remove_master(struct sdw_bus *bus, int sdw_stream_remove_master(struct sdw_bus *bus,
struct sdw_stream_runtime *stream); struct sdw_stream_runtime *stream);
int sdw_startup_stream(void *sdw_substream); int sdw_startup_stream(void *sdw_substream);
int sdw_prepare_stream(struct sdw_stream_runtime *stream); int sdw_prepare_stream(struct sdw_stream_runtime *stream);
int sdw_enable_stream(struct sdw_stream_runtime *stream); int sdw_enable_stream(struct sdw_stream_runtime *stream);

View File

@ -27,9 +27,11 @@
#define ACP_SDW0 0 #define ACP_SDW0 0
#define ACP_SDW1 1 #define ACP_SDW1 1
#define AMD_SDW_MAX_MANAGER_COUNT 2 #define AMD_SDW_MAX_MANAGER_COUNT 2
#define ACP63_PCI_REV_ID 0x63
struct acp_sdw_pdata { struct acp_sdw_pdata {
u16 instance; u16 instance;
u32 acp_rev;
/* mutex to protect acp common register access */ /* mutex to protect acp common register access */
struct mutex *acp_sdw_lock; struct mutex *acp_sdw_lock;
}; };
@ -66,6 +68,7 @@ struct sdw_amd_dai_runtime {
* @instance: SoundWire manager instance * @instance: SoundWire manager instance
* @quirks: SoundWire manager quirks * @quirks: SoundWire manager quirks
* @wake_en_mask: wake enable mask per SoundWire manager * @wake_en_mask: wake enable mask per SoundWire manager
* @acp_rev: acp pci device revision id
* @clk_stopped: flag set to true when clock is stopped * @clk_stopped: flag set to true when clock is stopped
* @power_mode_mask: flag interprets amd SoundWire manager power mode * @power_mode_mask: flag interprets amd SoundWire manager power mode
* @dai_runtime_array: dai runtime array * @dai_runtime_array: dai runtime array
@ -94,6 +97,7 @@ struct amd_sdw_manager {
u32 quirks; u32 quirks;
u32 wake_en_mask; u32 wake_en_mask;
u32 power_mode_mask; u32 power_mode_mask;
u32 acp_rev;
bool clk_stopped; bool clk_stopped;
struct sdw_amd_dai_runtime **dai_runtime_array; struct sdw_amd_dai_runtime **dai_runtime_array;
@ -131,6 +135,7 @@ struct sdw_amd_ctx {
* struct sdw_amd_res - Soundwire AMD global resource structure, * struct sdw_amd_res - Soundwire AMD global resource structure,
* typically populated by the DSP driver/Legacy driver * typically populated by the DSP driver/Legacy driver
* *
* @acp_rev: acp pci device revision id
* @addr: acp pci device resource start address * @addr: acp pci device resource start address
* @reg_range: ACP register range * @reg_range: ACP register range
* @link_mask: bit-wise mask listing links selected by the DSP driver/ * @link_mask: bit-wise mask listing links selected by the DSP driver/
@ -143,6 +148,7 @@ struct sdw_amd_ctx {
* @acp_lock: mutex protecting acp common registers access * @acp_lock: mutex protecting acp common registers access
*/ */
struct sdw_amd_res { struct sdw_amd_res {
u32 acp_rev;
u32 addr; u32 addr;
u32 reg_range; u32 reg_range;
u32 link_mask; u32 link_mask;

View File

@ -231,6 +231,7 @@ struct sdw_dma_ring_buf_reg {
* @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled
* @addr: pci ioremap address * @addr: pci ioremap address
* @reg_range: ACP reigister range * @reg_range: ACP reigister range
* @acp_rev: ACP PCI revision id
* @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance * @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance
* @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance * @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance
*/ */
@ -254,6 +255,7 @@ struct acp63_dev_data {
bool sdw_en_stat; bool sdw_en_stat;
u32 addr; u32 addr;
u32 reg_range; u32 reg_range;
u32 acp_rev;
u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS]; u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS]; u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
}; };

View File

@ -267,6 +267,7 @@ static int amd_sdw_probe(struct device *dev)
sdw_res.acp_lock = &acp_data->acp_lock; sdw_res.acp_lock = &acp_data->acp_lock;
sdw_res.count = acp_data->info.count; sdw_res.count = acp_data->info.count;
sdw_res.mmio_base = acp_data->acp63_base; sdw_res.mmio_base = acp_data->acp63_base;
sdw_res.acp_rev = acp_data->acp_rev;
sdw_res.link_mask = acp_data->info.link_mask; sdw_res.link_mask = acp_data->info.link_mask;
ret = sdw_amd_probe(&sdw_res, &acp_data->sdw); ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
if (ret) if (ret)
@ -575,6 +576,7 @@ static int snd_acp63_probe(struct pci_dev *pci,
} }
adata->addr = addr; adata->addr = addr;
adata->reg_range = ACP63_REG_END - ACP63_REG_START; adata->reg_range = ACP63_REG_END - ACP63_REG_START;
adata->acp_rev = pci->revision;
pci_set_master(pci); pci_set_master(pci);
pci_set_drvdata(pci, adata); pci_set_drvdata(pci, adata);
mutex_init(&adata->acp_lock); mutex_init(&adata->acp_lock);

View File

@ -693,6 +693,7 @@ static int amd_sof_sdw_probe(struct snd_sof_dev *sdev)
sdw_res.count = acp_data->info.count; sdw_res.count = acp_data->info.count;
sdw_res.link_mask = acp_data->info.link_mask; sdw_res.link_mask = acp_data->info.link_mask;
sdw_res.mmio_base = sdev->bar[ACP_DSP_BAR]; sdw_res.mmio_base = sdev->bar[ACP_DSP_BAR];
sdw_res.acp_rev = acp_data->pci_rev;
ret = sdw_amd_probe(&sdw_res, &acp_data->sdw); ret = sdw_amd_probe(&sdw_res, &acp_data->sdw);
if (ret) if (ret)