0086-media-starfive-Add-VIN-driver.patch 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694
  1. From 030f0312433a85899fab4dccada5b2cbceb3bad5 Mon Sep 17 00:00:00 2001
  2. From: Jack Zhu <[email protected]>
  3. Date: Fri, 12 May 2023 18:28:44 +0800
  4. Subject: [PATCH 086/122] media: starfive: Add VIN driver
  5. Add Video In Controller driver for StarFive Camera Subsystem.
  6. Signed-off-by: Jack Zhu <[email protected]>
  7. ---
  8. drivers/media/platform/starfive/Makefile | 4 +-
  9. drivers/media/platform/starfive/stf_camss.c | 39 +-
  10. drivers/media/platform/starfive/stf_camss.h | 2 +
  11. drivers/media/platform/starfive/stf_vin.c | 1134 +++++++++++++++++
  12. drivers/media/platform/starfive/stf_vin.h | 180 +++
  13. .../media/platform/starfive/stf_vin_hw_ops.c | 241 ++++
  14. 6 files changed, 1598 insertions(+), 2 deletions(-)
  15. create mode 100644 drivers/media/platform/starfive/stf_vin.c
  16. create mode 100644 drivers/media/platform/starfive/stf_vin.h
  17. create mode 100644 drivers/media/platform/starfive/stf_vin_hw_ops.c
  18. --- a/drivers/media/platform/starfive/Makefile
  19. +++ b/drivers/media/platform/starfive/Makefile
  20. @@ -7,6 +7,8 @@ starfive-camss-objs += \
  21. stf_camss.o \
  22. stf_isp.o \
  23. stf_isp_hw_ops.o \
  24. - stf_video.o
  25. + stf_video.o \
  26. + stf_vin.o \
  27. + stf_vin_hw_ops.o
  28. obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \
  29. --- a/drivers/media/platform/starfive/stf_camss.c
  30. +++ b/drivers/media/platform/starfive/stf_camss.c
  31. @@ -142,27 +142,61 @@ static int stfcamss_init_subdevices(stru
  32. return ret;
  33. }
  34. + ret = stf_vin_subdev_init(stfcamss);
  35. + if (ret < 0) {
  36. + dev_err(stfcamss->dev, "Failed to init vin subdev: %d\n", ret);
  37. + return ret;
  38. + }
  39. return ret;
  40. }
  41. static int stfcamss_register_subdevices(struct stfcamss *stfcamss)
  42. {
  43. int ret;
  44. + struct stf_vin_dev *vin_dev = &stfcamss->vin_dev;
  45. struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
  46. ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev);
  47. if (ret < 0) {
  48. dev_err(stfcamss->dev,
  49. "Failed to register stf isp%d entity: %d\n", 0, ret);
  50. - return ret;
  51. + goto err_reg_isp;
  52. + }
  53. +
  54. + ret = stf_vin_register(vin_dev, &stfcamss->v4l2_dev);
  55. + if (ret < 0) {
  56. + dev_err(stfcamss->dev,
  57. + "Failed to register vin entity: %d\n", ret);
  58. + goto err_reg_vin;
  59. }
  60. + ret = media_create_pad_link(&isp_dev->subdev.entity,
  61. + STF_ISP_PAD_SRC,
  62. + &vin_dev->line[VIN_LINE_ISP].subdev.entity,
  63. + STF_VIN_PAD_SINK,
  64. + 0);
  65. + if (ret < 0) {
  66. + dev_err(stfcamss->dev,
  67. + "Failed to link %s->%s entities: %d\n",
  68. + isp_dev->subdev.entity.name,
  69. + vin_dev->line[VIN_LINE_ISP].subdev.entity.name, ret);
  70. + goto err_link;
  71. + }
  72. +
  73. + return ret;
  74. +
  75. +err_link:
  76. + stf_vin_unregister(&stfcamss->vin_dev);
  77. +err_reg_vin:
  78. + stf_isp_unregister(&stfcamss->isp_dev);
  79. +err_reg_isp:
  80. return ret;
  81. }
  82. static void stfcamss_unregister_subdevices(struct stfcamss *stfcamss)
  83. {
  84. stf_isp_unregister(&stfcamss->isp_dev);
  85. + stf_vin_unregister(&stfcamss->vin_dev);
  86. }
  87. static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async,
  88. @@ -175,11 +209,14 @@ static int stfcamss_subdev_notifier_boun
  89. container_of(asd, struct stfcamss_async_subdev, asd);
  90. enum port_num port = csd->port;
  91. struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
  92. + struct stf_vin_dev *vin_dev = &stfcamss->vin_dev;
  93. struct host_data *host_data = &stfcamss->host_data;
  94. struct media_entity *source;
  95. int i, j;
  96. if (port == PORT_NUMBER_CSI2RX) {
  97. + host_data->host_entity[0] =
  98. + &vin_dev->line[VIN_LINE_WR].subdev.entity;
  99. host_data->host_entity[1] = &isp_dev->subdev.entity;
  100. } else if (port == PORT_NUMBER_DVP_SENSOR) {
  101. dev_err(stfcamss->dev, "Not support DVP sensor\n");
  102. --- a/drivers/media/platform/starfive/stf_camss.h
  103. +++ b/drivers/media/platform/starfive/stf_camss.h
  104. @@ -17,6 +17,7 @@
  105. #include "stf_common.h"
  106. #include "stf_isp.h"
  107. +#include "stf_vin.h"
  108. #define DRV_NAME "starfive-camss"
  109. #define STF_DVP_NAME "stf_dvp"
  110. @@ -72,6 +73,7 @@ struct stfcamss {
  111. struct media_device media_dev;
  112. struct media_pipeline pipe;
  113. struct device *dev;
  114. + struct stf_vin_dev vin_dev;
  115. struct stf_isp_dev isp_dev;
  116. struct v4l2_async_notifier notifier;
  117. struct host_data host_data;
  118. --- /dev/null
  119. +++ b/drivers/media/platform/starfive/stf_vin.c
  120. @@ -0,0 +1,1134 @@
  121. +// SPDX-License-Identifier: GPL-2.0
  122. +/*
  123. + * stf_vin.c
  124. + *
  125. + * StarFive Camera Subsystem - VIN Module
  126. + *
  127. + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
  128. + */
  129. +#include <linux/pm_runtime.h>
  130. +
  131. +#include "stf_camss.h"
  132. +
  133. +#define vin_line_array(ptr_line) \
  134. + ((const struct vin_line (*)[]) &(ptr_line)[-((ptr_line)->id)])
  135. +
  136. +#define line_to_vin_dev(ptr_line) \
  137. + container_of(vin_line_array(ptr_line), struct stf_vin_dev, line)
  138. +
  139. +#define VIN_FRAME_DROP_MAX_VAL 90
  140. +#define VIN_FRAME_DROP_MIN_VAL 4
  141. +#define VIN_FRAME_PER_SEC_MAX_VAL 90
  142. +
  143. +/* ISP ctrl need 1 sec to let frames become stable. */
  144. +#define VIN_FRAME_DROP_SEC_FOR_ISP_CTRL 1
  145. +
  146. +static const struct vin_format vin_formats_wr[] = {
  147. + { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
  148. + { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
  149. + { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
  150. + { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
  151. +};
  152. +
  153. +static const struct vin_format vin_formats_uo[] = {
  154. + { MEDIA_BUS_FMT_Y12_1X12, 8},
  155. +};
  156. +
  157. +static const struct vin_format_table vin_formats_table[] = {
  158. + /* VIN_LINE_WR */
  159. + { vin_formats_wr, ARRAY_SIZE(vin_formats_wr) },
  160. + /* VIN_LINE_ISP */
  161. + { vin_formats_uo, ARRAY_SIZE(vin_formats_uo) },
  162. +};
  163. +
  164. +static void vin_buffer_done(struct vin_line *line);
  165. +static void vin_change_buffer(struct vin_line *line);
  166. +static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output);
  167. +static void vin_output_init_addrs(struct vin_line *line);
  168. +static void vin_init_outputs(struct vin_line *line);
  169. +static struct v4l2_mbus_framefmt *
  170. +__vin_get_format(struct vin_line *line,
  171. + struct v4l2_subdev_state *state,
  172. + unsigned int pad,
  173. + enum v4l2_subdev_format_whence which);
  174. +
  175. +static char *vin_get_line_subdevname(int line_id)
  176. +{
  177. + char *name = NULL;
  178. +
  179. + switch (line_id) {
  180. + case VIN_LINE_WR:
  181. + name = "wr";
  182. + break;
  183. + case VIN_LINE_ISP:
  184. + name = "isp0";
  185. + break;
  186. + default:
  187. + name = "unknown";
  188. + break;
  189. + }
  190. + return name;
  191. +}
  192. +
  193. +static enum isp_line_id vin_map_isp_line(enum vin_line_id line)
  194. +{
  195. + enum isp_line_id line_id;
  196. +
  197. + if (line > VIN_LINE_WR && line < VIN_LINE_MAX)
  198. + line_id = STF_ISP_LINE_SRC;
  199. + else
  200. + line_id = STF_ISP_LINE_INVALID;
  201. +
  202. + return line_id;
  203. +}
  204. +
  205. +enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def)
  206. +{
  207. + enum isp_pad_id pad_id;
  208. +
  209. + if (line == VIN_LINE_WR)
  210. + pad_id = STF_ISP_PAD_SINK;
  211. + else if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX))
  212. + pad_id = (enum isp_pad_id)vin_map_isp_line(line);
  213. + else
  214. + pad_id = def;
  215. +
  216. + return pad_id;
  217. +}
  218. +
  219. +int stf_vin_subdev_init(struct stfcamss *stfcamss)
  220. +{
  221. + struct device *dev = stfcamss->dev;
  222. + struct stf_vin_dev *vin_dev = &stfcamss->vin_dev;
  223. + int i, ret = 0;
  224. +
  225. + vin_dev->stfcamss = stfcamss;
  226. +
  227. + vin_dev->isr_ops = devm_kzalloc(dev, sizeof(*vin_dev->isr_ops),
  228. + GFP_KERNEL);
  229. + if (!vin_dev->isr_ops)
  230. + return -ENOMEM;
  231. + vin_dev->isr_ops->isr_buffer_done = vin_buffer_done;
  232. + vin_dev->isr_ops->isr_change_buffer = vin_change_buffer;
  233. +
  234. + atomic_set(&vin_dev->ref_count, 0);
  235. +
  236. + ret = devm_request_irq(dev,
  237. + stfcamss->irq[STF_IRQ_VINWR],
  238. + stf_vin_wr_irq_handler,
  239. + 0, "vin_axiwr_irq", vin_dev);
  240. + if (ret) {
  241. + dev_err(dev, "Failed to request irq\n");
  242. + goto out;
  243. + }
  244. +
  245. + ret = devm_request_irq(dev,
  246. + stfcamss->irq[STF_IRQ_ISP],
  247. + stf_vin_isp_irq_handler,
  248. + 0, "vin_isp_irq", vin_dev);
  249. + if (ret) {
  250. + dev_err(dev, "Failed to request isp irq\n");
  251. + goto out;
  252. + }
  253. +
  254. + ret = devm_request_irq(dev,
  255. + stfcamss->irq[STF_IRQ_ISPCSIL],
  256. + stf_vin_isp_irq_csiline_handler,
  257. + 0, "vin_isp_irq_csiline", vin_dev);
  258. + if (ret) {
  259. + dev_err(dev, "failed to request isp irq csiline\n");
  260. + goto out;
  261. + }
  262. +
  263. + mutex_init(&vin_dev->power_lock);
  264. + vin_dev->power_count = 0;
  265. +
  266. + for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++) {
  267. + struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[i];
  268. +
  269. + mutex_init(&dummy_buffer->stream_lock);
  270. + dummy_buffer->nums =
  271. + i == 0 ? VIN_DUMMY_BUFFER_NUMS : ISP_DUMMY_BUFFER_NUMS;
  272. + dummy_buffer->stream_count = 0;
  273. + dummy_buffer->buffer =
  274. + devm_kzalloc(dev,
  275. + dummy_buffer->nums * sizeof(struct vin_dummy_buffer),
  276. + GFP_KERNEL);
  277. + atomic_set(&dummy_buffer->frame_skip, 0);
  278. + }
  279. +
  280. + for (i = VIN_LINE_WR; i < STF_ISP_LINE_MAX + 1; i++) {
  281. + struct vin_line *l = &vin_dev->line[i];
  282. +
  283. + l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  284. + l->video_out.stfcamss = stfcamss;
  285. + l->id = i;
  286. + l->sdev_type = STF_SUBDEV_TYPE_VIN;
  287. + l->formats = vin_formats_table[i].fmts;
  288. + l->nformats = vin_formats_table[i].nfmts;
  289. + spin_lock_init(&l->output_lock);
  290. +
  291. + mutex_init(&l->stream_lock);
  292. + l->stream_count = 0;
  293. + mutex_init(&l->power_lock);
  294. + l->power_count = 0;
  295. + }
  296. +
  297. + return 0;
  298. +out:
  299. + return ret;
  300. +}
  301. +
  302. +static enum link vin_get_link(struct media_entity *entity)
  303. +{
  304. + struct v4l2_subdev *subdev;
  305. + struct media_pad *pad;
  306. + bool isp = false;
  307. +
  308. + while (1) {
  309. + pad = &entity->pads[0];
  310. + if (!(pad->flags & MEDIA_PAD_FL_SINK))
  311. + return LINK_ERROR;
  312. +
  313. + pad = media_pad_remote_pad_first(pad);
  314. + if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
  315. + return LINK_ERROR;
  316. +
  317. + entity = pad->entity;
  318. + subdev = media_entity_to_v4l2_subdev(entity);
  319. +
  320. + if (!strncmp(subdev->name, STF_CSI_NAME,
  321. + strlen(STF_CSI_NAME))) {
  322. + if (isp)
  323. + return LINK_CSI_TO_ISP;
  324. + else
  325. + return LINK_CSI_TO_WR;
  326. + } else if (!strncmp(subdev->name, STF_DVP_NAME,
  327. + strlen(STF_DVP_NAME))) {
  328. + if (isp)
  329. + return LINK_DVP_TO_ISP;
  330. + else
  331. + return LINK_DVP_TO_WR;
  332. + } else if (!strncmp(subdev->name, STF_ISP_NAME,
  333. + strlen(STF_ISP_NAME))) {
  334. + isp = true;
  335. + } else {
  336. + return LINK_ERROR;
  337. + }
  338. + }
  339. +}
  340. +
  341. +static int vin_set_power(struct v4l2_subdev *sd, int on)
  342. +{
  343. + struct vin_line *line = v4l2_get_subdevdata(sd);
  344. + struct stf_vin_dev *vin_dev = line_to_vin_dev(line);
  345. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  346. + enum link link;
  347. +
  348. + mutex_lock(&line->power_lock);
  349. + if (on) {
  350. + if (line->power_count == 0)
  351. + vin_init_outputs(line);
  352. + line->power_count++;
  353. + } else {
  354. + if (line->power_count == 0) {
  355. + dev_err(stfcamss->dev,
  356. + "line power off on power_count = 0\n");
  357. + goto exit_line;
  358. + }
  359. + line->power_count--;
  360. + }
  361. +exit_line:
  362. + mutex_unlock(&line->power_lock);
  363. +
  364. + mutex_lock(&vin_dev->power_lock);
  365. + link = vin_get_link(&sd->entity);
  366. + if (link == LINK_ERROR)
  367. + goto exit;
  368. +
  369. + if (on) {
  370. + if (vin_dev->power_count == 0) {
  371. + pm_runtime_get_sync(stfcamss->dev);
  372. + stf_vin_clk_enable(vin_dev, link);
  373. + }
  374. + vin_dev->power_count++;
  375. + } else {
  376. + if (vin_dev->power_count == 0) {
  377. + dev_err(stfcamss->dev,
  378. + "vin_dev power off on power_count=0\n");
  379. + goto exit;
  380. + }
  381. + if (vin_dev->power_count == 1) {
  382. + stf_vin_clk_disable(vin_dev, link);
  383. + pm_runtime_put_sync(stfcamss->dev);
  384. + }
  385. + vin_dev->power_count--;
  386. + }
  387. +exit:
  388. +
  389. + mutex_unlock(&vin_dev->power_lock);
  390. +
  391. + return 0;
  392. +}
  393. +
  394. +static int vin_enable_output(struct vin_line *line)
  395. +{
  396. + struct vin_output *output = &line->output;
  397. + unsigned long flags;
  398. +
  399. + spin_lock_irqsave(&line->output_lock, flags);
  400. +
  401. + output->state = VIN_OUTPUT_IDLE;
  402. +
  403. + output->buf[0] = vin_buf_get_pending(output);
  404. +
  405. + if (!output->buf[0] && output->buf[1]) {
  406. + output->buf[0] = output->buf[1];
  407. + output->buf[1] = NULL;
  408. + }
  409. +
  410. + if (output->buf[0])
  411. + output->state = VIN_OUTPUT_SINGLE;
  412. +
  413. + output->sequence = 0;
  414. +
  415. + vin_output_init_addrs(line);
  416. + spin_unlock_irqrestore(&line->output_lock, flags);
  417. + return 0;
  418. +}
  419. +
  420. +static int vin_disable_output(struct vin_line *line)
  421. +{
  422. + struct vin_output *output = &line->output;
  423. + unsigned long flags;
  424. +
  425. + spin_lock_irqsave(&line->output_lock, flags);
  426. +
  427. + output->state = VIN_OUTPUT_OFF;
  428. +
  429. + spin_unlock_irqrestore(&line->output_lock, flags);
  430. + return 0;
  431. +}
  432. +
  433. +static u32 vin_line_to_dummy_module(struct vin_line *line)
  434. +{
  435. + u32 dummy_module = 0;
  436. +
  437. + switch (line->id) {
  438. + case VIN_LINE_WR:
  439. + dummy_module = STF_DUMMY_VIN;
  440. + break;
  441. + case VIN_LINE_ISP:
  442. + dummy_module = STF_DUMMY_ISP;
  443. + break;
  444. + default:
  445. + dummy_module = STF_DUMMY_VIN;
  446. + break;
  447. + }
  448. +
  449. + return dummy_module;
  450. +}
  451. +
  452. +static int vin_alloc_dummy_buffer(struct stf_vin_dev *vin_dev,
  453. + struct v4l2_mbus_framefmt *fmt,
  454. + int dummy_module)
  455. +{
  456. + struct device *dev = vin_dev->stfcamss->dev;
  457. + struct dummy_buffer *dummy_buffer =
  458. + &vin_dev->dummy_buffer[dummy_module];
  459. + struct vin_dummy_buffer *buffer = NULL;
  460. + int ret = 0, i;
  461. + u32 aligns;
  462. +
  463. + for (i = 0; i < dummy_buffer->nums; i++) {
  464. + buffer = &vin_dev->dummy_buffer[dummy_module].buffer[i];
  465. + buffer->width = fmt->width;
  466. + buffer->height = fmt->height;
  467. + buffer->mcode = fmt->code;
  468. + if (i == STF_VIN_PAD_SINK) {
  469. + aligns = ALIGN(fmt->width * 4,
  470. + STFCAMSS_FRAME_WIDTH_ALIGN_8);
  471. + buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height);
  472. + } else if (i == STF_ISP_PAD_SRC) {
  473. + aligns = ALIGN(fmt->width,
  474. + STFCAMSS_FRAME_WIDTH_ALIGN_8);
  475. + buffer->buffer_size =
  476. + PAGE_ALIGN(aligns * fmt->height * 3 / 2);
  477. + } else {
  478. + continue;
  479. + }
  480. +
  481. + buffer->vaddr = dma_alloc_coherent(dev,
  482. + buffer->buffer_size,
  483. + &buffer->paddr[0],
  484. + GFP_DMA | GFP_KERNEL);
  485. +
  486. + if (buffer->vaddr) {
  487. + if (i == STF_ISP_PAD_SRC)
  488. + buffer->paddr[1] =
  489. + (dma_addr_t)(buffer->paddr[0] + aligns * fmt->height);
  490. + else
  491. + dev_dbg(dev, "signal plane\n");
  492. + }
  493. + }
  494. +
  495. + return ret;
  496. +}
  497. +
  498. +static void vin_free_dummy_buffer(struct stf_vin_dev *vin_dev, int dummy_module)
  499. +{
  500. + struct device *dev = vin_dev->stfcamss->dev;
  501. + struct dummy_buffer *dummy_buffer =
  502. + &vin_dev->dummy_buffer[dummy_module];
  503. + struct vin_dummy_buffer *buffer = NULL;
  504. + int i;
  505. +
  506. + for (i = 0; i < dummy_buffer->nums; i++) {
  507. + buffer = &dummy_buffer->buffer[i];
  508. + if (buffer->vaddr)
  509. + dma_free_coherent(dev, buffer->buffer_size,
  510. + buffer->vaddr, buffer->paddr[0]);
  511. + memset(buffer, 0, sizeof(struct vin_dummy_buffer));
  512. + }
  513. +}
  514. +
  515. +static void vin_set_dummy_buffer(struct vin_line *line, u32 pad)
  516. +{
  517. + struct stf_vin_dev *vin_dev = line_to_vin_dev(line);
  518. + int dummy_module = vin_line_to_dummy_module(line);
  519. + struct dummy_buffer *dummy_buffer =
  520. + &vin_dev->dummy_buffer[dummy_module];
  521. + struct vin_dummy_buffer *buffer = NULL;
  522. +
  523. + switch (pad) {
  524. + case STF_VIN_PAD_SINK:
  525. + if (line->id == VIN_LINE_WR) {
  526. + buffer = &dummy_buffer->buffer[STF_VIN_PAD_SINK];
  527. + stf_vin_wr_set_ping_addr(vin_dev, buffer->paddr[0]);
  528. + stf_vin_wr_set_pong_addr(vin_dev, buffer->paddr[0]);
  529. + } else {
  530. + buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
  531. + stf_vin_isp_set_yuv_addr(vin_dev,
  532. + buffer->paddr[0],
  533. + buffer->paddr[1]);
  534. + }
  535. + break;
  536. + case STF_ISP_PAD_SRC:
  537. + buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
  538. + stf_vin_isp_set_yuv_addr(vin_dev,
  539. + buffer->paddr[0],
  540. + buffer->paddr[1]);
  541. + break;
  542. + default:
  543. + break;
  544. + }
  545. +}
  546. +
  547. +static int vin_set_stream(struct v4l2_subdev *sd, int enable)
  548. +{
  549. + struct vin_line *line = v4l2_get_subdevdata(sd);
  550. + struct stf_vin_dev *vin_dev = line_to_vin_dev(line);
  551. + int dummy_module = vin_line_to_dummy_module(line);
  552. + struct dummy_buffer *dummy_buffer =
  553. + &vin_dev->dummy_buffer[dummy_module];
  554. + struct v4l2_mbus_framefmt *fmt;
  555. + enum link link;
  556. +
  557. + fmt = __vin_get_format(line, NULL,
  558. + STF_VIN_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
  559. + mutex_lock(&dummy_buffer->stream_lock);
  560. + if (enable) {
  561. + if (dummy_buffer->stream_count == 0) {
  562. + vin_alloc_dummy_buffer(vin_dev, fmt, dummy_module);
  563. + vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
  564. + atomic_set(&dummy_buffer->frame_skip,
  565. + VIN_FRAME_DROP_MIN_VAL + 30);
  566. + }
  567. + dummy_buffer->stream_count++;
  568. + } else {
  569. + if (dummy_buffer->stream_count == 1) {
  570. + vin_free_dummy_buffer(vin_dev, dummy_module);
  571. + /* set buffer addr to zero */
  572. + vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
  573. + } else {
  574. + vin_set_dummy_buffer(line,
  575. + stf_vin_map_isp_pad(line->id, STF_ISP_PAD_SINK));
  576. + }
  577. +
  578. + dummy_buffer->stream_count--;
  579. + }
  580. + mutex_unlock(&dummy_buffer->stream_lock);
  581. +
  582. + mutex_lock(&line->stream_lock);
  583. + link = vin_get_link(&sd->entity);
  584. + if (link == LINK_ERROR)
  585. + goto exit;
  586. +
  587. + if (enable) {
  588. + if (line->stream_count == 0) {
  589. + stf_vin_stream_set(vin_dev, link);
  590. + if (line->id == VIN_LINE_WR) {
  591. + stf_vin_wr_irq_enable(vin_dev, 1);
  592. + stf_vin_wr_stream_set(vin_dev);
  593. + }
  594. + }
  595. + line->stream_count++;
  596. + } else {
  597. + if (line->stream_count == 1 && line->id == VIN_LINE_WR)
  598. + stf_vin_wr_irq_enable(vin_dev, 0);
  599. + line->stream_count--;
  600. + }
  601. +exit:
  602. + mutex_unlock(&line->stream_lock);
  603. +
  604. + if (enable)
  605. + vin_enable_output(line);
  606. + else
  607. + vin_disable_output(line);
  608. +
  609. + return 0;
  610. +}
  611. +
  612. +static struct v4l2_mbus_framefmt *
  613. +__vin_get_format(struct vin_line *line,
  614. + struct v4l2_subdev_state *state,
  615. + unsigned int pad,
  616. + enum v4l2_subdev_format_whence which)
  617. +{
  618. + if (which == V4L2_SUBDEV_FORMAT_TRY)
  619. + return v4l2_subdev_get_try_format(&line->subdev, state, pad);
  620. + return &line->fmt[pad];
  621. +}
  622. +
  623. +static void vin_try_format(struct vin_line *line,
  624. + struct v4l2_subdev_state *state,
  625. + unsigned int pad,
  626. + struct v4l2_mbus_framefmt *fmt,
  627. + enum v4l2_subdev_format_whence which)
  628. +{
  629. + unsigned int i;
  630. +
  631. + switch (pad) {
  632. + case STF_VIN_PAD_SINK:
  633. + /* Set format on sink pad */
  634. + for (i = 0; i < line->nformats; i++)
  635. + if (fmt->code == line->formats[i].code)
  636. + break;
  637. +
  638. + /* If not found, use UYVY as default */
  639. + if (i >= line->nformats)
  640. + fmt->code = line->formats[0].code;
  641. +
  642. + fmt->width = clamp_t(u32, fmt->width,
  643. + STFCAMSS_FRAME_MIN_WIDTH,
  644. + STFCAMSS_FRAME_MAX_WIDTH);
  645. + fmt->height = clamp_t(u32, fmt->height,
  646. + STFCAMSS_FRAME_MIN_HEIGHT,
  647. + STFCAMSS_FRAME_MAX_HEIGHT);
  648. +
  649. + fmt->field = V4L2_FIELD_NONE;
  650. + fmt->colorspace = V4L2_COLORSPACE_SRGB;
  651. + fmt->flags = 0;
  652. + break;
  653. +
  654. + case STF_VIN_PAD_SRC:
  655. + /* Set and return a format same as sink pad */
  656. + *fmt = *__vin_get_format(line, state, STF_VIN_PAD_SINK, which);
  657. + break;
  658. + }
  659. +
  660. + fmt->colorspace = V4L2_COLORSPACE_SRGB;
  661. +}
  662. +
  663. +static int vin_enum_mbus_code(struct v4l2_subdev *sd,
  664. + struct v4l2_subdev_state *state,
  665. + struct v4l2_subdev_mbus_code_enum *code)
  666. +{
  667. + struct vin_line *line = v4l2_get_subdevdata(sd);
  668. +
  669. + if (code->index >= line->nformats)
  670. + return -EINVAL;
  671. + if (code->pad == STF_VIN_PAD_SINK) {
  672. + code->code = line->formats[code->index].code;
  673. + } else {
  674. + struct v4l2_mbus_framefmt *sink_fmt;
  675. +
  676. + sink_fmt = __vin_get_format(line, state, STF_VIN_PAD_SINK,
  677. + code->which);
  678. +
  679. + code->code = sink_fmt->code;
  680. + if (!code->code)
  681. + return -EINVAL;
  682. + }
  683. + code->flags = 0;
  684. +
  685. + return 0;
  686. +}
  687. +
  688. +static int vin_enum_frame_size(struct v4l2_subdev *sd,
  689. + struct v4l2_subdev_state *state,
  690. + struct v4l2_subdev_frame_size_enum *fse)
  691. +{
  692. + struct vin_line *line = v4l2_get_subdevdata(sd);
  693. + struct v4l2_mbus_framefmt format;
  694. +
  695. + if (fse->index != 0)
  696. + return -EINVAL;
  697. +
  698. + format.code = fse->code;
  699. + format.width = 1;
  700. + format.height = 1;
  701. + vin_try_format(line, state, fse->pad, &format, fse->which);
  702. + fse->min_width = format.width;
  703. + fse->min_height = format.height;
  704. +
  705. + if (format.code != fse->code)
  706. + return -EINVAL;
  707. +
  708. + format.code = fse->code;
  709. + format.width = -1;
  710. + format.height = -1;
  711. + vin_try_format(line, state, fse->pad, &format, fse->which);
  712. + fse->max_width = format.width;
  713. + fse->max_height = format.height;
  714. +
  715. + return 0;
  716. +}
  717. +
  718. +static int vin_get_format(struct v4l2_subdev *sd,
  719. + struct v4l2_subdev_state *state,
  720. + struct v4l2_subdev_format *fmt)
  721. +{
  722. + struct vin_line *line = v4l2_get_subdevdata(sd);
  723. + struct v4l2_mbus_framefmt *format;
  724. +
  725. + format = __vin_get_format(line, state, fmt->pad, fmt->which);
  726. + if (!format)
  727. + return -EINVAL;
  728. +
  729. + fmt->format = *format;
  730. +
  731. + return 0;
  732. +}
  733. +
  734. +static int vin_set_format(struct v4l2_subdev *sd,
  735. + struct v4l2_subdev_state *state,
  736. + struct v4l2_subdev_format *fmt)
  737. +{
  738. + struct vin_line *line = v4l2_get_subdevdata(sd);
  739. + struct v4l2_mbus_framefmt *format;
  740. +
  741. + format = __vin_get_format(line, state, fmt->pad, fmt->which);
  742. + if (!format)
  743. + return -EINVAL;
  744. +
  745. + mutex_lock(&line->stream_lock);
  746. + if (line->stream_count) {
  747. + fmt->format = *format;
  748. + mutex_unlock(&line->stream_lock);
  749. + goto out;
  750. + } else {
  751. + vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
  752. + *format = fmt->format;
  753. + }
  754. + mutex_unlock(&line->stream_lock);
  755. +
  756. + if (fmt->pad == STF_VIN_PAD_SINK) {
  757. + /* Propagate the format from sink to source */
  758. + format = __vin_get_format(line, state, STF_VIN_PAD_SRC,
  759. + fmt->which);
  760. +
  761. + *format = fmt->format;
  762. + vin_try_format(line, state, STF_VIN_PAD_SRC, format,
  763. + fmt->which);
  764. + }
  765. +
  766. +out:
  767. + return 0;
  768. +}
  769. +
  770. +static int vin_init_formats(struct v4l2_subdev *sd,
  771. + struct v4l2_subdev_fh *fh)
  772. +{
  773. + struct v4l2_subdev_format format = {
  774. + .pad = STF_VIN_PAD_SINK,
  775. + .which = fh ?
  776. + V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE,
  777. + .format = {
  778. + .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
  779. + .width = 1920,
  780. + .height = 1080
  781. + }
  782. + };
  783. +
  784. + return vin_set_format(sd, fh ? fh->state : NULL, &format);
  785. +}
  786. +
  787. +static void vin_output_init_addrs(struct vin_line *line)
  788. +{
  789. + struct vin_output *output = &line->output;
  790. + struct stf_vin_dev *vin_dev = line_to_vin_dev(line);
  791. + dma_addr_t ping_addr;
  792. + dma_addr_t y_addr, uv_addr;
  793. +
  794. + output->active_buf = 0;
  795. +
  796. + if (output->buf[0]) {
  797. + ping_addr = output->buf[0]->addr[0];
  798. + y_addr = output->buf[0]->addr[0];
  799. + uv_addr = output->buf[0]->addr[1];
  800. + } else {
  801. + return;
  802. + }
  803. +
  804. + switch (vin_map_isp_line(line->id)) {
  805. + case STF_ISP_LINE_SRC:
  806. + stf_vin_isp_set_yuv_addr(vin_dev, y_addr, uv_addr);
  807. + break;
  808. + default:
  809. + if (line->id == VIN_LINE_WR) {
  810. + stf_vin_wr_set_ping_addr(vin_dev, ping_addr);
  811. + stf_vin_wr_set_pong_addr(vin_dev, ping_addr);
  812. + }
  813. + break;
  814. + }
  815. +}
  816. +
  817. +static void vin_init_outputs(struct vin_line *line)
  818. +{
  819. + struct vin_output *output = &line->output;
  820. +
  821. + output->state = VIN_OUTPUT_OFF;
  822. + output->buf[0] = NULL;
  823. + output->buf[1] = NULL;
  824. + output->active_buf = 0;
  825. + INIT_LIST_HEAD(&output->pending_bufs);
  826. + INIT_LIST_HEAD(&output->ready_bufs);
  827. +}
  828. +
  829. +static void vin_buf_add_ready(struct vin_output *output,
  830. + struct stfcamss_buffer *buffer)
  831. +{
  832. + INIT_LIST_HEAD(&buffer->queue);
  833. + list_add_tail(&buffer->queue, &output->ready_bufs);
  834. +}
  835. +
  836. +static struct stfcamss_buffer *vin_buf_get_ready(struct vin_output *output)
  837. +{
  838. + struct stfcamss_buffer *buffer = NULL;
  839. +
  840. + if (!list_empty(&output->ready_bufs)) {
  841. + buffer = list_first_entry(&output->ready_bufs,
  842. + struct stfcamss_buffer,
  843. + queue);
  844. + list_del(&buffer->queue);
  845. + }
  846. +
  847. + return buffer;
  848. +}
  849. +
  850. +static void vin_buf_add_pending(struct vin_output *output,
  851. + struct stfcamss_buffer *buffer)
  852. +{
  853. + INIT_LIST_HEAD(&buffer->queue);
  854. + list_add_tail(&buffer->queue, &output->pending_bufs);
  855. +}
  856. +
  857. +static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output)
  858. +{
  859. + struct stfcamss_buffer *buffer = NULL;
  860. +
  861. + if (!list_empty(&output->pending_bufs)) {
  862. + buffer = list_first_entry(&output->pending_bufs,
  863. + struct stfcamss_buffer,
  864. + queue);
  865. + list_del(&buffer->queue);
  866. + }
  867. +
  868. + return buffer;
  869. +}
  870. +
  871. +static void vin_buf_update_on_last(struct vin_line *line)
  872. +{
  873. + struct vin_output *output = &line->output;
  874. +
  875. + switch (output->state) {
  876. + case VIN_OUTPUT_CONTINUOUS:
  877. + output->state = VIN_OUTPUT_SINGLE;
  878. + output->active_buf = !output->active_buf;
  879. + break;
  880. + case VIN_OUTPUT_SINGLE:
  881. + output->state = VIN_OUTPUT_STOPPING;
  882. + break;
  883. + default:
  884. + break;
  885. + }
  886. +}
  887. +
  888. +static void vin_buf_update_on_next(struct vin_line *line)
  889. +{
  890. + struct vin_output *output = &line->output;
  891. +
  892. + switch (output->state) {
  893. + case VIN_OUTPUT_CONTINUOUS:
  894. + output->active_buf = !output->active_buf;
  895. + break;
  896. + case VIN_OUTPUT_SINGLE:
  897. + default:
  898. + break;
  899. + }
  900. +}
  901. +
  902. +static void vin_buf_update_on_new(struct vin_line *line,
  903. + struct vin_output *output,
  904. + struct stfcamss_buffer *new_buf)
  905. +{
  906. + switch (output->state) {
  907. + case VIN_OUTPUT_SINGLE:
  908. + vin_buf_add_pending(output, new_buf);
  909. + break;
  910. + case VIN_OUTPUT_IDLE:
  911. + if (!output->buf[0]) {
  912. + output->buf[0] = new_buf;
  913. + vin_output_init_addrs(line);
  914. + output->state = VIN_OUTPUT_SINGLE;
  915. + } else {
  916. + vin_buf_add_pending(output, new_buf);
  917. + }
  918. + break;
  919. + case VIN_OUTPUT_STOPPING:
  920. + if (output->last_buffer) {
  921. + output->buf[output->active_buf] = output->last_buffer;
  922. + output->last_buffer = NULL;
  923. + }
  924. +
  925. + output->state = VIN_OUTPUT_SINGLE;
  926. + vin_buf_add_pending(output, new_buf);
  927. + break;
  928. + case VIN_OUTPUT_CONTINUOUS:
  929. + default:
  930. + vin_buf_add_pending(output, new_buf);
  931. + break;
  932. + }
  933. +}
  934. +
  935. +static void vin_buf_flush(struct vin_output *output,
  936. + enum vb2_buffer_state state)
  937. +{
  938. + struct stfcamss_buffer *buf;
  939. + struct stfcamss_buffer *t;
  940. +
  941. + list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) {
  942. + vb2_buffer_done(&buf->vb.vb2_buf, state);
  943. + list_del(&buf->queue);
  944. + }
  945. + list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) {
  946. + vb2_buffer_done(&buf->vb.vb2_buf, state);
  947. + list_del(&buf->queue);
  948. + }
  949. +}
  950. +
  951. +static void vin_buffer_done(struct vin_line *line)
  952. +{
  953. + struct stfcamss_buffer *ready_buf;
  954. + struct vin_output *output = &line->output;
  955. + unsigned long flags;
  956. + u64 ts = ktime_get_ns();
  957. +
  958. + if (output->state == VIN_OUTPUT_OFF ||
  959. + output->state == VIN_OUTPUT_RESERVED)
  960. + return;
  961. +
  962. + spin_lock_irqsave(&line->output_lock, flags);
  963. +
  964. + while ((ready_buf = vin_buf_get_ready(output))) {
  965. + ready_buf->vb.vb2_buf.timestamp = ts;
  966. + ready_buf->vb.sequence = output->sequence++;
  967. +
  968. + vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
  969. + }
  970. +
  971. + spin_unlock_irqrestore(&line->output_lock, flags);
  972. +}
  973. +
  974. +static void vin_change_buffer(struct vin_line *line)
  975. +{
  976. + struct stfcamss_buffer *ready_buf;
  977. + struct vin_output *output = &line->output;
  978. + struct stf_vin_dev *vin_dev = line_to_vin_dev(line);
  979. + dma_addr_t *new_addr;
  980. + unsigned long flags;
  981. + u32 active_index;
  982. +
  983. + if (output->state == VIN_OUTPUT_OFF ||
  984. + output->state == VIN_OUTPUT_STOPPING ||
  985. + output->state == VIN_OUTPUT_RESERVED ||
  986. + output->state == VIN_OUTPUT_IDLE)
  987. + return;
  988. +
  989. + spin_lock_irqsave(&line->output_lock, flags);
  990. +
  991. + active_index = output->active_buf;
  992. +
  993. + ready_buf = output->buf[active_index];
  994. + if (!ready_buf) {
  995. + dev_warn(vin_dev->stfcamss->dev, "Missing ready buf %d %d!\n",
  996. + active_index, output->state);
  997. + active_index = !active_index;
  998. + ready_buf = output->buf[active_index];
  999. + if (!ready_buf) {
  1000. + dev_err(vin_dev->stfcamss->dev,
  1001. + "Missing ready buf2 %d %d!\n",
  1002. + active_index, output->state);
  1003. + goto out_unlock;
  1004. + }
  1005. + }
  1006. +
  1007. + /* Get next buffer */
  1008. + output->buf[active_index] = vin_buf_get_pending(output);
  1009. + if (!output->buf[active_index]) {
  1010. + /* No next buffer - set same address */
  1011. + new_addr = ready_buf->addr;
  1012. + vin_buf_update_on_last(line);
  1013. + } else {
  1014. + new_addr = output->buf[active_index]->addr;
  1015. + vin_buf_update_on_next(line);
  1016. + }
  1017. +
  1018. + if (output->state == VIN_OUTPUT_STOPPING) {
  1019. + output->last_buffer = ready_buf;
  1020. + } else {
  1021. + switch (vin_map_isp_line(line->id)) {
  1022. + case STF_ISP_LINE_SRC:
  1023. + stf_vin_isp_set_yuv_addr(vin_dev,
  1024. + new_addr[0],
  1025. + new_addr[1]);
  1026. + break;
  1027. + default:
  1028. + if (line->id == VIN_LINE_WR) {
  1029. + stf_vin_wr_set_ping_addr(vin_dev, new_addr[0]);
  1030. + stf_vin_wr_set_pong_addr(vin_dev, new_addr[0]);
  1031. + }
  1032. + break;
  1033. + }
  1034. +
  1035. + vin_buf_add_ready(output, ready_buf);
  1036. + }
  1037. +
  1038. + spin_unlock_irqrestore(&line->output_lock, flags);
  1039. + return;
  1040. +
  1041. +out_unlock:
  1042. + spin_unlock_irqrestore(&line->output_lock, flags);
  1043. +}
  1044. +
  1045. +static int vin_queue_buffer(struct stfcamss_video *vid,
  1046. + struct stfcamss_buffer *buf)
  1047. +{
  1048. + struct vin_line *line = container_of(vid, struct vin_line, video_out);
  1049. + struct vin_output *output;
  1050. + unsigned long flags;
  1051. +
  1052. + output = &line->output;
  1053. +
  1054. + spin_lock_irqsave(&line->output_lock, flags);
  1055. +
  1056. + vin_buf_update_on_new(line, output, buf);
  1057. +
  1058. + spin_unlock_irqrestore(&line->output_lock, flags);
  1059. +
  1060. + return 0;
  1061. +}
  1062. +
  1063. +static int vin_flush_buffers(struct stfcamss_video *vid,
  1064. + enum vb2_buffer_state state)
  1065. +{
  1066. + struct vin_line *line = container_of(vid, struct vin_line, video_out);
  1067. + struct vin_output *output = &line->output;
  1068. + unsigned long flags;
  1069. +
  1070. + spin_lock_irqsave(&line->output_lock, flags);
  1071. +
  1072. + vin_buf_flush(output, state);
  1073. + if (output->buf[0])
  1074. + vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);
  1075. +
  1076. + if (output->buf[1])
  1077. + vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state);
  1078. +
  1079. + if (output->last_buffer) {
  1080. + vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state);
  1081. + output->last_buffer = NULL;
  1082. + }
  1083. + output->buf[0] = NULL;
  1084. + output->buf[1] = NULL;
  1085. +
  1086. + spin_unlock_irqrestore(&line->output_lock, flags);
  1087. + return 0;
  1088. +}
  1089. +
  1090. +static int vin_link_setup(struct media_entity *entity,
  1091. + const struct media_pad *local,
  1092. + const struct media_pad *remote, u32 flags)
  1093. +{
  1094. + if (flags & MEDIA_LNK_FL_ENABLED)
  1095. + if (media_pad_remote_pad_first(local))
  1096. + return -EBUSY;
  1097. + return 0;
  1098. +}
  1099. +
  1100. +static const struct v4l2_subdev_core_ops vin_core_ops = {
  1101. + .s_power = vin_set_power,
  1102. +};
  1103. +
  1104. +static const struct v4l2_subdev_video_ops vin_video_ops = {
  1105. + .s_stream = vin_set_stream,
  1106. +};
  1107. +
  1108. +static const struct v4l2_subdev_pad_ops vin_pad_ops = {
  1109. + .enum_mbus_code = vin_enum_mbus_code,
  1110. + .enum_frame_size = vin_enum_frame_size,
  1111. + .get_fmt = vin_get_format,
  1112. + .set_fmt = vin_set_format,
  1113. +};
  1114. +
  1115. +static const struct v4l2_subdev_ops vin_v4l2_ops = {
  1116. + .core = &vin_core_ops,
  1117. + .video = &vin_video_ops,
  1118. + .pad = &vin_pad_ops,
  1119. +};
  1120. +
  1121. +static const struct v4l2_subdev_internal_ops vin_v4l2_internal_ops = {
  1122. + .open = vin_init_formats,
  1123. +};
  1124. +
  1125. +static const struct stfcamss_video_ops stfcamss_vin_video_ops = {
  1126. + .queue_buffer = vin_queue_buffer,
  1127. + .flush_buffers = vin_flush_buffers,
  1128. +};
  1129. +
  1130. +static const struct media_entity_operations vin_media_ops = {
  1131. + .link_setup = vin_link_setup,
  1132. + .link_validate = v4l2_subdev_link_validate,
  1133. +};
  1134. +
  1135. +int stf_vin_register(struct stf_vin_dev *vin_dev, struct v4l2_device *v4l2_dev)
  1136. +{
  1137. + struct v4l2_subdev *sd;
  1138. + struct stfcamss_video *video_out;
  1139. + struct media_pad *pads;
  1140. + int ret;
  1141. + int i;
  1142. +
  1143. + for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
  1144. + char name[32];
  1145. + char *sub_name = vin_get_line_subdevname(i);
  1146. +
  1147. + sd = &vin_dev->line[i].subdev;
  1148. + pads = vin_dev->line[i].pads;
  1149. + video_out = &vin_dev->line[i].video_out;
  1150. + video_out->id = i;
  1151. +
  1152. + v4l2_subdev_init(sd, &vin_v4l2_ops);
  1153. + sd->internal_ops = &vin_v4l2_internal_ops;
  1154. + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
  1155. + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s",
  1156. + STF_VIN_NAME, 0, sub_name);
  1157. + v4l2_set_subdevdata(sd, &vin_dev->line[i]);
  1158. +
  1159. + ret = vin_init_formats(sd, NULL);
  1160. + if (ret < 0) {
  1161. + dev_err(vin_dev->stfcamss->dev,
  1162. + "Failed to init format: %d\n", ret);
  1163. + goto err_init;
  1164. + }
  1165. +
  1166. + pads[STF_VIN_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
  1167. + pads[STF_VIN_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
  1168. +
  1169. + sd->entity.function =
  1170. + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
  1171. + sd->entity.ops = &vin_media_ops;
  1172. + ret = media_entity_pads_init(&sd->entity,
  1173. + STF_VIN_PADS_NUM, pads);
  1174. + if (ret < 0) {
  1175. + dev_err(vin_dev->stfcamss->dev,
  1176. + "Failed to init media entity: %d\n",
  1177. + ret);
  1178. + goto err_init;
  1179. + }
  1180. +
  1181. + ret = v4l2_device_register_subdev(v4l2_dev, sd);
  1182. + if (ret < 0) {
  1183. + dev_err(vin_dev->stfcamss->dev,
  1184. + "Failed to register subdev: %d\n", ret);
  1185. + goto err_reg_subdev;
  1186. + }
  1187. +
  1188. + video_out->ops = &stfcamss_vin_video_ops;
  1189. + video_out->bpl_alignment = 16 * 8;
  1190. +
  1191. + snprintf(name, ARRAY_SIZE(name), "%s_%s%d",
  1192. + sd->name, "video", i);
  1193. + ret = stf_video_register(video_out, v4l2_dev, name);
  1194. + if (ret < 0) {
  1195. + dev_err(vin_dev->stfcamss->dev,
  1196. + "Failed to register video node: %d\n", ret);
  1197. + goto err_vid_reg;
  1198. + }
  1199. +
  1200. + ret = media_create_pad_link(
  1201. + &sd->entity, STF_VIN_PAD_SRC,
  1202. + &video_out->vdev.entity, 0,
  1203. + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
  1204. + if (ret < 0) {
  1205. + dev_err(vin_dev->stfcamss->dev,
  1206. + "Failed to link %s->%s entities: %d\n",
  1207. + sd->entity.name, video_out->vdev.entity.name,
  1208. + ret);
  1209. + goto err_create_link;
  1210. + }
  1211. + }
  1212. +
  1213. + return 0;
  1214. +
  1215. +err_create_link:
  1216. + stf_video_unregister(video_out);
  1217. +err_vid_reg:
  1218. + v4l2_device_unregister_subdev(sd);
  1219. +err_reg_subdev:
  1220. + media_entity_cleanup(&sd->entity);
  1221. +err_init:
  1222. + for (i--; i >= 0; i--) {
  1223. + sd = &vin_dev->line[i].subdev;
  1224. + video_out = &vin_dev->line[i].video_out;
  1225. +
  1226. + stf_video_unregister(video_out);
  1227. + v4l2_device_unregister_subdev(sd);
  1228. + media_entity_cleanup(&sd->entity);
  1229. + }
  1230. + return ret;
  1231. +}
  1232. +
  1233. +int stf_vin_unregister(struct stf_vin_dev *vin_dev)
  1234. +{
  1235. + struct v4l2_subdev *sd;
  1236. + struct stfcamss_video *video_out;
  1237. + int i;
  1238. +
  1239. + mutex_destroy(&vin_dev->power_lock);
  1240. + for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++)
  1241. + mutex_destroy(&vin_dev->dummy_buffer[i].stream_lock);
  1242. +
  1243. + for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
  1244. + sd = &vin_dev->line[i].subdev;
  1245. + video_out = &vin_dev->line[i].video_out;
  1246. +
  1247. + stf_video_unregister(video_out);
  1248. + v4l2_device_unregister_subdev(sd);
  1249. + media_entity_cleanup(&sd->entity);
  1250. + mutex_destroy(&vin_dev->line[i].stream_lock);
  1251. + mutex_destroy(&vin_dev->line[i].power_lock);
  1252. + }
  1253. + return 0;
  1254. +}
  1255. --- /dev/null
  1256. +++ b/drivers/media/platform/starfive/stf_vin.h
  1257. @@ -0,0 +1,180 @@
  1258. +/* SPDX-License-Identifier: GPL-2.0 */
  1259. +/*
  1260. + * stf_vin.h
  1261. + *
  1262. + * StarFive Camera Subsystem - VIN Module
  1263. + *
  1264. + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
  1265. + */
  1266. +
  1267. +#ifndef STF_VIN_H
  1268. +#define STF_VIN_H
  1269. +
  1270. +#include <linux/interrupt.h>
  1271. +#include <linux/spinlock_types.h>
  1272. +#include <media/v4l2-subdev.h>
  1273. +
  1274. +#include "stf_video.h"
  1275. +
  1276. +#define SYSCONSAIF_SYSCFG(x) (x)
  1277. +
  1278. +/* syscon offset 0 */
  1279. +#define U0_VIN_CNFG_AXI_DVP_EN BIT(2)
  1280. +
  1281. +/* syscon offset 20 */
  1282. +#define U0_VIN_CHANNEL_SEL_MASK GENMASK(3, 0)
  1283. +#define U0_VIN_AXIWR0_EN BIT(4)
  1284. +#define CHANNEL(x) ((x) << 0)
  1285. +
  1286. +/* syscon offset 32 */
  1287. +#define U0_VIN_INTR_CLEAN BIT(0)
  1288. +#define U0_VIN_INTR_M BIT(1)
  1289. +#define U0_VIN_PIX_CNT_END_MASK GENMASK(12, 2)
  1290. +#define U0_VIN_PIX_CT_MASK GENMASK(14, 13)
  1291. +#define U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS GENMASK(16, 15)
  1292. +
  1293. +#define PIX_CNT_END(x) ((x) << 2)
  1294. +#define PIX_CT(x) ((x) << 13)
  1295. +#define PIXEL_HEIGH_BIT_SEL(x) ((x) << 15)
  1296. +
  1297. +/* syscon offset 36 */
  1298. +#define U0_VIN_CNFG_DVP_HS_POS BIT(1)
  1299. +#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2)
  1300. +#define U0_VIN_CNFG_DVP_VS_POS BIT(3)
  1301. +#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4)
  1302. +#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5)
  1303. +#define U0_VIN_MIPI_BYTE_EN_ISP0(n) ((n) << 6)
  1304. +#define U0_VIN_MIPI_CHANNEL_SEL0(n) ((n) << 8)
  1305. +#define U0_VIN_P_I_MIPI_HAEDER_EN0(n) ((n) << 12)
  1306. +#define U0_VIN_PIX_NUM(n) ((n) << 13)
  1307. +#define U0_VIN_MIPI_BYTE_EN_ISP0_MASK GENMASK(7, 6)
  1308. +#define U0_VIN_MIPI_CHANNEL_SEL0_MASK GENMASK(11, 8)
  1309. +#define U0_VIN_P_I_MIPI_HAEDER_EN0_MASK BIT(12)
  1310. +#define U0_VIN_PIX_NUM_MASK GENMASK(16, 13)
  1311. +
  1312. +#define STF_VIN_PAD_SINK 0
  1313. +#define STF_VIN_PAD_SRC 1
  1314. +#define STF_VIN_PADS_NUM 2
  1315. +
  1316. +#define ISP_DUMMY_BUFFER_NUMS STF_ISP_PAD_MAX
  1317. +#define VIN_DUMMY_BUFFER_NUMS 1
  1318. +
  1319. +enum {
  1320. + STF_DUMMY_VIN,
  1321. + STF_DUMMY_ISP,
  1322. + STF_DUMMY_MODULE_NUMS,
  1323. +};
  1324. +
  1325. +enum link {
  1326. + LINK_ERROR = -1,
  1327. + LINK_DVP_TO_WR,
  1328. + LINK_DVP_TO_ISP,
  1329. + LINK_CSI_TO_WR,
  1330. + LINK_CSI_TO_ISP,
  1331. +};
  1332. +
  1333. +struct vin_format {
  1334. + u32 code;
  1335. + u8 bpp;
  1336. +};
  1337. +
  1338. +struct vin_format_table {
  1339. + const struct vin_format *fmts;
  1340. + int nfmts;
  1341. +};
  1342. +
  1343. +enum vin_output_state {
  1344. + VIN_OUTPUT_OFF,
  1345. + VIN_OUTPUT_RESERVED,
  1346. + VIN_OUTPUT_SINGLE,
  1347. + VIN_OUTPUT_CONTINUOUS,
  1348. + VIN_OUTPUT_IDLE,
  1349. + VIN_OUTPUT_STOPPING
  1350. +};
  1351. +
  1352. +struct vin_output {
  1353. + int active_buf;
  1354. + struct stfcamss_buffer *buf[2];
  1355. + struct stfcamss_buffer *last_buffer;
  1356. + struct list_head pending_bufs;
  1357. + struct list_head ready_bufs;
  1358. + enum vin_output_state state;
  1359. + unsigned int sequence;
  1360. + unsigned int frame_skip;
  1361. +};
  1362. +
  1363. +/* The vin output lines */
  1364. +enum vin_line_id {
  1365. + VIN_LINE_NONE = -1,
  1366. + VIN_LINE_WR = 0,
  1367. + VIN_LINE_ISP,
  1368. + VIN_LINE_MAX,
  1369. +};
  1370. +
  1371. +struct vin_line {
  1372. + enum stf_subdev_type sdev_type; /* must be frist */
  1373. + enum vin_line_id id;
  1374. + struct v4l2_subdev subdev;
  1375. + struct media_pad pads[STF_VIN_PADS_NUM];
  1376. + struct v4l2_mbus_framefmt fmt[STF_VIN_PADS_NUM];
  1377. + struct stfcamss_video video_out;
  1378. + struct mutex stream_lock; /* serialize stream control */
  1379. + int stream_count;
  1380. + struct mutex power_lock; /* serialize pipeline control in power process*/
  1381. + int power_count;
  1382. + struct vin_output output; /* pipeline and stream states */
  1383. + spinlock_t output_lock;
  1384. + const struct vin_format *formats;
  1385. + unsigned int nformats;
  1386. +};
  1387. +
  1388. +struct vin_dummy_buffer {
  1389. + dma_addr_t paddr[3];
  1390. + void *vaddr;
  1391. + u32 buffer_size;
  1392. + u32 width;
  1393. + u32 height;
  1394. + u32 mcode;
  1395. +};
  1396. +
  1397. +struct dummy_buffer {
  1398. + struct vin_dummy_buffer *buffer;
  1399. + u32 nums;
  1400. + struct mutex stream_lock; /* protects buffer data */
  1401. + int stream_count;
  1402. + atomic_t frame_skip;
  1403. +};
  1404. +
  1405. +struct vin_isr_ops {
  1406. + void (*isr_buffer_done)(struct vin_line *line);
  1407. + void (*isr_change_buffer)(struct vin_line *line);
  1408. +};
  1409. +
  1410. +struct stf_vin_dev {
  1411. + struct stfcamss *stfcamss;
  1412. + struct vin_line line[VIN_LINE_MAX];
  1413. + struct dummy_buffer dummy_buffer[STF_DUMMY_MODULE_NUMS];
  1414. + struct vin_isr_ops *isr_ops;
  1415. + atomic_t ref_count;
  1416. + struct mutex power_lock; /* serialize power control*/
  1417. + int power_count;
  1418. +};
  1419. +
  1420. +int stf_vin_clk_enable(struct stf_vin_dev *vin_dev, enum link link);
  1421. +int stf_vin_clk_disable(struct stf_vin_dev *vin_dev, enum link link);
  1422. +int stf_vin_wr_stream_set(struct stf_vin_dev *vin_dev);
  1423. +int stf_vin_stream_set(struct stf_vin_dev *vin_dev, enum link link);
  1424. +void stf_vin_wr_irq_enable(struct stf_vin_dev *vin_dev, int enable);
  1425. +void stf_vin_wr_set_ping_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr);
  1426. +void stf_vin_wr_set_pong_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr);
  1427. +void stf_vin_isp_set_yuv_addr(struct stf_vin_dev *vin_dev,
  1428. + dma_addr_t y_addr, dma_addr_t uv_addr);
  1429. +irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv);
  1430. +irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv);
  1431. +irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv);
  1432. +int stf_vin_subdev_init(struct stfcamss *stfcamss);
  1433. +int stf_vin_register(struct stf_vin_dev *vin_dev, struct v4l2_device *v4l2_dev);
  1434. +int stf_vin_unregister(struct stf_vin_dev *vin_dev);
  1435. +enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def);
  1436. +
  1437. +#endif /* STF_VIN_H */
  1438. --- /dev/null
  1439. +++ b/drivers/media/platform/starfive/stf_vin_hw_ops.c
  1440. @@ -0,0 +1,241 @@
  1441. +// SPDX-License-Identifier: GPL-2.0
  1442. +/*
  1443. + * stf_vin_hw_ops.c
  1444. + *
  1445. + * Register interface file for StarFive VIN module driver
  1446. + *
  1447. + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
  1448. + */
  1449. +#include "stf_camss.h"
  1450. +
  1451. +static void vin_intr_clear(struct stfcamss *stfcamss)
  1452. +{
  1453. + stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1454. + U0_VIN_INTR_CLEAN);
  1455. + stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1456. + U0_VIN_INTR_CLEAN);
  1457. +}
  1458. +
  1459. +irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv)
  1460. +{
  1461. + struct stf_vin_dev *vin_dev = priv;
  1462. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1463. + struct dummy_buffer *dummy_buffer =
  1464. + &vin_dev->dummy_buffer[STF_DUMMY_VIN];
  1465. +
  1466. + if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
  1467. + vin_dev->isr_ops->isr_change_buffer(&vin_dev->line[VIN_LINE_WR]);
  1468. + vin_dev->isr_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR]);
  1469. + }
  1470. +
  1471. + vin_intr_clear(stfcamss);
  1472. +
  1473. + return IRQ_HANDLED;
  1474. +}
  1475. +
  1476. +irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
  1477. +{
  1478. + struct stf_vin_dev *vin_dev = priv;
  1479. + u32 int_status;
  1480. +
  1481. + int_status = stf_isp_reg_read(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0);
  1482. +
  1483. + if (int_status & ISPC_INTS) {
  1484. + if ((int_status & ISPC_ENUO))
  1485. + vin_dev->isr_ops->isr_buffer_done(
  1486. + &vin_dev->line[VIN_LINE_ISP]);
  1487. +
  1488. + /* clear interrupt */
  1489. + stf_isp_reg_write(vin_dev->stfcamss,
  1490. + ISP_REG_ISP_CTRL_0,
  1491. + (int_status & ~EN_INT_ALL) |
  1492. + EN_INT_ISP_DONE |
  1493. + EN_INT_CSI_DONE |
  1494. + EN_INT_SC_DONE);
  1495. + }
  1496. +
  1497. + return IRQ_HANDLED;
  1498. +}
  1499. +
  1500. +irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
  1501. +{
  1502. + struct stf_vin_dev *vin_dev = priv;
  1503. + struct stf_isp_dev *isp_dev;
  1504. + u32 int_status;
  1505. +
  1506. + isp_dev = &vin_dev->stfcamss->isp_dev;
  1507. +
  1508. + int_status = stf_isp_reg_read(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0);
  1509. + if (int_status & ISPC_SCFEINT) {
  1510. + struct dummy_buffer *dummy_buffer =
  1511. + &vin_dev->dummy_buffer[STF_DUMMY_ISP];
  1512. +
  1513. + if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
  1514. + if ((int_status & ISPC_ENUO))
  1515. + vin_dev->isr_ops->isr_change_buffer(
  1516. + &vin_dev->line[VIN_LINE_ISP]);
  1517. + }
  1518. +
  1519. + stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_CSIINTS,
  1520. + CSI_INTS_MASK, CSI_INTS(0x3));
  1521. + stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_IESHD,
  1522. + SHAD_UP_M | SHAD_UP_EN, 0x3);
  1523. +
  1524. + /* clear interrupt */
  1525. + stf_isp_reg_write(vin_dev->stfcamss, ISP_REG_ISP_CTRL_0,
  1526. + (int_status & ~EN_INT_ALL) | EN_INT_LINE_INT);
  1527. + }
  1528. +
  1529. + return IRQ_HANDLED;
  1530. +}
  1531. +
  1532. +int stf_vin_clk_enable(struct stf_vin_dev *vin_dev, enum link link)
  1533. +{
  1534. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1535. +
  1536. + clk_set_rate(stfcamss->sys_clk[STF_CLK_APB_FUNC].clk, 49500000);
  1537. +
  1538. + switch (link) {
  1539. + case LINK_CSI_TO_WR:
  1540. + clk_set_rate(stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk,
  1541. + 198000000);
  1542. + reset_control_deassert(stfcamss->sys_rst[STF_RST_AXIWR].rstc);
  1543. + clk_set_parent(stfcamss->sys_clk[STF_CLK_AXIWR].clk,
  1544. + stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk);
  1545. + break;
  1546. + case LINK_CSI_TO_ISP:
  1547. + clk_set_rate(stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk,
  1548. + 198000000);
  1549. + clk_set_parent(stfcamss->sys_clk[STF_CLK_WRAPPER_CLK_C].clk,
  1550. + stfcamss->sys_clk[STF_CLK_MIPI_RX0_PXL].clk);
  1551. + break;
  1552. + case LINK_DVP_TO_WR:
  1553. + case LINK_DVP_TO_ISP:
  1554. + default:
  1555. + return -EINVAL;
  1556. + }
  1557. +
  1558. + return 0;
  1559. +}
  1560. +
  1561. +int stf_vin_clk_disable(struct stf_vin_dev *vin_dev, enum link link)
  1562. +{
  1563. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1564. +
  1565. + switch (link) {
  1566. + case LINK_CSI_TO_WR:
  1567. + reset_control_assert(stfcamss->sys_rst[STF_RST_AXIWR].rstc);
  1568. + break;
  1569. + case LINK_CSI_TO_ISP:
  1570. + break;
  1571. + case LINK_DVP_TO_WR:
  1572. + case LINK_DVP_TO_ISP:
  1573. + default:
  1574. + return -EINVAL;
  1575. + }
  1576. +
  1577. + return 0;
  1578. +}
  1579. +
  1580. +int stf_vin_wr_stream_set(struct stf_vin_dev *vin_dev)
  1581. +{
  1582. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1583. +
  1584. + /* make the axiwr alway on */
  1585. + stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(20),
  1586. + U0_VIN_AXIWR0_EN);
  1587. +
  1588. + return 0;
  1589. +}
  1590. +
  1591. +int stf_vin_stream_set(struct stf_vin_dev *vin_dev, enum link link)
  1592. +{
  1593. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1594. + u32 val;
  1595. +
  1596. + switch (link) {
  1597. + case LINK_CSI_TO_WR:
  1598. + val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(20));
  1599. + val &= ~U0_VIN_CHANNEL_SEL_MASK;
  1600. + val |= CHANNEL(0);
  1601. + stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(20), val);
  1602. +
  1603. + val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(28));
  1604. + val &= ~U0_VIN_PIX_CT_MASK;
  1605. + val |= PIX_CT(1);
  1606. +
  1607. + val &= ~U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS;
  1608. + val |= PIXEL_HEIGH_BIT_SEL(0);
  1609. +
  1610. + val &= ~U0_VIN_PIX_CNT_END_MASK;
  1611. + val |= PIX_CNT_END(IMAGE_MAX_WIDTH / 4 - 1);
  1612. +
  1613. + stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(28), val);
  1614. + break;
  1615. + case LINK_CSI_TO_ISP:
  1616. + val = stf_syscon_reg_read(stfcamss, SYSCONSAIF_SYSCFG(36));
  1617. + val &= ~U0_VIN_MIPI_BYTE_EN_ISP0_MASK;
  1618. + val |= U0_VIN_MIPI_BYTE_EN_ISP0(0);
  1619. +
  1620. + val &= ~U0_VIN_MIPI_CHANNEL_SEL0_MASK;
  1621. + val |= U0_VIN_MIPI_CHANNEL_SEL0(0);
  1622. +
  1623. + val &= ~U0_VIN_PIX_NUM_MASK;
  1624. + val |= U0_VIN_PIX_NUM(0);
  1625. +
  1626. + val &= ~U0_VIN_P_I_MIPI_HAEDER_EN0_MASK;
  1627. + val |= U0_VIN_P_I_MIPI_HAEDER_EN0(1);
  1628. +
  1629. + stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(36), val);
  1630. + break;
  1631. + case LINK_DVP_TO_WR:
  1632. + case LINK_DVP_TO_ISP:
  1633. + default:
  1634. + return -EINVAL;
  1635. + }
  1636. +
  1637. + return 0;
  1638. +}
  1639. +
  1640. +void stf_vin_wr_irq_enable(struct stf_vin_dev *vin_dev, int enable)
  1641. +{
  1642. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1643. +
  1644. + if (enable) {
  1645. + stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1646. + U0_VIN_INTR_M);
  1647. + } else {
  1648. + /* clear vin interrupt */
  1649. + stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1650. + U0_VIN_INTR_CLEAN);
  1651. + stf_syscon_reg_clear_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1652. + U0_VIN_INTR_CLEAN);
  1653. + stf_syscon_reg_set_bit(stfcamss, SYSCONSAIF_SYSCFG(28),
  1654. + U0_VIN_INTR_M);
  1655. + }
  1656. +}
  1657. +
  1658. +void stf_vin_wr_set_ping_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr)
  1659. +{
  1660. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1661. +
  1662. + /* set the start address */
  1663. + stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(32), (long)addr);
  1664. +}
  1665. +
  1666. +void stf_vin_wr_set_pong_addr(struct stf_vin_dev *vin_dev, dma_addr_t addr)
  1667. +{
  1668. + struct stfcamss *stfcamss = vin_dev->stfcamss;
  1669. +
  1670. + /* set the start address */
  1671. + stf_syscon_reg_write(stfcamss, SYSCONSAIF_SYSCFG(24), (long)addr);
  1672. +}
  1673. +
  1674. +void stf_vin_isp_set_yuv_addr(struct stf_vin_dev *vin_dev,
  1675. + dma_addr_t y_addr, dma_addr_t uv_addr)
  1676. +{
  1677. + stf_isp_reg_write(vin_dev->stfcamss,
  1678. + ISP_REG_Y_PLANE_START_ADDR, y_addr);
  1679. + stf_isp_reg_write(vin_dev->stfcamss,
  1680. + ISP_REG_UV_PLANE_START_ADDR, uv_addr);
  1681. +}