brintos

brintos / linux-shallow public Read only

0
0
Text · 28.6 KiB · 421da0f Raw
1115 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)2// Copyright(c) 2015-17 Intel Corporation.3 4/*5 * Soundwire Intel Master Driver6 */7 8#include <linux/acpi.h>9#include <linux/cleanup.h>10#include <linux/debugfs.h>11#include <linux/delay.h>12#include <linux/io.h>13#include <sound/pcm_params.h>14#include <linux/pm_runtime.h>15#include <sound/soc.h>16#include <linux/soundwire/sdw_registers.h>17#include <linux/soundwire/sdw.h>18#include <linux/soundwire/sdw_intel.h>19#include "cadence_master.h"20#include "bus.h"21#include "intel.h"22 23static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)24{25	int timeout = 10;26	u32 reg_read;27 28	do {29		reg_read = readl(base + offset);30		if ((reg_read & mask) == target)31			return 0;32 33		timeout--;34		usleep_range(50, 100);35	} while (timeout != 0);36 37	return -EAGAIN;38}39 40static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask)41{42	writel(value, base + offset);43	return intel_wait_bit(base, offset, mask, 0);44}45 46static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)47{48	writel(value, base + offset);49	return intel_wait_bit(base, offset, mask, mask);50}51 52/*53 * debugfs54 */55#ifdef CONFIG_DEBUG_FS56 57#define RD_BUF (2 * PAGE_SIZE)58 59static ssize_t intel_sprintf(void __iomem *mem, bool l,60			     char *buf, size_t pos, unsigned int reg)61{62	int value;63 64	if (l)65		value = intel_readl(mem, reg);66	else67		value = intel_readw(mem, reg);68 69	return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);70}71 72static int intel_reg_show(struct seq_file *s_file, void *data)73{74	struct sdw_intel *sdw = s_file->private;75	void __iomem *s = sdw->link_res->shim;76	void __iomem *a = sdw->link_res->alh;77	ssize_t ret;78	int i, j;79	unsigned int links, reg;80 81	char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);82	if (!buf)83		return -ENOMEM;84 85	links = intel_readl(s, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_LCOUNT_MASK;86 87	ret = scnprintf(buf, RD_BUF, "Register  Value\n");88	ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");89 90	for (i = 0; i < links; i++) {91		reg = SDW_SHIM_LCAP + i * 4;92		ret += intel_sprintf(s, true, buf, ret, reg);93	}94 95	for (i = 0; i < links; i++) {96		ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);97		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));98		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));99		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));100		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));101		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));102		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));103 104		ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n");105 106		/*107		 * the value 10 is the number of PDIs. We will need a108		 * cleanup to remove hard-coded Intel configurations109		 * from cadence_master.c110		 */111		for (j = 0; j < 10; j++) {112			ret += intel_sprintf(s, false, buf, ret,113					SDW_SHIM_PCMSYCHM(i, j));114			ret += intel_sprintf(s, false, buf, ret,115					SDW_SHIM_PCMSYCHC(i, j));116		}117		ret += scnprintf(buf + ret, RD_BUF - ret, "\n IOCTL, CTMCTL\n");118 119		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));120		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));121	}122 123	ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");124	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);125	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);126 127	ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n");128	for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)129		ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));130 131	seq_printf(s_file, "%s", buf);132 133	return 0;134}135DEFINE_SHOW_ATTRIBUTE(intel_reg);136 137static int intel_set_m_datamode(void *data, u64 value)138{139	struct sdw_intel *sdw = data;140	struct sdw_bus *bus = &sdw->cdns.bus;141 142	if (value > SDW_PORT_DATA_MODE_STATIC_1)143		return -EINVAL;144 145	/* Userspace changed the hardware state behind the kernel's back */146	add_taint(TAINT_USER, LOCKDEP_STILL_OK);147 148	bus->params.m_data_mode = value;149 150	return 0;151}152DEFINE_DEBUGFS_ATTRIBUTE(intel_set_m_datamode_fops, NULL,153			 intel_set_m_datamode, "%llu\n");154 155static int intel_set_s_datamode(void *data, u64 value)156{157	struct sdw_intel *sdw = data;158	struct sdw_bus *bus = &sdw->cdns.bus;159 160	if (value > SDW_PORT_DATA_MODE_STATIC_1)161		return -EINVAL;162 163	/* Userspace changed the hardware state behind the kernel's back */164	add_taint(TAINT_USER, LOCKDEP_STILL_OK);165 166	bus->params.s_data_mode = value;167 168	return 0;169}170DEFINE_DEBUGFS_ATTRIBUTE(intel_set_s_datamode_fops, NULL,171			 intel_set_s_datamode, "%llu\n");172 173static void intel_debugfs_init(struct sdw_intel *sdw)174{175	struct dentry *root = sdw->cdns.bus.debugfs;176 177	if (!root)178		return;179 180	sdw->debugfs = debugfs_create_dir("intel-sdw", root);181 182	debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,183			    &intel_reg_fops);184 185	debugfs_create_file("intel-m-datamode", 0200, sdw->debugfs, sdw,186			    &intel_set_m_datamode_fops);187 188	debugfs_create_file("intel-s-datamode", 0200, sdw->debugfs, sdw,189			    &intel_set_s_datamode_fops);190 191	sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);192}193 194static void intel_debugfs_exit(struct sdw_intel *sdw)195{196	debugfs_remove_recursive(sdw->debugfs);197}198#else199static void intel_debugfs_init(struct sdw_intel *sdw) {}200static void intel_debugfs_exit(struct sdw_intel *sdw) {}201#endif /* CONFIG_DEBUG_FS */202 203/*204 * shim ops205 */206/* this needs to be called with shim_lock */207static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)208{209	void __iomem *shim = sdw->link_res->shim;210	unsigned int link_id = sdw->instance;211	u16 ioctl;212 213	/* Switch to MIP from Glue logic */214	ioctl = intel_readw(shim,  SDW_SHIM_IOCTL(link_id));215 216	ioctl &= ~(SDW_SHIM_IOCTL_DOE);217	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);218	usleep_range(10, 15);219 220	ioctl &= ~(SDW_SHIM_IOCTL_DO);221	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);222	usleep_range(10, 15);223 224	ioctl |= (SDW_SHIM_IOCTL_MIF);225	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);226	usleep_range(10, 15);227 228	ioctl &= ~(SDW_SHIM_IOCTL_BKE);229	ioctl &= ~(SDW_SHIM_IOCTL_COE);230	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);231	usleep_range(10, 15);232 233	/* at this point Master IP has full control of the I/Os */234}235 236/* this needs to be called with shim_lock */237static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)238{239	unsigned int link_id = sdw->instance;240	void __iomem *shim = sdw->link_res->shim;241	u16 ioctl;242 243	/* Glue logic */244	ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));245	ioctl |= SDW_SHIM_IOCTL_BKE;246	ioctl |= SDW_SHIM_IOCTL_COE;247	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);248	usleep_range(10, 15);249 250	ioctl &= ~(SDW_SHIM_IOCTL_MIF);251	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);252	usleep_range(10, 15);253 254	/* at this point Integration Glue has full control of the I/Os */255}256 257/* this needs to be called with shim_lock */258static void intel_shim_init(struct sdw_intel *sdw)259{260	void __iomem *shim = sdw->link_res->shim;261	unsigned int link_id = sdw->instance;262	u16 ioctl = 0, act;263 264	/* Initialize Shim */265	ioctl |= SDW_SHIM_IOCTL_BKE;266	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);267	usleep_range(10, 15);268 269	ioctl |= SDW_SHIM_IOCTL_WPDD;270	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);271	usleep_range(10, 15);272 273	ioctl |= SDW_SHIM_IOCTL_DO;274	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);275	usleep_range(10, 15);276 277	ioctl |= SDW_SHIM_IOCTL_DOE;278	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);279	usleep_range(10, 15);280 281	intel_shim_glue_to_master_ip(sdw);282 283	act = intel_readw(shim, SDW_SHIM_CTMCTL(link_id));284	u16p_replace_bits(&act, 0x1, SDW_SHIM_CTMCTL_DOAIS);285	act |= SDW_SHIM_CTMCTL_DACTQE;286	act |= SDW_SHIM_CTMCTL_DODS;287	intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);288	usleep_range(10, 15);289}290 291static int intel_shim_check_wake(struct sdw_intel *sdw)292{293	void __iomem *shim;294	u16 wake_sts;295 296	shim = sdw->link_res->shim;297	wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);298 299	return wake_sts & BIT(sdw->instance);300}301 302static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)303{304	void __iomem *shim = sdw->link_res->shim;305	unsigned int link_id = sdw->instance;306	u16 wake_en, wake_sts;307 308	mutex_lock(sdw->link_res->shim_lock);309	wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);310 311	if (wake_enable) {312		/* Enable the wakeup */313		wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id);314		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);315	} else {316		/* Disable the wake up interrupt */317		wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);318		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);319 320		/* Clear wake status */321		wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);322		wake_sts |= (SDW_SHIM_WAKESTS_STATUS << link_id);323		intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts);324	}325	mutex_unlock(sdw->link_res->shim_lock);326}327 328static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)329{330	void __iomem *shim = sdw->link_res->shim;331	int sync_reg;332 333	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);334	return !!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK);335}336 337static int intel_link_power_up(struct sdw_intel *sdw)338{339	unsigned int link_id = sdw->instance;340	void __iomem *shim = sdw->link_res->shim;341	u32 *shim_mask = sdw->link_res->shim_mask;342	struct sdw_bus *bus = &sdw->cdns.bus;343	struct sdw_master_prop *prop = &bus->prop;344	u32 spa_mask, cpa_mask;345	u32 link_control;346	int ret = 0;347	u32 clock_source;348	u32 syncprd;349	u32 sync_reg;350	bool lcap_mlcs;351 352	mutex_lock(sdw->link_res->shim_lock);353 354	/*355	 * The hardware relies on an internal counter, typically 4kHz,356	 * to generate the SoundWire SSP - which defines a 'safe'357	 * synchronization point between commands and audio transport358	 * and allows for multi link synchronization. The SYNCPRD value359	 * is only dependent on the oscillator clock provided to360	 * the IP, so adjust based on _DSD properties reported in DSDT361	 * tables. The values reported are based on either 24MHz362	 * (CNL/CML) or 38.4 MHz (ICL/TGL+). On MeteorLake additional363	 * frequencies are available with the MLCS clock source selection.364	 */365	lcap_mlcs = intel_readl(shim, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_MLCS_MASK;366 367	if (prop->mclk_freq % 6000000) {368		if (prop->mclk_freq % 2400000) {369			if (lcap_mlcs) {370				syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576;371				clock_source = SDW_SHIM_MLCS_CARDINAL_CLK;372			} else {373				dev_err(sdw->cdns.dev, "%s: invalid clock configuration, mclk %d lcap_mlcs %d\n",374					__func__, prop->mclk_freq, lcap_mlcs);375				ret = -EINVAL;376				goto out;377			}378		} else {379			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;380			clock_source = SDW_SHIM_MLCS_XTAL_CLK;381		}382	} else {383		if (lcap_mlcs) {384			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96;385			clock_source = SDW_SHIM_MLCS_AUDIO_PLL_CLK;386		} else {387			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;388			clock_source = SDW_SHIM_MLCS_XTAL_CLK;389		}390	}391 392	if (!*shim_mask) {393		dev_dbg(sdw->cdns.dev, "powering up all links\n");394 395		/* we first need to program the SyncPRD/CPU registers */396		dev_dbg(sdw->cdns.dev,397			"first link up, programming SYNCPRD\n");398 399		/* set SyncPRD period */400		sync_reg = intel_readl(shim, SDW_SHIM_SYNC);401		u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);402 403		/* Set SyncCPU bit */404		sync_reg |= SDW_SHIM_SYNC_SYNCCPU;405		intel_writel(shim, SDW_SHIM_SYNC, sync_reg);406 407		/* Link power up sequence */408		link_control = intel_readl(shim, SDW_SHIM_LCTL);409 410		/* only power-up enabled links */411		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);412		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);413 414		link_control |=  spa_mask;415 416		ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);417		if (ret < 0) {418			dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);419			goto out;420		}421 422		/* SyncCPU will change once link is active */423		ret = intel_wait_bit(shim, SDW_SHIM_SYNC,424				     SDW_SHIM_SYNC_SYNCCPU, 0);425		if (ret < 0) {426			dev_err(sdw->cdns.dev,427				"Failed to set SHIM_SYNC: %d\n", ret);428			goto out;429		}430 431		/* update link clock if needed */432		if (lcap_mlcs) {433			link_control = intel_readl(shim, SDW_SHIM_LCTL);434			u32p_replace_bits(&link_control, clock_source, SDW_SHIM_LCTL_MLCS_MASK);435			intel_writel(shim, SDW_SHIM_LCTL, link_control);436		}437	}438 439	*shim_mask |= BIT(link_id);440 441	sdw->cdns.link_up = true;442 443	intel_shim_init(sdw);444 445out:446	mutex_unlock(sdw->link_res->shim_lock);447 448	return ret;449}450 451static int intel_link_power_down(struct sdw_intel *sdw)452{453	u32 link_control, spa_mask, cpa_mask;454	unsigned int link_id = sdw->instance;455	void __iomem *shim = sdw->link_res->shim;456	u32 *shim_mask = sdw->link_res->shim_mask;457	int ret = 0;458 459	mutex_lock(sdw->link_res->shim_lock);460 461	if (!(*shim_mask & BIT(link_id)))462		dev_err(sdw->cdns.dev,463			"%s: Unbalanced power-up/down calls\n", __func__);464 465	sdw->cdns.link_up = false;466 467	intel_shim_master_ip_to_glue(sdw);468 469	*shim_mask &= ~BIT(link_id);470 471	if (!*shim_mask) {472 473		dev_dbg(sdw->cdns.dev, "powering down all links\n");474 475		/* Link power down sequence */476		link_control = intel_readl(shim, SDW_SHIM_LCTL);477 478		/* only power-down enabled links */479		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, ~sdw->link_res->link_mask);480		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);481 482		link_control &=  spa_mask;483 484		ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);485		if (ret < 0) {486			dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);487 488			/*489			 * we leave the sdw->cdns.link_up flag as false since we've disabled490			 * the link at this point and cannot handle interrupts any longer.491			 */492		}493	}494 495	mutex_unlock(sdw->link_res->shim_lock);496 497	return ret;498}499 500static void intel_shim_sync_arm(struct sdw_intel *sdw)501{502	void __iomem *shim = sdw->link_res->shim;503	u32 sync_reg;504 505	mutex_lock(sdw->link_res->shim_lock);506 507	/* update SYNC register */508	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);509	sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance);510	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);511 512	mutex_unlock(sdw->link_res->shim_lock);513}514 515static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)516{517	void __iomem *shim = sdw->link_res->shim;518	u32 sync_reg;519 520	/* Read SYNC register */521	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);522 523	/*524	 * Set SyncGO bit to synchronously trigger a bank switch for525	 * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all526	 * the Masters.527	 */528	sync_reg |= SDW_SHIM_SYNC_SYNCGO;529 530	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);531 532	return 0;533}534 535static int intel_shim_sync_go(struct sdw_intel *sdw)536{537	int ret;538 539	mutex_lock(sdw->link_res->shim_lock);540 541	ret = intel_shim_sync_go_unlocked(sdw);542 543	mutex_unlock(sdw->link_res->shim_lock);544 545	return ret;546}547 548/*549 * PDI routines550 */551static void intel_pdi_init(struct sdw_intel *sdw,552			   struct sdw_cdns_stream_config *config)553{554	void __iomem *shim = sdw->link_res->shim;555	unsigned int link_id = sdw->instance;556	int pcm_cap;557 558	/* PCM Stream Capability */559	pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));560 561	config->pcm_bd = FIELD_GET(SDW_SHIM_PCMSCAP_BSS, pcm_cap);562	config->pcm_in = FIELD_GET(SDW_SHIM_PCMSCAP_ISS, pcm_cap);563	config->pcm_out = FIELD_GET(SDW_SHIM_PCMSCAP_OSS, pcm_cap);564 565	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",566		config->pcm_bd, config->pcm_in, config->pcm_out);567}568 569static int570intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)571{572	void __iomem *shim = sdw->link_res->shim;573	unsigned int link_id = sdw->instance;574	int count;575 576	count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));577 578	/*579	 * WORKAROUND: on all existing Intel controllers, pdi580	 * number 2 reports channel count as 1 even though it581	 * supports 8 channels. Performing hardcoding for pdi582	 * number 2.583	 */584	if (pdi_num == 2)585		count = 7;586 587	/* zero based values for channel count in register */588	count++;589 590	return count;591}592 593static int intel_pdi_get_ch_update(struct sdw_intel *sdw,594				   struct sdw_cdns_pdi *pdi,595				   unsigned int num_pdi,596				   unsigned int *num_ch)597{598	int i, ch_count = 0;599 600	for (i = 0; i < num_pdi; i++) {601		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);602		ch_count += pdi->ch_count;603		pdi++;604	}605 606	*num_ch = ch_count;607	return 0;608}609 610static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,611				      struct sdw_cdns_streams *stream)612{613	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,614				&stream->num_ch_bd);615 616	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,617				&stream->num_ch_in);618 619	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,620				&stream->num_ch_out);621 622	return 0;623}624 625static void626intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)627{628	void __iomem *shim = sdw->link_res->shim;629	unsigned int link_id = sdw->instance;630	int pdi_conf = 0;631 632	/* the Bulk and PCM streams are not contiguous */633	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;634	if (pdi->num >= 2)635		pdi->intel_alh_id += 2;636 637	/*638	 * Program stream parameters to stream SHIM register639	 * This is applicable for PCM stream only.640	 */641	if (pdi->type != SDW_STREAM_PCM)642		return;643 644	if (pdi->dir == SDW_DATA_DIR_RX)645		pdi_conf |= SDW_SHIM_PCMSYCM_DIR;646	else647		pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);648 649	u32p_replace_bits(&pdi_conf, pdi->intel_alh_id, SDW_SHIM_PCMSYCM_STREAM);650	u32p_replace_bits(&pdi_conf, pdi->l_ch_num, SDW_SHIM_PCMSYCM_LCHN);651	u32p_replace_bits(&pdi_conf, pdi->h_ch_num, SDW_SHIM_PCMSYCM_HCHN);652 653	intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);654}655 656static void657intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)658{659	void __iomem *alh = sdw->link_res->alh;660	unsigned int link_id = sdw->instance;661	unsigned int conf;662 663	/* the Bulk and PCM streams are not contiguous */664	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;665	if (pdi->num >= 2)666		pdi->intel_alh_id += 2;667 668	/* Program Stream config ALH register */669	conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));670 671	u32p_replace_bits(&conf, SDW_ALH_STRMZCFG_DMAT_VAL, SDW_ALH_STRMZCFG_DMAT);672	u32p_replace_bits(&conf, pdi->ch_count - 1, SDW_ALH_STRMZCFG_CHN);673 674	intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);675}676 677static int intel_params_stream(struct sdw_intel *sdw,678			       struct snd_pcm_substream *substream,679			       struct snd_soc_dai *dai,680			       struct snd_pcm_hw_params *hw_params,681			       int link_id, int alh_stream_id)682{683	struct sdw_intel_link_res *res = sdw->link_res;684	struct sdw_intel_stream_params_data params_data;685 686	params_data.substream = substream;687	params_data.dai = dai;688	params_data.hw_params = hw_params;689	params_data.link_id = link_id;690	params_data.alh_stream_id = alh_stream_id;691 692	if (res->ops && res->ops->params_stream && res->dev)693		return res->ops->params_stream(res->dev,694					       &params_data);695	return -EIO;696}697 698/*699 * DAI routines700 */701 702static int intel_free_stream(struct sdw_intel *sdw,703			     struct snd_pcm_substream *substream,704			     struct snd_soc_dai *dai,705			     int link_id)706{707	struct sdw_intel_link_res *res = sdw->link_res;708	struct sdw_intel_stream_free_data free_data;709 710	free_data.substream = substream;711	free_data.dai = dai;712	free_data.link_id = link_id;713 714	if (res->ops && res->ops->free_stream && res->dev)715		return res->ops->free_stream(res->dev, &free_data);716 717	return 0;718}719 720static int intel_hw_params(struct snd_pcm_substream *substream,721			   struct snd_pcm_hw_params *params,722			   struct snd_soc_dai *dai)723{724	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);725	struct sdw_intel *sdw = cdns_to_intel(cdns);726	struct sdw_cdns_dai_runtime *dai_runtime;727	struct sdw_cdns_pdi *pdi;728	struct sdw_stream_config sconfig;729	int ch, dir;730	int ret;731 732	dai_runtime = cdns->dai_runtime_array[dai->id];733	if (!dai_runtime)734		return -EIO;735 736	ch = params_channels(params);737	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)738		dir = SDW_DATA_DIR_RX;739	else740		dir = SDW_DATA_DIR_TX;741 742	pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);743 744	if (!pdi)745		return -EINVAL;746 747	/* do run-time configurations for SHIM, ALH and PDI/PORT */748	intel_pdi_shim_configure(sdw, pdi);749	intel_pdi_alh_configure(sdw, pdi);750	sdw_cdns_config_stream(cdns, ch, dir, pdi);751 752	/* store pdi and hw_params, may be needed in prepare step */753	dai_runtime->paused = false;754	dai_runtime->suspended = false;755	dai_runtime->pdi = pdi;756 757	/* Inform DSP about PDI stream number */758	ret = intel_params_stream(sdw, substream, dai, params,759				  sdw->instance,760				  pdi->intel_alh_id);761	if (ret)762		return ret;763 764	sconfig.direction = dir;765	sconfig.ch_count = ch;766	sconfig.frame_rate = params_rate(params);767	sconfig.type = dai_runtime->stream_type;768 769	sconfig.bps = snd_pcm_format_width(params_format(params));770 771	/* Port configuration */772	struct sdw_port_config *pconfig __free(kfree) = kzalloc(sizeof(*pconfig),773								GFP_KERNEL);774	if (!pconfig)775		return -ENOMEM;776 777	pconfig->num = pdi->num;778	pconfig->ch_mask = (1 << ch) - 1;779 780	ret = sdw_stream_add_master(&cdns->bus, &sconfig,781				    pconfig, 1, dai_runtime->stream);782	if (ret)783		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);784 785	return ret;786}787 788static int intel_prepare(struct snd_pcm_substream *substream,789			 struct snd_soc_dai *dai)790{791	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);792	struct sdw_intel *sdw = cdns_to_intel(cdns);793	struct sdw_cdns_dai_runtime *dai_runtime;794	int ch, dir;795	int ret = 0;796 797	dai_runtime = cdns->dai_runtime_array[dai->id];798	if (!dai_runtime) {799		dev_err(dai->dev, "failed to get dai runtime in %s\n",800			__func__);801		return -EIO;802	}803 804	if (dai_runtime->suspended) {805		struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);806		struct snd_pcm_hw_params *hw_params;807 808		hw_params = &rtd->dpcm[substream->stream].hw_params;809 810		dai_runtime->suspended = false;811 812		/*813		 * .prepare() is called after system resume, where we814		 * need to reinitialize the SHIM/ALH/Cadence IP.815		 * .prepare() is also called to deal with underflows,816		 * but in those cases we cannot touch ALH/SHIM817		 * registers818		 */819 820		/* configure stream */821		ch = params_channels(hw_params);822		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)823			dir = SDW_DATA_DIR_RX;824		else825			dir = SDW_DATA_DIR_TX;826 827		intel_pdi_shim_configure(sdw, dai_runtime->pdi);828		intel_pdi_alh_configure(sdw, dai_runtime->pdi);829		sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);830 831		/* Inform DSP about PDI stream number */832		ret = intel_params_stream(sdw, substream, dai,833					  hw_params,834					  sdw->instance,835					  dai_runtime->pdi->intel_alh_id);836	}837 838	return ret;839}840 841static int842intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)843{844	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);845	struct sdw_intel *sdw = cdns_to_intel(cdns);846	struct sdw_cdns_dai_runtime *dai_runtime;847	int ret;848 849	dai_runtime = cdns->dai_runtime_array[dai->id];850	if (!dai_runtime)851		return -EIO;852 853	/*854	 * The sdw stream state will transition to RELEASED when stream->855	 * master_list is empty. So the stream state will transition to856	 * DEPREPARED for the first cpu-dai and to RELEASED for the last857	 * cpu-dai.858	 */859	ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);860	if (ret < 0) {861		dev_err(dai->dev, "remove master from stream %s failed: %d\n",862			dai_runtime->stream->name, ret);863		return ret;864	}865 866	ret = intel_free_stream(sdw, substream, dai, sdw->instance);867	if (ret < 0) {868		dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);869		return ret;870	}871 872	dai_runtime->pdi = NULL;873 874	return 0;875}876 877static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,878				    void *stream, int direction)879{880	return cdns_set_sdw_stream(dai, stream, direction);881}882 883static void *intel_get_sdw_stream(struct snd_soc_dai *dai,884				  int direction)885{886	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);887	struct sdw_cdns_dai_runtime *dai_runtime;888 889	dai_runtime = cdns->dai_runtime_array[dai->id];890	if (!dai_runtime)891		return ERR_PTR(-EINVAL);892 893	return dai_runtime->stream;894}895 896static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)897{898	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);899	struct sdw_cdns_dai_runtime *dai_runtime;900	int ret = 0;901 902	dai_runtime = cdns->dai_runtime_array[dai->id];903	if (!dai_runtime) {904		dev_err(dai->dev, "failed to get dai runtime in %s\n",905			__func__);906		return -EIO;907	}908 909	switch (cmd) {910	case SNDRV_PCM_TRIGGER_SUSPEND:911 912		/*913		 * The .prepare callback is used to deal with xruns and resume operations.914		 * In the case of xruns, the DMAs and SHIM registers cannot be touched,915		 * but for resume operations the DMAs and SHIM registers need to be initialized.916		 * the .trigger callback is used to track the suspend case only.917		 */918 919		dai_runtime->suspended = true;920 921		break;922 923	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:924		dai_runtime->paused = true;925		break;926	case SNDRV_PCM_TRIGGER_STOP:927	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:928		dai_runtime->paused = false;929		break;930	default:931		break;932	}933 934	return ret;935}936 937static int intel_component_probe(struct snd_soc_component *component)938{939	int ret;940 941	/*942	 * make sure the device is pm_runtime_active before initiating943	 * bus transactions during the card registration.944	 * We use pm_runtime_resume() here, without taking a reference945	 * and releasing it immediately.946	 */947	ret = pm_runtime_resume(component->dev);948	if (ret < 0 && ret != -EACCES)949		return ret;950 951	return 0;952}953 954static int intel_component_dais_suspend(struct snd_soc_component *component)955{956	struct snd_soc_dai *dai;957 958	/*959	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core960	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.961	 * Since the component suspend is called last, we can trap this corner case962	 * and force the DAIs to release their resources.963	 */964	for_each_component_dais(component, dai) {965		struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);966		struct sdw_cdns_dai_runtime *dai_runtime;967 968		dai_runtime = cdns->dai_runtime_array[dai->id];969 970		if (!dai_runtime)971			continue;972 973		if (dai_runtime->suspended)974			continue;975 976		if (dai_runtime->paused)977			dai_runtime->suspended = true;978	}979 980	return 0;981}982 983static const struct snd_soc_dai_ops intel_pcm_dai_ops = {984	.hw_params = intel_hw_params,985	.prepare = intel_prepare,986	.hw_free = intel_hw_free,987	.trigger = intel_trigger,988	.set_stream = intel_pcm_set_sdw_stream,989	.get_stream = intel_get_sdw_stream,990};991 992static const struct snd_soc_component_driver dai_component = {993	.name			= "soundwire",994	.probe			= intel_component_probe,995	.suspend		= intel_component_dais_suspend,996	.legacy_dai_naming	= 1,997};998 999static int intel_create_dai(struct sdw_cdns *cdns,1000			    struct snd_soc_dai_driver *dais,1001			    enum intel_pdi_type type,1002			    u32 num, u32 off, u32 max_ch)1003{1004	int i;1005 1006	if (num == 0)1007		return 0;1008 1009	for (i = off; i < (off + num); i++) {1010		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,1011					      "SDW%d Pin%d",1012					      cdns->instance, i);1013		if (!dais[i].name)1014			return -ENOMEM;1015 1016		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {1017			dais[i].playback.channels_min = 1;1018			dais[i].playback.channels_max = max_ch;1019		}1020 1021		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {1022			dais[i].capture.channels_min = 1;1023			dais[i].capture.channels_max = max_ch;1024		}1025 1026		dais[i].ops = &intel_pcm_dai_ops;1027	}1028 1029	return 0;1030}1031 1032static int intel_register_dai(struct sdw_intel *sdw)1033{1034	struct sdw_cdns_dai_runtime **dai_runtime_array;1035	struct sdw_cdns_stream_config config;1036	struct sdw_cdns *cdns = &sdw->cdns;1037	struct sdw_cdns_streams *stream;1038	struct snd_soc_dai_driver *dais;1039	int num_dai, ret, off = 0;1040 1041	/* Read the PDI config and initialize cadence PDI */1042	intel_pdi_init(sdw, &config);1043	ret = sdw_cdns_pdi_init(cdns, config);1044	if (ret)1045		return ret;1046 1047	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);1048 1049	/* DAIs are created based on total number of PDIs supported */1050	num_dai = cdns->pcm.num_pdi;1051 1052	dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,1053					 sizeof(struct sdw_cdns_dai_runtime *),1054					 GFP_KERNEL);1055	if (!dai_runtime_array)1056		return -ENOMEM;1057	cdns->dai_runtime_array = dai_runtime_array;1058 1059	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);1060	if (!dais)1061		return -ENOMEM;1062 1063	/* Create PCM DAIs */1064	stream = &cdns->pcm;1065 1066	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,1067			       off, stream->num_ch_in);1068	if (ret)1069		return ret;1070 1071	off += cdns->pcm.num_in;1072	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,1073			       off, stream->num_ch_out);1074	if (ret)1075		return ret;1076 1077	off += cdns->pcm.num_out;1078	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,1079			       off, stream->num_ch_bd);1080	if (ret)1081		return ret;1082 1083	return devm_snd_soc_register_component(cdns->dev, &dai_component,1084					       dais, num_dai);1085}1086 1087 1088const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {1089	.debugfs_init = intel_debugfs_init,1090	.debugfs_exit = intel_debugfs_exit,1091 1092	.register_dai = intel_register_dai,1093 1094	.check_clock_stop = intel_check_clock_stop,1095	.start_bus = intel_start_bus,1096	.start_bus_after_reset = intel_start_bus_after_reset,1097	.start_bus_after_clock_stop = intel_start_bus_after_clock_stop,1098	.stop_bus = intel_stop_bus,1099 1100	.link_power_up = intel_link_power_up,1101	.link_power_down = intel_link_power_down,1102 1103	.shim_check_wake = intel_shim_check_wake,1104	.shim_wake = intel_shim_wake,1105 1106	.pre_bank_switch = intel_pre_bank_switch,1107	.post_bank_switch = intel_post_bank_switch,1108 1109	.sync_arm = intel_shim_sync_arm,1110	.sync_go_unlocked = intel_shim_sync_go_unlocked,1111	.sync_go = intel_shim_sync_go,1112	.sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,1113};1114EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL);1115