aio-core.c 31 KB

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