From patchwork Wed Mar 28 09:38:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinod Koul X-Patchwork-Id: 10312677 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0997A60467 for ; Wed, 28 Mar 2018 09:36:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 015AF29B45 for ; Wed, 28 Mar 2018 09:36:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E869729C34; Wed, 28 Mar 2018 09:36:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 060CC29B45 for ; Wed, 28 Mar 2018 09:36:34 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id D76FD2673A6; Wed, 28 Mar 2018 11:35:16 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 62C892673DC; Wed, 28 Mar 2018 11:35:14 +0200 (CEST) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by alsa0.perex.cz (Postfix) with ESMTP id 3C8212673A6 for ; Wed, 28 Mar 2018 11:35:07 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Mar 2018 02:35:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,370,1517904000"; d="scan'208";a="186679581" Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143]) by orsmga004.jf.intel.com with ESMTP; 28 Mar 2018 02:35:03 -0700 From: Vinod Koul To: Greg KH Date: Wed, 28 Mar 2018 15:08:37 +0530 Message-Id: <1522229918-4748-13-git-send-email-vinod.koul@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1522229918-4748-1-git-send-email-vinod.koul@intel.com> References: <1522229918-4748-1-git-send-email-vinod.koul@intel.com> Cc: ALSA , tiwai@suse.de, Pierre-Louis Bossart , liam.r.girdwood@linux.intel.com, patches.audio@intel.com, broonie@kernel.org, Vinod Koul Subject: [alsa-devel] [PATCH 12/13] soundwire: intel: Add stream initialization X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Add Intel stream init routines which initialize the Physical Data Interface (PDI), Audio Link Hub (ALH) and Audio shim. Also add bank switch routines. Signed-off-by: Hardik T Shah Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index a64f87a08cfd..e0fb88397a88 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -234,6 +236,209 @@ static int intel_shim_init(struct sdw_intel *sdw) return ret; } +/* + * PDI routines + */ +static void intel_pdi_init(struct sdw_intel *sdw, + struct sdw_cdns_stream_config *config) +{ + void __iomem *shim = sdw->res->shim; + unsigned int link_id = sdw->instance; + int pcm_cap, pdm_cap; + + /* PCM Stream Capability */ + pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id)); + + config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >> + SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS); + config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >> + SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS); + config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >> + SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS); + + /* PDM Stream Capability */ + pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); + + config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >> + SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS); + config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >> + SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS); + config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >> + SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS); +} + +static int +intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) +{ + void __iomem *shim = sdw->res->shim; + unsigned int link_id = sdw->instance; + int count; + + if (pcm) { + + count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); + + /* + * TODO: pdi number 2 reports channel count as 1 even though + * it supports 8 channel. Performing hardcoding for pdi + * number 2. + */ + if (pdi_num == 2) + count = 7; + + } else { + count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); + count = ((count & SDW_SHIM_PDMSCAP_CPSS) >> + SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS)); + } + + /* zero based values for channel count in register */ + count++; + + return count; +} + +static int intel_pdi_get_ch_update(struct sdw_intel *sdw, + struct sdw_cdns_pdi *pdi, + unsigned int num_pdi, + unsigned int *num_ch, bool pcm) +{ + int i, ch_count = 0; + + for (i = 0; i < num_pdi; i++) { + pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm); + ch_count += pdi->ch_count; + pdi++; + } + + *num_ch = ch_count; + return 0; +} + +static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, + struct sdw_cdns_streams *stream, bool pcm) +{ + intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd, + &stream->num_ch_bd, pcm); + + intel_pdi_get_ch_update(sdw, stream->in, stream->num_in, + &stream->num_ch_in, pcm); + + intel_pdi_get_ch_update(sdw, stream->out, stream->num_out, + &stream->num_ch_out, pcm); + + return 0; +} + +static int intel_pdi_ch_update(struct sdw_intel *sdw) +{ + /* First update PCM streams followed by PDM streams */ + intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true); + intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false); + + return 0; +} + +static void +intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) +{ + void __iomem *shim = sdw->res->shim; + unsigned int link_id = sdw->instance; + int pdi_conf = 0; + + pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; + + /* + * Program stream parameters to stream SHIM register + * This is applicable for PCM stream only. + */ + if (pdi->type != SDW_STREAM_PCM) + return; + + if (pdi->dir == SDW_DATA_DIR_IN) + pdi_conf |= SDW_SHIM_PCMSYCM_DIR; + else + pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR); + + pdi_conf |= (pdi->intel_alh_id << + SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM)); + pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN)); + pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN)); + + intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf); +} + +static void +intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) +{ + void __iomem *alh = sdw->res->alh; + unsigned int link_id = sdw->instance; + unsigned int conf; + + pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; + + /* Program Stream config ALH register */ + conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id)); + + conf |= (SDW_ALH_STRMZCFG_DMAT_VAL << + SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT)); + + conf |= ((pdi->ch_count - 1) << + SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN)); + + intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf); +} + +/* + * bank switch routines + */ + +static int intel_pre_bank_switch(struct sdw_bus *bus) +{ + struct sdw_cdns *cdns = bus_to_cdns(bus); + struct sdw_intel *sdw = cdns_to_intel(cdns); + void __iomem *shim = sdw->res->shim; + int sync_reg; + + if (!bus->multi_link) + return 0; + + /* Read SYNC register */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance; + intel_writel(shim, SDW_SHIM_SYNC, sync_reg); + + return 0; +} + +static int intel_post_bank_switch(struct sdw_bus *bus) +{ + struct sdw_cdns *cdns = bus_to_cdns(bus); + struct sdw_intel *sdw = cdns_to_intel(cdns); + void __iomem *shim = sdw->res->shim; + int sync_reg, ret; + + if (!bus->multi_link) + return 0; + + /* Read SYNC register */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + + /* Check CMDSYNC bit set for any Master */ + if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) + return 0; + + /* Set SyncGO bit */ + sync_reg |= SDW_SHIM_SYNC_SYNCGO; + + ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, + SDW_SHIM_SYNC_SYNCGO); + if (ret < 0) + dev_err(sdw->cdns.dev, "Post bank switch failed: %d", ret); + + return ret; +} + static int intel_prop_read(struct sdw_bus *bus) { /* Initialize with default handler to read all DisCo properties */ @@ -265,6 +470,7 @@ static struct sdw_master_ops sdw_intel_ops = { */ static int intel_probe(struct platform_device *pdev) { + struct sdw_cdns_stream_config config; struct sdw_intel *sdw; int ret; @@ -287,6 +493,11 @@ static int intel_probe(struct platform_device *pdev) sdw_intel_ops.read_prop = intel_prop_read; sdw->cdns.bus.ops = &sdw_intel_ops; + sdw_intel_ops.pre_bank_switch = intel_pre_bank_switch; + sdw_intel_ops.post_bank_switch = intel_post_bank_switch; + sdw_intel_ops.read_prop = intel_prop_read; + sdw->cdns.bus.ops = &sdw_intel_ops; + platform_set_drvdata(pdev, sdw); ret = sdw_add_bus_master(&sdw->cdns.bus); @@ -304,9 +515,15 @@ static int intel_probe(struct platform_device *pdev) goto err_init; ret = sdw_cdns_enable_interrupt(&sdw->cdns); + + /* Read the PDI config and initialize cadence PDI */ + intel_pdi_init(sdw, &config); + ret = sdw_cdns_pdi_init(&sdw->cdns, config); if (ret) goto err_init; + intel_pdi_ch_update(sdw); + /* Acquire IRQ */ ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq, sdw_cdns_thread, IRQF_SHARED, KBUILD_MODNAME,