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

soundwire: cdns: Add port routines

Add support for Cadence port management and implement
master port ops.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>

+344
+243
drivers/soundwire/cadence_master.c
··· 669 669 } 670 670 EXPORT_SYMBOL(sdw_cdns_enable_interrupt); 671 671 672 + static int cdns_allocate_pdi(struct sdw_cdns *cdns, 673 + struct sdw_cdns_pdi **stream, 674 + u32 num, u32 pdi_offset) 675 + { 676 + struct sdw_cdns_pdi *pdi; 677 + int i; 678 + 679 + if (!num) 680 + return 0; 681 + 682 + pdi = devm_kcalloc(cdns->dev, num, sizeof(*pdi), GFP_KERNEL); 683 + if (!pdi) 684 + return -ENOMEM; 685 + 686 + for (i = 0; i < num; i++) { 687 + pdi[i].num = i + pdi_offset; 688 + pdi[i].assigned = false; 689 + } 690 + 691 + *stream = pdi; 692 + return 0; 693 + } 694 + 695 + /** 696 + * sdw_cdns_pdi_init() - PDI initialization routine 697 + * 698 + * @cdns: Cadence instance 699 + * @config: Stream configurations 700 + */ 701 + int sdw_cdns_pdi_init(struct sdw_cdns *cdns, 702 + struct sdw_cdns_stream_config config) 703 + { 704 + struct sdw_cdns_streams *stream; 705 + int offset, i, ret; 706 + 707 + cdns->pcm.num_bd = config.pcm_bd; 708 + cdns->pcm.num_in = config.pcm_in; 709 + cdns->pcm.num_out = config.pcm_out; 710 + cdns->pdm.num_bd = config.pdm_bd; 711 + cdns->pdm.num_in = config.pdm_in; 712 + cdns->pdm.num_out = config.pdm_out; 713 + 714 + /* Allocate PDIs for PCMs */ 715 + stream = &cdns->pcm; 716 + 717 + /* First two PDIs are reserved for bulk transfers */ 718 + stream->num_bd -= CDNS_PCM_PDI_OFFSET; 719 + offset = CDNS_PCM_PDI_OFFSET; 720 + 721 + ret = cdns_allocate_pdi(cdns, &stream->bd, 722 + stream->num_bd, offset); 723 + if (ret) 724 + return ret; 725 + 726 + offset += stream->num_bd; 727 + 728 + ret = cdns_allocate_pdi(cdns, &stream->in, 729 + stream->num_in, offset); 730 + if (ret) 731 + return ret; 732 + 733 + offset += stream->num_in; 734 + 735 + ret = cdns_allocate_pdi(cdns, &stream->out, 736 + stream->num_out, offset); 737 + if (ret) 738 + return ret; 739 + 740 + /* Update total number of PCM PDIs */ 741 + stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; 742 + cdns->num_ports = stream->num_pdi; 743 + 744 + /* Allocate PDIs for PDMs */ 745 + stream = &cdns->pdm; 746 + offset = CDNS_PDM_PDI_OFFSET; 747 + ret = cdns_allocate_pdi(cdns, &stream->bd, 748 + stream->num_bd, offset); 749 + if (ret) 750 + return ret; 751 + 752 + offset += stream->num_bd; 753 + 754 + ret = cdns_allocate_pdi(cdns, &stream->in, 755 + stream->num_in, offset); 756 + if (ret) 757 + return ret; 758 + 759 + offset += stream->num_in; 760 + 761 + ret = cdns_allocate_pdi(cdns, &stream->out, 762 + stream->num_out, offset); 763 + if (ret) 764 + return ret; 765 + 766 + /* Update total number of PDM PDIs */ 767 + stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out; 768 + cdns->num_ports += stream->num_pdi; 769 + 770 + cdns->ports = devm_kcalloc(cdns->dev, cdns->num_ports, 771 + sizeof(*cdns->ports), GFP_KERNEL); 772 + if (!cdns->ports) { 773 + ret = -ENOMEM; 774 + return ret; 775 + } 776 + 777 + for (i = 0; i < cdns->num_ports; i++) { 778 + cdns->ports[i].assigned = false; 779 + cdns->ports[i].num = i + 1; /* Port 0 reserved for bulk */ 780 + } 781 + 782 + return 0; 783 + } 784 + EXPORT_SYMBOL(sdw_cdns_pdi_init); 785 + 672 786 /** 673 787 * sdw_cdns_init() - Cadence initialization 674 788 * @cdns: Cadence instance ··· 844 730 } 845 731 EXPORT_SYMBOL(sdw_cdns_init); 846 732 733 + int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params) 734 + { 735 + struct sdw_cdns *cdns = bus_to_cdns(bus); 736 + int mcp_clkctrl_off, mcp_clkctrl; 737 + int divider; 738 + 739 + if (!params->curr_dr_freq) { 740 + dev_err(cdns->dev, "NULL curr_dr_freq"); 741 + return -EINVAL; 742 + } 743 + 744 + divider = (params->max_dr_freq / params->curr_dr_freq) - 1; 745 + 746 + if (params->next_bank) 747 + mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1; 748 + else 749 + mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0; 750 + 751 + mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off); 752 + mcp_clkctrl |= divider; 753 + cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl); 754 + 755 + return 0; 756 + } 757 + EXPORT_SYMBOL(cdns_bus_conf); 758 + 759 + static int cdns_port_params(struct sdw_bus *bus, 760 + struct sdw_port_params *p_params, unsigned int bank) 761 + { 762 + struct sdw_cdns *cdns = bus_to_cdns(bus); 763 + int dpn_config = 0, dpn_config_off; 764 + 765 + if (bank) 766 + dpn_config_off = CDNS_DPN_B1_CONFIG(p_params->num); 767 + else 768 + dpn_config_off = CDNS_DPN_B0_CONFIG(p_params->num); 769 + 770 + dpn_config = cdns_readl(cdns, dpn_config_off); 771 + 772 + dpn_config |= ((p_params->bps - 1) << 773 + SDW_REG_SHIFT(CDNS_DPN_CONFIG_WL)); 774 + dpn_config |= (p_params->flow_mode << 775 + SDW_REG_SHIFT(CDNS_DPN_CONFIG_PORT_FLOW)); 776 + dpn_config |= (p_params->data_mode << 777 + SDW_REG_SHIFT(CDNS_DPN_CONFIG_PORT_DAT)); 778 + 779 + cdns_writel(cdns, dpn_config_off, dpn_config); 780 + 781 + return 0; 782 + } 783 + 784 + static int cdns_transport_params(struct sdw_bus *bus, 785 + struct sdw_transport_params *t_params, 786 + enum sdw_reg_bank bank) 787 + { 788 + struct sdw_cdns *cdns = bus_to_cdns(bus); 789 + int dpn_offsetctrl = 0, dpn_offsetctrl_off; 790 + int dpn_config = 0, dpn_config_off; 791 + int dpn_hctrl = 0, dpn_hctrl_off; 792 + int num = t_params->port_num; 793 + int dpn_samplectrl_off; 794 + 795 + /* 796 + * Note: Only full data port is supported on the Master side for 797 + * both PCM and PDM ports. 798 + */ 799 + 800 + if (bank) { 801 + dpn_config_off = CDNS_DPN_B1_CONFIG(num); 802 + dpn_samplectrl_off = CDNS_DPN_B1_SAMPLE_CTRL(num); 803 + dpn_hctrl_off = CDNS_DPN_B1_HCTRL(num); 804 + dpn_offsetctrl_off = CDNS_DPN_B1_OFFSET_CTRL(num); 805 + } else { 806 + dpn_config_off = CDNS_DPN_B0_CONFIG(num); 807 + dpn_samplectrl_off = CDNS_DPN_B0_SAMPLE_CTRL(num); 808 + dpn_hctrl_off = CDNS_DPN_B0_HCTRL(num); 809 + dpn_offsetctrl_off = CDNS_DPN_B0_OFFSET_CTRL(num); 810 + } 811 + 812 + dpn_config = cdns_readl(cdns, dpn_config_off); 813 + 814 + dpn_config |= (t_params->blk_grp_ctrl << 815 + SDW_REG_SHIFT(CDNS_DPN_CONFIG_BGC)); 816 + dpn_config |= (t_params->blk_pkg_mode << 817 + SDW_REG_SHIFT(CDNS_DPN_CONFIG_BPM)); 818 + cdns_writel(cdns, dpn_config_off, dpn_config); 819 + 820 + dpn_offsetctrl |= (t_params->offset1 << 821 + SDW_REG_SHIFT(CDNS_DPN_OFFSET_CTRL_1)); 822 + dpn_offsetctrl |= (t_params->offset2 << 823 + SDW_REG_SHIFT(CDNS_DPN_OFFSET_CTRL_2)); 824 + cdns_writel(cdns, dpn_offsetctrl_off, dpn_offsetctrl); 825 + 826 + dpn_hctrl |= (t_params->hstart << 827 + SDW_REG_SHIFT(CDNS_DPN_HCTRL_HSTART)); 828 + dpn_hctrl |= (t_params->hstop << SDW_REG_SHIFT(CDNS_DPN_HCTRL_HSTOP)); 829 + dpn_hctrl |= (t_params->lane_ctrl << 830 + SDW_REG_SHIFT(CDNS_DPN_HCTRL_LCTRL)); 831 + 832 + cdns_writel(cdns, dpn_hctrl_off, dpn_hctrl); 833 + cdns_writel(cdns, dpn_samplectrl_off, (t_params->sample_interval - 1)); 834 + 835 + return 0; 836 + } 837 + 838 + static int cdns_port_enable(struct sdw_bus *bus, 839 + struct sdw_enable_ch *enable_ch, unsigned int bank) 840 + { 841 + struct sdw_cdns *cdns = bus_to_cdns(bus); 842 + int dpn_chnen_off, ch_mask; 843 + 844 + if (bank) 845 + dpn_chnen_off = CDNS_DPN_B1_CH_EN(enable_ch->port_num); 846 + else 847 + dpn_chnen_off = CDNS_DPN_B0_CH_EN(enable_ch->port_num); 848 + 849 + ch_mask = enable_ch->ch_mask * enable_ch->enable; 850 + cdns_writel(cdns, dpn_chnen_off, ch_mask); 851 + 852 + return 0; 853 + } 854 + 855 + static const struct sdw_master_port_ops cdns_port_ops = { 856 + .dpn_set_port_params = cdns_port_params, 857 + .dpn_set_port_transport_params = cdns_transport_params, 858 + .dpn_port_enable_ch = cdns_port_enable, 859 + }; 860 + 847 861 /** 848 862 * sdw_cdns_probe() - Cadence probe routine 849 863 * @cdns: Cadence instance ··· 979 737 int sdw_cdns_probe(struct sdw_cdns *cdns) 980 738 { 981 739 init_completion(&cdns->tx_complete); 740 + cdns->bus.port_ops = &cdns_port_ops; 982 741 983 742 return 0; 984 743 }
+100
drivers/soundwire/cadence_master.h
··· 5 5 #define __SDW_CADENCE_H 6 6 7 7 /** 8 + * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance 9 + * 10 + * @assigned: pdi assigned 11 + * @num: pdi number 12 + * @intel_alh_id: link identifier 13 + * @l_ch_num: low channel for PDI 14 + * @h_ch_num: high channel for PDI 15 + * @ch_count: total channel count for PDI 16 + * @dir: data direction 17 + * @type: stream type, PDM or PCM 18 + */ 19 + struct sdw_cdns_pdi { 20 + bool assigned; 21 + int num; 22 + int intel_alh_id; 23 + int l_ch_num; 24 + int h_ch_num; 25 + int ch_count; 26 + enum sdw_data_direction dir; 27 + enum sdw_stream_type type; 28 + }; 29 + 30 + /** 31 + * struct sdw_cdns_port: Cadence port structure 32 + * 33 + * @num: port number 34 + * @assigned: port assigned 35 + * @ch: channel count 36 + * @direction: data port direction 37 + * @pdi: pdi for this port 38 + */ 39 + struct sdw_cdns_port { 40 + unsigned int num; 41 + bool assigned; 42 + unsigned int ch; 43 + enum sdw_data_direction direction; 44 + struct sdw_cdns_pdi *pdi; 45 + }; 46 + 47 + /** 48 + * struct sdw_cdns_streams: Cadence stream data structure 49 + * 50 + * @num_bd: number of bidirectional streams 51 + * @num_in: number of input streams 52 + * @num_out: number of output streams 53 + * @num_ch_bd: number of bidirectional stream channels 54 + * @num_ch_bd: number of input stream channels 55 + * @num_ch_bd: number of output stream channels 56 + * @num_pdi: total number of PDIs 57 + * @bd: bidirectional streams 58 + * @in: input streams 59 + * @out: output streams 60 + */ 61 + struct sdw_cdns_streams { 62 + unsigned int num_bd; 63 + unsigned int num_in; 64 + unsigned int num_out; 65 + unsigned int num_ch_bd; 66 + unsigned int num_ch_in; 67 + unsigned int num_ch_out; 68 + unsigned int num_pdi; 69 + struct sdw_cdns_pdi *bd; 70 + struct sdw_cdns_pdi *in; 71 + struct sdw_cdns_pdi *out; 72 + }; 73 + 74 + /** 75 + * struct sdw_cdns_stream_config: stream configuration 76 + * 77 + * @pcm_bd: number of bidirectional PCM streams supported 78 + * @pcm_in: number of input PCM streams supported 79 + * @pcm_out: number of output PCM streams supported 80 + * @pdm_bd: number of bidirectional PDM streams supported 81 + * @pdm_in: number of input PDM streams supported 82 + * @pdm_out: number of output PDM streams supported 83 + */ 84 + struct sdw_cdns_stream_config { 85 + unsigned int pcm_bd; 86 + unsigned int pcm_in; 87 + unsigned int pcm_out; 88 + unsigned int pdm_bd; 89 + unsigned int pdm_in; 90 + unsigned int pdm_out; 91 + }; 92 + 93 + /** 8 94 * struct sdw_cdns - Cadence driver context 9 95 * @dev: Linux device 10 96 * @bus: Bus handle ··· 98 12 * @response_buf: SoundWire response buffer 99 13 * @tx_complete: Tx completion 100 14 * @defer: Defer pointer 15 + * @ports: Data ports 16 + * @num_ports: Total number of data ports 17 + * @pcm: PCM streams 18 + * @pdm: PDM streams 101 19 * @registers: Cadence registers 102 20 * @link_up: Link status 103 21 * @msg_count: Messages sent on bus ··· 114 24 u32 response_buf[0x80]; 115 25 struct completion tx_complete; 116 26 struct sdw_defer *defer; 27 + 28 + struct sdw_cdns_port *ports; 29 + int num_ports; 30 + 31 + struct sdw_cdns_streams pcm; 32 + struct sdw_cdns_streams pdm; 117 33 118 34 void __iomem *registers; 119 35 ··· 138 42 irqreturn_t sdw_cdns_thread(int irq, void *dev_id); 139 43 140 44 int sdw_cdns_init(struct sdw_cdns *cdns); 45 + int sdw_cdns_pdi_init(struct sdw_cdns *cdns, 46 + struct sdw_cdns_stream_config config); 141 47 int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns); 142 48 143 49 enum sdw_command_response ··· 151 53 152 54 enum sdw_command_response 153 55 cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num); 56 + 57 + int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params); 154 58 #endif /* __SDW_CADENCE_H */
+1
drivers/soundwire/intel.c
··· 257 257 .xfer_msg = cdns_xfer_msg, 258 258 .xfer_msg_defer = cdns_xfer_msg_defer, 259 259 .reset_page_addr = cdns_reset_page_addr, 260 + .set_bus_conf = cdns_bus_conf, 260 261 }; 261 262 262 263 /*