From 02e824e524055c04ff0488cb62a9bfaa49327611 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 6 May 2024 10:55:05 -0500 Subject: [PATCH 01/17] ALSA/hda: intel-sdw-acpi: cleanup sdw_intel_scan_controller Remove unnecessary initialization and un-shadow return code. Suggested-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/hda/intel-sdw-acpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 04d6b6beabca58..770dabe0124f1d 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -63,7 +63,6 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) return -EINVAL; /* Found controller, find links supported */ - count = 0; ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), "mipi-sdw-master-count", &count, 1); @@ -82,7 +81,7 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) if (ret) { dev_err(&adev->dev, "Failed to read mipi-sdw-master-count: %d\n", ret); - return -EINVAL; + return ret; } /* Check count is within bounds */ From c0b24c735a4d344dd8340c66fa5c4bcef0256bf2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 13 May 2024 10:17:16 -0500 Subject: [PATCH 02/17] ALSA/hda: intel-sdw-acpi: fetch fwnode once in sdw_intel_scan_controller() Optimize a bit by using an intermediate 'fwnode' variable. Suggested-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/hda/intel-sdw-acpi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 770dabe0124f1d..7a3735e9454549 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -56,15 +56,17 @@ static int sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) { struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle); + struct fwnode_handle *fwnode; u8 count, i; int ret; if (!adev) return -EINVAL; + fwnode = acpi_fwnode_handle(adev); + /* Found controller, find links supported */ - ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), - "mipi-sdw-master-count", &count, 1); + ret = fwnode_property_read_u8_array(fwnode, "mipi-sdw-master-count", &count, 1); /* * In theory we could check the number of links supported in @@ -107,7 +109,7 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) continue; } - if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { + if (!is_link_enabled(fwnode, i)) { dev_dbg(&adev->dev, "Link %d not selected in firmware\n", i); continue; From 52f4f5d9d2743bc7616de6f7818212d930e77064 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 14:54:45 -0500 Subject: [PATCH 03/17] ALSA/hda: intel-sdw-acpi: simplify sdw-master-count property read For some reason we used an array of one u8 when the specification requires a u32. Signed-off-by: Pierre-Louis Bossart --- sound/hda/intel-sdw-acpi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 7a3735e9454549..582e761e7b9fc1 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -57,7 +57,8 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) { struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle); struct fwnode_handle *fwnode; - u8 count, i; + unsigned int i; + u32 count; int ret; if (!adev) @@ -66,7 +67,7 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) fwnode = acpi_fwnode_handle(adev); /* Found controller, find links supported */ - ret = fwnode_property_read_u8_array(fwnode, "mipi-sdw-master-count", &count, 1); + ret = fwnode_property_read_u32(fwnode, "mipi-sdw-master-count", &count); /* * In theory we could check the number of links supported in From 087438944ba392334039c9aff0b851c7d673f4c3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 15:05:26 -0500 Subject: [PATCH 04/17] ALSA/hda: intel-sdw-acpi: add support for sdw-manager-list property read The DisCo for SoundWire 2.0 spec adds support for a new sdw-manager-list property. Add it in backwards-compatible mode with 'sdw-master-count', which assumed that all links between 0..count-1 exist. Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw_intel.h | 2 +- sound/hda/intel-sdw-acpi.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 37ae69365fe263..734dc1fa3b5bc3 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -227,7 +227,7 @@ struct sdw_intel_ops { /** * struct sdw_intel_acpi_info - Soundwire Intel information found in ACPI tables * @handle: ACPI controller handle - * @count: link count found with "sdw-master-count" property + * @count: link count found with "sdw-master-count" or "sdw-manager-list" property * @link_mask: bit-wise mask listing links enabled by BIOS menu * * this structure could be expanded to e.g. provide all the _ADR diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 582e761e7b9fc1..ed530e0dd4ddcc 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -57,8 +57,10 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) { struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle); struct fwnode_handle *fwnode; + unsigned long list; unsigned int i; u32 count; + u32 tmp; int ret; if (!adev) @@ -66,10 +68,9 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) fwnode = acpi_fwnode_handle(adev); - /* Found controller, find links supported */ - ret = fwnode_property_read_u32(fwnode, "mipi-sdw-master-count", &count); - /* + * Found controller, find links supported + * * In theory we could check the number of links supported in * hardware, but in that step we cannot assume SoundWire IP is * powered. @@ -80,11 +81,19 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) * * We will check the hardware capabilities in the startup() step */ - + ret = fwnode_property_read_u32(fwnode, "mipi-sdw-manager-list", &tmp); if (ret) { - dev_err(&adev->dev, - "Failed to read mipi-sdw-master-count: %d\n", ret); - return ret; + ret = fwnode_property_read_u32(fwnode, "mipi-sdw-master-count", &count); + if (ret) { + dev_err(&adev->dev, + "Failed to read mipi-sdw-master-count: %d\n", + ret); + return ret; + } + list = GENMASK(count - 1, 0); + } else { + list = tmp; + count = hweight32(list); } /* Check count is within bounds */ @@ -103,7 +112,7 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) info->count = count; info->link_mask = 0; - for (i = 0; i < count; i++) { + for_each_set_bit(i, &list, SDW_INTEL_MAX_LINKS) { if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { dev_dbg(&adev->dev, "Link %d masked, will not be enabled\n", i); From 06532cb233101b5f32481c083a79b19cca98b7c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 16:44:18 +0200 Subject: [PATCH 05/17] soundwire: optimize sdw_stream_runtime memory layout pahole suggestion: swap position of 'm_rt_count' before: pahole -C sdw_stream_runtime drivers/soundwire/soundwire-bus.ko struct sdw_stream_runtime { const char * name; /* 0 8 */ struct sdw_stream_params params; /* 8 12 */ enum sdw_stream_state state; /* 20 4 */ enum sdw_stream_type type; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ struct list_head master_list; /* 32 16 */ int m_rt_count; /* 48 4 */ /* size: 56, cachelines: 1, members: 6 */ /* sum members: 48, holes: 1, sum holes: 4 */ /* padding: 4 */ /* last cacheline: 56 bytes */ }; after: pahole --reorganize -C sdw_stream_runtime drivers/soundwire/soundwire-bus.ko struct sdw_stream_runtime { const char * name; /* 0 8 */ struct sdw_stream_params params; /* 8 12 */ enum sdw_stream_state state; /* 20 4 */ enum sdw_stream_type type; /* 24 4 */ int m_rt_count; /* 28 4 */ struct list_head master_list; /* 32 16 */ /* size: 48, cachelines: 1, members: 6 */ /* last cacheline: 48 bytes */ }; /* saved 8 bytes! */ Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 5e0dd47a041240..a4fa4513203052 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -820,15 +820,15 @@ struct sdw_master_port_ops { struct sdw_msg; /** - * struct sdw_defer - SDW deffered message - * @length: message length + * struct sdw_defer - SDW deferred message * @complete: message completion * @msg: SDW message + * @length: message length */ struct sdw_defer { + struct sdw_msg *msg; int length; struct completion complete; - struct sdw_msg *msg; }; /** @@ -1010,18 +1010,18 @@ struct sdw_stream_params { * @params: Stream parameters * @state: Current state of the stream * @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 can contain only one m_rt per Master instance * for a stream - * @m_rt_count: Count of Master runtime(s) in this stream */ struct sdw_stream_runtime { const char *name; struct sdw_stream_params params; enum sdw_stream_state state; enum sdw_stream_type type; - struct list_head master_list; int m_rt_count; + struct list_head master_list; }; struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name); From 6fc18a3653a80506fa466372fe797536de84a3d5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 21:38:52 +0200 Subject: [PATCH 06/17] soundwire: optimize sdw_master_prop Make pahole happy by moving pointers and u64 first instead of interleaving them. Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index a4fa4513203052..2caea7345c3eb7 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -406,13 +406,14 @@ struct sdw_slave_prop { /** * 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 * @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported * @max_clk_freq: Maximum Bus clock frequency, in Hz * @num_clk_gears: Number of clock gears supported - * @clk_gears: Clock gears supported * @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_row: Number of rows * @default_col: Number of columns @@ -421,24 +422,23 @@ struct sdw_slave_prop { * command * @mclk_freq: clock reference passed to SoundWire Master, in Hz. * @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 { + u32 *clk_gears; + u32 *clk_freq; + u64 quirks; u32 revision; u32 clk_stop_modes; u32 max_clk_freq; u32 num_clk_gears; - u32 *clk_gears; u32 num_clk_freq; - u32 *clk_freq; u32 default_frame_rate; u32 default_row; u32 default_col; - bool dynamic_frame; u32 err_threshold; u32 mclk_freq; + bool dynamic_frame; bool hw_disabled; - u64 quirks; }; /* Definitions for Master quirks */ From 96fbb525d508f8f99fb57d565bd23e3af678f08f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 21:35:58 +0200 Subject: [PATCH 07/17] soundwire: optimize sdw_bus structure The sdw_bus structure has seen multiple additions over the years. It's one of the most used structures in this subsystem, so there's merit in reshuffling the members a bit with 'pahole' to reduce holes and structures across cache lines. before: struct sdw_bus { struct device * dev; /* 0 8 */ struct sdw_master_device * md; /* 8 8 */ int controller_id; /* 16 4 */ unsigned int link_id; /* 20 4 */ int id; /* 24 4 */ /* XXX 4 bytes hole, try to pack */ struct list_head slaves; /* 32 16 */ long unsigned int assigned[1]; /* 48 8 */ struct mutex bus_lock; /* 56 160 */ /* --- cacheline 3 boundary (192 bytes) was 24 bytes ago --- */ struct lock_class_key bus_lock_key; /* 216 16 */ struct mutex msg_lock; /* 232 160 */ /* --- cacheline 6 boundary (384 bytes) was 8 bytes ago --- */ struct lock_class_key msg_lock_key; /* 392 16 */ int (*compute_params)(struct sdw_bus *); /* 408 8 */ const struct sdw_master_ops * ops; /* 416 8 */ const struct sdw_master_port_ops * port_ops; /* 424 8 */ struct sdw_bus_params params; /* 432 36 */ /* XXX 4 bytes hole, try to pack */ /* --- cacheline 7 boundary (448 bytes) was 24 bytes ago --- */ struct sdw_master_prop prop; /* 472 72 */ /* XXX last struct has 6 bytes of padding */ /* --- cacheline 8 boundary (512 bytes) was 32 bytes ago --- */ void * vendor_specific_prop; /* 544 8 */ struct list_head m_rt_list; /* 552 16 */ struct dentry * debugfs; /* 568 8 */ /* --- cacheline 9 boundary (576 bytes) --- */ struct irq_chip irq_chip; /* 576 264 */ /* --- cacheline 13 boundary (832 bytes) was 8 bytes ago --- */ struct irq_domain * domain; /* 840 8 */ struct sdw_defer defer_msg; /* 848 112 */ /* --- cacheline 15 boundary (960 bytes) --- */ unsigned int clk_stop_timeout; /* 960 4 */ u32 bank_switch_timeout; /* 964 4 */ bool multi_link; /* 968 1 */ /* XXX 3 bytes hole, try to pack */ int hw_sync_min_links; /* 972 4 */ int stream_refcount; /* 976 4 */ /* size: 984, cachelines: 16, members: 27 */ /* sum members: 969, holes: 3, sum holes: 11 */ /* padding: 4 */ /* paddings: 1, sum paddings: 6 */ /* last cacheline: 24 bytes */ }; after: struct sdw_bus { struct device * dev; /* 0 8 */ struct sdw_master_device * md; /* 8 8 */ struct lock_class_key bus_lock_key; /* 16 16 */ struct mutex bus_lock; /* 32 160 */ /* --- cacheline 3 boundary (192 bytes) --- */ struct list_head slaves; /* 192 16 */ struct lock_class_key msg_lock_key; /* 208 16 */ struct mutex msg_lock; /* 224 160 */ /* --- cacheline 6 boundary (384 bytes) --- */ struct list_head m_rt_list; /* 384 16 */ struct sdw_defer defer_msg; /* 400 112 */ /* --- cacheline 8 boundary (512 bytes) --- */ struct sdw_bus_params params; /* 512 36 */ int stream_refcount; /* 548 4 */ const struct sdw_master_ops * ops; /* 552 8 */ const struct sdw_master_port_ops * port_ops; /* 560 8 */ struct sdw_master_prop prop; /* 568 72 */ /* XXX last struct has 6 bytes of padding */ /* --- cacheline 10 boundary (640 bytes) --- */ void * vendor_specific_prop; /* 640 8 */ int hw_sync_min_links; /* 648 4 */ int controller_id; /* 652 4 */ unsigned int link_id; /* 656 4 */ int id; /* 660 4 */ int (*compute_params)(struct sdw_bus *); /* 664 8 */ long unsigned int assigned[1]; /* 672 8 */ unsigned int clk_stop_timeout; /* 680 4 */ u32 bank_switch_timeout; /* 684 4 */ struct irq_chip irq_chip; /* 688 264 */ /* --- cacheline 14 boundary (896 bytes) was 56 bytes ago --- */ struct irq_domain * domain; /* 952 8 */ /* --- cacheline 15 boundary (960 bytes) --- */ struct dentry * debugfs; /* 960 8 */ bool multi_link; /* 968 1 */ /* size: 976, cachelines: 16, members: 27 */ /* padding: 7 */ /* paddings: 1, sum paddings: 6 */ /* last cacheline: 16 bytes */ }; Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 77 ++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 2caea7345c3eb7..6fcf122c183129 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -871,68 +871,71 @@ struct sdw_master_ops { * struct sdw_bus - SoundWire bus * @dev: Shortcut to &bus->md->dev to avoid changing the entire code. * @md: Master device - * @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 - * @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_key: bus lock key associated to @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 - * @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 * is used to compute and program bus bandwidth, clock, frame shape, * transport and port parameters - * @debugfs: Bus debugfs - * @domain: IRQ domain * @defer_msg: Defer message - * @clk_stop_timeout: Clock stop timeout computed - * @bank_switch_timeout: Bank switch timeout computed - * @multi_link: Store bus property that indicates if multi links - * are supported. This flag is populated by drivers after reading - * appropriate firmware (ACPI/DT). + * @params: Current bus parameters + * @stream_refcount: number of streams currently using this bus + * @ops: Master callback ops + * @port_ops: Master port callback ops + * @prop: Master properties + * @vendor_specific_prop: pointer to non-standard properties * @hw_sync_min_links: Number of links used by a stream above which * hardware-based synchronization is required. This value is only * meaningful if multi_link is set. If set to 1, hardware-based * synchronization will be used even if a stream only uses a single * 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 device *dev; struct sdw_master_device *md; - int controller_id; - unsigned int link_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 mutex bus_lock; + struct list_head slaves; struct lock_class_key msg_lock_key; - int (*compute_params)(struct sdw_bus *bus); + 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_bus_params params; struct sdw_master_prop prop; void *vendor_specific_prop; - struct list_head m_rt_list; + int hw_sync_min_links; + int controller_id; + unsigned int link_id; + int id; + int (*compute_params)(struct sdw_bus *bus); + DECLARE_BITMAP(assigned, SDW_MAX_DEVICES); + unsigned int clk_stop_timeout; + u32 bank_switch_timeout; + struct irq_chip irq_chip; + struct irq_domain *domain; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; #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; - int hw_sync_min_links; - int stream_refcount; }; int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, From eb0a70187fc38b9bf412bebf0d0fb90af9d616d0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 21:52:33 +0200 Subject: [PATCH 08/17] soundwire: optimize sdw_slave_prop move pointers first, and move booleans together. before: struct sdw_slave_prop { u32 mipi_revision; /* 0 4 */ bool wake_capable; /* 4 1 */ bool test_mode_capable; /* 5 1 */ bool clk_stop_mode1; /* 6 1 */ bool simple_clk_stop_capable; /* 7 1 */ u32 clk_stop_timeout; /* 8 4 */ u32 ch_prep_timeout; /* 12 4 */ enum sdw_clk_stop_reset_behave reset_behave; /* 16 4 */ bool high_PHY_capable; /* 20 1 */ bool paging_support; /* 21 1 */ bool bank_delay_support; /* 22 1 */ /* XXX 1 byte hole, try to pack */ enum sdw_p15_behave p15_behave; /* 24 4 */ bool lane_control_support; /* 28 1 */ /* XXX 3 bytes hole, try to pack */ u32 master_count; /* 32 4 */ u32 source_ports; /* 36 4 */ u32 sink_ports; /* 40 4 */ /* XXX 4 bytes hole, try to pack */ struct sdw_dp0_prop * dp0_prop; /* 48 8 */ struct sdw_dpn_prop * src_dpn_prop; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct sdw_dpn_prop * sink_dpn_prop; /* 64 8 */ u8 scp_int1_mask; /* 72 1 */ /* XXX 3 bytes hole, try to pack */ u32 quirks; /* 76 4 */ bool clock_reg_supported; /* 80 1 */ bool use_domain_irq; /* 81 1 */ /* size: 88, cachelines: 2, members: 23 */ /* sum members: 71, holes: 4, sum holes: 11 */ /* padding: 6 */ /* last cacheline: 24 bytes */ }; after: truct sdw_slave_prop { struct sdw_dp0_prop * dp0_prop; /* 0 8 */ struct sdw_dpn_prop * src_dpn_prop; /* 8 8 */ struct sdw_dpn_prop * sink_dpn_prop; /* 16 8 */ u32 mipi_revision; /* 24 4 */ bool wake_capable; /* 28 1 */ bool test_mode_capable; /* 29 1 */ bool clk_stop_mode1; /* 30 1 */ bool simple_clk_stop_capable; /* 31 1 */ u32 clk_stop_timeout; /* 32 4 */ u32 ch_prep_timeout; /* 36 4 */ enum sdw_clk_stop_reset_behave reset_behave; /* 40 4 */ bool high_PHY_capable; /* 44 1 */ bool paging_support; /* 45 1 */ bool bank_delay_support; /* 46 1 */ bool lane_control_support; /* 47 1 */ enum sdw_p15_behave p15_behave; /* 48 4 */ u32 master_count; /* 52 4 */ u32 source_ports; /* 56 4 */ u32 sink_ports; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ u32 quirks; /* 64 4 */ u8 scp_int1_mask; /* 68 1 */ bool clock_reg_supported; /* 69 1 */ bool use_domain_irq; /* 70 1 */ /* size: 72, cachelines: 2, members: 23 */ /* padding: 1 */ /* last cacheline: 8 bytes */ }; Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 6fcf122c183129..38db81f5bdb976 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -344,6 +344,9 @@ struct sdw_dpn_prop { /** * 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 * @wake_capable: Wake-up events are supported * @test_mode_capable: If test mode is supported @@ -360,15 +363,12 @@ struct sdw_dpn_prop { * SCP_AddrPage2 * @bank_delay_support: Slave implements bank delay/bridge support registers * 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 * alias - * @lane_control_support: Slave supports lane control * @master_count: Number of Masters present on this Slave * @source_ports: Bitmap identifying source 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 * @clock_reg_supported: the Peripheral implements the clock base and scale @@ -377,6 +377,9 @@ struct sdw_dpn_prop { * @use_domain_irq: call actual IRQ handler on slave, as well as callback */ 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; bool wake_capable; bool test_mode_capable; @@ -388,16 +391,13 @@ struct sdw_slave_prop { bool high_PHY_capable; bool paging_support; bool bank_delay_support; - enum sdw_p15_behave p15_behave; bool lane_control_support; + enum sdw_p15_behave p15_behave; u32 master_count; u32 source_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; + u8 scp_int1_mask; bool clock_reg_supported; bool use_domain_irq; }; From 023c30d43877ef7c71aad796f3ea30c9cc15a93f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2024 21:57:43 +0200 Subject: [PATCH 09/17] soundwire: optimize sdw_dp0_prop Move pointers and booleans. Before: struct sdw_dp0_prop { u32 max_word; /* 0 4 */ u32 min_word; /* 4 4 */ u32 num_words; /* 8 4 */ /* XXX 4 bytes hole, try to pack */ u32 * words; /* 16 8 */ bool BRA_flow_controlled; /* 24 1 */ bool simple_ch_prep_sm; /* 25 1 */ /* XXX 2 bytes hole, try to pack */ u32 ch_prep_timeout; /* 28 4 */ bool imp_def_interrupts; /* 32 1 */ /* size: 40, cachelines: 1, members: 8 */ /* sum members: 27, holes: 2, sum holes: 6 */ /* padding: 7 */ /* last cacheline: 40 bytes */ }; after: struct sdw_dp0_prop { u32 * words; /* 0 8 */ u32 max_word; /* 8 4 */ u32 min_word; /* 12 4 */ u32 num_words; /* 16 4 */ u32 ch_prep_timeout; /* 20 4 */ bool BRA_flow_controlled; /* 24 1 */ bool simple_ch_prep_sm; /* 25 1 */ bool imp_def_interrupts; /* 26 1 */ /* size: 32, cachelines: 1, members: 8 */ /* padding: 5 */ /* last cacheline: 32 bytes */ }; Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 38db81f5bdb976..c72095137a35ea 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -226,16 +226,16 @@ enum sdw_clk_stop_mode { /** * struct sdw_dp0_prop - DP0 properties + * @words: wordlengths supported * @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64 * (inclusive) * @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64 * (inclusive) * @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 * response * @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 * implementation-defined interrupts * @@ -244,13 +244,13 @@ enum sdw_clk_stop_mode { * support */ struct sdw_dp0_prop { + u32 *words; u32 max_word; u32 min_word; u32 num_words; - u32 *words; + u32 ch_prep_timeout; bool BRA_flow_controlled; bool simple_ch_prep_sm; - u32 ch_prep_timeout; bool imp_def_interrupts; }; From 67809a7189b4c0c6b5e656642204876e821238b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 25 Jun 2024 09:58:54 +0200 Subject: [PATCH 10/17] soundwire: optimize sdw_dpn_prop before: struct sdw_dpn_prop { u32 num; /* 0 4 */ u32 max_word; /* 4 4 */ u32 min_word; /* 8 4 */ u32 num_words; /* 12 4 */ u32 * words; /* 16 8 */ enum sdw_dpn_type type; /* 24 4 */ u32 max_grouping; /* 28 4 */ bool simple_ch_prep_sm; /* 32 1 */ /* XXX 3 bytes hole, try to pack */ u32 ch_prep_timeout; /* 36 4 */ u32 imp_def_interrupts; /* 40 4 */ u32 max_ch; /* 44 4 */ u32 min_ch; /* 48 4 */ u32 num_channels; /* 52 4 */ u32 * channels; /* 56 8 */ /* --- cacheline 1 boundary (64 bytes) --- */ u32 num_ch_combinations; /* 64 4 */ /* XXX 4 bytes hole, try to pack */ u32 * ch_combinations; /* 72 8 */ u32 modes; /* 80 4 */ u32 max_async_buffer; /* 84 4 */ bool block_pack_mode; /* 88 1 */ bool read_only_wordlength; /* 89 1 */ /* XXX 2 bytes hole, try to pack */ u32 port_encoding; /* 92 4 */ struct sdw_dpn_audio_mode * audio_modes; /* 96 8 */ /* size: 104, cachelines: 2, members: 22 */ /* sum members: 95, holes: 3, sum holes: 9 */ /* last cacheline: 40 bytes */ }; after: struct sdw_dpn_prop { struct sdw_dpn_audio_mode * audio_modes; /* 0 8 */ u32 num; /* 8 4 */ u32 max_word; /* 12 4 */ u32 min_word; /* 16 4 */ u32 num_words; /* 20 4 */ u32 * words; /* 24 8 */ enum sdw_dpn_type type; /* 32 4 */ u32 max_grouping; /* 36 4 */ u32 ch_prep_timeout; /* 40 4 */ u32 imp_def_interrupts; /* 44 4 */ u32 max_ch; /* 48 4 */ u32 min_ch; /* 52 4 */ u32 num_channels; /* 56 4 */ u32 num_ch_combinations; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ u32 * channels; /* 64 8 */ u32 * ch_combinations; /* 72 8 */ u32 modes; /* 80 4 */ u32 max_async_buffer; /* 84 4 */ u32 port_encoding; /* 88 4 */ bool block_pack_mode; /* 92 1 */ bool read_only_wordlength; /* 93 1 */ bool simple_ch_prep_sm; /* 94 1 */ /* size: 96, cachelines: 2, members: 22 */ /* padding: 1 */ /* last cacheline: 32 bytes */ }; Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index c72095137a35ea..cc0afb8af3332b 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -288,6 +288,7 @@ struct sdw_dpn_audio_mode { /** * struct sdw_dpn_prop - Data Port DPn properties + * @audio_modes: Audio modes supported * @num: port number * @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64 * (inclusive) @@ -298,26 +299,26 @@ struct sdw_dpn_audio_mode { * @type: Data port type. Full, Simplified or Reduced * @max_grouping: Maximum number of samples that can be grouped together for * 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 * @imp_def_interrupts: If set, each bit corresponds to support for * implementation-defined interrupts * @max_ch: Maximum channels supported * @min_ch: Minimum channels supported * @num_channels: Number of discrete channels supported - * @channels: Discrete channels supported * @num_ch_combinations: Number of channel combinations supported + * @channels: Discrete channels supported * @ch_combinations: Channel combinations supported * @modes: SDW mode supported * @max_async_buffer: Number of samples that this port can buffer in * asynchronous modes + * @port_encoding: Payload Channel Sample encoding schemes supported * @block_pack_mode: Type of block port mode supported * @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register - * @port_encoding: Payload Channel Sample encoding schemes supported - * @audio_modes: Audio modes supported + * @simple_ch_prep_sm: If the port supports simplified channel prepare state + * machine */ struct sdw_dpn_prop { + struct sdw_dpn_audio_mode *audio_modes; u32 num; u32 max_word; u32 min_word; @@ -325,21 +326,20 @@ struct sdw_dpn_prop { u32 *words; enum sdw_dpn_type type; u32 max_grouping; - bool simple_ch_prep_sm; u32 ch_prep_timeout; u32 imp_def_interrupts; u32 max_ch; u32 min_ch; u32 num_channels; - u32 *channels; u32 num_ch_combinations; + u32 *channels; u32 *ch_combinations; u32 modes; u32 max_async_buffer; + u32 port_encoding; bool block_pack_mode; bool read_only_wordlength; - u32 port_encoding; - struct sdw_dpn_audio_mode *audio_modes; + bool simple_ch_prep_sm; }; /** From aad12d9493b61aff6a157921b904087275ac2268 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 17:52:49 -0500 Subject: [PATCH 11/17] soundwire: mipi-disco: remove DPn audio-modes The concept of DPn audio-modes was never used by anyone, and was removed from the DisCo for SoundWire 2.0 specification. Remove the definitions and TODO. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 2 -- include/linux/soundwire/sdw.h | 34 ---------------------------------- 2 files changed, 36 deletions(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index e5d9df26d4dc95..49278f4864a483 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -284,8 +284,6 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type", &dpn[i].port_encoding); - /* TODO: Read audio mode */ - fwnode_handle_put(node); i++; diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index cc0afb8af3332b..66feaa79ecfc7e 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -254,41 +254,8 @@ struct sdw_dp0_prop { bool imp_def_interrupts; }; -/** - * 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; -}; - /** * struct sdw_dpn_prop - Data Port DPn properties - * @audio_modes: Audio modes supported * @num: port number * @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64 * (inclusive) @@ -318,7 +285,6 @@ struct sdw_dpn_audio_mode { * machine */ struct sdw_dpn_prop { - struct sdw_dpn_audio_mode *audio_modes; u32 num; u32 max_word; u32 min_word; From 833e028e9b27f632aa6b211b6ed72f4f209fe7fb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 10 May 2024 09:16:05 -0500 Subject: [PATCH 12/17] soundwire: mipi-disco: add error handling for property array read The existing code assumes that there are no possible errors when using fwnode_property_read_u32_array(), because fwnode_property_count_u32() reads this array to determine its number of elements. We need to also protect the second read to be completely bullet-proof. Suggested-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index 49278f4864a483..e59ef3ee420c03 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -32,7 +32,9 @@ int sdw_master_read_prop(struct sdw_bus *bus) struct sdw_master_prop *prop = &bus->prop; struct fwnode_handle *link; char name[32]; - int nval, i; + int nval; + int ret; + int i; device_property_read_u32(bus->dev, "mipi-sdw-sw-interface-revision", @@ -71,9 +73,11 @@ int sdw_master_read_prop(struct sdw_bus *bus) return -ENOMEM; } - fwnode_property_read_u32_array(link, + ret = fwnode_property_read_u32_array(link, "mipi-sdw-clock-frequencies-supported", prop->clk_freq, prop->num_clk_freq); + if (ret < 0) + return ret; } /* @@ -99,10 +103,12 @@ int sdw_master_read_prop(struct sdw_bus *bus) return -ENOMEM; } - fwnode_property_read_u32_array(link, + ret = fwnode_property_read_u32_array(link, "mipi-sdw-supported-clock-gears", prop->clk_gears, prop->num_clk_gears); + if (ret < 0) + return ret; } fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", @@ -131,6 +137,7 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, struct sdw_dp0_prop *dp0) { int nval; + int ret; fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength", &dp0->max_word); @@ -148,9 +155,11 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, if (!dp0->words) return -ENOMEM; - fwnode_property_read_u32_array(port, + ret = fwnode_property_read_u32_array(port, "mipi-sdw-port-wordlength-configs", dp0->words, dp0->num_words); + if (ret < 0) + return ret; } dp0->BRA_flow_controlled = fwnode_property_read_bool(port, @@ -171,9 +180,10 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, { struct fwnode_handle *node; u32 bit, i = 0; - int nval; unsigned long addr; char name[40]; + int nval; + int ret; addr = ports; /* valid ports are 1 to 14 so apply mask */ @@ -208,9 +218,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-port-wordlength-configs", dpn[i].words, dpn[i].num_words); + if (ret < 0) + return ret; } fwnode_property_read_u32(node, "mipi-sdw-data-port-type", @@ -249,9 +261,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-channel-number-list", dpn[i].channels, dpn[i].num_channels); + if (ret < 0) + return ret; } nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list"); @@ -266,10 +280,12 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-channel-combination-list", dpn[i].ch_combinations, dpn[i].num_ch_combinations); + if (ret < 0) + return ret; } fwnode_property_read_u32(node, From 79e477f531c01cb6b97db667971eb4d6b7790b09 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 16:18:56 -0500 Subject: [PATCH 13/17] soundwire: mipi_disco: add support for clock-scales property The DisCo for SoundWire 2.0 spec adds support for the 'mipi-sdw-supported-clock-scales' property, which is just a rename. Add in a backwards-compatible manner. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index e59ef3ee420c03..02eb66a616d255 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -31,6 +31,7 @@ int sdw_master_read_prop(struct sdw_bus *bus) { struct sdw_master_prop *prop = &bus->prop; struct fwnode_handle *link; + const char *scales_prop; char name[32]; int nval; int ret; @@ -92,7 +93,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) { prop->num_clk_gears = nval; prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears, @@ -104,7 +110,7 @@ int sdw_master_read_prop(struct sdw_bus *bus) } ret = fwnode_property_read_u32_array(link, - "mipi-sdw-supported-clock-gears", + scales_prop, prop->clk_gears, prop->num_clk_gears); if (ret < 0) From e0e25cc29b084c42656fc19f8df0f64e6c522970 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 16:28:38 -0500 Subject: [PATCH 14/17] soundwire: mipi-disco: add support for peripheral channelprepare timeout The DisCo for SoundWire 2.0 spec renamed the 'mipi-sdw-slave-channelprepare-timeout', add support for the new definition in backwards-compatible ways. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index 02eb66a616d255..59954fb6eae753 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -324,6 +324,7 @@ int sdw_slave_read_prop(struct sdw_slave *slave) struct device *dev = &slave->dev; struct fwnode_handle *port; int nval; + int ret; device_property_read_u32(dev, "mipi-sdw-sw-interface-revision", &prop->mipi_revision); @@ -346,8 +347,11 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout", &prop->clk_stop_timeout); - device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout", - &prop->ch_prep_timeout); + ret = device_property_read_u32(dev, "mipi-sdw-peripheral-channelprepare-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, "mipi-sdw-clockstopprepare-hard-reset-behavior", From 04518fbcbfdbfc7969b53e5077ef64831082cef5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 16:44:42 -0500 Subject: [PATCH 15/17] soundwire: mipi-disco: add comment on DP0-supported property The DisCo for SoundWire 2.0 spec adds support for a new property, but it's not very helpful. Add a comment to explain that it's intentionally ignored. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index 59954fb6eae753..210a9cfcecb988 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -378,7 +378,11 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-sink-port-list", &prop->sink_ports); - /* Read dp0 properties */ + /* + * 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"); if (!port) { dev_dbg(dev, "DP0 node not found!!\n"); From 7ba1fa5fc9122ea7769ba8b0c532fa2d4d571c5e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 17:00:33 -0500 Subject: [PATCH 16/17] soundwire: mipi-disco: add new properties from 2.0 spec The DisCo for SoundWire 2.0 spec adds support for new 'mipi-sdw-sdca-interrupt-register-list' and 'mipi-sdw-commit-register-supported'. This patch only adds the definitions and property reads, but the use of these properties will come at some point in the future when needed. Note a slight conceptual disconnect between the MIPI DisCo definition of a boolean property and the Linux implementation. The latter only checks the presence of the property to set its value to 'true', whereas the MIPI definitions allow for a property with a 'false' value. This patch relies on a read_u8() even if the DisCo property is defined as boolean. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 13 +++++++++++++ include/linux/soundwire/sdw.h | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index 210a9cfcecb988..f11e5bb03adedf 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -378,6 +378,19 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-sink-port-list", &prop->sink_ports); + device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list", + &prop->sdca_interrupt_register_list); + + /* + * The specification defines the property value as boolean, but + * the value can be defined as zero. This is not aligned the + * implementation of device_property_read_bool() which only checks + * the presence of the property. + * Let's use read_u8 to work-around this conceptual disconnect. + */ + device_property_read_u8(dev, "mipi-sdw-commit-register-supported", + &prop->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 diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 66feaa79ecfc7e..952514f044f0d6 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -335,8 +335,11 @@ struct sdw_dpn_prop { * @master_count: Number of Masters present on this Slave * @source_ports: Bitmap identifying source ports * @sink_ports: Bitmap identifying sink ports - * @scp_int1_mask: SCP_INT1_MASK desired settings * @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 * registers introduced with the SoundWire 1.2 specification. SDCA devices * do not need to set this boolean property as the registers are required. @@ -363,6 +366,8 @@ struct sdw_slave_prop { u32 source_ports; u32 sink_ports; u32 quirks; + u32 sdca_interrupt_register_list; + u8 commit_register_supported; u8 scp_int1_mask; bool clock_reg_supported; bool use_domain_irq; From 93a039c7a06cea715f34a38d5b2ac02a43b8503d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Mar 2024 17:39:10 -0500 Subject: [PATCH 17/17] soundwire: mipi-disco: add support for DP0/DPn 'lane-list' property The SoundWire specification did not clearly require that ports could use all Lanes. Some SoundWire/SDCA peripheral adopters added restrictions on which lanes can be used by what port, and the DisCo for SoundWire 2.1 specification added a 'lane-list' property to model this hardware limitation. When not specified, the ports can use all Lanes. Otherwise, the 'lane-list' indicates which Lanes can be used, sorted by order of preference (most-preferred-first). This patch only reads the properties, the use of this property will come at a later time with multi-lane support. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/mipi_disco.c | 32 ++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 8 ++++++++ 2 files changed, 40 insertions(+) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index f11e5bb03adedf..d9f2a60f52bc2e 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -177,6 +177,22 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, dp0->imp_def_interrupts = fwnode_property_read_bool(port, "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; } @@ -306,6 +322,22 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type", &dpn[i].port_encoding); + 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); i++; diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 952514f044f0d6..73f655334fe9c7 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -238,6 +238,8 @@ enum sdw_clk_stop_mode { * @simple_ch_prep_sm: If channel prepare sequence is required * @imp_def_interrupts: If set, each bit corresponds to support for * 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 * discrete values, implementation can define based on the wordlengths they @@ -252,6 +254,8 @@ struct sdw_dp0_prop { bool BRA_flow_controlled; bool simple_ch_prep_sm; bool imp_def_interrupts; + int num_lanes; + u32 *lane_list; }; /** @@ -275,6 +279,8 @@ struct sdw_dp0_prop { * @num_ch_combinations: Number of channel combinations supported * @channels: Discrete channels 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 * @max_async_buffer: Number of samples that this port can buffer in * asynchronous modes @@ -300,6 +306,8 @@ struct sdw_dpn_prop { u32 num_ch_combinations; u32 *channels; u32 *ch_combinations; + u32 *lane_list; + int num_lanes; u32 modes; u32 max_async_buffer; u32 port_encoding;