csisp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2021 Renesas Electronics Corp.
  4. *
  5. * Driver for Renesas R-Car ISP Channel Selector
  6. *
  7. * The ISP hardware is capable of more than just channel selection, features
  8. * such as demosaicing, white balance control and color space conversion are
  9. * also possible. These more advanced features are not supported by the driver
  10. * due to lack of documentation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/mutex.h>
  14. #include <linux/of.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/pm_runtime.h>
  17. #include <linux/reset.h>
  18. #include <media/mipi-csi2.h>
  19. #include <media/v4l2-subdev.h>
  20. #define ISPINPUTSEL0_REG 0x0008
  21. #define ISPINPUTSEL0_SEL_CSI0 BIT(31)
  22. #define ISPSTART_REG 0x0014
  23. #define ISPSTART_START 0xffff
  24. #define ISPSTART_STOP 0x0000
  25. #define ISPPROCMODE_DT_REG(n) (0x1100 + (0x4 * (n)))
  26. #define ISPPROCMODE_DT_PROC_MODE_VC3(pm) (((pm) & 0x3f) << 24)
  27. #define ISPPROCMODE_DT_PROC_MODE_VC2(pm) (((pm) & 0x3f) << 16)
  28. #define ISPPROCMODE_DT_PROC_MODE_VC1(pm) (((pm) & 0x3f) << 8)
  29. #define ISPPROCMODE_DT_PROC_MODE_VC0(pm) ((pm) & 0x3f)
  30. #define ISPCS_FILTER_ID_CH_REG(n) (0x3000 + (0x0100 * (n)))
  31. #define ISPCS_DT_CODE03_CH_REG(n) (0x3008 + (0x100 * (n)))
  32. #define ISPCS_DT_CODE03_EN3 BIT(31)
  33. #define ISPCS_DT_CODE03_DT3(dt) (((dt) & 0x3f) << 24)
  34. #define ISPCS_DT_CODE03_EN2 BIT(23)
  35. #define ISPCS_DT_CODE03_DT2(dt) (((dt) & 0x3f) << 16)
  36. #define ISPCS_DT_CODE03_EN1 BIT(15)
  37. #define ISPCS_DT_CODE03_DT1(dt) (((dt) & 0x3f) << 8)
  38. #define ISPCS_DT_CODE03_EN0 BIT(7)
  39. #define ISPCS_DT_CODE03_DT0(dt) ((dt) & 0x3f)
  40. struct rcar_isp_format {
  41. u32 code;
  42. unsigned int datatype;
  43. unsigned int procmode;
  44. };
  45. static const struct rcar_isp_format rcar_isp_formats[] = {
  46. {
  47. .code = MEDIA_BUS_FMT_RGB888_1X24,
  48. .datatype = MIPI_CSI2_DT_RGB888,
  49. .procmode = 0x15
  50. }, {
  51. .code = MEDIA_BUS_FMT_Y10_1X10,
  52. .datatype = MIPI_CSI2_DT_RAW10,
  53. .procmode = 0x10,
  54. }, {
  55. .code = MEDIA_BUS_FMT_UYVY8_1X16,
  56. .datatype = MIPI_CSI2_DT_YUV422_8B,
  57. .procmode = 0x0c,
  58. }, {
  59. .code = MEDIA_BUS_FMT_YUYV8_1X16,
  60. .datatype = MIPI_CSI2_DT_YUV422_8B,
  61. .procmode = 0x0c,
  62. }, {
  63. .code = MEDIA_BUS_FMT_UYVY8_2X8,
  64. .datatype = MIPI_CSI2_DT_YUV422_8B,
  65. .procmode = 0x0c,
  66. }, {
  67. .code = MEDIA_BUS_FMT_YUYV10_2X10,
  68. .datatype = MIPI_CSI2_DT_YUV422_8B,
  69. .procmode = 0x0c,
  70. }, {
  71. .code = MEDIA_BUS_FMT_SBGGR8_1X8,
  72. .datatype = MIPI_CSI2_DT_RAW8,
  73. .procmode = 0x00,
  74. }, {
  75. .code = MEDIA_BUS_FMT_SGBRG8_1X8,
  76. .datatype = MIPI_CSI2_DT_RAW8,
  77. .procmode = 0x00,
  78. }, {
  79. .code = MEDIA_BUS_FMT_SGRBG8_1X8,
  80. .datatype = MIPI_CSI2_DT_RAW8,
  81. .procmode = 0x00,
  82. }, {
  83. .code = MEDIA_BUS_FMT_SRGGB8_1X8,
  84. .datatype = MIPI_CSI2_DT_RAW8,
  85. .procmode = 0x00,
  86. }, {
  87. .code = MEDIA_BUS_FMT_SBGGR10_1X10,
  88. .datatype = MIPI_CSI2_DT_RAW10,
  89. .procmode = 0x01,
  90. }, {
  91. .code = MEDIA_BUS_FMT_SGBRG10_1X10,
  92. .datatype = MIPI_CSI2_DT_RAW10,
  93. .procmode = 0x01,
  94. }, {
  95. .code = MEDIA_BUS_FMT_SGRBG10_1X10,
  96. .datatype = MIPI_CSI2_DT_RAW10,
  97. .procmode = 0x01,
  98. }, {
  99. .code = MEDIA_BUS_FMT_SRGGB10_1X10,
  100. .datatype = MIPI_CSI2_DT_RAW10,
  101. .procmode = 0x01,
  102. }, {
  103. .code = MEDIA_BUS_FMT_SBGGR12_1X12,
  104. .datatype = MIPI_CSI2_DT_RAW12,
  105. .procmode = 0x02,
  106. }, {
  107. .code = MEDIA_BUS_FMT_SGBRG12_1X12,
  108. .datatype = MIPI_CSI2_DT_RAW12,
  109. .procmode = 0x02,
  110. }, {
  111. .code = MEDIA_BUS_FMT_SGRBG12_1X12,
  112. .datatype = MIPI_CSI2_DT_RAW12,
  113. .procmode = 0x02,
  114. }, {
  115. .code = MEDIA_BUS_FMT_SRGGB12_1X12,
  116. .datatype = MIPI_CSI2_DT_RAW12,
  117. .procmode = 0x02,
  118. },
  119. };
  120. static const struct rcar_isp_format *risp_code_to_fmt(unsigned int code)
  121. {
  122. unsigned int i;
  123. for (i = 0; i < ARRAY_SIZE(rcar_isp_formats); i++) {
  124. if (rcar_isp_formats[i].code == code)
  125. return &rcar_isp_formats[i];
  126. }
  127. return NULL;
  128. }
  129. enum rcar_isp_input {
  130. RISP_CSI_INPUT0,
  131. RISP_CSI_INPUT1,
  132. };
  133. enum rcar_isp_pads {
  134. RCAR_ISP_SINK,
  135. RCAR_ISP_PORT0,
  136. RCAR_ISP_PORT1,
  137. RCAR_ISP_PORT2,
  138. RCAR_ISP_PORT3,
  139. RCAR_ISP_PORT4,
  140. RCAR_ISP_PORT5,
  141. RCAR_ISP_PORT6,
  142. RCAR_ISP_PORT7,
  143. RCAR_ISP_NUM_PADS,
  144. };
  145. struct rcar_isp {
  146. struct device *dev;
  147. void __iomem *csbase;
  148. struct reset_control *rstc;
  149. enum rcar_isp_input csi_input;
  150. struct v4l2_subdev subdev;
  151. struct media_pad pads[RCAR_ISP_NUM_PADS];
  152. struct v4l2_async_notifier notifier;
  153. struct v4l2_subdev *remote;
  154. unsigned int remote_pad;
  155. int stream_count;
  156. };
  157. static inline struct rcar_isp *sd_to_isp(struct v4l2_subdev *sd)
  158. {
  159. return container_of(sd, struct rcar_isp, subdev);
  160. }
  161. static inline struct rcar_isp *notifier_to_isp(struct v4l2_async_notifier *n)
  162. {
  163. return container_of(n, struct rcar_isp, notifier);
  164. }
  165. static void risp_write_cs(struct rcar_isp *isp, u32 offset, u32 value)
  166. {
  167. iowrite32(value, isp->csbase + offset);
  168. }
  169. static u32 risp_read_cs(struct rcar_isp *isp, u32 offset)
  170. {
  171. return ioread32(isp->csbase + offset);
  172. }
  173. static int risp_power_on(struct rcar_isp *isp)
  174. {
  175. int ret;
  176. ret = pm_runtime_resume_and_get(isp->dev);
  177. if (ret < 0)
  178. return ret;
  179. ret = reset_control_deassert(isp->rstc);
  180. if (ret < 0) {
  181. pm_runtime_put(isp->dev);
  182. return ret;
  183. }
  184. return 0;
  185. }
  186. static void risp_power_off(struct rcar_isp *isp)
  187. {
  188. reset_control_assert(isp->rstc);
  189. pm_runtime_put(isp->dev);
  190. }
  191. static int risp_start(struct rcar_isp *isp, struct v4l2_subdev_state *state)
  192. {
  193. const struct v4l2_mbus_framefmt *fmt;
  194. const struct rcar_isp_format *format;
  195. unsigned int vc;
  196. u32 sel_csi = 0;
  197. int ret;
  198. fmt = v4l2_subdev_state_get_format(state, RCAR_ISP_SINK);
  199. if (!fmt)
  200. return -EINVAL;
  201. format = risp_code_to_fmt(fmt->code);
  202. if (!format) {
  203. dev_err(isp->dev, "Unsupported bus format\n");
  204. return -EINVAL;
  205. }
  206. ret = risp_power_on(isp);
  207. if (ret) {
  208. dev_err(isp->dev, "Failed to power on ISP\n");
  209. return ret;
  210. }
  211. /* Select CSI-2 input source. */
  212. if (isp->csi_input == RISP_CSI_INPUT1)
  213. sel_csi = ISPINPUTSEL0_SEL_CSI0;
  214. risp_write_cs(isp, ISPINPUTSEL0_REG,
  215. risp_read_cs(isp, ISPINPUTSEL0_REG) | sel_csi);
  216. /* Configure Channel Selector. */
  217. for (vc = 0; vc < 4; vc++) {
  218. u8 ch = vc + 4;
  219. u8 dt = format->datatype;
  220. risp_write_cs(isp, ISPCS_FILTER_ID_CH_REG(ch), BIT(vc));
  221. risp_write_cs(isp, ISPCS_DT_CODE03_CH_REG(ch),
  222. ISPCS_DT_CODE03_EN3 | ISPCS_DT_CODE03_DT3(dt) |
  223. ISPCS_DT_CODE03_EN2 | ISPCS_DT_CODE03_DT2(dt) |
  224. ISPCS_DT_CODE03_EN1 | ISPCS_DT_CODE03_DT1(dt) |
  225. ISPCS_DT_CODE03_EN0 | ISPCS_DT_CODE03_DT0(dt));
  226. }
  227. /* Setup processing method. */
  228. risp_write_cs(isp, ISPPROCMODE_DT_REG(format->datatype),
  229. ISPPROCMODE_DT_PROC_MODE_VC3(format->procmode) |
  230. ISPPROCMODE_DT_PROC_MODE_VC2(format->procmode) |
  231. ISPPROCMODE_DT_PROC_MODE_VC1(format->procmode) |
  232. ISPPROCMODE_DT_PROC_MODE_VC0(format->procmode));
  233. /* Start ISP. */
  234. risp_write_cs(isp, ISPSTART_REG, ISPSTART_START);
  235. ret = v4l2_subdev_enable_streams(isp->remote, isp->remote_pad,
  236. BIT_ULL(0));
  237. if (ret)
  238. risp_power_off(isp);
  239. return ret;
  240. }
  241. static void risp_stop(struct rcar_isp *isp)
  242. {
  243. v4l2_subdev_disable_streams(isp->remote, isp->remote_pad, BIT_ULL(0));
  244. /* Stop ISP. */
  245. risp_write_cs(isp, ISPSTART_REG, ISPSTART_STOP);
  246. risp_power_off(isp);
  247. }
  248. static int risp_enable_streams(struct v4l2_subdev *sd,
  249. struct v4l2_subdev_state *state, u32 source_pad,
  250. u64 source_streams_mask)
  251. {
  252. struct rcar_isp *isp = sd_to_isp(sd);
  253. int ret = 0;
  254. if (source_streams_mask != 1)
  255. return -EINVAL;
  256. if (!isp->remote)
  257. return -ENODEV;
  258. if (isp->stream_count == 0) {
  259. ret = risp_start(isp, state);
  260. if (ret)
  261. return ret;
  262. }
  263. isp->stream_count += 1;
  264. return ret;
  265. }
  266. static int risp_disable_streams(struct v4l2_subdev *sd,
  267. struct v4l2_subdev_state *state, u32 source_pad,
  268. u64 source_streams_mask)
  269. {
  270. struct rcar_isp *isp = sd_to_isp(sd);
  271. if (source_streams_mask != 1)
  272. return -EINVAL;
  273. if (!isp->remote)
  274. return -ENODEV;
  275. if (isp->stream_count == 1)
  276. risp_stop(isp);
  277. isp->stream_count -= 1;
  278. return 0;
  279. }
  280. static int risp_set_pad_format(struct v4l2_subdev *sd,
  281. struct v4l2_subdev_state *state,
  282. struct v4l2_subdev_format *format)
  283. {
  284. struct v4l2_mbus_framefmt *framefmt;
  285. if (format->pad > RCAR_ISP_SINK)
  286. return v4l2_subdev_get_fmt(sd, state, format);
  287. if (!risp_code_to_fmt(format->format.code))
  288. format->format.code = rcar_isp_formats[0].code;
  289. for (unsigned int i = 0; i < RCAR_ISP_NUM_PADS; i++) {
  290. framefmt = v4l2_subdev_state_get_format(state, i);
  291. *framefmt = format->format;
  292. }
  293. return 0;
  294. }
  295. static const struct v4l2_subdev_pad_ops risp_pad_ops = {
  296. .enable_streams = risp_enable_streams,
  297. .disable_streams = risp_disable_streams,
  298. .set_fmt = risp_set_pad_format,
  299. .get_fmt = v4l2_subdev_get_fmt,
  300. .link_validate = v4l2_subdev_link_validate_default,
  301. };
  302. static const struct v4l2_subdev_ops rcar_isp_subdev_ops = {
  303. .pad = &risp_pad_ops,
  304. };
  305. /* -----------------------------------------------------------------------------
  306. * Async handling and registration of subdevices and links
  307. */
  308. static int risp_notify_bound(struct v4l2_async_notifier *notifier,
  309. struct v4l2_subdev *subdev,
  310. struct v4l2_async_connection *asd)
  311. {
  312. struct rcar_isp *isp = notifier_to_isp(notifier);
  313. int pad;
  314. pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
  315. MEDIA_PAD_FL_SOURCE);
  316. if (pad < 0) {
  317. dev_err(isp->dev, "Failed to find pad for %s\n", subdev->name);
  318. return pad;
  319. }
  320. isp->remote = subdev;
  321. isp->remote_pad = pad;
  322. dev_dbg(isp->dev, "Bound %s pad: %d\n", subdev->name, pad);
  323. return media_create_pad_link(&subdev->entity, pad,
  324. &isp->subdev.entity, 0,
  325. MEDIA_LNK_FL_ENABLED |
  326. MEDIA_LNK_FL_IMMUTABLE);
  327. }
  328. static void risp_notify_unbind(struct v4l2_async_notifier *notifier,
  329. struct v4l2_subdev *subdev,
  330. struct v4l2_async_connection *asd)
  331. {
  332. struct rcar_isp *isp = notifier_to_isp(notifier);
  333. isp->remote = NULL;
  334. dev_dbg(isp->dev, "Unbind %s\n", subdev->name);
  335. }
  336. static const struct v4l2_async_notifier_operations risp_notify_ops = {
  337. .bound = risp_notify_bound,
  338. .unbind = risp_notify_unbind,
  339. };
  340. static int risp_parse_dt(struct rcar_isp *isp)
  341. {
  342. struct v4l2_async_connection *asd;
  343. struct fwnode_handle *fwnode;
  344. struct fwnode_handle *ep;
  345. unsigned int id;
  346. int ret;
  347. for (id = 0; id < 2; id++) {
  348. ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(isp->dev),
  349. 0, id, 0);
  350. if (ep)
  351. break;
  352. }
  353. if (!ep) {
  354. dev_err(isp->dev, "Not connected to subdevice\n");
  355. return -EINVAL;
  356. }
  357. if (id == 1)
  358. isp->csi_input = RISP_CSI_INPUT1;
  359. fwnode = fwnode_graph_get_remote_endpoint(ep);
  360. fwnode_handle_put(ep);
  361. dev_dbg(isp->dev, "Found '%pOF'\n", to_of_node(fwnode));
  362. v4l2_async_subdev_nf_init(&isp->notifier, &isp->subdev);
  363. isp->notifier.ops = &risp_notify_ops;
  364. asd = v4l2_async_nf_add_fwnode(&isp->notifier, fwnode,
  365. struct v4l2_async_connection);
  366. fwnode_handle_put(fwnode);
  367. if (IS_ERR(asd))
  368. return PTR_ERR(asd);
  369. ret = v4l2_async_nf_register(&isp->notifier);
  370. if (ret)
  371. v4l2_async_nf_cleanup(&isp->notifier);
  372. return ret;
  373. }
  374. /* -----------------------------------------------------------------------------
  375. * Platform Device Driver
  376. */
  377. static const struct media_entity_operations risp_entity_ops = {
  378. .link_validate = v4l2_subdev_link_validate,
  379. };
  380. static int risp_probe_resources(struct rcar_isp *isp,
  381. struct platform_device *pdev)
  382. {
  383. struct resource *res;
  384. /*
  385. * For backward compatibility allow cs base to be the only reg if no
  386. * reg-names are set in DT.
  387. */
  388. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs");
  389. if (!res)
  390. isp->csbase = devm_platform_ioremap_resource(pdev, 0);
  391. else
  392. isp->csbase = devm_ioremap_resource(&pdev->dev, res);
  393. if (IS_ERR(isp->csbase))
  394. return PTR_ERR(isp->csbase);
  395. isp->rstc = devm_reset_control_get(&pdev->dev, NULL);
  396. return PTR_ERR_OR_ZERO(isp->rstc);
  397. }
  398. static const struct of_device_id risp_of_id_table[] = {
  399. { .compatible = "renesas,r8a779a0-isp" },
  400. { .compatible = "renesas,r8a779g0-isp" },
  401. /* Keep above for compatibility with old DTB files. */
  402. { .compatible = "renesas,rcar-gen4-isp" },
  403. { /* sentinel */ }
  404. };
  405. MODULE_DEVICE_TABLE(of, risp_of_id_table);
  406. static int risp_probe(struct platform_device *pdev)
  407. {
  408. struct rcar_isp *isp;
  409. unsigned int i;
  410. int ret;
  411. isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
  412. if (!isp)
  413. return -ENOMEM;
  414. isp->dev = &pdev->dev;
  415. ret = risp_probe_resources(isp, pdev);
  416. if (ret) {
  417. dev_err(isp->dev, "Failed to get resources\n");
  418. return ret;
  419. }
  420. platform_set_drvdata(pdev, isp);
  421. pm_runtime_enable(&pdev->dev);
  422. ret = risp_parse_dt(isp);
  423. if (ret)
  424. goto error_pm;
  425. isp->subdev.owner = THIS_MODULE;
  426. isp->subdev.dev = &pdev->dev;
  427. v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops);
  428. v4l2_set_subdevdata(&isp->subdev, &pdev->dev);
  429. snprintf(isp->subdev.name, sizeof(isp->subdev.name), "%s %s",
  430. KBUILD_MODNAME, dev_name(&pdev->dev));
  431. isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
  432. isp->subdev.entity.function = MEDIA_ENT_F_VID_MUX;
  433. isp->subdev.entity.ops = &risp_entity_ops;
  434. isp->pads[RCAR_ISP_SINK].flags = MEDIA_PAD_FL_SINK;
  435. for (i = RCAR_ISP_PORT0; i < RCAR_ISP_NUM_PADS; i++)
  436. isp->pads[i].flags = MEDIA_PAD_FL_SOURCE;
  437. ret = media_entity_pads_init(&isp->subdev.entity, RCAR_ISP_NUM_PADS,
  438. isp->pads);
  439. if (ret)
  440. goto error_notifier;
  441. ret = v4l2_subdev_init_finalize(&isp->subdev);
  442. if (ret)
  443. goto error_notifier;
  444. ret = v4l2_async_register_subdev(&isp->subdev);
  445. if (ret < 0)
  446. goto error_subdev;
  447. dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input);
  448. return 0;
  449. error_subdev:
  450. v4l2_subdev_cleanup(&isp->subdev);
  451. error_notifier:
  452. v4l2_async_nf_unregister(&isp->notifier);
  453. v4l2_async_nf_cleanup(&isp->notifier);
  454. error_pm:
  455. pm_runtime_disable(&pdev->dev);
  456. return ret;
  457. }
  458. static void risp_remove(struct platform_device *pdev)
  459. {
  460. struct rcar_isp *isp = platform_get_drvdata(pdev);
  461. v4l2_async_nf_unregister(&isp->notifier);
  462. v4l2_async_nf_cleanup(&isp->notifier);
  463. v4l2_async_unregister_subdev(&isp->subdev);
  464. v4l2_subdev_cleanup(&isp->subdev);
  465. pm_runtime_disable(&pdev->dev);
  466. }
  467. static struct platform_driver rcar_isp_driver = {
  468. .driver = {
  469. .name = "rcar-isp",
  470. .suppress_bind_attrs = true,
  471. .of_match_table = risp_of_id_table,
  472. },
  473. .probe = risp_probe,
  474. .remove = risp_remove,
  475. };
  476. module_platform_driver(rcar_isp_driver);
  477. MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
  478. MODULE_DESCRIPTION("Renesas R-Car ISP Channel Selector driver");
  479. MODULE_LICENSE("GPL");