cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

aio-core.c (31817B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Socionext UniPhier AIO ALSA common driver.
      4//
      5// Copyright (c) 2016-2018 Socionext Inc.
      6
      7#include <linux/bitfield.h>
      8#include <linux/errno.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <sound/core.h>
     12#include <sound/pcm.h>
     13#include <sound/pcm_params.h>
     14#include <sound/soc.h>
     15
     16#include "aio.h"
     17#include "aio-reg.h"
     18
     19static u64 rb_cnt(u64 wr, u64 rd, u64 len)
     20{
     21	if (rd <= wr)
     22		return wr - rd;
     23	else
     24		return len - (rd - wr);
     25}
     26
     27static u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
     28{
     29	if (rd <= wr)
     30		return wr - rd;
     31	else
     32		return len - rd;
     33}
     34
     35static u64 rb_space(u64 wr, u64 rd, u64 len)
     36{
     37	if (rd <= wr)
     38		return len - (wr - rd) - 8;
     39	else
     40		return rd - wr - 8;
     41}
     42
     43static u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
     44{
     45	if (rd > wr)
     46		return rd - wr - 8;
     47	else if (rd > 0)
     48		return len - wr;
     49	else
     50		return len - wr - 8;
     51}
     52
     53u64 aio_rb_cnt(struct uniphier_aio_sub *sub)
     54{
     55	return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
     56}
     57
     58u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
     59{
     60	return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
     61}
     62
     63u64 aio_rb_space(struct uniphier_aio_sub *sub)
     64{
     65	return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
     66}
     67
     68u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
     69{
     70	return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
     71}
     72
     73/**
     74 * aio_iecout_set_enable - setup IEC output via SoC glue
     75 * @chip: the AIO chip pointer
     76 * @enable: false to stop the output, true to start
     77 *
     78 * Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
     79 * This function need to call at driver startup.
     80 *
     81 * The regmap of SoC glue is specified by 'socionext,syscon' optional property
     82 * of DT. This function has no effect if no property.
     83 */
     84void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
     85{
     86	struct regmap *r = chip->regmap_sg;
     87
     88	if (!r)
     89		return;
     90
     91	regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
     92}
     93
     94/**
     95 * aio_chip_set_pll - set frequency to audio PLL
     96 * @chip: the AIO chip pointer
     97 * @pll_id: PLL
     98 * @freq: frequency in Hz, 0 is ignored
     99 *
    100 * Sets frequency of audio PLL. This function can be called anytime,
    101 * but it takes time till PLL is locked.
    102 *
    103 * Return: Zero if successful, otherwise a negative value on error.
    104 */
    105int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
    106		     unsigned int freq)
    107{
    108	struct device *dev = &chip->pdev->dev;
    109	struct regmap *r = chip->regmap;
    110	int shift;
    111	u32 v;
    112
    113	/* Not change */
    114	if (freq == 0)
    115		return 0;
    116
    117	switch (pll_id) {
    118	case AUD_PLL_A1:
    119		shift = 0;
    120		break;
    121	case AUD_PLL_F1:
    122		shift = 1;
    123		break;
    124	case AUD_PLL_A2:
    125		shift = 2;
    126		break;
    127	case AUD_PLL_F2:
    128		shift = 3;
    129		break;
    130	default:
    131		dev_err(dev, "PLL(%d) not supported\n", pll_id);
    132		return -EINVAL;
    133	}
    134
    135	switch (freq) {
    136	case 36864000:
    137		v = A2APLLCTR1_APLLX_36MHZ;
    138		break;
    139	case 33868800:
    140		v = A2APLLCTR1_APLLX_33MHZ;
    141		break;
    142	default:
    143		dev_err(dev, "PLL frequency not supported(%d)\n", freq);
    144		return -EINVAL;
    145	}
    146	chip->plls[pll_id].freq = freq;
    147
    148	regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
    149			   v << shift);
    150
    151	return 0;
    152}
    153
    154/**
    155 * aio_chip_init - initialize AIO whole settings
    156 * @chip: the AIO chip pointer
    157 *
    158 * Sets AIO fixed and whole device settings to AIO.
    159 * This function need to call once at driver startup.
    160 *
    161 * The register area that is changed by this function is shared by all
    162 * modules of AIO. But there is not race condition since this function
    163 * has always set the same initialize values.
    164 */
    165void aio_chip_init(struct uniphier_aio_chip *chip)
    166{
    167	struct regmap *r = chip->regmap;
    168
    169	regmap_update_bits(r, A2APLLCTR0,
    170			   A2APLLCTR0_APLLXPOW_MASK,
    171			   A2APLLCTR0_APLLXPOW_PWON);
    172
    173	regmap_update_bits(r, A2EXMCLKSEL0,
    174			   A2EXMCLKSEL0_EXMCLK_MASK,
    175			   A2EXMCLKSEL0_EXMCLK_OUTPUT);
    176
    177	regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
    178			   A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
    179			   A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
    180			   A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
    181			   A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
    182
    183	if (chip->chip_spec->addr_ext)
    184		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
    185				   CDA2D_TEST_DDR_MODE_EXTON0);
    186	else
    187		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
    188				   CDA2D_TEST_DDR_MODE_EXTOFF1);
    189}
    190
    191/**
    192 * aio_init - initialize AIO substream
    193 * @sub: the AIO substream pointer
    194 *
    195 * Sets fixed settings of each AIO substreams.
    196 * This function need to call once at substream startup.
    197 *
    198 * Return: Zero if successful, otherwise a negative value on error.
    199 */
    200int aio_init(struct uniphier_aio_sub *sub)
    201{
    202	struct device *dev = &sub->aio->chip->pdev->dev;
    203	struct regmap *r = sub->aio->chip->regmap;
    204
    205	regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
    206		     MAPCTR0_EN | sub->swm->rb.map);
    207	regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
    208		     MAPCTR0_EN | sub->swm->ch.map);
    209
    210	switch (sub->swm->type) {
    211	case PORT_TYPE_I2S:
    212	case PORT_TYPE_SPDIF:
    213	case PORT_TYPE_EVE:
    214		if (sub->swm->dir == PORT_DIR_INPUT) {
    215			regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
    216				     MAPCTR0_EN | sub->swm->iif.map);
    217			regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
    218				     MAPCTR0_EN | sub->swm->iport.map);
    219		} else {
    220			regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
    221				     MAPCTR0_EN | sub->swm->oif.map);
    222			regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
    223				     MAPCTR0_EN | sub->swm->oport.map);
    224		}
    225		break;
    226	case PORT_TYPE_CONV:
    227		regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
    228			     MAPCTR0_EN | sub->swm->oif.map);
    229		regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
    230			     MAPCTR0_EN | sub->swm->oport.map);
    231		regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
    232			     MAPCTR0_EN | sub->swm->och.map);
    233		regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
    234			     MAPCTR0_EN | sub->swm->iif.map);
    235		break;
    236	default:
    237		dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
    238		return -EINVAL;
    239	}
    240
    241	return 0;
    242}
    243
    244/**
    245 * aio_port_reset - reset AIO port block
    246 * @sub: the AIO substream pointer
    247 *
    248 * Resets the digital signal input/output port block of AIO.
    249 */
    250void aio_port_reset(struct uniphier_aio_sub *sub)
    251{
    252	struct regmap *r = sub->aio->chip->regmap;
    253
    254	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    255		regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
    256		regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
    257	} else {
    258		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
    259				   IPORTMXRSTCTR_RSTPI_MASK,
    260				   IPORTMXRSTCTR_RSTPI_RESET);
    261		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
    262				   IPORTMXRSTCTR_RSTPI_MASK,
    263				   IPORTMXRSTCTR_RSTPI_RELEASE);
    264	}
    265}
    266
    267/**
    268 * aio_port_set_ch - set channels of LPCM
    269 * @sub: the AIO substream pointer, PCM substream only
    270 *
    271 * Set suitable slot selecting to input/output port block of AIO.
    272 *
    273 * This function may return error if non-PCM substream.
    274 *
    275 * Return: Zero if successful, otherwise a negative value on error.
    276 */
    277static int aio_port_set_ch(struct uniphier_aio_sub *sub)
    278{
    279	struct regmap *r = sub->aio->chip->regmap;
    280	u32 slotsel_2ch[] = {
    281		0, 0, 0, 0, 0,
    282	};
    283	u32 slotsel_multi[] = {
    284		OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
    285		OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
    286		OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
    287		OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
    288		OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
    289	};
    290	u32 mode, *slotsel;
    291	int i;
    292
    293	switch (params_channels(&sub->params)) {
    294	case 8:
    295	case 6:
    296		mode = OPORTMXTYSLOTCTR_MODE;
    297		slotsel = slotsel_multi;
    298		break;
    299	case 2:
    300		mode = 0;
    301		slotsel = slotsel_2ch;
    302		break;
    303	default:
    304		return -EINVAL;
    305	}
    306
    307	for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
    308		regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
    309				   OPORTMXTYSLOTCTR_MODE, mode);
    310		regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
    311				   OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
    312	}
    313
    314	return 0;
    315}
    316
    317/**
    318 * aio_port_set_rate - set sampling rate of LPCM
    319 * @sub: the AIO substream pointer, PCM substream only
    320 * @rate: Sampling rate in Hz.
    321 *
    322 * Set suitable I2S format settings to input/output port block of AIO.
    323 * Parameter is specified by hw_params().
    324 *
    325 * This function may return error if non-PCM substream.
    326 *
    327 * Return: Zero if successful, otherwise a negative value on error.
    328 */
    329static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
    330{
    331	struct regmap *r = sub->aio->chip->regmap;
    332	struct device *dev = &sub->aio->chip->pdev->dev;
    333	u32 v;
    334
    335	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    336		switch (rate) {
    337		case 8000:
    338			v = OPORTMXCTR1_FSSEL_8;
    339			break;
    340		case 11025:
    341			v = OPORTMXCTR1_FSSEL_11_025;
    342			break;
    343		case 12000:
    344			v = OPORTMXCTR1_FSSEL_12;
    345			break;
    346		case 16000:
    347			v = OPORTMXCTR1_FSSEL_16;
    348			break;
    349		case 22050:
    350			v = OPORTMXCTR1_FSSEL_22_05;
    351			break;
    352		case 24000:
    353			v = OPORTMXCTR1_FSSEL_24;
    354			break;
    355		case 32000:
    356			v = OPORTMXCTR1_FSSEL_32;
    357			break;
    358		case 44100:
    359			v = OPORTMXCTR1_FSSEL_44_1;
    360			break;
    361		case 48000:
    362			v = OPORTMXCTR1_FSSEL_48;
    363			break;
    364		case 88200:
    365			v = OPORTMXCTR1_FSSEL_88_2;
    366			break;
    367		case 96000:
    368			v = OPORTMXCTR1_FSSEL_96;
    369			break;
    370		case 176400:
    371			v = OPORTMXCTR1_FSSEL_176_4;
    372			break;
    373		case 192000:
    374			v = OPORTMXCTR1_FSSEL_192;
    375			break;
    376		default:
    377			dev_err(dev, "Rate not supported(%d)\n", rate);
    378			return -EINVAL;
    379		}
    380
    381		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
    382				   OPORTMXCTR1_FSSEL_MASK, v);
    383	} else {
    384		switch (rate) {
    385		case 8000:
    386			v = IPORTMXCTR1_FSSEL_8;
    387			break;
    388		case 11025:
    389			v = IPORTMXCTR1_FSSEL_11_025;
    390			break;
    391		case 12000:
    392			v = IPORTMXCTR1_FSSEL_12;
    393			break;
    394		case 16000:
    395			v = IPORTMXCTR1_FSSEL_16;
    396			break;
    397		case 22050:
    398			v = IPORTMXCTR1_FSSEL_22_05;
    399			break;
    400		case 24000:
    401			v = IPORTMXCTR1_FSSEL_24;
    402			break;
    403		case 32000:
    404			v = IPORTMXCTR1_FSSEL_32;
    405			break;
    406		case 44100:
    407			v = IPORTMXCTR1_FSSEL_44_1;
    408			break;
    409		case 48000:
    410			v = IPORTMXCTR1_FSSEL_48;
    411			break;
    412		case 88200:
    413			v = IPORTMXCTR1_FSSEL_88_2;
    414			break;
    415		case 96000:
    416			v = IPORTMXCTR1_FSSEL_96;
    417			break;
    418		case 176400:
    419			v = IPORTMXCTR1_FSSEL_176_4;
    420			break;
    421		case 192000:
    422			v = IPORTMXCTR1_FSSEL_192;
    423			break;
    424		default:
    425			dev_err(dev, "Rate not supported(%d)\n", rate);
    426			return -EINVAL;
    427		}
    428
    429		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
    430				   IPORTMXCTR1_FSSEL_MASK, v);
    431	}
    432
    433	return 0;
    434}
    435
    436/**
    437 * aio_port_set_fmt - set format of I2S data
    438 * @sub: the AIO substream pointer, PCM substream only
    439 * This parameter has no effect if substream is I2S or PCM.
    440 *
    441 * Set suitable I2S format settings to input/output port block of AIO.
    442 * Parameter is specified by set_fmt().
    443 *
    444 * This function may return error if non-PCM substream.
    445 *
    446 * Return: Zero if successful, otherwise a negative value on error.
    447 */
    448static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
    449{
    450	struct regmap *r = sub->aio->chip->regmap;
    451	struct device *dev = &sub->aio->chip->pdev->dev;
    452	u32 v;
    453
    454	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    455		switch (sub->aio->fmt) {
    456		case SND_SOC_DAIFMT_LEFT_J:
    457			v = OPORTMXCTR1_I2SLRSEL_LEFT;
    458			break;
    459		case SND_SOC_DAIFMT_RIGHT_J:
    460			v = OPORTMXCTR1_I2SLRSEL_RIGHT;
    461			break;
    462		case SND_SOC_DAIFMT_I2S:
    463			v = OPORTMXCTR1_I2SLRSEL_I2S;
    464			break;
    465		default:
    466			dev_err(dev, "Format is not supported(%d)\n",
    467				sub->aio->fmt);
    468			return -EINVAL;
    469		}
    470
    471		v |= OPORTMXCTR1_OUTBITSEL_24;
    472		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
    473				   OPORTMXCTR1_I2SLRSEL_MASK |
    474				   OPORTMXCTR1_OUTBITSEL_MASK, v);
    475	} else {
    476		switch (sub->aio->fmt) {
    477		case SND_SOC_DAIFMT_LEFT_J:
    478			v = IPORTMXCTR1_LRSEL_LEFT;
    479			break;
    480		case SND_SOC_DAIFMT_RIGHT_J:
    481			v = IPORTMXCTR1_LRSEL_RIGHT;
    482			break;
    483		case SND_SOC_DAIFMT_I2S:
    484			v = IPORTMXCTR1_LRSEL_I2S;
    485			break;
    486		default:
    487			dev_err(dev, "Format is not supported(%d)\n",
    488				sub->aio->fmt);
    489			return -EINVAL;
    490		}
    491
    492		v |= IPORTMXCTR1_OUTBITSEL_24 |
    493			IPORTMXCTR1_CHSEL_ALL;
    494		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
    495				   IPORTMXCTR1_LRSEL_MASK |
    496				   IPORTMXCTR1_OUTBITSEL_MASK |
    497				   IPORTMXCTR1_CHSEL_MASK, v);
    498	}
    499
    500	return 0;
    501}
    502
    503/**
    504 * aio_port_set_clk - set clock and divider of AIO port block
    505 * @sub: the AIO substream pointer
    506 *
    507 * Set suitable PLL clock divider and relational settings to
    508 * input/output port block of AIO. Parameters are specified by
    509 * set_sysclk() and set_pll().
    510 *
    511 * Return: Zero if successful, otherwise a negative value on error.
    512 */
    513static int aio_port_set_clk(struct uniphier_aio_sub *sub)
    514{
    515	struct uniphier_aio_chip *chip = sub->aio->chip;
    516	struct device *dev = &sub->aio->chip->pdev->dev;
    517	struct regmap *r = sub->aio->chip->regmap;
    518	u32 v_pll[] = {
    519		OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
    520		OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
    521		OPORTMXCTR2_ACLKSEL_A2PLL,
    522		OPORTMXCTR2_ACLKSEL_RX1,
    523	};
    524	u32 v_div[] = {
    525		OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
    526		OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
    527	};
    528	u32 v;
    529
    530	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    531		if (sub->swm->type == PORT_TYPE_I2S) {
    532			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
    533				dev_err(dev, "PLL(%d) is invalid\n",
    534					sub->aio->pll_out);
    535				return -EINVAL;
    536			}
    537			if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
    538				dev_err(dev, "PLL divider(%d) is invalid\n",
    539					sub->aio->plldiv);
    540				return -EINVAL;
    541			}
    542
    543			v = v_pll[sub->aio->pll_out] |
    544				OPORTMXCTR2_MSSEL_MASTER |
    545				v_div[sub->aio->plldiv];
    546
    547			switch (chip->plls[sub->aio->pll_out].freq) {
    548			case 0:
    549			case 36864000:
    550			case 33868800:
    551				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
    552				break;
    553			default:
    554				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
    555				break;
    556			}
    557		} else if (sub->swm->type == PORT_TYPE_EVE) {
    558			v = OPORTMXCTR2_ACLKSEL_A2PLL |
    559				OPORTMXCTR2_MSSEL_MASTER |
    560				OPORTMXCTR2_EXTLSIFSSEL_36 |
    561				OPORTMXCTR2_DACCKSEL_1_2;
    562		} else if (sub->swm->type == PORT_TYPE_SPDIF) {
    563			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
    564				dev_err(dev, "PLL(%d) is invalid\n",
    565					sub->aio->pll_out);
    566				return -EINVAL;
    567			}
    568			v = v_pll[sub->aio->pll_out] |
    569				OPORTMXCTR2_MSSEL_MASTER |
    570				OPORTMXCTR2_DACCKSEL_1_2;
    571
    572			switch (chip->plls[sub->aio->pll_out].freq) {
    573			case 0:
    574			case 36864000:
    575			case 33868800:
    576				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
    577				break;
    578			default:
    579				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
    580				break;
    581			}
    582		} else {
    583			v = OPORTMXCTR2_ACLKSEL_A1 |
    584				OPORTMXCTR2_MSSEL_MASTER |
    585				OPORTMXCTR2_EXTLSIFSSEL_36 |
    586				OPORTMXCTR2_DACCKSEL_1_2;
    587		}
    588		regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
    589	} else {
    590		v = IPORTMXCTR2_ACLKSEL_A1 |
    591			IPORTMXCTR2_MSSEL_SLAVE |
    592			IPORTMXCTR2_EXTLSIFSSEL_36 |
    593			IPORTMXCTR2_DACCKSEL_1_2;
    594		regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
    595	}
    596
    597	return 0;
    598}
    599
    600/**
    601 * aio_port_set_param - set parameters of AIO port block
    602 * @sub: the AIO substream pointer
    603 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
    604 * This parameter has no effect if substream is I2S or PCM.
    605 * @params: hardware parameters of ALSA
    606 *
    607 * Set suitable setting to input/output port block of AIO to process the
    608 * specified in params.
    609 *
    610 * Return: Zero if successful, otherwise a negative value on error.
    611 */
    612int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
    613		       const struct snd_pcm_hw_params *params)
    614{
    615	struct regmap *r = sub->aio->chip->regmap;
    616	unsigned int rate;
    617	u32 v;
    618	int ret;
    619
    620	if (!pass_through) {
    621		if (sub->swm->type == PORT_TYPE_EVE ||
    622		    sub->swm->type == PORT_TYPE_CONV) {
    623			rate = 48000;
    624		} else {
    625			rate = params_rate(params);
    626		}
    627
    628		ret = aio_port_set_ch(sub);
    629		if (ret)
    630			return ret;
    631
    632		ret = aio_port_set_rate(sub, rate);
    633		if (ret)
    634			return ret;
    635
    636		ret = aio_port_set_fmt(sub);
    637		if (ret)
    638			return ret;
    639	}
    640
    641	ret = aio_port_set_clk(sub);
    642	if (ret)
    643		return ret;
    644
    645	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    646		if (pass_through)
    647			v = OPORTMXCTR3_SRCSEL_STREAM |
    648				OPORTMXCTR3_VALID_STREAM;
    649		else
    650			v = OPORTMXCTR3_SRCSEL_PCM |
    651				OPORTMXCTR3_VALID_PCM;
    652
    653		v |= OPORTMXCTR3_IECTHUR_IECOUT |
    654			OPORTMXCTR3_PMSEL_PAUSE |
    655			OPORTMXCTR3_PMSW_MUTE_OFF;
    656		regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
    657	} else {
    658		regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
    659			     IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
    660		regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
    661			     IPORTMXEXNOE_PCMINOE_INPUT);
    662	}
    663
    664	return 0;
    665}
    666
    667/**
    668 * aio_port_set_enable - start or stop of AIO port block
    669 * @sub: the AIO substream pointer
    670 * @enable: zero to stop the block, otherwise to start
    671 *
    672 * Start or stop the signal input/output port block of AIO.
    673 */
    674void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
    675{
    676	struct regmap *r = sub->aio->chip->regmap;
    677
    678	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    679		regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
    680			     sub->swm->oif.map);
    681
    682		regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
    683				   OPORTMXMASK_IUDXMSK_MASK |
    684				   OPORTMXMASK_IUXCKMSK_MASK |
    685				   OPORTMXMASK_DXMSK_MASK |
    686				   OPORTMXMASK_XCKMSK_MASK,
    687				   OPORTMXMASK_IUDXMSK_OFF |
    688				   OPORTMXMASK_IUXCKMSK_OFF |
    689				   OPORTMXMASK_DXMSK_OFF |
    690				   OPORTMXMASK_XCKMSK_OFF);
    691
    692		if (enable)
    693			regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
    694		else
    695			regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
    696	} else {
    697		regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
    698				   IPORTMXMASK_IUXCKMSK_MASK |
    699				   IPORTMXMASK_XCKMSK_MASK,
    700				   IPORTMXMASK_IUXCKMSK_OFF |
    701				   IPORTMXMASK_XCKMSK_OFF);
    702
    703		if (enable)
    704			regmap_update_bits(r,
    705					   IPORTMXCTR2(sub->swm->iport.map),
    706					   IPORTMXCTR2_REQEN_MASK,
    707					   IPORTMXCTR2_REQEN_ENABLE);
    708		else
    709			regmap_update_bits(r,
    710					   IPORTMXCTR2(sub->swm->iport.map),
    711					   IPORTMXCTR2_REQEN_MASK,
    712					   IPORTMXCTR2_REQEN_DISABLE);
    713	}
    714}
    715
    716/**
    717 * aio_port_get_volume - get volume of AIO port block
    718 * @sub: the AIO substream pointer
    719 *
    720 * Return: current volume, range is 0x0000 - 0xffff
    721 */
    722int aio_port_get_volume(struct uniphier_aio_sub *sub)
    723{
    724	struct regmap *r = sub->aio->chip->regmap;
    725	u32 v;
    726
    727	regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
    728
    729	return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
    730}
    731
    732/**
    733 * aio_port_set_volume - set volume of AIO port block
    734 * @sub: the AIO substream pointer
    735 * @vol: target volume, range is 0x0000 - 0xffff.
    736 *
    737 * Change digital volume and perfome fade-out/fade-in effect for specified
    738 * output slot of port. Gained PCM value can calculate as the following:
    739 *   Gained = Original * vol / 0x4000
    740 */
    741void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
    742{
    743	struct regmap *r = sub->aio->chip->regmap;
    744	int oport_map = sub->swm->oport.map;
    745	int cur, diff, slope = 0, fs;
    746
    747	if (sub->swm->dir == PORT_DIR_INPUT)
    748		return;
    749
    750	cur = aio_port_get_volume(sub);
    751	diff = abs(vol - cur);
    752	fs = params_rate(&sub->params);
    753	if (fs)
    754		slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
    755	slope = max(1, slope);
    756
    757	regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
    758			   OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
    759	regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
    760			   OPORTMXTYVOLPARA2_TARGET_MASK, vol);
    761
    762	if (cur < vol)
    763		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
    764				   OPORTMXTYVOLPARA2_FADE_MASK,
    765				   OPORTMXTYVOLPARA2_FADE_FADEIN);
    766	else
    767		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
    768				   OPORTMXTYVOLPARA2_FADE_MASK,
    769				   OPORTMXTYVOLPARA2_FADE_FADEOUT);
    770
    771	regmap_write(r, AOUTFADECTR0, BIT(oport_map));
    772}
    773
    774/**
    775 * aio_if_set_param - set parameters of AIO DMA I/F block
    776 * @sub: the AIO substream pointer
    777 * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
    778 * This parameter has no effect if substream is I2S or PCM.
    779 *
    780 * Set suitable setting to DMA interface block of AIO to process the
    781 * specified in settings.
    782 *
    783 * Return: Zero if successful, otherwise a negative value on error.
    784 */
    785int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
    786{
    787	struct regmap *r = sub->aio->chip->regmap;
    788	u32 memfmt, v;
    789
    790	if (sub->swm->dir == PORT_DIR_OUTPUT) {
    791		if (pass_through) {
    792			v = PBOUTMXCTR0_ENDIAN_0123 |
    793				PBOUTMXCTR0_MEMFMT_STREAM;
    794		} else {
    795			switch (params_channels(&sub->params)) {
    796			case 2:
    797				memfmt = PBOUTMXCTR0_MEMFMT_2CH;
    798				break;
    799			case 6:
    800				memfmt = PBOUTMXCTR0_MEMFMT_6CH;
    801				break;
    802			case 8:
    803				memfmt = PBOUTMXCTR0_MEMFMT_8CH;
    804				break;
    805			default:
    806				return -EINVAL;
    807			}
    808			v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
    809		}
    810
    811		regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
    812		regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
    813	} else {
    814		regmap_write(r, PBINMXCTR(sub->swm->iif.map),
    815			     PBINMXCTR_NCONNECT_CONNECT |
    816			     PBINMXCTR_INOUTSEL_IN |
    817			     (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
    818			     PBINMXCTR_ENDIAN_3210 |
    819			     PBINMXCTR_MEMFMT_D0);
    820	}
    821
    822	return 0;
    823}
    824
    825/**
    826 * aio_oport_set_stream_type - set parameters of AIO playback port block
    827 * @sub: the AIO substream pointer
    828 * @pc: Pc type of IEC61937
    829 *
    830 * Set special setting to output port block of AIO to output the stream
    831 * via S/PDIF.
    832 *
    833 * Return: Zero if successful, otherwise a negative value on error.
    834 */
    835int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
    836			      enum IEC61937_PC pc)
    837{
    838	struct regmap *r = sub->aio->chip->regmap;
    839	u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
    840
    841	switch (pc) {
    842	case IEC61937_PC_AC3:
    843		repet = OPORTMXREPET_STRLENGTH_AC3 |
    844			OPORTMXREPET_PMLENGTH_AC3;
    845		pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
    846		break;
    847	case IEC61937_PC_MPA:
    848		repet = OPORTMXREPET_STRLENGTH_MPA |
    849			OPORTMXREPET_PMLENGTH_MPA;
    850		pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
    851		break;
    852	case IEC61937_PC_MP3:
    853		repet = OPORTMXREPET_STRLENGTH_MP3 |
    854			OPORTMXREPET_PMLENGTH_MP3;
    855		pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
    856		break;
    857	case IEC61937_PC_DTS1:
    858		repet = OPORTMXREPET_STRLENGTH_DTS1 |
    859			OPORTMXREPET_PMLENGTH_DTS1;
    860		pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
    861		break;
    862	case IEC61937_PC_DTS2:
    863		repet = OPORTMXREPET_STRLENGTH_DTS2 |
    864			OPORTMXREPET_PMLENGTH_DTS2;
    865		pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
    866		break;
    867	case IEC61937_PC_DTS3:
    868		repet = OPORTMXREPET_STRLENGTH_DTS3 |
    869			OPORTMXREPET_PMLENGTH_DTS3;
    870		pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
    871		break;
    872	case IEC61937_PC_AAC:
    873		repet = OPORTMXREPET_STRLENGTH_AAC |
    874			OPORTMXREPET_PMLENGTH_AAC;
    875		pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
    876		break;
    877	case IEC61937_PC_PAUSE:
    878		/* Do nothing */
    879		break;
    880	}
    881
    882	regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
    883	regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
    884
    885	return 0;
    886}
    887
    888/**
    889 * aio_src_reset - reset AIO SRC block
    890 * @sub: the AIO substream pointer
    891 *
    892 * Resets the digital signal input/output port with sampling rate converter
    893 * block of AIO.
    894 * This function has no effect if substream is not supported rate converter.
    895 */
    896void aio_src_reset(struct uniphier_aio_sub *sub)
    897{
    898	struct regmap *r = sub->aio->chip->regmap;
    899
    900	if (sub->swm->dir != PORT_DIR_OUTPUT)
    901		return;
    902
    903	regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
    904	regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
    905}
    906
    907/**
    908 * aio_src_set_param - set parameters of AIO SRC block
    909 * @sub: the AIO substream pointer
    910 * @params: hardware parameters of ALSA
    911 *
    912 * Set suitable setting to input/output port with sampling rate converter
    913 * block of AIO to process the specified in params.
    914 * This function has no effect if substream is not supported rate converter.
    915 *
    916 * Return: Zero if successful, otherwise a negative value on error.
    917 */
    918int aio_src_set_param(struct uniphier_aio_sub *sub,
    919		      const struct snd_pcm_hw_params *params)
    920{
    921	struct regmap *r = sub->aio->chip->regmap;
    922	u32 v;
    923
    924	if (sub->swm->dir != PORT_DIR_OUTPUT)
    925		return 0;
    926
    927	regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
    928		     OPORTMXSRC1CTR_THMODE_SRC |
    929		     OPORTMXSRC1CTR_SRCPATH_CALC |
    930		     OPORTMXSRC1CTR_SYNC_ASYNC |
    931		     OPORTMXSRC1CTR_FSIIPSEL_INNER |
    932		     OPORTMXSRC1CTR_FSISEL_ACLK);
    933
    934	switch (params_rate(params)) {
    935	default:
    936	case 48000:
    937		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
    938			OPORTMXRATE_I_MCKSEL_36 |
    939			OPORTMXRATE_I_FSSEL_48;
    940		break;
    941	case 44100:
    942		v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
    943			OPORTMXRATE_I_MCKSEL_33 |
    944			OPORTMXRATE_I_FSSEL_44_1;
    945		break;
    946	case 32000:
    947		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
    948			OPORTMXRATE_I_MCKSEL_36 |
    949			OPORTMXRATE_I_FSSEL_32;
    950		break;
    951	}
    952
    953	regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
    954		     v | OPORTMXRATE_I_ACLKSRC_APLL |
    955		     OPORTMXRATE_I_LRCKSTP_STOP);
    956	regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
    957			   OPORTMXRATE_I_LRCKSTP_MASK,
    958			   OPORTMXRATE_I_LRCKSTP_START);
    959
    960	return 0;
    961}
    962
    963int aio_srcif_set_param(struct uniphier_aio_sub *sub)
    964{
    965	struct regmap *r = sub->aio->chip->regmap;
    966
    967	regmap_write(r, PBINMXCTR(sub->swm->iif.map),
    968		     PBINMXCTR_NCONNECT_CONNECT |
    969		     PBINMXCTR_INOUTSEL_OUT |
    970		     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
    971		     PBINMXCTR_ENDIAN_3210 |
    972		     PBINMXCTR_MEMFMT_D0);
    973
    974	return 0;
    975}
    976
    977int aio_srcch_set_param(struct uniphier_aio_sub *sub)
    978{
    979	struct regmap *r = sub->aio->chip->regmap;
    980
    981	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
    982		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
    983
    984	regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
    985		     CDA2D_CHMXAMODE_ENDIAN_3210 |
    986		     CDA2D_CHMXAMODE_AUPDT_FIX |
    987		     CDA2D_CHMXAMODE_TYPE_NORMAL);
    988
    989	regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
    990		     CDA2D_CHMXAMODE_ENDIAN_3210 |
    991		     CDA2D_CHMXAMODE_AUPDT_INC |
    992		     CDA2D_CHMXAMODE_TYPE_RING |
    993		     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
    994
    995	return 0;
    996}
    997
    998void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
    999{
   1000	struct regmap *r = sub->aio->chip->regmap;
   1001	u32 v;
   1002
   1003	if (enable)
   1004		v = CDA2D_STRT0_STOP_START;
   1005	else
   1006		v = CDA2D_STRT0_STOP_STOP;
   1007
   1008	regmap_write(r, CDA2D_STRT0,
   1009		     v | BIT(sub->swm->och.map));
   1010}
   1011
   1012int aiodma_ch_set_param(struct uniphier_aio_sub *sub)
   1013{
   1014	struct regmap *r = sub->aio->chip->regmap;
   1015	u32 v;
   1016
   1017	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
   1018		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
   1019
   1020	v = CDA2D_CHMXAMODE_ENDIAN_3210 |
   1021		CDA2D_CHMXAMODE_AUPDT_INC |
   1022		CDA2D_CHMXAMODE_TYPE_NORMAL |
   1023		(sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
   1024	if (sub->swm->dir == PORT_DIR_OUTPUT)
   1025		regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
   1026	else
   1027		regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
   1028
   1029	return 0;
   1030}
   1031
   1032void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
   1033{
   1034	struct regmap *r = sub->aio->chip->regmap;
   1035
   1036	if (enable) {
   1037		regmap_write(r, CDA2D_STRT0,
   1038			     CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
   1039
   1040		regmap_update_bits(r, INTRBIM(0),
   1041				   BIT(sub->swm->rb.map),
   1042				   BIT(sub->swm->rb.map));
   1043	} else {
   1044		regmap_write(r, CDA2D_STRT0,
   1045			     CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
   1046
   1047		regmap_update_bits(r, INTRBIM(0),
   1048				   BIT(sub->swm->rb.map),
   1049				   0);
   1050	}
   1051}
   1052
   1053static u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
   1054{
   1055	struct regmap *r = sub->aio->chip->regmap;
   1056	u32 pos_u, pos_l;
   1057	int i;
   1058
   1059	regmap_write(r, CDA2D_RDPTRLOAD,
   1060		     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
   1061	/* Wait for setup */
   1062	for (i = 0; i < 6; i++)
   1063		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
   1064
   1065	regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
   1066	regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
   1067	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
   1068
   1069	return ((u64)pos_u << 32) | pos_l;
   1070}
   1071
   1072static void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
   1073{
   1074	struct regmap *r = sub->aio->chip->regmap;
   1075	u32 tmp;
   1076	int i;
   1077
   1078	regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
   1079	regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
   1080	regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
   1081	/* Wait for setup */
   1082	for (i = 0; i < 6; i++)
   1083		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
   1084}
   1085
   1086static u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
   1087{
   1088	struct regmap *r = sub->aio->chip->regmap;
   1089	u32 pos_u, pos_l;
   1090	int i;
   1091
   1092	regmap_write(r, CDA2D_WRPTRLOAD,
   1093		     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
   1094	/* Wait for setup */
   1095	for (i = 0; i < 6; i++)
   1096		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
   1097
   1098	regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
   1099	regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
   1100	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
   1101
   1102	return ((u64)pos_u << 32) | pos_l;
   1103}
   1104
   1105static void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
   1106{
   1107	struct regmap *r = sub->aio->chip->regmap;
   1108	u32 tmp;
   1109	int i;
   1110
   1111	regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
   1112		     lower_32_bits(pos));
   1113	regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
   1114		     upper_32_bits(pos));
   1115	regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
   1116	/* Wait for setup */
   1117	for (i = 0; i < 6; i++)
   1118		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
   1119}
   1120
   1121int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
   1122{
   1123	struct regmap *r = sub->aio->chip->regmap;
   1124
   1125	if (size <= th)
   1126		return -EINVAL;
   1127
   1128	regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
   1129	regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
   1130
   1131	return 0;
   1132}
   1133
   1134int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
   1135			 int period)
   1136{
   1137	struct regmap *r = sub->aio->chip->regmap;
   1138	u64 size = end - start;
   1139	int ret;
   1140
   1141	if (end < start || period < 0)
   1142		return -EINVAL;
   1143
   1144	regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
   1145	regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
   1146		     lower_32_bits(start));
   1147	regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
   1148		     upper_32_bits(start));
   1149	regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
   1150		     lower_32_bits(end));
   1151	regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
   1152		     upper_32_bits(end));
   1153
   1154	regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
   1155
   1156	ret = aiodma_rb_set_threshold(sub, size, 2 * period);
   1157	if (ret)
   1158		return ret;
   1159
   1160	if (sub->swm->dir == PORT_DIR_OUTPUT) {
   1161		aiodma_rb_set_rp(sub, start);
   1162		aiodma_rb_set_wp(sub, end - period);
   1163
   1164		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
   1165				   CDA2D_RBMXIX_SPACE,
   1166				   CDA2D_RBMXIX_SPACE);
   1167	} else {
   1168		aiodma_rb_set_rp(sub, end - period);
   1169		aiodma_rb_set_wp(sub, start);
   1170
   1171		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
   1172				   CDA2D_RBMXIX_REMAIN,
   1173				   CDA2D_RBMXIX_REMAIN);
   1174	}
   1175
   1176	sub->threshold = 2 * period;
   1177	sub->rd_offs = 0;
   1178	sub->wr_offs = 0;
   1179	sub->rd_org = 0;
   1180	sub->wr_org = 0;
   1181	sub->rd_total = 0;
   1182	sub->wr_total = 0;
   1183
   1184	return 0;
   1185}
   1186
   1187void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
   1188		    int period)
   1189{
   1190	if (sub->swm->dir == PORT_DIR_OUTPUT) {
   1191		sub->rd_offs = aiodma_rb_get_rp(sub) - start;
   1192
   1193		if (sub->use_mmap) {
   1194			sub->threshold = 2 * period;
   1195			aiodma_rb_set_threshold(sub, size, 2 * period);
   1196
   1197			sub->wr_offs = sub->rd_offs - period;
   1198			if (sub->rd_offs < period)
   1199				sub->wr_offs += size;
   1200		}
   1201		aiodma_rb_set_wp(sub, sub->wr_offs + start);
   1202	} else {
   1203		sub->wr_offs = aiodma_rb_get_wp(sub) - start;
   1204
   1205		if (sub->use_mmap) {
   1206			sub->threshold = 2 * period;
   1207			aiodma_rb_set_threshold(sub, size, 2 * period);
   1208
   1209			sub->rd_offs = sub->wr_offs - period;
   1210			if (sub->wr_offs < period)
   1211				sub->rd_offs += size;
   1212		}
   1213		aiodma_rb_set_rp(sub, sub->rd_offs + start);
   1214	}
   1215
   1216	sub->rd_total += sub->rd_offs - sub->rd_org;
   1217	if (sub->rd_offs < sub->rd_org)
   1218		sub->rd_total += size;
   1219	sub->wr_total += sub->wr_offs - sub->wr_org;
   1220	if (sub->wr_offs < sub->wr_org)
   1221		sub->wr_total += size;
   1222
   1223	sub->rd_org = sub->rd_offs;
   1224	sub->wr_org = sub->wr_offs;
   1225}
   1226
   1227bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
   1228{
   1229	struct regmap *r = sub->aio->chip->regmap;
   1230	u32 ir;
   1231
   1232	regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
   1233
   1234	if (sub->swm->dir == PORT_DIR_OUTPUT)
   1235		return !!(ir & CDA2D_RBMXIX_SPACE);
   1236	else
   1237		return !!(ir & CDA2D_RBMXIX_REMAIN);
   1238}
   1239
   1240void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
   1241{
   1242	struct regmap *r = sub->aio->chip->regmap;
   1243
   1244	if (sub->swm->dir == PORT_DIR_OUTPUT)
   1245		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
   1246			     CDA2D_RBMXIX_SPACE);
   1247	else
   1248		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
   1249			     CDA2D_RBMXIX_REMAIN);
   1250}