Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: Add support for multi link bank switch

In cases of multiple Masters in a stream, synchronization
between multiple Master(s) is achieved by performing bank switch
together and using Master methods.

Add sdw_ml_bank_switch() to wait for completion of bank switch.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Shreyas NC and committed by
Vinod Koul
ce6e74d0 48949722

+144 -12
+5
drivers/soundwire/bus.c
··· 35 35 INIT_LIST_HEAD(&bus->slaves); 36 36 INIT_LIST_HEAD(&bus->m_rt_list); 37 37 38 + /* 39 + * Initialize multi_link flag 40 + * TODO: populate this flag by reading property from FW node 41 + */ 42 + bus->multi_link = false; 38 43 if (bus->ops->read_prop) { 39 44 ret = bus->ops->read_prop(bus); 40 45 if (ret < 0) {
+2
drivers/soundwire/bus.h
··· 4 4 #ifndef __SDW_BUS_H 5 5 #define __SDW_BUS_H 6 6 7 + #define DEFAULT_BANK_SWITCH_TIMEOUT 3000 8 + 7 9 #if IS_ENABLED(CONFIG_ACPI) 8 10 int sdw_acpi_find_slaves(struct sdw_bus *bus); 9 11 #else
+133 -12
drivers/soundwire/stream.c
··· 626 626 return ret; 627 627 } 628 628 629 - static int sdw_bank_switch(struct sdw_bus *bus) 629 + static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count) 630 630 { 631 631 int col_index, row_index; 632 + bool multi_link; 632 633 struct sdw_msg *wr_msg; 633 634 u8 *wbuf = NULL; 634 635 int ret = 0; ··· 638 637 wr_msg = kzalloc(sizeof(*wr_msg), GFP_KERNEL); 639 638 if (!wr_msg) 640 639 return -ENOMEM; 640 + 641 + bus->defer_msg.msg = wr_msg; 641 642 642 643 wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL); 643 644 if (!wbuf) { ··· 661 658 SDW_MSG_FLAG_WRITE, wbuf); 662 659 wr_msg->ssp_sync = true; 663 660 664 - ret = sdw_transfer(bus, wr_msg); 661 + /* 662 + * Set the multi_link flag only when both the hardware supports 663 + * and there is a stream handled by multiple masters 664 + */ 665 + multi_link = bus->multi_link && (m_rt_count > 1); 666 + 667 + if (multi_link) 668 + ret = sdw_transfer_defer(bus, wr_msg, &bus->defer_msg); 669 + else 670 + ret = sdw_transfer(bus, wr_msg); 671 + 665 672 if (ret < 0) { 666 673 dev_err(bus->dev, "Slave frame_ctrl reg write failed"); 667 674 goto error; 668 675 } 669 676 670 - kfree(wr_msg); 671 - kfree(wbuf); 672 - bus->defer_msg.msg = NULL; 673 - bus->params.curr_bank = !bus->params.curr_bank; 674 - bus->params.next_bank = !bus->params.next_bank; 677 + if (!multi_link) { 678 + kfree(wr_msg); 679 + kfree(wbuf); 680 + bus->defer_msg.msg = NULL; 681 + bus->params.curr_bank = !bus->params.curr_bank; 682 + bus->params.next_bank = !bus->params.next_bank; 683 + } 675 684 676 685 return 0; 677 686 ··· 694 679 return ret; 695 680 } 696 681 682 + /** 683 + * sdw_ml_sync_bank_switch: Multilink register bank switch 684 + * 685 + * @bus: SDW bus instance 686 + * 687 + * Caller function should free the buffers on error 688 + */ 689 + static int sdw_ml_sync_bank_switch(struct sdw_bus *bus) 690 + { 691 + unsigned long time_left; 692 + 693 + if (!bus->multi_link) 694 + return 0; 695 + 696 + /* Wait for completion of transfer */ 697 + time_left = wait_for_completion_timeout(&bus->defer_msg.complete, 698 + bus->bank_switch_timeout); 699 + 700 + if (!time_left) { 701 + dev_err(bus->dev, "Controller Timed out on bank switch"); 702 + return -ETIMEDOUT; 703 + } 704 + 705 + bus->params.curr_bank = !bus->params.curr_bank; 706 + bus->params.next_bank = !bus->params.next_bank; 707 + 708 + if (bus->defer_msg.msg) { 709 + kfree(bus->defer_msg.msg->buf); 710 + kfree(bus->defer_msg.msg); 711 + } 712 + 713 + return 0; 714 + } 715 + 697 716 static int do_bank_switch(struct sdw_stream_runtime *stream) 698 717 { 699 718 struct sdw_master_runtime *m_rt = NULL; 700 719 const struct sdw_master_ops *ops; 701 720 struct sdw_bus *bus = NULL; 721 + bool multi_link = false; 702 722 int ret = 0; 703 - 704 723 705 724 list_for_each_entry(m_rt, &stream->master_list, stream_node) { 706 725 bus = m_rt->bus; 707 726 ops = bus->ops; 727 + 728 + if (bus->multi_link) { 729 + multi_link = true; 730 + mutex_lock(&bus->msg_lock); 731 + } 708 732 709 733 /* Pre-bank switch */ 710 734 if (ops->pre_bank_switch) { ··· 751 697 if (ret < 0) { 752 698 dev_err(bus->dev, 753 699 "Pre bank switch op failed: %d", ret); 754 - return ret; 700 + goto msg_unlock; 755 701 } 756 702 } 757 703 758 - /* Bank switch */ 759 - ret = sdw_bank_switch(bus); 704 + /* 705 + * Perform Bank switch operation. 706 + * For multi link cases, the actual bank switch is 707 + * synchronized across all Masters and happens later as a 708 + * part of post_bank_switch ops. 709 + */ 710 + ret = sdw_bank_switch(bus, stream->m_rt_count); 760 711 if (ret < 0) { 761 712 dev_err(bus->dev, "Bank switch failed: %d", ret); 762 - return ret; 713 + goto error; 714 + 763 715 } 764 716 } 765 717 718 + /* 719 + * For multi link cases, it is expected that the bank switch is 720 + * triggered by the post_bank_switch for the first Master in the list 721 + * and for the other Masters the post_bank_switch() should return doing 722 + * nothing. 723 + */ 766 724 list_for_each_entry(m_rt, &stream->master_list, stream_node) { 767 725 bus = m_rt->bus; 768 726 ops = bus->ops; ··· 785 719 if (ret < 0) { 786 720 dev_err(bus->dev, 787 721 "Post bank switch op failed: %d", ret); 722 + goto error; 788 723 } 724 + } else if (bus->multi_link && stream->m_rt_count > 1) { 725 + dev_err(bus->dev, 726 + "Post bank switch ops not implemented"); 727 + goto error; 728 + } 729 + 730 + /* Set the bank switch timeout to default, if not set */ 731 + if (!bus->bank_switch_timeout) 732 + bus->bank_switch_timeout = DEFAULT_BANK_SWITCH_TIMEOUT; 733 + 734 + /* Check if bank switch was successful */ 735 + ret = sdw_ml_sync_bank_switch(bus); 736 + if (ret < 0) { 737 + dev_err(bus->dev, 738 + "multi link bank switch failed: %d", ret); 739 + goto error; 740 + } 741 + 742 + mutex_unlock(&bus->msg_lock); 743 + } 744 + 745 + return ret; 746 + 747 + error: 748 + list_for_each_entry(m_rt, &stream->master_list, stream_node) { 749 + 750 + bus = m_rt->bus; 751 + 752 + kfree(bus->defer_msg.msg->buf); 753 + kfree(bus->defer_msg.msg); 754 + } 755 + 756 + msg_unlock: 757 + 758 + if (multi_link) { 759 + list_for_each_entry(m_rt, &stream->master_list, stream_node) { 760 + bus = m_rt->bus; 761 + if (mutex_is_locked(&bus->msg_lock)) 762 + mutex_unlock(&bus->msg_lock); 789 763 } 790 764 } 791 765 ··· 1070 964 1071 965 sdw_master_port_release(bus, m_rt); 1072 966 sdw_release_master_stream(m_rt, stream); 967 + stream->m_rt_count--; 1073 968 } 1074 969 1075 970 if (list_empty(&stream->master_list)) ··· 1257 1150 1258 1151 mutex_lock(&bus->bus_lock); 1259 1152 1153 + /* 1154 + * For multi link streams, add the second master only if 1155 + * the bus supports it. 1156 + * Check if bus->multi_link is set 1157 + */ 1158 + if (!bus->multi_link && stream->m_rt_count > 0) { 1159 + dev_err(bus->dev, 1160 + "Multilink not supported, link %d", bus->link_id); 1161 + ret = -EINVAL; 1162 + goto unlock; 1163 + } 1164 + 1260 1165 m_rt = sdw_alloc_master_rt(bus, stream_config, stream); 1261 1166 if (!m_rt) { 1262 1167 dev_err(bus->dev, ··· 1285 1166 ret = sdw_master_port_config(bus, m_rt, port_config, num_ports); 1286 1167 if (ret) 1287 1168 goto stream_error; 1169 + 1170 + stream->m_rt_count++; 1288 1171 1289 1172 goto unlock; 1290 1173
+4
include/linux/soundwire/sdw.h
··· 678 678 * @defer_msg: Defer message 679 679 * @clk_stop_timeout: Clock stop timeout computed 680 680 * @bank_switch_timeout: Bank switch timeout computed 681 + * @multi_link: Store bus property that indicates if multi links 682 + * are supported. This flag is populated by drivers after reading 683 + * appropriate firmware (ACPI/DT). 681 684 */ 682 685 struct sdw_bus { 683 686 struct device *dev; ··· 697 694 struct sdw_defer defer_msg; 698 695 unsigned int clk_stop_timeout; 699 696 u32 bank_switch_timeout; 697 + bool multi_link; 700 698 }; 701 699 702 700 int sdw_add_bus_master(struct sdw_bus *bus);