History

Merge tag 'media/v6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab: - New V4L2 ioctl VIDIOC_REMOVE_BUFS - experimental support for using generic metaformats on V4L2 core - New drivers: Intel IPU6 controller driver, Broadcom BCM283x/BCM271x - More cleanups at atomisp driver - Usual bunch of driver cleanups, improvements and fixes * tag 'media/v6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (328 commits) media: bcm2835-unicam: Depend on COMMON_CLK Revert "media: v4l2-ctrls: show all owned controls in log_status" media: ov2740: Ensure proper reset sequence on probe() media: intel/ipu6: Don't print user-triggerable errors to kernel log media: bcm2835-unicam: Fix driver path in MAINTAINERS media: bcm2835-unicam: Fix a NULL vs IS_ERR() check media: bcm2835-unicam: Do not print error when irq not found media: bcm2835-unicam: Do not replace IRQ retcode during probe media: bcm2835-unicam: Convert to platform remove callback returning void media: media: intel/ipu6: Fix spelling mistake "remappinp" -> "remapping" media: intel/ipu6: explicitly include vmalloc.h media: cec.h: Fix kerneldoc media: uvcvideo: Refactor iterators media: v4l: async: refactor v4l2_async_create_ancillary_links media: intel/ipu6: Don't re-allocate memory for firmware media: dvb-frontends: tda10048: Fix integer overflow media: tc358746: Use the correct div_ function media: i2c: st-mipid02: Use the correct div function media: tegra-vde: Refactor timeout handling media: stk1160: Use min macro ...

Linus Torvalds committed 2 years ago

Commit 6fd600d2 parents 972a254 8771b7f307 files · +22908 −5428Browse files

Unified · Split

307 files
  1. Documentation/admin-guide/media/ipu6-isys.rst +161 −0
  2. Documentation/admin-guide/media/ipu6_isys_graph.svg +548 −0
  3. Documentation/admin-guide/media/mgb4.rst +15 −20
  4. Documentation/admin-guide/media/v4l-drivers.rst +1 −0
  5. Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml +127 −0
  6. Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml +1 −1
  7. Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml +1 −1
  8. Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml +25 −10
  9. Documentation/devicetree/bindings/media/i2c/ovti,ov8856.yaml +1 −1
  10. Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml +1 −1
  11. Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml +4 −1
  12. Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml +1 −1
  13. Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml +1 −0
  14. Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml +11 −0
  15. Documentation/devicetree/bindings/media/qcom,sc8280xp-camss.yaml +512 −0
  16. Documentation/driver-api/media/drivers/index.rst +1 −0
  17. Documentation/driver-api/media/drivers/ipu6.rst +205 −0
  18. Documentation/userspace-api/media/cec/cec-func-open.rst +2 −2
  19. Documentation/userspace-api/media/dvb/frontend_f_open.rst +1 −1
  20. Documentation/userspace-api/media/glossary.rst +12 −0
  21. Documentation/userspace-api/media/v4l/dev-meta.rst +21 −0
  22. Documentation/userspace-api/media/v4l/dev-subdev.rst +28 −3
  23. Documentation/userspace-api/media/v4l/func-open.rst +2 −2
  24. Documentation/userspace-api/media/v4l/meta-formats.rst +2 −1
  25. Documentation/userspace-api/media/v4l/metafmt-generic.rst +340 −0
  26. Documentation/userspace-api/media/v4l/mmap.rst +1 −1
  27. Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst +48 −0
  28. Documentation/userspace-api/media/v4l/subdev-formats.rst +262 −7
  29. Documentation/userspace-api/media/v4l/user-func.rst +1 −0
  30. Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst +7 −0
  31. Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst +86 −0
  32. Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +1 −0
  33. Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst +3 −3
  34. Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +33 −18
  35. Documentation/userspace-api/media/videodev2.h.rst.exceptions +1 −0
  36. MAINTAINERS +18 −1
  37. drivers/media/cec/core/cec-adap.c +20 −4
  38. drivers/media/cec/core/cec-api.c +4 −1
  39. drivers/media/cec/core/cec-core.c +2 −2
  40. drivers/media/cec/platform/cros-ec/cros-ec-cec.c +8 −1
  41. drivers/media/common/saa7146/saa7146_hlp.c +4 −4
  42. drivers/media/common/videobuf2/videobuf2-core.c +163 −68
  43. drivers/media/common/videobuf2/videobuf2-v4l2.c +28 −6
  44. drivers/media/dvb-core/dvbdev.c +1 −1
  45. drivers/media/dvb-frontends/as102_fe_types.h +1 −1
  46. drivers/media/dvb-frontends/cxd2880/Kconfig +1 −1
  47. drivers/media/dvb-frontends/drx39xyj/drx_driver.h +0 −2
  48. drivers/media/dvb-frontends/drx39xyj/drxj.c +26 −32
  49. drivers/media/dvb-frontends/lgdt3306a.c +5 −0
  50. drivers/media/dvb-frontends/m88ds3103.c +7 −0
  51. drivers/media/dvb-frontends/mxl5xx.c +11 −11
  52. drivers/media/dvb-frontends/si2165.c +2 −4
  53. drivers/media/dvb-frontends/stb0899_drv.c +1 −1
  54. drivers/media/dvb-frontends/tda10048.c +6 −3
  55. drivers/media/dvb-frontends/tda18271c2dd.c +2 −2
  56. drivers/media/i2c/Kconfig +2 −0
  57. drivers/media/i2c/adv7180.c +1 −1
  58. drivers/media/i2c/adv748x/adv748x-hdmi.c +8 −8
  59. drivers/media/i2c/adv7511-v4l2.c +11 −5
  60. drivers/media/i2c/adv7604.c +10 −10
  61. drivers/media/i2c/adv7842.c +17 −8
  62. drivers/media/i2c/dw9714.c +3 −3
  63. drivers/media/i2c/et8ek8/et8ek8_driver.c +2 −2
  64. drivers/media/i2c/hi556.c +93 −12
  65. drivers/media/i2c/imx214.c +1 −0
  66. drivers/media/i2c/imx219.c +35 −42
  67. drivers/media/i2c/imx335.c +304 −333
  68. drivers/media/i2c/max9271.h +5 −0
  69. drivers/media/i2c/ov2680.c +77 −26
  70. drivers/media/i2c/ov2740.c +14 −6
  71. drivers/media/i2c/ov4689.c +359 −314
  72. drivers/media/i2c/rdacm20.c +2 −2
  73. drivers/media/i2c/st-mipid02.c +1 −1
  74. drivers/media/i2c/tc358743.c +17 −8
  75. drivers/media/i2c/tc358746.c +1 −2
  76. drivers/media/i2c/tda1997x.c +7 −7
  77. drivers/media/i2c/ths7303.c +7 −3
  78. drivers/media/i2c/ths8200.c +10 −4
  79. drivers/media/i2c/tvp7002.c +21 −11
  80. drivers/media/mc/mc-devnode.c +2 −3
  81. drivers/media/mc/mc-entity.c +6 −0
  82. drivers/media/mmc/siano/smssdio.c +1 −24
  83. drivers/media/pci/cobalt/cobalt-v4l2.c +6 −6
  84. drivers/media/pci/intel/Kconfig +3 −1
  85. drivers/media/pci/intel/Makefile +1 −0
  86. drivers/media/pci/intel/ipu-bridge.c +47 −19
  87. drivers/media/pci/intel/ipu3/ipu3-cio2.c +9 −20
  88. drivers/media/pci/intel/ipu3/ipu3-cio2.h +0 −4
  89. drivers/media/pci/intel/ipu6/Kconfig +18 −0
  90. drivers/media/pci/intel/ipu6/Makefile +23 −0
  91. drivers/media/pci/intel/ipu6/ipu6-bus.c +165 −0
  92. drivers/media/pci/intel/ipu6/ipu6-bus.h +58 −0
  93. drivers/media/pci/intel/ipu6/ipu6-buttress.c +917 −0
  94. drivers/media/pci/intel/ipu6/ipu6-buttress.h +92 −0
  95. drivers/media/pci/intel/ipu6/ipu6-cpd.c +362 −0
  96. drivers/media/pci/intel/ipu6/ipu6-cpd.h +105 −0
  97. drivers/media/pci/intel/ipu6/ipu6-dma.c +502 −0
  98. drivers/media/pci/intel/ipu6/ipu6-dma.h +19 −0
  99. drivers/media/pci/intel/ipu6/ipu6-fw-com.c +413 −0
  100. drivers/media/pci/intel/ipu6/ipu6-fw-com.h +47 −0
  101. drivers/media/pci/intel/ipu6/ipu6-fw-isys.c +487 −0
  102. drivers/media/pci/intel/ipu6/ipu6-fw-isys.h +596 −0
  103. drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c +663 −0
  104. drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h +82 −0
  105. drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +536 −0
  106. drivers/media/pci/intel/ipu6/ipu6-isys-jsl-phy.c +242 −0
  107. drivers/media/pci/intel/ipu6/ipu6-isys-mcd-phy.c +720 −0
  108. drivers/media/pci/intel/ipu6/ipu6-isys-queue.c +810 −0
  109. drivers/media/pci/intel/ipu6/ipu6-isys-queue.h +78 −0
  110. drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c +403 −0
  111. drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h +59 −0
  112. drivers/media/pci/intel/ipu6/ipu6-isys-video.c +1420 −0
  113. drivers/media/pci/intel/ipu6/ipu6-isys-video.h +141 −0
  114. drivers/media/pci/intel/ipu6/ipu6-isys.c +1367 −0
  115. drivers/media/pci/intel/ipu6/ipu6-isys.h +206 −0
  116. drivers/media/pci/intel/ipu6/ipu6-mmu.c +846 −0
  117. drivers/media/pci/intel/ipu6/ipu6-mmu.h +73 −0
  118. drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h +226 −0
  119. drivers/media/pci/intel/ipu6/ipu6-platform-isys-csi2-reg.h +172 −0
  120. drivers/media/pci/intel/ipu6/ipu6-platform-regs.h +179 −0
  121. drivers/media/pci/intel/ipu6/ipu6.c +856 −0
  122. drivers/media/pci/intel/ipu6/ipu6.h +342 −0
  123. drivers/media/pci/intel/ivsc/mei_csi.c +18 −2
  124. drivers/media/pci/mgb4/mgb4_core.c +2 −2
  125. drivers/media/pci/mgb4/mgb4_regs.c +1 −1
  126. drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c +1 −1
  127. drivers/media/pci/ngene/ngene-core.c +3 −1
  128. drivers/media/pci/saa7134/saa7134-alsa.c +2 −7
  129. drivers/media/pci/solo6x10/solo6x10-core.c +4 −12
  130. drivers/media/pci/ttpci/budget-av.c +286 −287
  131. drivers/media/pci/ttpci/budget-ci.c +247 −248
  132. drivers/media/pci/ttpci/budget-core.c +20 −18
  133. drivers/media/pci/ttpci/budget.c +93 −80
  134. drivers/media/pci/ttpci/budget.h +13 −8
  135. drivers/media/platform/Kconfig +1 −0
  136. drivers/media/platform/Makefile +1 −0
  137. drivers/media/platform/broadcom/Kconfig +23 −0
  138. drivers/media/platform/broadcom/Makefile +3 −0
  139. drivers/media/platform/broadcom/bcm2835-unicam-regs.h +246 −0
  140. drivers/media/platform/broadcom/bcm2835-unicam.c +2739 −0
  141. drivers/media/platform/cadence/cdns-csi2rx.c +14 −12
  142. drivers/media/platform/chips-media/wave5/wave5-helper.c +15 −2
  143. drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +12 −1
  144. drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +12 −1
  145. drivers/media/platform/chips-media/wave5/wave5-vpu.c +83 −42
  146. drivers/media/platform/chips-media/wave5/wave5-vpuapi.h +4 −0
  147. drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +5 −5
  148. drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +3 −3
  149. drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h +1 −1
  150. drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +3 −3
  151. drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c +2 −0
  152. drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c +11 −12
  153. drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c +1 −1
  154. drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +2 −2
  155. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c +25 −17
  156. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c +6 −6
  157. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h +9 −6
  158. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c +7 −7
  159. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c +3 −3
  160. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c +2 −2
  161. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c +2 −2
  162. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c +1 −1
  163. drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c +2 −2
  164. drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h +2 −2
  165. drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h +2 −2
  166. drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +1 −1
  167. drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c +3 −1
  168. drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h +1 −1
  169. drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c +3 −2
  170. drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c +4 −1
  171. drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h +1 −1
  172. drivers/media/platform/nvidia/tegra-vde/h264.c +3 −3
  173. drivers/media/platform/nxp/imx-mipi-csis.c +33 −1
  174. drivers/media/platform/qcom/camss/Makefile +1 −1
  175. drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +105 −3
  176. drivers/media/platform/qcom/camss/camss-csiphy.c +1 −0
  177. drivers/media/platform/qcom/camss/camss-vfe-17x.c +0 −0
  178. drivers/media/platform/qcom/camss/camss-vfe.c +20 −5
  179. drivers/media/platform/qcom/camss/camss-video.c +1 −0
  180. drivers/media/platform/qcom/camss/camss.c +307 −0
  181. drivers/media/platform/qcom/camss/camss.h +1 −0
  182. drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +6 −3
  183. drivers/media/platform/renesas/rcar-vin/rcar-vin.h +1 −1
  184. drivers/media/platform/st/sti/c8sectpfe/Kconfig +0 −1
  185. drivers/media/platform/st/sti/c8sectpfe/Makefile +5 −2
  186. drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +1 −2
  187. drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h +5 −0
  188. drivers/media/platform/st/sti/hva/hva-hw.c +1 −2
  189. drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +2 −5
  190. drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig +1 −0
  191. drivers/media/platform/ti/davinci/vpif_capture.c +2 −2
  192. drivers/media/platform/ti/davinci/vpif_display.c +1 −1
  193. drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +2 −3
  194. drivers/media/platform/verisilicon/hantro_h1_regs.h +2 −2
  195. drivers/media/platform/verisilicon/hantro_v4l2.c +1 −0
  196. drivers/media/radio/radio-shark2.c +1 −1
  197. drivers/media/rc/gpio-ir-recv.c +0 −1
  198. drivers/media/rc/imon.c +6 −6
  199. drivers/media/rc/ir-spi.c +22 −19
  200. drivers/media/rc/lirc_dev.c +9 −9
  201. drivers/media/spi/cxd2880-spi.c +1 −1
  202. drivers/media/spi/gs1662.c +18 −9
  203. drivers/media/test-drivers/vicodec/vicodec-core.c +1 −0
  204. drivers/media/test-drivers/vimc/vimc-capture.c +2 −1
  205. drivers/media/test-drivers/visl/visl-video.c +1 −0
  206. drivers/media/test-drivers/vivid/vivid-core.c +5 −4
  207. drivers/media/test-drivers/vivid/vivid-meta-out.c +0 −4
  208. drivers/media/test-drivers/vivid/vivid-touch-cap.c +0 −4
  209. drivers/media/tuners/xc5000.c +17 −22
  210. drivers/media/usb/as102/as102_usb_drv.c +1 −1
  211. drivers/media/usb/au0828/au0828-video.c +1 −4
  212. drivers/media/usb/b2c2/flexcop-usb.c +10 −7
  213. drivers/media/usb/dvb-usb-v2/af9035.c +9 −1
  214. drivers/media/usb/dvb-usb-v2/anysee.c +2 −2
  215. drivers/media/usb/dvb-usb/dib0700_devices.c +15 −3
  216. drivers/media/usb/dvb-usb/dw2102.c +242 −220
  217. drivers/media/usb/go7007/go7007-fw.c +2 −2
  218. drivers/media/usb/gspca/cpia1.c +2 −4
  219. drivers/media/usb/s2255/s2255drv.c +10 −10
  220. drivers/media/usb/siano/smsusb.c +14 −6
  221. drivers/media/usb/stk1160/stk1160-video.c +17 −13
  222. drivers/media/usb/uvc/uvc_ctrl.c +14 −12
  223. drivers/media/usb/uvc/uvc_driver.c +53 −1
  224. drivers/media/usb/uvc/uvcvideo.h +2 −0
  225. drivers/media/v4l2-core/v4l2-async.c +15 −15
  226. drivers/media/v4l2-core/v4l2-common.c +2 −0
  227. drivers/media/v4l2-core/v4l2-ctrls-api.c +19 −14
  228. drivers/media/v4l2-core/v4l2-ctrls-core.c +11 −13
  229. drivers/media/v4l2-core/v4l2-dev.c +6 −0
  230. drivers/media/v4l2-core/v4l2-device.c +7 −5
  231. drivers/media/v4l2-core/v4l2-i2c.c +1 −1
  232. drivers/media/v4l2-core/v4l2-ioctl.c +66 −7
  233. drivers/media/v4l2-core/v4l2-mem2mem.c +15 −0
  234. drivers/media/v4l2-core/v4l2-spi.c +1 −1
  235. drivers/media/v4l2-core/v4l2-subdev.c +85 −28
  236. drivers/staging/media/atomisp/Makefile +0 −1
  237. drivers/staging/media/atomisp/i2c/Kconfig +0 −15
  238. drivers/staging/media/atomisp/i2c/Makefile +0 −5
  239. drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +1 −1
  240. drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +0 −955
  241. drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +2 −2
  242. drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +1 −13
  243. drivers/staging/media/atomisp/i2c/ov2722.h +0 −1
  244. drivers/staging/media/atomisp/include/linux/atomisp.h +0 −81
  245. drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +1 −5
  246. drivers/staging/media/atomisp/include/linux/atomisp_platform.h +1 −40
  247. drivers/staging/media/atomisp/include/media/lm3554.h +0 −132
  248. drivers/staging/media/atomisp/pci/atomisp_cmd.c +125 −156
  249. drivers/staging/media/atomisp/pci/atomisp_cmd.h +9 −4
  250. drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +1 −30
  251. drivers/staging/media/atomisp/pci/atomisp_csi2.c +3 −23
  252. drivers/staging/media/atomisp/pci/atomisp_fops.c +1 −48
  253. drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +32 −91
  254. drivers/staging/media/atomisp/pci/atomisp_internal.h +3 −16
  255. drivers/staging/media/atomisp/pci/atomisp_ioctl.c +40 −453
  256. drivers/staging/media/atomisp/pci/atomisp_subdev.c +52 −50
  257. drivers/staging/media/atomisp/pci/atomisp_subdev.h +1 −16
  258. drivers/staging/media/atomisp/pci/atomisp_tpg.c +0 −164
  259. drivers/staging/media/atomisp/pci/atomisp_tpg.h +0 −39
  260. drivers/staging/media/atomisp/pci/atomisp_v4l2.c +61 −122
  261. drivers/staging/media/atomisp/pci/bits.h +2 −2
  262. drivers/staging/media/atomisp/pci/defs.h +0 −37
  263. drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h +0 −1
  264. drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +0 −38
  265. drivers/staging/media/atomisp/pci/hive_types.h +0 −19
  266. drivers/staging/media/atomisp/pci/ia_css.h +0 −1
  267. drivers/staging/media/atomisp/pci/ia_css_frame_public.h +0 −8
  268. drivers/staging/media/atomisp/pci/ia_css_stream_public.h +0 −17
  269. drivers/staging/media/atomisp/pci/ia_css_tpg.h +0 −79
  270. drivers/staging/media/atomisp/pci/isp2400_input_system_global.h +0 −1
  271. drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +0 −15
  272. drivers/staging/media/atomisp/pci/isp2401_input_system_global.h +0 −1
  273. drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +2 −18
  274. drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c +0 −11
  275. drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c +1 −27
  276. drivers/staging/media/atomisp/pci/sh_css.c +9 −129
  277. drivers/staging/media/atomisp/pci/sh_css_internal.h +0 −1
  278. drivers/staging/media/atomisp/pci/sh_css_mipi.c +1 −1
  279. drivers/staging/media/atomisp/pci/sh_css_sp.c +61 −66
  280. drivers/staging/media/atomisp/pci/sh_css_sp.h +0 −7
  281. drivers/staging/media/atomisp/pci/system_global.h +0 −12
  282. drivers/staging/media/imx/Kconfig +0 −1
  283. drivers/staging/media/ipu3/ipu3-css-fw.c +3 −1
  284. drivers/staging/media/ipu3/ipu3-css-fw.h +2 −0
  285. drivers/staging/media/ipu3/ipu3-css.c +0 −1
  286. drivers/staging/media/ipu3/ipu3.c +7 −3
  287. drivers/staging/media/max96712/max96712.c +1 −1
  288. drivers/staging/media/starfive/camss/stf-camss.c +8 −4
  289. drivers/staging/media/starfive/camss/stf-isp.c +2 −8
  290. drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c +1 −2
  291. drivers/staging/media/tegra-video/tegra20.c +3 −7
  292. drivers/staging/media/tegra-video/vi.c +6 −6
  293. include/media/cec.h +3 −1
  294. include/media/ipu6-pci-table.h +28 −0
  295. include/media/media-device.h +6 −0
  296. include/media/v4l2-async.h +3 −1
  297. include/media/v4l2-device.h +5 −2
  298. include/media/v4l2-ioctl.h +4 −0
  299. include/media/v4l2-mem2mem.h +2 −0
  300. include/media/v4l2-subdev.h +56 −14
  301. include/media/videobuf2-core.h +42 −10
  302. include/media/videobuf2-v4l2.h +2 −0
  303. include/uapi/linux/dvb/frontend.h +1 −1
  304. include/uapi/linux/media-bus-format.h +9 −0
  305. include/uapi/linux/v4l2-mediabus.h +12 −6
  306. include/uapi/linux/v4l2-subdev.h +11 −3
  307. include/uapi/linux/videodev2.h +44 −1
Documentation/admin-guide/media/ipu6-isys.rst+161−0
@@ -0,0 +1,161 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3.. include:: <isonum.txt>
4
5========================================================
6Intel Image Processing Unit 6 (IPU6) Input System driver
7========================================================
8
9Copyright |copy| 2023--2024 Intel Corporation
10
11Introduction
12============
13
14This file documents the Intel IPU6 (6th generation Image Processing Unit)
15Input System (MIPI CSI2 receiver) drivers located under
16drivers/media/pci/intel/ipu6.
17
18The Intel IPU6 can be found in certain Intel SoCs but not in all SKUs:
19
20* Tiger Lake
21* Jasper Lake
22* Alder Lake
23* Raptor Lake
24* Meteor Lake
25
26Intel IPU6 is made up of two components - Input System (ISYS) and Processing
27System (PSYS).
28
29The Input System mainly works as MIPI CSI-2 receiver which receives and
30processes the image data from the sensors and outputs the frames to memory.
31
32There are 2 driver modules - intel-ipu6 and intel-ipu6-isys. intel-ipu6 is an
33IPU6 common driver which does PCI configuration, firmware loading and parsing,
34firmware authentication, DMA mapping and IPU-MMU (internal Memory mapping Unit)
35configuration. intel_ipu6_isys implements V4L2, Media Controller and V4L2
36sub-device interfaces. The IPU6 ISYS driver supports camera sensors connected
37to the IPU6 ISYS through V4L2 sub-device sensor drivers.
38
39.. Note:: See Documentation/driver-api/media/drivers/ipu6.rst for more
40 information about the IPU6 hardware.
41
42Input system driver
43===================
44
45The Input System driver mainly configures CSI-2 D-PHY, constructs the firmware
46stream configuration, sends commands to firmware, gets response from hardware
47and firmware and then returns buffers to user. The ISYS is represented as
48several V4L2 sub-devices as well as video nodes.
49
50.. kernel-figure:: ipu6_isys_graph.svg
51 :alt: ipu6 isys media graph with multiple streams support
52
53 IPU6 ISYS media graph with multiple streams support
54
55The graph has been produced using the following command:
56
57.. code-block:: none
58
59 fdp -Gsplines=true -Tsvg < dot > dot.svg
60
61Capturing frames with IPU6 ISYS
62-------------------------------
63
64IPU6 ISYS is used to capture frames from the camera sensors connected to the
65CSI2 ports. The supported input formats of ISYS are listed in table below:
66
67.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|
68
69.. flat-table::
70 :header-rows: 1
71
72 * - IPU6 ISYS supported input formats
73
74 * - RGB565, RGB888
75
76 * - UYVY8, YUYV8
77
78 * - RAW8, RAW10, RAW12
79
80.. _ipu6_isys_capture_examples:
81
82Examples
83~~~~~~~~
84
85Here is an example of IPU6 ISYS raw capture on Dell XPS 9315 laptop. On this
86machine, ov01a10 sensor is connected to IPU ISYS CSI-2 port 2, which can
87generate images at sBGGR10 with resolution 1280x800.
88
89Using the media controller APIs, we can configure ov01a10 sensor by
90media-ctl [#f1]_ and yavta [#f2]_ to transmit frames to IPU6 ISYS.
91
92.. code-block:: none
93
94 # Example 1 capture frame from ov01a10 camera sensor
95 # This example assumes /dev/media0 as the IPU ISYS media device
96 export MDEV=/dev/media0
97
98 # Establish the link for the media devices using media-ctl
99 media-ctl -d $MDEV -l "\"ov01a10 3-0036\":0 -> \"Intel IPU6 CSI2 2\":0[1]"
100
101 # Set the format for the media devices
102 media-ctl -d $MDEV -V "ov01a10:0 [fmt:SBGGR10/1280x800]"
103 media-ctl -d $MDEV -V "Intel IPU6 CSI2 2:0 [fmt:SBGGR10/1280x800]"
104 media-ctl -d $MDEV -V "Intel IPU6 CSI2 2:1 [fmt:SBGGR10/1280x800]"
105
106Once the media pipeline is configured, desired sensor specific settings
107(such as exposure and gain settings) can be set, using the yavta tool.
108
109e.g
110
111.. code-block:: none
112
113 # and that ov01a10 sensor is connected to i2c bus 3 with address 0x36
114 export SDEV=$(media-ctl -d $MDEV -e "ov01a10 3-0036")
115
116 yavta -w 0x009e0903 400 $SDEV
117 yavta -w 0x009e0913 1000 $SDEV
118 yavta -w 0x009e0911 2000 $SDEV
119
120Once the desired sensor settings are set, frame captures can be done as below.
121
122e.g
123
124.. code-block:: none
125
126 yavta --data-prefix -u -c10 -n5 -I -s 1280x800 --file=/tmp/frame-#.bin \
127 -f SBGGR10 $(media-ctl -d $MDEV -e "Intel IPU6 ISYS Capture 0")
128
129With the above command, 10 frames are captured at 1280x800 resolution with
130sBGGR10 format. The captured frames are available as /tmp/frame-#.bin files.
131
132Here is another example of IPU6 ISYS RAW and metadata capture from camera
133sensor ov2740 on Lenovo X1 Yoga laptop.
134
135.. code-block:: none
136
137 media-ctl -l "\"ov2740 14-0036\":0 -> \"Intel IPU6 CSI2 1\":0[1]"
138 media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[5]"
139 media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[5]"
140
141 # set routing
142 media-ctl -v -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]"
143
144 media-ctl -v "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]"
145 media-ctl -v "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]"
146 media-ctl -v "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]"
147 media-ctl -v "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]"
148
149 CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0")
150 ./yavta --data-prefix -c100 -n5 -I -s1932x1092 --file=/tmp/frame-#.bin \
151 -f SGRBG10 ${CAPTURE_DEV}
152
153 CAPTURE_META=$(media-ctl -e "Intel IPU6 ISYS Capture 1")
154 ./yavta --data-prefix -c100 -n5 -I -s97x1 -B meta-capture \
155 --file=/tmp/meta-#.bin -f GENERIC_8 ${CAPTURE_META}
156
157References
158==========
159
160.. [#f1] https://git.ideasonboard.org/media-ctl.git
161.. [#f2] https://git.ideasonboard.org/yavta.git
Documentation/admin-guide/media/ipu6_isys_graph.svg+548−0
@@ -0,0 +1,548 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<!-- Generated by graphviz version 2.43.0 (0)
5 -->
6<!-- Title: board Pages: 1 -->
7<svg width="1703pt" height="1473pt"
8 viewBox="0.00 0.00 1703.00 1473.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1469)">
10<title>board</title>
11<polygon fill="white" stroke="transparent" points="-4,4 -4,-1469 1699,-1469 1699,4 -4,4"/>
12<!-- n00000001 -->
13<g id="node1" class="node">
14<title>n00000001</title>
15<polygon fill="yellow" stroke="black" points="832.99,-750.08 629.99,-750.08 629.99,-712.08 832.99,-712.08 832.99,-750.08"/>
16<text text-anchor="middle" x="731.49" y="-734.88" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 0</text>
17<text text-anchor="middle" x="731.49" y="-719.88" font-family="Times,serif" font-size="14.00">/dev/video0</text>
18</g>
19<!-- n00000005 -->
20<g id="node2" class="node">
21<title>n00000005</title>
22<polygon fill="yellow" stroke="black" points="1396.59,-771.88 1193.59,-771.88 1193.59,-733.88 1396.59,-733.88 1396.59,-771.88"/>
23<text text-anchor="middle" x="1295.09" y="-756.68" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 1</text>
24<text text-anchor="middle" x="1295.09" y="-741.68" font-family="Times,serif" font-size="14.00">/dev/video1</text>
25</g>
26<!-- n00000009 -->
27<g id="node3" class="node">
28<title>n00000009</title>
29<polygon fill="yellow" stroke="black" points="1118.52,-690.47 915.52,-690.47 915.52,-652.47 1118.52,-652.47 1118.52,-690.47"/>
30<text text-anchor="middle" x="1017.02" y="-675.27" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 2</text>
31<text text-anchor="middle" x="1017.02" y="-660.27" font-family="Times,serif" font-size="14.00">/dev/video2</text>
32</g>
33<!-- n0000000d -->
34<g id="node4" class="node">
35<title>n0000000d</title>
36<polygon fill="yellow" stroke="black" points="1105.89,-838.84 902.89,-838.84 902.89,-800.84 1105.89,-800.84 1105.89,-838.84"/>
37<text text-anchor="middle" x="1004.39" y="-823.64" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 3</text>
38<text text-anchor="middle" x="1004.39" y="-808.64" font-family="Times,serif" font-size="14.00">/dev/video3</text>
39</g>
40<!-- n00000011 -->
41<g id="node5" class="node">
42<title>n00000011</title>
43<polygon fill="yellow" stroke="black" points="1279.22,-992.95 1076.22,-992.95 1076.22,-954.95 1279.22,-954.95 1279.22,-992.95"/>
44<text text-anchor="middle" x="1177.72" y="-977.75" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 4</text>
45<text text-anchor="middle" x="1177.72" y="-962.75" font-family="Times,serif" font-size="14.00">/dev/video4</text>
46</g>
47<!-- n00000015 -->
48<g id="node6" class="node">
49<title>n00000015</title>
50<polygon fill="yellow" stroke="black" points="939.18,-984.91 736.18,-984.91 736.18,-946.91 939.18,-946.91 939.18,-984.91"/>
51<text text-anchor="middle" x="837.68" y="-969.71" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 5</text>
52<text text-anchor="middle" x="837.68" y="-954.71" font-family="Times,serif" font-size="14.00">/dev/video5</text>
53</g>
54<!-- n00000019 -->
55<g id="node7" class="node">
56<title>n00000019</title>
57<polygon fill="yellow" stroke="black" points="957.87,-527.99 754.87,-527.99 754.87,-489.99 957.87,-489.99 957.87,-527.99"/>
58<text text-anchor="middle" x="856.37" y="-512.79" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 6</text>
59<text text-anchor="middle" x="856.37" y="-497.79" font-family="Times,serif" font-size="14.00">/dev/video6</text>
60</g>
61<!-- n0000001d -->
62<g id="node8" class="node">
63<title>n0000001d</title>
64<polygon fill="yellow" stroke="black" points="1291.02,-542.15 1088.02,-542.15 1088.02,-504.15 1291.02,-504.15 1291.02,-542.15"/>
65<text text-anchor="middle" x="1189.52" y="-526.95" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 7</text>
66<text text-anchor="middle" x="1189.52" y="-511.95" font-family="Times,serif" font-size="14.00">/dev/video7</text>
67</g>
68<!-- n00000021 -->
69<g id="node9" class="node">
70<title>n00000021</title>
71<polygon fill="yellow" stroke="black" points="202.74,-611.46 -0.26,-611.46 -0.26,-573.46 202.74,-573.46 202.74,-611.46"/>
72<text text-anchor="middle" x="101.24" y="-596.26" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 8</text>
73<text text-anchor="middle" x="101.24" y="-581.26" font-family="Times,serif" font-size="14.00">/dev/video8</text>
74</g>
75<!-- n00000025 -->
76<g id="node10" class="node">
77<title>n00000025</title>
78<polygon fill="yellow" stroke="black" points="764.86,-637.89 561.86,-637.89 561.86,-599.89 764.86,-599.89 764.86,-637.89"/>
79<text text-anchor="middle" x="663.36" y="-622.69" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 9</text>
80<text text-anchor="middle" x="663.36" y="-607.69" font-family="Times,serif" font-size="14.00">/dev/video9</text>
81</g>
82<!-- n00000029 -->
83<g id="node11" class="node">
84<title>n00000029</title>
85<polygon fill="yellow" stroke="black" points="358.62,-519.5 146.62,-519.5 146.62,-481.5 358.62,-481.5 358.62,-519.5"/>
86<text text-anchor="middle" x="252.62" y="-504.3" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 10</text>
87<text text-anchor="middle" x="252.62" y="-489.3" font-family="Times,serif" font-size="14.00">/dev/video10</text>
88</g>
89<!-- n0000002d -->
90<g id="node12" class="node">
91<title>n0000002d</title>
92<polygon fill="yellow" stroke="black" points="481.4,-662.59 269.4,-662.59 269.4,-624.59 481.4,-624.59 481.4,-662.59"/>
93<text text-anchor="middle" x="375.4" y="-647.39" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 11</text>
94<text text-anchor="middle" x="375.4" y="-632.39" font-family="Times,serif" font-size="14.00">/dev/video11</text>
95</g>
96<!-- n00000031 -->
97<g id="node13" class="node">
98<title>n00000031</title>
99<polygon fill="yellow" stroke="black" points="637.17,-837.47 425.17,-837.47 425.17,-799.47 637.17,-799.47 637.17,-837.47"/>
100<text text-anchor="middle" x="531.17" y="-822.27" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 12</text>
101<text text-anchor="middle" x="531.17" y="-807.27" font-family="Times,serif" font-size="14.00">/dev/video12</text>
102</g>
103<!-- n00000035 -->
104<g id="node14" class="node">
105<title>n00000035</title>
106<polygon fill="yellow" stroke="black" points="337.75,-833.67 125.75,-833.67 125.75,-795.67 337.75,-795.67 337.75,-833.67"/>
107<text text-anchor="middle" x="231.75" y="-818.47" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 13</text>
108<text text-anchor="middle" x="231.75" y="-803.47" font-family="Times,serif" font-size="14.00">/dev/video13</text>
109</g>
110<!-- n00000039 -->
111<g id="node15" class="node">
112<title>n00000039</title>
113<polygon fill="yellow" stroke="black" points="393.07,-317.96 181.07,-317.96 181.07,-279.96 393.07,-279.96 393.07,-317.96"/>
114<text text-anchor="middle" x="287.07" y="-302.76" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 14</text>
115<text text-anchor="middle" x="287.07" y="-287.76" font-family="Times,serif" font-size="14.00">/dev/video14</text>
116</g>
117<!-- n0000003d -->
118<g id="node16" class="node">
119<title>n0000003d</title>
120<polygon fill="yellow" stroke="black" points="701.46,-391.04 489.46,-391.04 489.46,-353.04 701.46,-353.04 701.46,-391.04"/>
121<text text-anchor="middle" x="595.46" y="-375.84" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 15</text>
122<text text-anchor="middle" x="595.46" y="-360.84" font-family="Times,serif" font-size="14.00">/dev/video15</text>
123</g>
124<!-- n00000041 -->
125<g id="node17" class="node">
126<title>n00000041</title>
127<polygon fill="yellow" stroke="black" points="212.45,-1228.8 0.45,-1228.8 0.45,-1190.8 212.45,-1190.8 212.45,-1228.8"/>
128<text text-anchor="middle" x="106.45" y="-1213.6" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 16</text>
129<text text-anchor="middle" x="106.45" y="-1198.6" font-family="Times,serif" font-size="14.00">/dev/video16</text>
130</g>
131<!-- n00000045 -->
132<g id="node18" class="node">
133<title>n00000045</title>
134<polygon fill="yellow" stroke="black" points="784.86,-1252.38 572.86,-1252.38 572.86,-1214.38 784.86,-1214.38 784.86,-1252.38"/>
135<text text-anchor="middle" x="678.86" y="-1237.18" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 17</text>
136<text text-anchor="middle" x="678.86" y="-1222.18" font-family="Times,serif" font-size="14.00">/dev/video17</text>
137</g>
138<!-- n00000049 -->
139<g id="node19" class="node">
140<title>n00000049</title>
141<polygon fill="yellow" stroke="black" points="503.14,-1169.96 291.14,-1169.96 291.14,-1131.96 503.14,-1131.96 503.14,-1169.96"/>
142<text text-anchor="middle" x="397.14" y="-1154.76" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 18</text>
143<text text-anchor="middle" x="397.14" y="-1139.76" font-family="Times,serif" font-size="14.00">/dev/video18</text>
144</g>
145<!-- n0000004d -->
146<g id="node20" class="node">
147<title>n0000004d</title>
148<polygon fill="yellow" stroke="black" points="492.62,-1319.4 280.62,-1319.4 280.62,-1281.4 492.62,-1281.4 492.62,-1319.4"/>
149<text text-anchor="middle" x="386.62" y="-1304.2" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 19</text>
150<text text-anchor="middle" x="386.62" y="-1289.2" font-family="Times,serif" font-size="14.00">/dev/video19</text>
151</g>
152<!-- n00000051 -->
153<g id="node21" class="node">
154<title>n00000051</title>
155<polygon fill="yellow" stroke="black" points="680.74,-1464.66 468.74,-1464.66 468.74,-1426.66 680.74,-1426.66 680.74,-1464.66"/>
156<text text-anchor="middle" x="574.74" y="-1449.46" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 20</text>
157<text text-anchor="middle" x="574.74" y="-1434.46" font-family="Times,serif" font-size="14.00">/dev/video20</text>
158</g>
159<!-- n00000055 -->
160<g id="node22" class="node">
161<title>n00000055</title>
162<polygon fill="yellow" stroke="black" points="302.42,-1452.56 90.42,-1452.56 90.42,-1414.56 302.42,-1414.56 302.42,-1452.56"/>
163<text text-anchor="middle" x="196.42" y="-1437.36" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 21</text>
164<text text-anchor="middle" x="196.42" y="-1422.36" font-family="Times,serif" font-size="14.00">/dev/video21</text>
165</g>
166<!-- n00000059 -->
167<g id="node23" class="node">
168<title>n00000059</title>
169<polygon fill="yellow" stroke="black" points="319.89,-1018.32 107.89,-1018.32 107.89,-980.32 319.89,-980.32 319.89,-1018.32"/>
170<text text-anchor="middle" x="213.89" y="-1003.12" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 22</text>
171<text text-anchor="middle" x="213.89" y="-988.12" font-family="Times,serif" font-size="14.00">/dev/video22</text>
172</g>
173<!-- n0000005d -->
174<g id="node24" class="node">
175<title>n0000005d</title>
176<polygon fill="yellow" stroke="black" points="692.62,-1031.39 480.62,-1031.39 480.62,-993.39 692.62,-993.39 692.62,-1031.39"/>
177<text text-anchor="middle" x="586.62" y="-1016.19" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 23</text>
178<text text-anchor="middle" x="586.62" y="-1001.19" font-family="Times,serif" font-size="14.00">/dev/video23</text>
179</g>
180<!-- n00000061 -->
181<g id="node25" class="node">
182<title>n00000061</title>
183<polygon fill="yellow" stroke="black" points="1122.45,-248.8 910.45,-248.8 910.45,-210.8 1122.45,-210.8 1122.45,-248.8"/>
184<text text-anchor="middle" x="1016.45" y="-233.6" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 24</text>
185<text text-anchor="middle" x="1016.45" y="-218.6" font-family="Times,serif" font-size="14.00">/dev/video24</text>
186</g>
187<!-- n00000065 -->
188<g id="node26" class="node">
189<title>n00000065</title>
190<polygon fill="yellow" stroke="black" points="1694.86,-272.38 1482.86,-272.38 1482.86,-234.38 1694.86,-234.38 1694.86,-272.38"/>
191<text text-anchor="middle" x="1588.86" y="-257.18" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 25</text>
192<text text-anchor="middle" x="1588.86" y="-242.18" font-family="Times,serif" font-size="14.00">/dev/video25</text>
193</g>
194<!-- n00000069 -->
195<g id="node27" class="node">
196<title>n00000069</title>
197<polygon fill="yellow" stroke="black" points="1413.14,-189.96 1201.14,-189.96 1201.14,-151.96 1413.14,-151.96 1413.14,-189.96"/>
198<text text-anchor="middle" x="1307.14" y="-174.76" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 26</text>
199<text text-anchor="middle" x="1307.14" y="-159.76" font-family="Times,serif" font-size="14.00">/dev/video26</text>
200</g>
201<!-- n0000006d -->
202<g id="node28" class="node">
203<title>n0000006d</title>
204<polygon fill="yellow" stroke="black" points="1402.62,-339.4 1190.62,-339.4 1190.62,-301.4 1402.62,-301.4 1402.62,-339.4"/>
205<text text-anchor="middle" x="1296.62" y="-324.2" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 27</text>
206<text text-anchor="middle" x="1296.62" y="-309.2" font-family="Times,serif" font-size="14.00">/dev/video27</text>
207</g>
208<!-- n00000071 -->
209<g id="node29" class="node">
210<title>n00000071</title>
211<polygon fill="yellow" stroke="black" points="1590.74,-484.66 1378.74,-484.66 1378.74,-446.66 1590.74,-446.66 1590.74,-484.66"/>
212<text text-anchor="middle" x="1484.74" y="-469.46" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 28</text>
213<text text-anchor="middle" x="1484.74" y="-454.46" font-family="Times,serif" font-size="14.00">/dev/video28</text>
214</g>
215<!-- n00000075 -->
216<g id="node30" class="node">
217<title>n00000075</title>
218<polygon fill="yellow" stroke="black" points="1212.42,-472.56 1000.42,-472.56 1000.42,-434.56 1212.42,-434.56 1212.42,-472.56"/>
219<text text-anchor="middle" x="1106.42" y="-457.36" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 29</text>
220<text text-anchor="middle" x="1106.42" y="-442.36" font-family="Times,serif" font-size="14.00">/dev/video29</text>
221</g>
222<!-- n00000079 -->
223<g id="node31" class="node">
224<title>n00000079</title>
225<polygon fill="yellow" stroke="black" points="1229.89,-38.32 1017.89,-38.32 1017.89,-0.32 1229.89,-0.32 1229.89,-38.32"/>
226<text text-anchor="middle" x="1123.89" y="-23.12" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 30</text>
227<text text-anchor="middle" x="1123.89" y="-8.12" font-family="Times,serif" font-size="14.00">/dev/video30</text>
228</g>
229<!-- n0000007d -->
230<g id="node32" class="node">
231<title>n0000007d</title>
232<polygon fill="yellow" stroke="black" points="1602.62,-51.39 1390.62,-51.39 1390.62,-13.39 1602.62,-13.39 1602.62,-51.39"/>
233<text text-anchor="middle" x="1496.62" y="-36.19" font-family="Times,serif" font-size="14.00">Intel IPU6 ISYS Capture 31</text>
234<text text-anchor="middle" x="1496.62" y="-21.19" font-family="Times,serif" font-size="14.00">/dev/video31</text>
235</g>
236<!-- n00000081 -->
237<g id="node33" class="node">
238<title>n00000081</title>
239<path fill="green" stroke="black" d="M924.28,-700.28C924.28,-700.28 1108.28,-700.28 1108.28,-700.28 1114.28,-700.28 1120.28,-706.28 1120.28,-712.28 1120.28,-712.28 1120.28,-772.28 1120.28,-772.28 1120.28,-778.28 1114.28,-784.28 1108.28,-784.28 1108.28,-784.28 924.28,-784.28 924.28,-784.28 918.28,-784.28 912.28,-778.28 912.28,-772.28 912.28,-772.28 912.28,-712.28 912.28,-712.28 912.28,-706.28 918.28,-700.28 924.28,-700.28"/>
240<text text-anchor="middle" x="1016.28" y="-769.08" font-family="Times,serif" font-size="14.00">0</text>
241<polyline fill="none" stroke="black" points="912.28,-761.28 1120.28,-761.28 "/>
242<text text-anchor="middle" x="1016.28" y="-746.08" font-family="Times,serif" font-size="14.00">Intel IPU6 CSI2 0</text>
243<text text-anchor="middle" x="1016.28" y="-731.08" font-family="Times,serif" font-size="14.00">/dev/v4l&#45;subdev0</text>
244<polyline fill="none" stroke="black" points="912.28,-723.28 1120.28,-723.28 "/>
245<text text-anchor="middle" x="925.28" y="-708.08" font-family="Times,serif" font-size="14.00">1</text>
246<polyline fill="none" stroke="black" points="938.28,-700.28 938.28,-723.28 "/>
247<text text-anchor="middle" x="951.28" y="-708.08" font-family="Times,serif" font-size="14.00">2</text>
248<polyline fill="none" stroke="black" points="964.28,-700.28 964.28,-723.28 "/>
249<text text-anchor="middle" x="977.28" y="-708.08" font-family="Times,serif" font-size="14.00">3</text>
250<polyline fill="none" stroke="black" points="990.28,-700.28 990.28,-723.28 "/>
251<text text-anchor="middle" x="1003.28" y="-708.08" font-family="Times,serif" font-size="14.00">4</text>
252<polyline fill="none" stroke="black" points="1016.28,-700.28 1016.28,-723.28 "/>
253<text text-anchor="middle" x="1029.28" y="-708.08" font-family="Times,serif" font-size="14.00">5</text>
254<polyline fill="none" stroke="black" points="1042.28,-700.28 1042.28,-723.28 "/>
255<text text-anchor="middle" x="1055.28" y="-708.08" font-family="Times,serif" font-size="14.00">6</text>
256<polyline fill="none" stroke="black" points="1068.28,-700.28 1068.28,-723.28 "/>
257<text text-anchor="middle" x="1081.28" y="-708.08" font-family="Times,serif" font-size="14.00">7</text>
258<polyline fill="none" stroke="black" points="1094.28,-700.28 1094.28,-723.28 "/>
259<text text-anchor="middle" x="1107.28" y="-708.08" font-family="Times,serif" font-size="14.00">8</text>
260</g>
261<!-- n00000081&#45;&gt;n00000001 -->
262<g id="edge1" class="edge">
263<title>n00000081:port1&#45;&gt;n00000001</title>
264<path fill="none" stroke="black" stroke-dasharray="5,2" d="M912.28,-711.28C912.28,-711.28 880.33,-714.78 843.28,-718.84"/>
265<polygon fill="black" stroke="black" points="842.81,-715.37 833.25,-719.94 843.57,-722.33 842.81,-715.37"/>
266</g>
267<!-- n00000081&#45;&gt;n00000005 -->
268<g id="edge2" class="edge">
269<title>n00000081:port2&#45;&gt;n00000005</title>
270<path fill="none" stroke="black" stroke-dasharray="5,2" d="M951.38,-700.28C951.38,-700.28 1086.18,-688.61 1123.48,-697.08 1155.93,-704.45 1158.99,-719.67 1190.39,-730.68 1190.49,-730.71 1190.59,-730.75 1190.69,-730.78"/>
271<polygon fill="black" stroke="black" points="1189.45,-734.06 1200.05,-733.86 1191.64,-727.41 1189.45,-734.06"/>
272</g>
273<!-- n00000081&#45;&gt;n00000009 -->
274<g id="edge3" class="edge">
275<title>n00000081:port3&#45;&gt;n00000009</title>
276<path fill="none" stroke="black" stroke-dasharray="5,2" d="M977.28,-700.28C977.28,-700.28 979.31,-698.81 982.45,-696.54"/>
277<polygon fill="black" stroke="black" points="984.7,-699.23 990.74,-690.53 980.59,-693.56 984.7,-699.23"/>
278</g>
279<!-- n00000081&#45;&gt;n0000000d -->
280<g id="edge4" class="edge">
281<title>n00000081:port4&#45;&gt;n0000000d</title>
282<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1003.38,-700.26C1003.38,-700.26 916.62,-689.8 909.08,-697.08 880.2,-725.01 885.68,-754.82 909.08,-787.48 910.88,-789.99 918.96,-793.59 929.7,-797.47"/>
283<polygon fill="black" stroke="black" points="928.69,-800.82 939.28,-800.79 930.98,-794.21 928.69,-800.82"/>
284</g>
285<!-- n00000081&#45;&gt;n00000011 -->
286<g id="edge5" class="edge">
287<title>n00000081:port5&#45;&gt;n00000011</title>
288<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1029.19,-700.26C1029.19,-700.26 1115.28,-690.56 1123.48,-697.08 1198.37,-756.64 1190.55,-886.51 1182.64,-944.71"/>
289<polygon fill="black" stroke="black" points="1179.16,-944.31 1181.18,-954.71 1186.09,-945.32 1179.16,-944.31"/>
290</g>
291<!-- n00000081&#45;&gt;n00000015 -->
292<g id="edge6" class="edge">
293<title>n00000081:port6&#45;&gt;n00000015</title>
294<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1055.18,-700.28C1055.18,-700.28 915.57,-692.2 909.08,-697.08 834.02,-753.51 831.79,-879.34 835.06,-936.56"/>
295<polygon fill="black" stroke="black" points="831.58,-936.99 835.74,-946.73 838.56,-936.52 831.58,-936.99"/>
296</g>
297<!-- n00000081&#45;&gt;n00000019 -->
298<g id="edge7" class="edge">
299<title>n00000081:port7&#45;&gt;n00000019</title>
300<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1081.28,-700.28C1081.28,-700.28 916.04,-696.54 912.32,-693.67 864.52,-656.73 856.3,-580.22 855.62,-538.2"/>
301<polygon fill="black" stroke="black" points="859.11,-538.05 855.59,-528.06 852.11,-538.07 859.11,-538.05"/>
302</g>
303<!-- n00000081&#45;&gt;n0000001d -->
304<g id="edge8" class="edge">
305<title>n00000081:port8&#45;&gt;n0000001d</title>
306<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1107.28,-700.28C1107.28,-700.28 1119.29,-696.23 1121.72,-693.67 1159.76,-653.62 1177.38,-589.6 1184.78,-552.46"/>
307<polygon fill="black" stroke="black" points="1188.29,-552.76 1186.69,-542.29 1181.41,-551.47 1188.29,-552.76"/>
308</g>
309<!-- n0000008b -->
310<g id="node34" class="node">
311<title>n0000008b</title>
312<path fill="green" stroke="black" d="M293.1,-532.08C293.1,-532.08 477.1,-532.08 477.1,-532.08 483.1,-532.08 489.1,-538.08 489.1,-544.08 489.1,-544.08 489.1,-604.08 489.1,-604.08 489.1,-610.08 483.1,-616.08 477.1,-616.08 477.1,-616.08 293.1,-616.08 293.1,-616.08 287.1,-616.08 281.1,-610.08 281.1,-604.08 281.1,-604.08 281.1,-544.08 281.1,-544.08 281.1,-538.08 287.1,-532.08 293.1,-532.08"/>
313<text text-anchor="middle" x="385.1" y="-600.88" font-family="Times,serif" font-size="14.00">0</text>
314<polyline fill="none" stroke="black" points="281.1,-593.08 489.1,-593.08 "/>
315<text text-anchor="middle" x="385.1" y="-577.88" font-family="Times,serif" font-size="14.00">Intel IPU6 CSI2 1</text>
316<text text-anchor="middle" x="385.1" y="-562.88" font-family="Times,serif" font-size="14.00">/dev/v4l&#45;subdev1</text>
317<polyline fill="none" stroke="black" points="281.1,-555.08 489.1,-555.08 "/>
318<text text-anchor="middle" x="294.1" y="-539.88" font-family="Times,serif" font-size="14.00">1</text>
319<polyline fill="none" stroke="black" points="307.1,-532.08 307.1,-555.08 "/>
320<text text-anchor="middle" x="320.1" y="-539.88" font-family="Times,serif" font-size="14.00">2</text>
321<polyline fill="none" stroke="black" points="333.1,-532.08 333.1,-555.08 "/>
322<text text-anchor="middle" x="346.1" y="-539.88" font-family="Times,serif" font-size="14.00">3</text>
323<polyline fill="none" stroke="black" points="359.1,-532.08 359.1,-555.08 "/>
324<text text-anchor="middle" x="372.1" y="-539.88" font-family="Times,serif" font-size="14.00">4</text>
325<polyline fill="none" stroke="black" points="385.1,-532.08 385.1,-555.08 "/>
326<text text-anchor="middle" x="398.1" y="-539.88" font-family="Times,serif" font-size="14.00">5</text>
327<polyline fill="none" stroke="black" points="411.1,-532.08 411.1,-555.08 "/>
328<text text-anchor="middle" x="424.1" y="-539.88" font-family="Times,serif" font-size="14.00">6</text>
329<polyline fill="none" stroke="black" points="437.1,-532.08 437.1,-555.08 "/>
330<text text-anchor="middle" x="450.1" y="-539.88" font-family="Times,serif" font-size="14.00">7</text>
331<polyline fill="none" stroke="black" points="463.1,-532.08 463.1,-555.08 "/>
332<text text-anchor="middle" x="476.1" y="-539.88" font-family="Times,serif" font-size="14.00">8</text>
333</g>
334<!-- n0000008b&#45;&gt;n00000021 -->
335<g id="edge9" class="edge">
336<title>n0000008b:port1&#45;&gt;n00000021</title>
337<path fill="none" stroke="black" d="M281.1,-543.08C281.1,-543.08 240.1,-560.51 205.94,-570.26 205.35,-570.43 204.77,-570.59 204.18,-570.76"/>
338<polygon fill="black" stroke="black" points="203.2,-567.39 194.47,-573.39 205.03,-574.15 203.2,-567.39"/>
339</g>
340<!-- n0000008b&#45;&gt;n00000025 -->
341<g id="edge10" class="edge">
342<title>n0000008b:port2&#45;&gt;n00000025</title>
343<path fill="none" stroke="black" d="M320.2,-532.07C320.2,-532.07 456.9,-514.37 492.3,-528.88 528.42,-543.68 522.86,-571.78 556.11,-594.53"/>
344<polygon fill="black" stroke="black" points="554.54,-597.67 564.9,-599.88 558.18,-591.69 554.54,-597.67"/>
345</g>
346<!-- n0000008b&#45;&gt;n00000029 -->
347<g id="edge11" class="edge">
348<title>n0000008b:port3&#45;&gt;n00000029</title>
349<path fill="none" stroke="black" stroke-dasharray="5,2" d="M346.1,-532.08C346.1,-532.08 333.93,-527.96 318.37,-522.71"/>
350<polygon fill="black" stroke="black" points="319.48,-519.39 308.88,-519.5 317.24,-526.02 319.48,-519.39"/>
351</g>
352<!-- n0000008b&#45;&gt;n0000002d -->
353<g id="edge12" class="edge">
354<title>n0000008b:port4&#45;&gt;n0000002d</title>
355<path fill="none" stroke="black" stroke-dasharray="5,2" d="M372.19,-532.05C372.19,-532.05 292.97,-514.3 277.9,-528.88 249.01,-556.8 253.16,-587.62 277.9,-619.28 278.34,-619.85 280.33,-620.69 283.45,-621.71"/>
356<polygon fill="black" stroke="black" points="282.71,-625.14 293.29,-624.58 284.67,-618.42 282.71,-625.14"/>
357</g>
358<!-- n0000008b&#45;&gt;n00000031 -->
359<g id="edge13" class="edge">
360<title>n0000008b:port5&#45;&gt;n00000031</title>
361<path fill="none" stroke="black" stroke-dasharray="5,2" d="M398,-532.05C398,-532.05 476.28,-515.34 492.3,-528.88 568.49,-593.29 550.55,-729.67 538.14,-789.41"/>
362<polygon fill="black" stroke="black" points="534.69,-788.79 535.99,-799.31 541.53,-790.28 534.69,-788.79"/>
363</g>
364<!-- n0000008b&#45;&gt;n00000035 -->
365<g id="edge14" class="edge">
366<title>n0000008b:port6&#45;&gt;n00000035</title>
367<path fill="none" stroke="black" stroke-dasharray="5,2" d="M424,-532.07C424,-532.07 290.37,-518.48 277.9,-528.88 202.27,-591.86 215.34,-725.69 225.66,-785.15"/>
368<polygon fill="black" stroke="black" points="222.29,-786.14 227.54,-795.35 229.17,-784.88 222.29,-786.14"/>
369</g>
370<!-- n0000008b&#45;&gt;n00000039 -->
371<g id="edge15" class="edge">
372<title>n0000008b:port7&#45;&gt;n00000039</title>
373<path fill="none" stroke="black" stroke-dasharray="5,2" d="M450.1,-532.08C450.1,-532.08 395.22,-528.13 383.45,-518.65 375.46,-512.21 322.64,-385.46 298.76,-327.47"/>
374<polygon fill="black" stroke="black" points="301.96,-326.05 294.92,-318.14 295.49,-328.72 301.96,-326.05"/>
375</g>
376<!-- n0000008b&#45;&gt;n0000003d -->
377<g id="edge16" class="edge">
378<title>n0000008b:port8&#45;&gt;n0000003d</title>
379<path fill="none" stroke="black" stroke-dasharray="5,2" d="M476.1,-532.08C476.1,-532.08 522.37,-522.39 526.85,-518.65 563.15,-488.33 581.38,-434.52 589.6,-401.2"/>
380<polygon fill="black" stroke="black" points="593.08,-401.69 591.93,-391.16 586.26,-400.11 593.08,-401.69"/>
381</g>
382<!-- n00000095 -->
383<g id="node35" class="node">
384<title>n00000095</title>
385<path fill="green" stroke="black" d="M301.38,-1180.11C301.38,-1180.11 485.38,-1180.11 485.38,-1180.11 491.38,-1180.11 497.38,-1186.11 497.38,-1192.11 497.38,-1192.11 497.38,-1252.11 497.38,-1252.11 497.38,-1258.11 491.38,-1264.11 485.38,-1264.11 485.38,-1264.11 301.38,-1264.11 301.38,-1264.11 295.38,-1264.11 289.38,-1258.11 289.38,-1252.11 289.38,-1252.11 289.38,-1192.11 289.38,-1192.11 289.38,-1186.11 295.38,-1180.11 301.38,-1180.11"/>
386<text text-anchor="middle" x="393.38" y="-1248.91" font-family="Times,serif" font-size="14.00">0</text>
387<polyline fill="none" stroke="black" points="289.38,-1241.11 497.38,-1241.11 "/>
388<text text-anchor="middle" x="393.38" y="-1225.91" font-family="Times,serif" font-size="14.00">Intel IPU6 CSI2 2</text>
389<text text-anchor="middle" x="393.38" y="-1210.91" font-family="Times,serif" font-size="14.00">/dev/v4l&#45;subdev2</text>
390<polyline fill="none" stroke="black" points="289.38,-1203.11 497.38,-1203.11 "/>
391<text text-anchor="middle" x="302.38" y="-1187.91" font-family="Times,serif" font-size="14.00">1</text>
392<polyline fill="none" stroke="black" points="315.38,-1180.11 315.38,-1203.11 "/>
393<text text-anchor="middle" x="328.38" y="-1187.91" font-family="Times,serif" font-size="14.00">2</text>
394<polyline fill="none" stroke="black" points="341.38,-1180.11 341.38,-1203.11 "/>
395<text text-anchor="middle" x="354.38" y="-1187.91" font-family="Times,serif" font-size="14.00">3</text>
396<polyline fill="none" stroke="black" points="367.38,-1180.11 367.38,-1203.11 "/>
397<text text-anchor="middle" x="380.38" y="-1187.91" font-family="Times,serif" font-size="14.00">4</text>
398<polyline fill="none" stroke="black" points="393.38,-1180.11 393.38,-1203.11 "/>
399<text text-anchor="middle" x="406.38" y="-1187.91" font-family="Times,serif" font-size="14.00">5</text>
400<polyline fill="none" stroke="black" points="419.38,-1180.11 419.38,-1203.11 "/>
401<text text-anchor="middle" x="432.38" y="-1187.91" font-family="Times,serif" font-size="14.00">6</text>
402<polyline fill="none" stroke="black" points="445.38,-1180.11 445.38,-1203.11 "/>
403<text text-anchor="middle" x="458.38" y="-1187.91" font-family="Times,serif" font-size="14.00">7</text>
404<polyline fill="none" stroke="black" points="471.38,-1180.11 471.38,-1203.11 "/>
405<text text-anchor="middle" x="484.38" y="-1187.91" font-family="Times,serif" font-size="14.00">8</text>
406</g>
407<!-- n00000095&#45;&gt;n00000041 -->
408<g id="edge17" class="edge">
409<title>n00000095:port1&#45;&gt;n00000041</title>
410<path fill="none" stroke="black" stroke-dasharray="5,2" d="M289.38,-1191.11C289.38,-1191.11 258.94,-1194.22 222.89,-1197.91"/>
411<polygon fill="black" stroke="black" points="222.19,-1194.46 212.6,-1198.96 222.9,-1201.42 222.19,-1194.46"/>
412</g>
413<!-- n00000095&#45;&gt;n00000045 -->
414<g id="edge18" class="edge">
415<title>n00000095:port2&#45;&gt;n00000045</title>
416<path fill="none" stroke="black" stroke-dasharray="5,2" d="M328.48,-1180.11C328.48,-1180.11 463.26,-1168.53 500.58,-1176.91 534.02,-1184.43 537.24,-1200.06 569.66,-1211.18 569.76,-1211.22 569.86,-1211.25 569.96,-1211.29"/>
417<polygon fill="black" stroke="black" points="568.86,-1214.61 579.45,-1214.34 571,-1207.95 568.86,-1214.61"/>
418</g>
419<!-- n00000095&#45;&gt;n00000049 -->
420<g id="edge19" class="edge">
421<title>n00000095:port3&#45;&gt;n00000049</title>
422<path fill="none" stroke="black" stroke-dasharray="5,2" d="M354.38,-1180.11C354.38,-1180.11 356.8,-1178.46 360.49,-1175.94"/>
423<polygon fill="black" stroke="black" points="362.56,-1178.77 368.86,-1170.24 358.62,-1172.98 362.56,-1178.77"/>
424</g>
425<!-- n00000095&#45;&gt;n0000004d -->
426<g id="edge20" class="edge">
427<title>n00000095:port4&#45;&gt;n0000004d</title>
428<path fill="none" stroke="black" stroke-dasharray="5,2" d="M380.47,-1180.09C380.47,-1180.09 293.71,-1169.63 286.18,-1176.91 257.29,-1204.84 262.63,-1234.76 286.18,-1267.31 288.16,-1270.05 297.33,-1273.96 309.38,-1278.13"/>
429<polygon fill="black" stroke="black" points="308.49,-1281.53 319.09,-1281.36 310.7,-1274.88 308.49,-1281.53"/>
430</g>
431<!-- n00000095&#45;&gt;n00000051 -->
432<g id="edge21" class="edge">
433<title>n00000095:port5&#45;&gt;n00000051</title>
434<path fill="none" stroke="black" stroke-dasharray="5,2" d="M406.28,-1180.09C406.28,-1180.09 492.13,-1170.7 500.58,-1176.91 576.41,-1232.66 579.83,-1358.79 577.09,-1416.2"/>
435<polygon fill="black" stroke="black" points="573.59,-1416.23 576.51,-1426.41 580.58,-1416.63 573.59,-1416.23"/>
436</g>
437<!-- n00000095&#45;&gt;n00000055 -->
438<g id="edge22" class="edge">
439<title>n00000095:port6&#45;&gt;n00000055</title>
440<path fill="none" stroke="black" stroke-dasharray="5,2" d="M432.28,-1180.11C432.28,-1180.11 292.85,-1172.29 286.18,-1176.91 211.26,-1228.86 198.3,-1348.49 196.45,-1404.12"/>
441<polygon fill="black" stroke="black" points="192.94,-1404.28 196.21,-1414.36 199.94,-1404.44 192.94,-1404.28"/>
442</g>
443<!-- n00000095&#45;&gt;n00000059 -->
444<g id="edge23" class="edge">
445<title>n00000095:port7&#45;&gt;n00000059</title>
446<path fill="none" stroke="black" stroke-dasharray="5,2" d="M458.38,-1180.11C458.38,-1180.11 291.84,-1175.85 287.94,-1173.16 239.87,-1139.96 222.85,-1068.83 216.94,-1028.6"/>
447<polygon fill="black" stroke="black" points="220.39,-1028.06 215.6,-1018.61 213.46,-1028.98 220.39,-1028.06"/>
448</g>
449<!-- n00000095&#45;&gt;n0000005d -->
450<g id="edge24" class="edge">
451<title>n00000095:port8&#45;&gt;n0000005d</title>
452<path fill="none" stroke="black" stroke-dasharray="5,2" d="M484.38,-1180.11C484.38,-1180.11 502.45,-1176.49 506.34,-1173.16 547.25,-1138.2 569.47,-1077.38 579.62,-1041.41"/>
453<polygon fill="black" stroke="black" points="583.06,-1042.09 582.28,-1031.53 576.3,-1040.27 583.06,-1042.09"/>
454</g>
455<!-- n0000009f -->
456<g id="node36" class="node">
457<title>n0000009f</title>
458<path fill="green" stroke="black" d="M1211.38,-200.11C1211.38,-200.11 1395.38,-200.11 1395.38,-200.11 1401.38,-200.11 1407.38,-206.11 1407.38,-212.11 1407.38,-212.11 1407.38,-272.11 1407.38,-272.11 1407.38,-278.11 1401.38,-284.11 1395.38,-284.11 1395.38,-284.11 1211.38,-284.11 1211.38,-284.11 1205.38,-284.11 1199.38,-278.11 1199.38,-272.11 1199.38,-272.11 1199.38,-212.11 1199.38,-212.11 1199.38,-206.11 1205.38,-200.11 1211.38,-200.11"/>
459<text text-anchor="middle" x="1303.38" y="-268.91" font-family="Times,serif" font-size="14.00">0</text>
460<polyline fill="none" stroke="black" points="1199.38,-261.11 1407.38,-261.11 "/>
461<text text-anchor="middle" x="1303.38" y="-245.91" font-family="Times,serif" font-size="14.00">Intel IPU6 CSI2 3</text>
462<text text-anchor="middle" x="1303.38" y="-230.91" font-family="Times,serif" font-size="14.00">/dev/v4l&#45;subdev3</text>
463<polyline fill="none" stroke="black" points="1199.38,-223.11 1407.38,-223.11 "/>
464<text text-anchor="middle" x="1212.38" y="-207.91" font-family="Times,serif" font-size="14.00">1</text>
465<polyline fill="none" stroke="black" points="1225.38,-200.11 1225.38,-223.11 "/>
466<text text-anchor="middle" x="1238.38" y="-207.91" font-family="Times,serif" font-size="14.00">2</text>
467<polyline fill="none" stroke="black" points="1251.38,-200.11 1251.38,-223.11 "/>
468<text text-anchor="middle" x="1264.38" y="-207.91" font-family="Times,serif" font-size="14.00">3</text>
469<polyline fill="none" stroke="black" points="1277.38,-200.11 1277.38,-223.11 "/>
470<text text-anchor="middle" x="1290.38" y="-207.91" font-family="Times,serif" font-size="14.00">4</text>
471<polyline fill="none" stroke="black" points="1303.38,-200.11 1303.38,-223.11 "/>
472<text text-anchor="middle" x="1316.38" y="-207.91" font-family="Times,serif" font-size="14.00">5</text>
473<polyline fill="none" stroke="black" points="1329.38,-200.11 1329.38,-223.11 "/>
474<text text-anchor="middle" x="1342.38" y="-207.91" font-family="Times,serif" font-size="14.00">6</text>
475<polyline fill="none" stroke="black" points="1355.38,-200.11 1355.38,-223.11 "/>
476<text text-anchor="middle" x="1368.38" y="-207.91" font-family="Times,serif" font-size="14.00">7</text>
477<polyline fill="none" stroke="black" points="1381.38,-200.11 1381.38,-223.11 "/>
478<text text-anchor="middle" x="1394.38" y="-207.91" font-family="Times,serif" font-size="14.00">8</text>
479</g>
480<!-- n0000009f&#45;&gt;n00000061 -->
481<g id="edge25" class="edge">
482<title>n0000009f:port1&#45;&gt;n00000061</title>
483<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1199.38,-211.11C1199.38,-211.11 1168.94,-214.22 1132.89,-217.91"/>
484<polygon fill="black" stroke="black" points="1132.19,-214.46 1122.6,-218.96 1132.9,-221.42 1132.19,-214.46"/>
485</g>
486<!-- n0000009f&#45;&gt;n00000065 -->
487<g id="edge26" class="edge">
488<title>n0000009f:port2&#45;&gt;n00000065</title>
489<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1238.48,-200.11C1238.48,-200.11 1373.26,-188.53 1410.58,-196.91 1444.02,-204.43 1447.24,-220.06 1479.66,-231.18 1479.76,-231.22 1479.86,-231.25 1479.96,-231.29"/>
490<polygon fill="black" stroke="black" points="1478.86,-234.61 1489.45,-234.34 1481,-227.95 1478.86,-234.61"/>
491</g>
492<!-- n0000009f&#45;&gt;n00000069 -->
493<g id="edge27" class="edge">
494<title>n0000009f:port3&#45;&gt;n00000069</title>
495<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1264.38,-200.11C1264.38,-200.11 1266.8,-198.46 1270.49,-195.94"/>
496<polygon fill="black" stroke="black" points="1272.56,-198.77 1278.86,-190.24 1268.62,-192.98 1272.56,-198.77"/>
497</g>
498<!-- n0000009f&#45;&gt;n0000006d -->
499<g id="edge28" class="edge">
500<title>n0000009f:port4&#45;&gt;n0000006d</title>
501<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1290.47,-200.09C1290.47,-200.09 1203.71,-189.63 1196.18,-196.91 1167.29,-224.84 1172.63,-254.76 1196.18,-287.31 1198.16,-290.05 1207.33,-293.96 1219.38,-298.13"/>
502<polygon fill="black" stroke="black" points="1218.49,-301.53 1229.09,-301.36 1220.7,-294.88 1218.49,-301.53"/>
503</g>
504<!-- n0000009f&#45;&gt;n00000071 -->
505<g id="edge29" class="edge">
506<title>n0000009f:port5&#45;&gt;n00000071</title>
507<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1316.28,-200.09C1316.28,-200.09 1402.13,-190.7 1410.58,-196.91 1486.41,-252.66 1489.83,-378.79 1487.09,-436.2"/>
508<polygon fill="black" stroke="black" points="1483.59,-436.23 1486.51,-446.41 1490.58,-436.63 1483.59,-436.23"/>
509</g>
510<!-- n0000009f&#45;&gt;n00000075 -->
511<g id="edge30" class="edge">
512<title>n0000009f:port6&#45;&gt;n00000075</title>
513<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1342.28,-200.11C1342.28,-200.11 1202.85,-192.29 1196.18,-196.91 1121.26,-248.86 1108.3,-368.49 1106.45,-424.12"/>
514<polygon fill="black" stroke="black" points="1102.94,-424.28 1106.21,-434.36 1109.94,-424.44 1102.94,-424.28"/>
515</g>
516<!-- n0000009f&#45;&gt;n00000079 -->
517<g id="edge31" class="edge">
518<title>n0000009f:port7&#45;&gt;n00000079</title>
519<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1368.38,-200.11C1368.38,-200.11 1201.84,-195.85 1197.94,-193.16 1149.87,-159.96 1132.85,-88.83 1126.94,-48.6"/>
520<polygon fill="black" stroke="black" points="1130.39,-48.06 1125.6,-38.61 1123.46,-48.98 1130.39,-48.06"/>
521</g>
522<!-- n0000009f&#45;&gt;n0000007d -->
523<g id="edge32" class="edge">
524<title>n0000009f:port8&#45;&gt;n0000007d</title>
525<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1394.38,-200.11C1394.38,-200.11 1412.45,-196.49 1416.34,-193.16 1457.25,-158.2 1479.47,-97.38 1489.62,-61.41"/>
526<polygon fill="black" stroke="black" points="1493.06,-62.09 1492.28,-51.53 1486.3,-60.27 1493.06,-62.09"/>
527</g>
528<!-- n000000e9 -->
529<g id="node37" class="node">
530<title>n000000e9</title>
531<path fill="green" stroke="black" d="M398.65,-431.45C398.65,-431.45 511.65,-431.45 511.65,-431.45 517.65,-431.45 523.65,-437.45 523.65,-443.45 523.65,-443.45 523.65,-503.45 523.65,-503.45 523.65,-509.45 517.65,-515.45 511.65,-515.45 511.65,-515.45 398.65,-515.45 398.65,-515.45 392.65,-515.45 386.65,-509.45 386.65,-503.45 386.65,-503.45 386.65,-443.45 386.65,-443.45 386.65,-437.45 392.65,-431.45 398.65,-431.45"/>
532<text text-anchor="middle" x="420.65" y="-500.25" font-family="Times,serif" font-size="14.00">1</text>
533<polyline fill="none" stroke="black" points="454.65,-492.45 454.65,-515.45 "/>
534<text text-anchor="middle" x="489.15" y="-500.25" font-family="Times,serif" font-size="14.00">2</text>
535<polyline fill="none" stroke="black" points="386.65,-492.45 523.65,-492.45 "/>
536<text text-anchor="middle" x="455.15" y="-477.25" font-family="Times,serif" font-size="14.00">ov2740 4&#45;0036</text>
537<text text-anchor="middle" x="455.15" y="-462.25" font-family="Times,serif" font-size="14.00">/dev/v4l&#45;subdev4</text>
538<polyline fill="none" stroke="black" points="386.65,-454.45 523.65,-454.45 "/>
539<text text-anchor="middle" x="455.15" y="-439.25" font-family="Times,serif" font-size="14.00">0</text>
540</g>
541<!-- n000000e9&#45;&gt;n0000008b -->
542<g id="edge33" class="edge">
543<title>n000000e9:port0&#45;&gt;n0000008b:port0</title>
544<path fill="none" stroke="black" stroke-width="2" d="M386.14,-442.55C386.14,-442.55 361.11,-493.23 383.45,-518.65 391.47,-527.78 484.31,-519.72 492.3,-528.88 508.64,-547.6 499.26,-579.87 493.12,-595.68"/>
545<polygon fill="black" stroke="black" stroke-width="2" points="489.86,-594.41 489.11,-604.98 496.29,-597.19 489.86,-594.41"/>
546</g>
547</g>
548</svg>
Documentation/admin-guide/media/mgb4.rst+15−20
@@ -1,8 +1,10 @@
1.. SPDX-License-Identifier: GPL-2.01.. SPDX-License-Identifier: GPL-2.0
2 2
3====================3The mgb4 driver
4mgb4 sysfs interface4===============
5====================5
6sysfs interface
7---------------
6 8
7The mgb4 driver provides a sysfs interface, that is used to configure video9The mgb4 driver provides a sysfs interface, that is used to configure video
8stream related parameters (some of them must be set properly before the v4l210stream related parameters (some of them must be set properly before the v4l2
@@ -12,9 +14,8 @@ There are two types of parameters - global / PCI card related, found under · 3 unmodified lines
12``/sys/class/video4linux/videoX/device`` and module specific found under14``/sys/class/video4linux/videoX/device`` and module specific found under
13``/sys/class/video4linux/videoX``.15``/sys/class/video4linux/videoX``.
14 16
15
16Global (PCI card) parameters17Global (PCI card) parameters
17============================18~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 19
19**module_type** (R):20**module_type** (R):
20 Module type.21 Module type.
@@ -42,9 +43,8 @@ Global (PCI card) parameters · 21 unmodified lines
42 43
43 where each component is a 8b number.44 where each component is a 8b number.
44 45
45
46Common FPDL3/GMSL input parameters46Common FPDL3/GMSL input parameters
47==================================47~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48 48
49**input_id** (R):49**input_id** (R):
50 Input number ID, zero based.50 Input number ID, zero based.
@@ -190,9 +190,8 @@ Common FPDL3/GMSL input parameters · 139 unmodified lines
190 *Note: This parameter can not be changed while the input v4l2 device is190 *Note: This parameter can not be changed while the input v4l2 device is
191 open.*191 open.*
192 192
193
194Common FPDL3/GMSL output parameters193Common FPDL3/GMSL output parameters
195===================================194~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196 195
197**output_id** (R):196**output_id** (R):
198 Output number ID, zero based.197 Output number ID, zero based.
@@ -282,9 +281,8 @@ Common FPDL3/GMSL output parameters · 83 unmodified lines
282 Number of video lines between the end of the last valid pixel line (marked281 Number of video lines between the end of the last valid pixel line (marked
283 by DE=1) and assertion of the VSYNC signal. The default value is 2.282 by DE=1) and assertion of the VSYNC signal. The default value is 2.
284 283
285
286FPDL3 specific input parameters284FPDL3 specific input parameters
287===============================285~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
288 286
289**fpdl3_input_width** (RW):287**fpdl3_input_width** (RW):
290 Number of deserializer input lines.288 Number of deserializer input lines.
@@ -294,7 +292,7 @@ FPDL3 specific input parameters · 3 unmodified lines
294 | 2 - dual292 | 2 - dual
295 293
296FPDL3 specific output parameters294FPDL3 specific output parameters
297================================295~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298 296
299**fpdl3_output_width** (RW):297**fpdl3_output_width** (RW):
300 Number of serializer output lines.298 Number of serializer output lines.
@@ -304,7 +302,7 @@ FPDL3 specific output parameters · 3 unmodified lines
304 | 2 - dual302 | 2 - dual
305 303
306GMSL specific input parameters304GMSL specific input parameters
307==============================305~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
308 306
309**gmsl_mode** (RW):307**gmsl_mode** (RW):
310 GMSL speed mode.308 GMSL speed mode.
@@ -328,10 +326,8 @@ GMSL specific input parameters · 17 unmodified lines
328 | 0 - disabled326 | 0 - disabled
329 | 1 - enabled (default)327 | 1 - enabled (default)
330 328
331 329MTD partitions
332====================330--------------
333mgb4 mtd partitions
334====================
335 331
336The mgb4 driver creates a MTD device with two partitions:332The mgb4 driver creates a MTD device with two partitions:
337 - mgb4-fw.X - FPGA firmware.333 - mgb4-fw.X - FPGA firmware.
@@ -344,9 +340,8 @@ also have a third partition named *mgb4-flash* available in the system. This · 6 unmodified lines
344partition represents the whole, unpartitioned, card's FLASH memory and one should340partition represents the whole, unpartitioned, card's FLASH memory and one should
345not fiddle with it...341not fiddle with it...
346 342
347====================343IIO (triggers)
348mgb4 iio (triggers)344--------------
349====================
350 345
351The mgb4 driver creates an Industrial I/O (IIO) device that provides trigger and346The mgb4 driver creates an Industrial I/O (IIO) device that provides trigger and
352signal level status capability. The following scan elements are available:347signal level status capability. The following scan elements are available:
Documentation/admin-guide/media/v4l-drivers.rst+1−0
@@ -16,6 +16,7 @@ Video4Linux (V4L) driver-specific documentation · 15 unmodified lines
16 imx16 imx
17 imx717 imx7
18 ipu318 ipu3
19 ipu6-isys
19 ivtv20 ivtv
20 mgb421 mgb4
21 omap3isp22 omap3isp
Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml+127−0
@@ -0,0 +1,127 @@
1# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/media/brcm,bcm2835-unicam.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: Broadcom BCM283x Camera Interface (Unicam)
8
9maintainers:
10 - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
11
12description: |-
13 The Unicam block on BCM283x SoCs is the receiver for either
14 CSI-2 or CCP2 data from image sensors or similar devices.
15
16 The main platform using this SoC is the Raspberry Pi family of boards. On
17 the Pi the VideoCore firmware can also control this hardware block, and
18 driving it from two different processors will cause issues. To avoid this,
19 the firmware checks the device tree configuration during boot. If it finds
20 device tree nodes whose name starts with 'csi' then it will stop the firmware
21 accessing the block, and it can then safely be used via the device tree
22 binding.
23
24properties:
25 compatible:
26 const: brcm,bcm2835-unicam
27
28 reg:
29 items:
30 - description: Unicam block.
31 - description: Clock Manager Image (CMI) block.
32
33 reg-names:
34 items:
35 - const: unicam
36 - const: cmi
37
38 interrupts:
39 maxItems: 1
40
41 clocks:
42 items:
43 - description: Clock to drive the LP state machine of Unicam.
44 - description: Clock for the VPU (core clock).
45
46 clock-names:
47 items:
48 - const: lp
49 - const: vpu
50
51 power-domains:
52 items:
53 - description: Unicam power domain
54
55 brcm,num-data-lanes:
56 $ref: /schemas/types.yaml#/definitions/uint32
57 enum: [ 2, 4 ]
58 description: |
59 Number of CSI-2 data lanes supported by this Unicam instance. The number
60 of data lanes actively used is specified with the data-lanes endpoint
61 property.
62
63 port:
64 $ref: /schemas/graph.yaml#/$defs/port-base
65 unevaluatedProperties: false
66
67 properties:
68 endpoint:
69 $ref: /schemas/media/video-interfaces.yaml#
70 additionalProperties: false
71
72 properties:
73 bus-type:
74 enum: [ 3, 4 ]
75
76 clock-noncontinuous: true
77 data-lanes: true
78 remote-endpoint: true
79
80 required:
81 - bus-type
82 - data-lanes
83 - remote-endpoint
84
85 required:
86 - endpoint
87
88required:
89 - compatible
90 - reg
91 - reg-names
92 - interrupts
93 - clocks
94 - clock-names
95 - power-domains
96 - brcm,num-data-lanes
97 - port
98
99additionalProperties: False
100
101examples:
102 - |
103 #include <dt-bindings/clock/bcm2835.h>
104 #include <dt-bindings/interrupt-controller/arm-gic.h>
105 #include <dt-bindings/media/video-interfaces.h>
106 #include <dt-bindings/power/raspberrypi-power.h>
107
108 csi1: csi@7e801000 {
109 compatible = "brcm,bcm2835-unicam";
110 reg = <0x7e801000 0x800>,
111 <0x7e802004 0x4>;
112 reg-names = "unicam", "cmi";
113 interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
114 clocks = <&clocks BCM2835_CLOCK_CAM1>,
115 <&firmware_clocks 4>;
116 clock-names = "lp", "vpu";
117 power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
118 brcm,num-data-lanes = <2>;
119 port {
120 csi1_ep: endpoint {
121 remote-endpoint = <&imx219_0>;
122 bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
123 data-lanes = <1 2>;
124 };
125 };
126 };
127...
Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml+1−1
@@ -15,7 +15,7 @@ description: | · 14 unmodified lines
15 They include an ISP capable of auto exposure and auto white balance.15 They include an ISP capable of auto exposure and auto white balance.
16 16
17allOf:17allOf:
18 - $ref: ../video-interface-devices.yaml#18 - $ref: /schemas/media/video-interface-devices.yaml#
19 19
20properties:20properties:
21 compatible:21 compatible:
Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml+1−1
@@ -19,7 +19,7 @@ description: · 18 unmodified lines
19 either through a parallel interface or through MIPI CSI-2.19 either through a parallel interface or through MIPI CSI-2.
20 20
21allOf:21allOf:
22 - $ref: ../video-interface-devices.yaml#22 - $ref: /schemas/media/video-interface-devices.yaml#
23 23
24properties:24properties:
25 compatible:25 compatible:
Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml+25−10
@@ -37,31 +37,45 @@ properties: · 36 unmodified lines
37 active low.37 active low.
38 maxItems: 138 maxItems: 1
39 39
40 dovdd-supply:40 DOVDD-supply:
41 description:41 description:
42 Definition of the regulator used as interface power supply.42 Definition of the regulator used as interface power supply.
43 43
44 avdd-supply:44 AVDD-supply:
45 description:45 description:
46 Definition of the regulator used as analog power supply.46 Definition of the regulator used as analog power supply.
47 47
48 dvdd-supply:48 DVDD-supply:
49 description:49 description:
50 Definition of the regulator used as digital power supply.50 Definition of the regulator used as digital power supply.
51 51
52 port:52 port:
53 $ref: /schemas/graph.yaml#/properties/port
54 description:53 description:
55 A node containing an output port node.54 A node containing an output port node.
55 $ref: /schemas/graph.yaml#/$defs/port-base
56 additionalProperties: false
57
58 properties:
59 endpoint:
60 $ref: /schemas/media/video-interfaces.yaml#
61 additionalProperties: false
62
63 properties:
64 link-frequencies: true
65
66 remote-endpoint: true
67
68 required:
69 - link-frequencies
56 70
57required:71required:
58 - compatible72 - compatible
59 - reg73 - reg
60 - clocks74 - clocks
61 - clock-names75 - clock-names
62 - dovdd-supply76 - DOVDD-supply
63 - avdd-supply77 - AVDD-supply
64 - dvdd-supply78 - DVDD-supply
65 - reset-gpios79 - reset-gpios
66 - port80 - port
67 81
@@ -82,13 +96,14 @@ examples: · 14 unmodified lines
82 clock-names = "xvclk";96 clock-names = "xvclk";
83 reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;97 reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
84 98
85 dovdd-supply = <&sw2_reg>;99 DOVDD-supply = <&sw2_reg>;
86 dvdd-supply = <&sw2_reg>;100 DVDD-supply = <&sw2_reg>;
87 avdd-supply = <&reg_peri_3p15v>;101 AVDD-supply = <&reg_peri_3p15v>;
88 102
89 port {103 port {
90 ov2680_to_mipi: endpoint {104 ov2680_to_mipi: endpoint {
91 remote-endpoint = <&mipi_from_sensor>;105 remote-endpoint = <&mipi_from_sensor>;
106 link-frequencies = /bits/ 64 <330000000>;
92 };107 };
93 };108 };
94 };109 };
Documentation/devicetree/bindings/media/i2c/ovti,ov8856.yamlrenamed from Documentation/devicetree/bindings/media/i2c/ov8856.yaml+1−1
@@ -2,7 +2,7 @@ · 1 unmodified line
2# Copyright (c) 2019 MediaTek Inc.2# Copyright (c) 2019 MediaTek Inc.
3%YAML 1.23%YAML 1.2
4---4---
5$id: http://devicetree.org/schemas/media/i2c/ov8856.yaml#5$id: http://devicetree.org/schemas/media/i2c/ovti,ov8856.yaml#
6$schema: http://devicetree.org/meta-schemas/core.yaml#6$schema: http://devicetree.org/meta-schemas/core.yaml#
7 7
8title: Omnivision OV8856 CMOS Sensor8title: Omnivision OV8856 CMOS Sensor
Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml+1−1
@@ -16,7 +16,7 @@ description: | · 15 unmodified lines
16 maximum throughput of 1.2Gbps/lane.16 maximum throughput of 1.2Gbps/lane.
17 17
18allOf:18allOf:
19 - $ref: ../video-interface-devices.yaml#19 - $ref: /schemas/media/video-interface-devices.yaml#
20 20
21properties:21properties:
22 compatible:22 compatible:
Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml+4−1
@@ -23,6 +23,9 @@ description: |- · 22 unmodified lines
23 is treated the same as this as it was the original compatible string.23 is treated the same as this as it was the original compatible string.
24 imx290llr is the mono version of the sensor.24 imx290llr is the mono version of the sensor.
25 25
26allOf:
27 - $ref: /schemas/media/video-interface-devices.yaml#
28
26properties:29properties:
27 compatible:30 compatible:
28 oneOf:31 oneOf:
@@ -101,7 +104,7 @@ required: · 72 unmodified lines
101 - vdddo-supply104 - vdddo-supply
102 - port105 - port
103 106
104additionalProperties: false107unevaluatedProperties: false
105 108
106examples:109examples:
107 - |110 - |
Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml+1−1
@@ -18,7 +18,7 @@ description: |- · 17 unmodified lines
18 available via CSI-2 serial data output (two or four lanes).18 available via CSI-2 serial data output (two or four lanes).
19 19
20allOf:20allOf:
21 - $ref: ../video-interface-devices.yaml#21 - $ref: /schemas/media/video-interface-devices.yaml#
22 22
23properties:23properties:
24 compatible:24 compatible:
Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml+1−0
@@ -84,6 +84,7 @@ allOf: · 83 unmodified lines
84 properties:84 properties:
85 port@0:85 port@0:
86 description: MIPI CSI-2 RX86 description: MIPI CSI-2 RX
87 port@1: false
87 required:88 required:
88 - port@089 - port@0
89 90
Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml+11−0
@@ -31,6 +31,11 @@ properties: · 30 unmodified lines
31 reg:31 reg:
32 maxItems: 132 maxItems: 1
33 33
34 clocks:
35 items:
36 - description: AXI DMA engine clock for fetching JPEG bitstream from memory (per)
37 - description: IP bus clock for register access (ipg)
38
34 interrupts:39 interrupts:
35 description: |40 description: |
36 There are 4 slots available in the IP, which the driver may use41 There are 4 slots available in the IP, which the driver may use
@@ -49,6 +54,7 @@ properties: · 12 unmodified lines
49required:54required:
50 - compatible55 - compatible
51 - reg56 - reg
57 - clocks
52 - interrupts58 - interrupts
53 - power-domains59 - power-domains
54 60
@@ -56,12 +62,15 @@ additionalProperties: false · 1 unmodified line
56 62
57examples:63examples:
58 - |64 - |
65 #include <dt-bindings/clock/imx8-lpcg.h>
59 #include <dt-bindings/interrupt-controller/arm-gic.h>66 #include <dt-bindings/interrupt-controller/arm-gic.h>
60 #include <dt-bindings/firmware/imx/rsrc.h>67 #include <dt-bindings/firmware/imx/rsrc.h>
61 68
62 jpegdec: jpegdec@58400000 {69 jpegdec: jpegdec@58400000 {
63 compatible = "nxp,imx8qxp-jpgdec";70 compatible = "nxp,imx8qxp-jpgdec";
64 reg = <0x58400000 0x00050000 >;71 reg = <0x58400000 0x00050000 >;
72 clocks = <&img_jpeg_dec_lpcg IMX_LPCG_CLK_0>,
73 <&img_jpeg_dec_lpcg IMX_LPCG_CLK_4>;
65 interrupts = <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,74 interrupts = <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
66 <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,75 <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
67 <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,76 <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,
@@ -76,6 +85,8 @@ examples: · 8 unmodified lines
76 jpegenc: jpegenc@58450000 {85 jpegenc: jpegenc@58450000 {
77 compatible = "nxp,imx8qm-jpgenc", "nxp,imx8qxp-jpgenc";86 compatible = "nxp,imx8qm-jpgenc", "nxp,imx8qxp-jpgenc";
78 reg = <0x58450000 0x00050000 >;87 reg = <0x58450000 0x00050000 >;
88 clocks = <&img_jpeg_enc_lpcg IMX_LPCG_CLK_0>,
89 <&img_jpeg__lpcg IMX_LPCG_CLK_4>;
79 interrupts = <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,90 interrupts = <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
80 <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,91 <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>,
81 <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,92 <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
Documentation/devicetree/bindings/media/qcom,sc8280xp-camss.yaml+512−0
@@ -0,0 +1,512 @@
1# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/media/qcom,sc8280xp-camss.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: Qualcomm SC8280XP Camera Subsystem (CAMSS)
8
9maintainers:
10 - Bryan O'Donoghue <bryan.odonoghue@linaro.org>
11
12description: |
13 The CAMSS IP is a CSI decoder and ISP present on Qualcomm platforms.
14
15properties:
16 compatible:
17 const: qcom,sc8280xp-camss
18
19 clocks:
20 maxItems: 40
21
22 clock-names:
23 items:
24 - const: camnoc_axi
25 - const: cpas_ahb
26 - const: csiphy0
27 - const: csiphy0_timer
28 - const: csiphy1
29 - const: csiphy1_timer
30 - const: csiphy2
31 - const: csiphy2_timer
32 - const: csiphy3
33 - const: csiphy3_timer
34 - const: vfe0_axi
35 - const: vfe0
36 - const: vfe0_cphy_rx
37 - const: vfe0_csid
38 - const: vfe1_axi
39 - const: vfe1
40 - const: vfe1_cphy_rx
41 - const: vfe1_csid
42 - const: vfe2_axi
43 - const: vfe2
44 - const: vfe2_cphy_rx
45 - const: vfe2_csid
46 - const: vfe3_axi
47 - const: vfe3
48 - const: vfe3_cphy_rx
49 - const: vfe3_csid
50 - const: vfe_lite0
51 - const: vfe_lite0_cphy_rx
52 - const: vfe_lite0_csid
53 - const: vfe_lite1
54 - const: vfe_lite1_cphy_rx
55 - const: vfe_lite1_csid
56 - const: vfe_lite2
57 - const: vfe_lite2_cphy_rx
58 - const: vfe_lite2_csid
59 - const: vfe_lite3
60 - const: vfe_lite3_cphy_rx
61 - const: vfe_lite3_csid
62 - const: gcc_axi_hf
63 - const: gcc_axi_sf
64
65 interrupts:
66 maxItems: 20
67
68 interrupt-names:
69 items:
70 - const: csid1_lite
71 - const: vfe_lite1
72 - const: csiphy3
73 - const: csid0
74 - const: vfe0
75 - const: csid1
76 - const: vfe1
77 - const: csid0_lite
78 - const: vfe_lite0
79 - const: csiphy0
80 - const: csiphy1
81 - const: csiphy2
82 - const: csid2
83 - const: vfe2
84 - const: csid3_lite
85 - const: csid2_lite
86 - const: vfe_lite3
87 - const: vfe_lite2
88 - const: csid3
89 - const: vfe3
90
91 iommus:
92 maxItems: 16
93
94 interconnects:
95 maxItems: 4
96
97 interconnect-names:
98 items:
99 - const: cam_ahb
100 - const: cam_hf_mnoc
101 - const: cam_sf_mnoc
102 - const: cam_sf_icp_mnoc
103
104 power-domains:
105 items:
106 - description: IFE0 GDSC - Image Front End, Global Distributed Switch Controller.
107 - description: IFE1 GDSC - Image Front End, Global Distributed Switch Controller.
108 - description: IFE2 GDSC - Image Front End, Global Distributed Switch Controller.
109 - description: IFE3 GDSC - Image Front End, Global Distributed Switch Controller.
110 - description: Titan Top GDSC - Titan ISP Block, Global Distributed Switch Controller.
111
112 power-domain-names:
113 items:
114 - const: ife0
115 - const: ife1
116 - const: ife2
117 - const: ife3
118 - const: top
119
120 ports:
121 $ref: /schemas/graph.yaml#/properties/ports
122
123 description:
124 CSI input ports.
125
126 properties:
127 port@0:
128 $ref: /schemas/graph.yaml#/$defs/port-base
129 unevaluatedProperties: false
130 description:
131 Input port for receiving CSI data from CSIPHY0.
132
133 properties:
134 endpoint:
135 $ref: video-interfaces.yaml#
136 unevaluatedProperties: false
137
138 properties:
139 clock-lanes:
140 maxItems: 1
141
142 data-lanes:
143 minItems: 1
144 maxItems: 4
145
146 required:
147 - clock-lanes
148 - data-lanes
149
150 port@1:
151 $ref: /schemas/graph.yaml#/$defs/port-base
152 unevaluatedProperties: false
153 description:
154 Input port for receiving CSI data from CSIPHY1.
155
156 properties:
157 endpoint:
158 $ref: video-interfaces.yaml#
159 unevaluatedProperties: false
160
161 properties:
162 clock-lanes:
163 maxItems: 1
164
165 data-lanes:
166 minItems: 1
167 maxItems: 4
168
169 required:
170 - clock-lanes
171 - data-lanes
172
173 port@2:
174 $ref: /schemas/graph.yaml#/$defs/port-base
175 unevaluatedProperties: false
176 description:
177 Input port for receiving CSI data from CSIPHY2.
178
179 properties:
180 endpoint:
181 $ref: video-interfaces.yaml#
182 unevaluatedProperties: false
183
184 properties:
185 clock-lanes:
186 maxItems: 1
187
188 data-lanes:
189 minItems: 1
190 maxItems: 4
191
192 required:
193 - clock-lanes
194 - data-lanes
195
196 port@3:
197 $ref: /schemas/graph.yaml#/$defs/port-base
198 unevaluatedProperties: false
199 description:
200 Input port for receiving CSI data from CSIPHY3.
201
202 properties:
203 endpoint:
204 $ref: video-interfaces.yaml#
205 unevaluatedProperties: false
206
207 properties:
208 clock-lanes:
209 maxItems: 1
210
211 data-lanes:
212 minItems: 1
213 maxItems: 4
214
215 required:
216 - clock-lanes
217 - data-lanes
218
219 reg:
220 maxItems: 20
221
222 reg-names:
223 items:
224 - const: csiphy2
225 - const: csiphy3
226 - const: csiphy0
227 - const: csiphy1
228 - const: vfe0
229 - const: csid0
230 - const: vfe1
231 - const: csid1
232 - const: vfe2
233 - const: csid2
234 - const: vfe_lite0
235 - const: csid0_lite
236 - const: vfe_lite1
237 - const: csid1_lite
238 - const: vfe_lite2
239 - const: csid2_lite
240 - const: vfe_lite3
241 - const: csid3_lite
242 - const: vfe3
243 - const: csid3
244
245 vdda-phy-supply:
246 description:
247 Phandle to a regulator supply to PHY core block.
248
249 vdda-pll-supply:
250 description:
251 Phandle to 1.8V regulator supply to PHY refclk pll block.
252
253required:
254 - clock-names
255 - clocks
256 - compatible
257 - interconnects
258 - interconnect-names
259 - interrupts
260 - interrupt-names
261 - iommus
262 - power-domains
263 - power-domain-names
264 - reg
265 - reg-names
266 - vdda-phy-supply
267 - vdda-pll-supply
268
269additionalProperties: false
270
271examples:
272 - |
273 #include <dt-bindings/interrupt-controller/arm-gic.h>
274 #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
275 #include <dt-bindings/clock/qcom,sc8280xp-camcc.h>
276 #include <dt-bindings/interconnect/qcom,sc8280xp.h>
277 #include <dt-bindings/power/qcom-rpmpd.h>
278
279 soc {
280 #address-cells = <2>;
281 #size-cells = <2>;
282
283 camss: camss@ac5a000 {
284 compatible = "qcom,sc8280xp-camss";
285
286 reg = <0 0x0ac5a000 0 0x2000>,
287 <0 0x0ac5c000 0 0x2000>,
288 <0 0x0ac65000 0 0x2000>,
289 <0 0x0ac67000 0 0x2000>,
290 <0 0x0acaf000 0 0x4000>,
291 <0 0x0acb3000 0 0x1000>,
292 <0 0x0acb6000 0 0x4000>,
293 <0 0x0acba000 0 0x1000>,
294 <0 0x0acbd000 0 0x4000>,
295 <0 0x0acc1000 0 0x1000>,
296 <0 0x0acc4000 0 0x4000>,
297 <0 0x0acc8000 0 0x1000>,
298 <0 0x0accb000 0 0x4000>,
299 <0 0x0accf000 0 0x1000>,
300 <0 0x0acd2000 0 0x4000>,
301 <0 0x0acd6000 0 0x1000>,
302 <0 0x0acd9000 0 0x4000>,
303 <0 0x0acdd000 0 0x1000>,
304 <0 0x0ace0000 0 0x4000>,
305 <0 0x0ace4000 0 0x1000>;
306
307 reg-names = "csiphy2",
308 "csiphy3",
309 "csiphy0",
310 "csiphy1",
311 "vfe0",
312 "csid0",
313 "vfe1",
314 "csid1",
315 "vfe2",
316 "csid2",
317 "vfe_lite0",
318 "csid0_lite",
319 "vfe_lite1",
320 "csid1_lite",
321 "vfe_lite2",
322 "csid2_lite",
323 "vfe_lite3",
324 "csid3_lite",
325 "vfe3",
326 "csid3";
327
328 vdda-phy-supply = <&vreg_l6d>;
329 vdda-pll-supply = <&vreg_l4d>;
330
331 interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
332 <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
333 <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
334 <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
335 <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
336 <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
337 <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
338 <GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
339 <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
340 <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
341 <GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
342 <GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>,
343 <GIC_SPI 640 IRQ_TYPE_LEVEL_HIGH>,
344 <GIC_SPI 641 IRQ_TYPE_LEVEL_HIGH>,
345 <GIC_SPI 758 IRQ_TYPE_LEVEL_HIGH>,
346 <GIC_SPI 759 IRQ_TYPE_LEVEL_HIGH>,
347 <GIC_SPI 760 IRQ_TYPE_LEVEL_HIGH>,
348 <GIC_SPI 761 IRQ_TYPE_LEVEL_HIGH>,
349 <GIC_SPI 762 IRQ_TYPE_LEVEL_HIGH>,
350 <GIC_SPI 764 IRQ_TYPE_LEVEL_HIGH>;
351
352 interrupt-names = "csid1_lite",
353 "vfe_lite1",
354 "csiphy3",
355 "csid0",
356 "vfe0",
357 "csid1",
358 "vfe1",
359 "csid0_lite",
360 "vfe_lite0",
361 "csiphy0",
362 "csiphy1",
363 "csiphy2",
364 "csid2",
365 "vfe2",
366 "csid3_lite",
367 "csid2_lite",
368 "vfe_lite3",
369 "vfe_lite2",
370 "csid3",
371 "vfe3";
372
373 power-domains = <&camcc IFE_0_GDSC>,
374 <&camcc IFE_1_GDSC>,
375 <&camcc IFE_2_GDSC>,
376 <&camcc IFE_3_GDSC>,
377 <&camcc TITAN_TOP_GDSC>;
378
379 power-domain-names = "ife0",
380 "ife1",
381 "ife2",
382 "ife3",
383 "top";
384
385 clocks = <&camcc CAMCC_CAMNOC_AXI_CLK>,
386 <&camcc CAMCC_CPAS_AHB_CLK>,
387 <&camcc CAMCC_CSIPHY0_CLK>,
388 <&camcc CAMCC_CSI0PHYTIMER_CLK>,
389 <&camcc CAMCC_CSIPHY1_CLK>,
390 <&camcc CAMCC_CSI1PHYTIMER_CLK>,
391 <&camcc CAMCC_CSIPHY2_CLK>,
392 <&camcc CAMCC_CSI2PHYTIMER_CLK>,
393 <&camcc CAMCC_CSIPHY3_CLK>,
394 <&camcc CAMCC_CSI3PHYTIMER_CLK>,
395 <&camcc CAMCC_IFE_0_AXI_CLK>,
396 <&camcc CAMCC_IFE_0_CLK>,
397 <&camcc CAMCC_IFE_0_CPHY_RX_CLK>,
398 <&camcc CAMCC_IFE_0_CSID_CLK>,
399 <&camcc CAMCC_IFE_1_AXI_CLK>,
400 <&camcc CAMCC_IFE_1_CLK>,
401 <&camcc CAMCC_IFE_1_CPHY_RX_CLK>,
402 <&camcc CAMCC_IFE_1_CSID_CLK>,
403 <&camcc CAMCC_IFE_2_AXI_CLK>,
404 <&camcc CAMCC_IFE_2_CLK>,
405 <&camcc CAMCC_IFE_2_CPHY_RX_CLK>,
406 <&camcc CAMCC_IFE_2_CSID_CLK>,
407 <&camcc CAMCC_IFE_3_AXI_CLK>,
408 <&camcc CAMCC_IFE_3_CLK>,
409 <&camcc CAMCC_IFE_3_CPHY_RX_CLK>,
410 <&camcc CAMCC_IFE_3_CSID_CLK>,
411 <&camcc CAMCC_IFE_LITE_0_CLK>,
412 <&camcc CAMCC_IFE_LITE_0_CPHY_RX_CLK>,
413 <&camcc CAMCC_IFE_LITE_0_CSID_CLK>,
414 <&camcc CAMCC_IFE_LITE_1_CLK>,
415 <&camcc CAMCC_IFE_LITE_1_CPHY_RX_CLK>,
416 <&camcc CAMCC_IFE_LITE_1_CSID_CLK>,
417 <&camcc CAMCC_IFE_LITE_2_CLK>,
418 <&camcc CAMCC_IFE_LITE_2_CPHY_RX_CLK>,
419 <&camcc CAMCC_IFE_LITE_2_CSID_CLK>,
420 <&camcc CAMCC_IFE_LITE_3_CLK>,
421 <&camcc CAMCC_IFE_LITE_3_CPHY_RX_CLK>,
422 <&camcc CAMCC_IFE_LITE_3_CSID_CLK>,
423 <&gcc GCC_CAMERA_HF_AXI_CLK>,
424 <&gcc GCC_CAMERA_SF_AXI_CLK>;
425
426 clock-names = "camnoc_axi",
427 "cpas_ahb",
428 "csiphy0",
429 "csiphy0_timer",
430 "csiphy1",
431 "csiphy1_timer",
432 "csiphy2",
433 "csiphy2_timer",
434 "csiphy3",
435 "csiphy3_timer",
436 "vfe0_axi",
437 "vfe0",
438 "vfe0_cphy_rx",
439 "vfe0_csid",
440 "vfe1_axi",
441 "vfe1",
442 "vfe1_cphy_rx",
443 "vfe1_csid",
444 "vfe2_axi",
445 "vfe2",
446 "vfe2_cphy_rx",
447 "vfe2_csid",
448 "vfe3_axi",
449 "vfe3",
450 "vfe3_cphy_rx",
451 "vfe3_csid",
452 "vfe_lite0",
453 "vfe_lite0_cphy_rx",
454 "vfe_lite0_csid",
455 "vfe_lite1",
456 "vfe_lite1_cphy_rx",
457 "vfe_lite1_csid",
458 "vfe_lite2",
459 "vfe_lite2_cphy_rx",
460 "vfe_lite2_csid",
461 "vfe_lite3",
462 "vfe_lite3_cphy_rx",
463 "vfe_lite3_csid",
464 "gcc_axi_hf",
465 "gcc_axi_sf";
466
467
468 iommus = <&apps_smmu 0x2000 0x4e0>,
469 <&apps_smmu 0x2020 0x4e0>,
470 <&apps_smmu 0x2040 0x4e0>,
471 <&apps_smmu 0x2060 0x4e0>,
472 <&apps_smmu 0x2080 0x4e0>,
473 <&apps_smmu 0x20e0 0x4e0>,
474 <&apps_smmu 0x20c0 0x4e0>,
475 <&apps_smmu 0x20a0 0x4e0>,
476 <&apps_smmu 0x2400 0x4e0>,
477 <&apps_smmu 0x2420 0x4e0>,
478 <&apps_smmu 0x2440 0x4e0>,
479 <&apps_smmu 0x2460 0x4e0>,
480 <&apps_smmu 0x2480 0x4e0>,
481 <&apps_smmu 0x24e0 0x4e0>,
482 <&apps_smmu 0x24c0 0x4e0>,
483 <&apps_smmu 0x24a0 0x4e0>;
484
485 interconnects = <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_CAMERA_CFG 0>,
486 <&mmss_noc MASTER_CAMNOC_HF 0 &mc_virt SLAVE_EBI1 0>,
487 <&mmss_noc MASTER_CAMNOC_SF 0 &mc_virt SLAVE_EBI1 0>,
488 <&mmss_noc MASTER_CAMNOC_ICP 0 &mc_virt SLAVE_EBI1 0>;
489 interconnect-names = "cam_ahb",
490 "cam_hf_mnoc",
491 "cam_sf_mnoc",
492 "cam_sf_icp_mnoc";
493
494 ports {
495 #address-cells = <1>;
496 #size-cells = <0>;
497
498 port@0 {
499 reg = <0>;
500 #address-cells = <1>;
501 #size-cells = <0>;
502
503 csiphy_ep0: endpoint@0 {
504 reg = <0>;
505 clock-lanes = <7>;
506 data-lanes = <0 1>;
507 remote-endpoint = <&sensor_ep>;
508 };
509 };
510 };
511 };
512 };
Documentation/driver-api/media/drivers/index.rst+1−0
@@ -26,6 +26,7 @@ Video4Linux (V4L) drivers · 25 unmodified lines
26 vimc-devel26 vimc-devel
27 zoran27 zoran
28 ccs/ccs28 ccs/ccs
29 ipu6
29 30
30 31
31Digital TV drivers32Digital TV drivers
Documentation/driver-api/media/drivers/ipu6.rst+205−0
@@ -0,0 +1,205 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3==================
4Intel IPU6 Driver
5==================
6
7Author: Bingbu Cao <bingbu.cao@intel.com>
8
9Overview
10=========
11
12Intel IPU6 is the sixth generation of Intel Image Processing Unit used in some
13Intel Chipsets such as Tiger Lake, Jasper Lake, Alder Lake, Raptor Lake and
14Meteor Lake. IPU6 consists of two major systems: Input System (ISYS) and
15Processing System (PSYS). IPU6 are visible on the PCI bus as a single device, it
16can be found by ``lspci``:
17
18``0000:00:05.0 Multimedia controller: Intel Corporation Device xxxx (rev xx)``
19
20IPU6 has a 16 MB BAR in PCI configuration Space for MMIO registers which is
21visible for driver.
22
23Buttress
24=========
25
26The IPU6 is connecting to the system fabric with Buttress which is enabling host
27driver to control the IPU6, it also allows IPU6 access the system memory to
28store and load frame pixel streams and any other metadata.
29
30Buttress mainly manages several system functionalities: power management,
31interrupt handling, firmware authentication and global timer sync.
32
33ISYS and PSYS Power flow
34------------------------
35
36IPU6 driver initialize the ISYS and PSYS power up or down request by setting the
37Buttress frequency control register for ISYS and PSYS
38(``IPU6_BUTTRESS_REG_IS_FREQ_CTL`` and ``IPU6_BUTTRESS_REG_PS_FREQ_CTL``) in
39function:
40
41.. c:function:: int ipu6_buttress_power(...)
42
43Buttress forwards the request to Punit, after Punit execute the power up flow,
44Buttress indicates driver that ISYS or PSYS is powered up by updating the power
45status registers.
46
47.. Note:: ISYS power up needs take place prior to PSYS power up, ISYS power down
48 needs take place after PSYS power down due to hardware limitation.
49
50Interrupt
51---------
52
53IPU6 interrupt can be generated as MSI or INTA, interrupt will be triggered when
54ISYS, PSYS, Buttress event or error happen, driver can get the interrupt cause
55by reading the interrupt status register ``BUTTRESS_REG_ISR_STATUS``, driver
56clears the irq status and then calls specific ISYS or PSYS irq handler.
57
58.. c:function:: irqreturn_t ipu6_buttress_isr(int irq, ...)
59
60Security and firmware authentication
61-------------------------------------
62
63To address the IPU6 firmware security concerns, the IPU6 firmware needs to
64undergo an authentication process before it is allowed to executed on the IPU6
65internal processors. The IPU6 driver will work with Converged Security Engine
66(CSE) to complete authentication process. The CSE is responsible of
67authenticating the IPU6 firmware. The authenticated firmware binary is copied
68into an isolated memory region. Firmware authentication process is implemented
69by CSE following an IPC handshake with the IPU6 driver. There are some Buttress
70registers used by the CSE and the IPU6 driver to communicate with each other via
71IPC.
72
73.. c:function:: int ipu6_buttress_authenticate(...)
74
75Global timer sync
76-----------------
77
78The IPU6 driver initiates a Hammock Harbor synchronization flow each time it
79starts camera operation. The IPU6 will synchronizes an internal counter in the
80Buttress with a copy of the SoC time, this counter maintains the up-to-date time
81until camera operation is stopped. The IPU6 driver can use this time counter to
82calibrate the timestamp based on the timestamp in response event from firmware.
83
84.. c:function:: int ipu6_buttress_start_tsc_sync(...)
85
86DMA and MMU
87============
88
89The IPU6 has its own scalar processor where the firmware run at and an internal
9032-bit virtual address space. The IPU6 has MMU address translation hardware to
91allow that scalar processors to access the internal memory and external system
92memory through IPU6 virtual address. The address translation is based on two
93levels of page lookup tables stored in system memory which are maintained by the
94IPU6 driver. The IPU6 driver sets the level-1 page table base address to MMU
95register and allows MMU to perform page table lookups.
96
97The IPU6 driver exports its own DMA operations. The IPU6 driver will update the
98page table entries for each DMA operation and invalidate the MMU TLB after each
99unmap and free.
100
101.. code-block:: none
102
103 const struct dma_map_ops ipu6_dma_ops = {
104 .alloc = ipu6_dma_alloc,
105 .free = ipu6_dma_free,
106 .mmap = ipu6_dma_mmap,
107 .map_sg = ipu6_dma_map_sg,
108 .unmap_sg = ipu6_dma_unmap_sg,
109 ...
110 };
111
112.. Note:: IPU6 MMU works behind IOMMU so for each IPU6 DMA ops, driver will call
113 generic PCI DMA ops to ask IOMMU to do the additional mapping if VT-d
114 enabled.
115
116Firmware file format
117====================
118
119The IPU6 firmware is in Code Partition Directory (CPD) file format. The CPD
120firmware contains a CPD header, several CPD entries and components. The CPD
121component includes 3 entries - manifest, metadata and module data. Manifest and
122metadata are defined by CSE and used by CSE for authentication. Module data is
123specific to IPU6 which holds the binary data of firmware called package
124directory. The IPU6 driver (``ipu6-cpd.c`` in particular) parses and validates
125the CPD firmware file and gets the package directory binary data of the IPU6
126firmware, copies it to specific DMA buffer and sets its base address to Buttress
127``FW_SOURCE_BASE`` register. Finally the CSE will do authentication for this
128firmware binary.
129
130
131Syscom interface
132================
133
134The IPU6 driver communicates with firmware via the Syscom ABI. Syscom is an
135inter-processor communication mechanism between the IPU scalar processors and
136the CPU. There are a number of resources shared between firmware and software.
137A system memory region where the message queues reside, firmware can access the
138memory region via the IPU MMU. The Syscom queues are FIFO fixed depth queues
139with a configurable number of tokens (messages). There are also common IPU6 MMIO
140registers where the queue read and write indices reside. Software and firmware
141function as producer and consumer of tokens in the queues and update the write
142and read indices separately when sending or receiving each message.
143
144The IPU6 driver must prepare and configure the number of input and output
145queues, configure the count of tokens per queue and the size of per token before
146initiating and starting the communication with firmware. Firmware and software
147must use same configurations. The IPU6 Buttress has a number of firmware boot
148parameter registers which can be used to store the address of configuration and
149initialise the Syscom state, then driver can request firmware to start and run via
150setting the scalar processor control status register.
151
152Input System
153============
154
155IPU6 input system consists of MIPI D-PHY and several CSI-2 receivers. It can
156capture image pixel data from camera sensors or other MIPI CSI-2 output devices.
157
158D-PHYs and CSI-2 ports lane mapping
159-----------------------------------
160
161The IPU6 integrates different D-PHY IPs on different SoCs, on Tiger Lake and
162Alder Lake, IPU6 integrates MCD10 D-PHY, IPU6SE on Jasper Lake integrates JSL
163D-PHY and IPU6EP on Meteor Lake integrates a Synopsys DWC D-PHY. There is an
164adaptional layer between D-PHY and CSI-2 receiver controller which includes port
165configuration, PHY wrapper or private test interfaces for D-PHY. There are 3
166D-PHY drivers ``ipu6-isys-mcd-phy.c``, ``ipu6-isys-jsl-phy.c`` and
167``ipu6-isys-dwc-phy.c`` program the above 3 D-PHYs in IPU6.
168
169Different IPU6 versions have different D-PHY lanes mappings, On Tiger Lake,
170there are 12 data lanes and 8 clock lanes, IPU6 support maximum 8 CSI-2 ports,
171see the PPI mmapping in ``ipu6-isys-mcd-phy.c`` for more information. On Jasper
172Lake and Alder Lake, D-PHY has 8 data lanes and 4 clock lanes, the IPU6 supports
173maximum 4 CSI-2 ports. For Meteor Lake, D-PHY has 12 data lanes and 6 clock
174lanes so IPU6 support maximum 6 CSI-2 ports.
175
176.. Note:: Each pair of CSI-2 two ports is a single unit that can share the data
177 lanes. For example, for CSI-2 port 0 and 1, CSI-2 port 0 support
178 maximum 4 data lanes, CSI-2 port 1 support maximum 2 data lanes, CSI-2
179 port 0 with 2 data lanes can work together with CSI-2 port 1 with 2
180 data lanes. If trying to use CSI-2 port 0 with 4 lanes, CSI-2 port 1
181 will not be available as the 4 data lanes are shared by CSI-2 port 0
182 and 1. The same applies to CSI ports 2/3, 4/5 and 7/8.
183
184ISYS firmware ABIs
185------------------
186
187The IPU6 firmware implements a series of ABIs for software access. In general,
188software firstly prepares the stream configuration ``struct
189ipu6_fw_isys_stream_cfg_data_abi`` and sends the configuration to firmware via
190sending ``STREAM_OPEN`` command. Stream configuration includes input pins and
191output pins, input pin ``struct ipu6_fw_isys_input_pin_info_abi`` defines the
192resolution and data type of input source, output pin ``struct
193ipu6_fw_isys_output_pin_info_abi`` defines the output resolution, stride and
194frame format, etc.
195
196Once the driver gets the interrupt from firmware that indicates stream open
197successfully, the driver will send the ``STREAM_START`` and ``STREAM_CAPTURE``
198command to request firmware to start capturing image frames. ``STREAM_CAPTURE``
199command queues the buffers to firmware with ``struct
200ipu6_fw_isys_frame_buff_set``, software then waits for the interrupt and
201response from firmware, ``PIN_DATA_READY`` means a buffer is ready on a specific
202output pin and then software can return the buffer to user.
203
204.. Note:: See :ref:`Examples<ipu6_isys_capture_examples>` about how to do
205 capture by IPU6 ISYS driver.
Documentation/userspace-api/media/cec/cec-func-open.rst+2−2
@@ -70,5 +70,5 @@ include: · 69 unmodified lines
70``ENOMEM``70``ENOMEM``
71 Insufficient kernel memory was available.71 Insufficient kernel memory was available.
72 72
73``ENXIO``73``ENODEV``
74 No device corresponding to this device special file exists.74 Device not found or was removed.
Documentation/userspace-api/media/dvb/frontend_f_open.rst+1−1
@@ -91,7 +91,7 @@ appropriately. · 90 unmodified lines
91 - The caller has no permission to access the device.91 - The caller has no permission to access the device.
92 92
93 - - ``EBUSY``93 - - ``EBUSY``
94 - The the device driver is already in use.94 - The device driver is already in use.
95 95
96 - - ``EMFILE``96 - - ``EMFILE``
97 - The process already has the maximum number of files open.97 - The process already has the maximum number of files open.
Documentation/userspace-api/media/glossary.rst+12−0
@@ -25,6 +25,13 @@ Glossary · 24 unmodified lines
25 25
26 See :ref:`cec`.26 See :ref:`cec`.
27 27
28 Data Unit
29
30 Unit of data transported by a bus. On parallel buses, the data unit
31 consists of one or more related samples while on serial buses the data
32 unit is logical. If the data unit is image data, it may also be called a
33 pixel.
34
28 Device Driver35 Device Driver
29 Part of the Linux Kernel that implements support for a hardware36 Part of the Linux Kernel that implements support for a hardware
30 component.37 component.
@@ -173,6 +180,11 @@ Glossary · 142 unmodified lines
173 An integrated circuit that integrates all components of a computer180 An integrated circuit that integrates all components of a computer
174 or other electronic systems.181 or other electronic systems.
175 182
183 Stream
184 A distinct flow of data (image data or metadata) from an initial source
185 to a final sink. The initial source may be e.g. an image sensor and the
186 final sink e.g. a memory buffer.
187
176 V4L2 API188 V4L2 API
177 **V4L2 userspace API**189 **V4L2 userspace API**
178 190
Documentation/userspace-api/media/v4l/dev-meta.rst+21−0
@@ -47,6 +47,12 @@ member of the ``fmt`` union as needed per the desired operation. Both drivers · 46 unmodified lines
47and applications must set the remainder of the :c:type:`v4l2_format` structure47and applications must set the remainder of the :c:type:`v4l2_format` structure
48to 0.48to 0.
49 49
50Devices that capture metadata by line have the struct v4l2_fmtdesc
51``V4L2_FMT_FLAG_META_LINE_BASED`` flag set for :c:func:`VIDIOC_ENUM_FMT`. Such
52devices can typically also :ref:`capture image data <capture>`. This primarily
53involves devices that receive the data from a different devices such as a camera
54sensor.
55
50.. c:type:: v4l2_meta_format56.. c:type:: v4l2_meta_format
51 57
52.. tabularcolumns:: |p{1.4cm}|p{2.4cm}|p{13.5cm}|58.. tabularcolumns:: |p{1.4cm}|p{2.4cm}|p{13.5cm}|
@@ -65,3 +71,18 @@ to 0. · 12 unmodified lines
65 - ``buffersize``71 - ``buffersize``
66 - Maximum buffer size in bytes required for data. The value is set by the72 - Maximum buffer size in bytes required for data. The value is set by the
67 driver.73 driver.
74 * - __u32
75 - ``width``
76 - Width of a line of metadata in Data Units. Valid when
77 :c:type`v4l2_fmtdesc` flag ``V4L2_FMT_FLAG_META_LINE_BASED`` is set,
78 otherwise zero. See :c:func:`VIDIOC_ENUM_FMT`.
79 * - __u32
80 - ``height``
81 - Number of rows of metadata. Valid when :c:type`v4l2_fmtdesc` flag
82 ``V4L2_FMT_FLAG_META_LINE_BASED`` is set, otherwise zero. See
83 :c:func:`VIDIOC_ENUM_FMT`.
84 * - __u32
85 - ``bytesperline``
86 - Offset in bytes between the beginning of two consecutive lines. Valid
87 when :c:type`v4l2_fmtdesc` flag ``V4L2_FMT_FLAG_META_LINE_BASED`` is
88 set, otherwise zero. See :c:func:`VIDIOC_ENUM_FMT`.
Documentation/userspace-api/media/v4l/dev-subdev.rst+28−3
@@ -506,6 +506,8 @@ source pads. · 505 unmodified lines
506 506
507 subdev-formats507 subdev-formats
508 508
509.. _subdev-routing:
510
509Streams, multiplexed media pads and internal routing511Streams, multiplexed media pads and internal routing
510----------------------------------------------------512----------------------------------------------------
511 513
@@ -527,9 +529,9 @@ the its sink pad and allows to route them individually to one of its source · 15 unmodified lines
527pads.529pads.
528 530
529Subdevice drivers that support multiplexed streams are compatible with531Subdevice drivers that support multiplexed streams are compatible with
530non-multiplexed subdev drivers, but, of course, require a routing configuration532non-multiplexed subdev drivers. However, if the driver at the sink end of a link
531where the link between those two types of drivers contains only a single533does not support streams, then only stream 0 of source end may be captured.
532stream.534There may be additional limitations specific to the sink device.
533 535
534Understanding streams536Understanding streams
535^^^^^^^^^^^^^^^^^^^^^537^^^^^^^^^^^^^^^^^^^^^
@@ -570,6 +572,29 @@ Any configurations of a stream within a pad, such as format or selections, · 34 unmodified lines
570are independent of similar configurations on other streams. This is572are independent of similar configurations on other streams. This is
571subject to change in the future.573subject to change in the future.
572 574
575Device types and routing setup
576^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
577
578Different kinds of sub-devices have differing behaviour for route activation,
579depending on the hardware. In all cases, however, only routes that have the
580``V4L2_SUBDEV_STREAM_FL_ACTIVE`` flag set are active.
581
582Devices generating the streams may allow enabling and disabling some of the
583routes or have a fixed routing configuration. If the routes can be disabled, not
584declaring the routes (or declaring them without
585``VIDIOC_SUBDEV_STREAM_FL_ACTIVE`` flag set) in ``VIDIOC_SUBDEV_S_ROUTING`` will
586disable the routes. ``VIDIOC_SUBDEV_S_ROUTING`` will still return such routes
587back to the user in the routes array, with the ``V4L2_SUBDEV_STREAM_FL_ACTIVE``
588flag unset.
589
590Devices transporting the streams almost always have more configurability with
591respect to routing. Typically any route between the sub-device's sink and source
592pads is possible, and multiple routes (usually up to certain limited number) may
593be active simultaneously. For such devices, no routes are created by the driver
594and user-created routes are fully replaced when ``VIDIOC_SUBDEV_S_ROUTING`` is
595called on the sub-device. Such newly created routes have the device's default
596configuration for format and selection rectangles.
597
573Configuring streams598Configuring streams
574^^^^^^^^^^^^^^^^^^^599^^^^^^^^^^^^^^^^^^^
575 600
Documentation/userspace-api/media/v4l/func-open.rst+2−2
@@ -65,8 +65,8 @@ EBUSY · 64 unmodified lines
65 The driver does not support multiple opens and the device is already65 The driver does not support multiple opens and the device is already
66 in use.66 in use.
67 67
68ENXIO68ENODEV
69 No device corresponding to this device special file exists.69 Device not found or was removed.
70 70
71ENOMEM71ENOMEM
72 Not enough kernel memory was available to complete the request.72 Not enough kernel memory was available to complete the request.
Documentation/userspace-api/media/v4l/meta-formats.rst+2−1
@@ -13,9 +13,10 @@ These formats are used for the :ref:`metadata` interface only. · 12 unmodified lines
13 :maxdepth: 113 :maxdepth: 1
14 14
15 metafmt-d4xx15 metafmt-d4xx
16 metafmt-generic
16 metafmt-intel-ipu317 metafmt-intel-ipu3
17 metafmt-rkisp118 metafmt-rkisp1
18 metafmt-uvc19 metafmt-uvc
20 metafmt-vivid
19 metafmt-vsp1-hgo21 metafmt-vsp1-hgo
20 metafmt-vsp1-hgt22 metafmt-vsp1-hgt
21 metafmt-vivid
Documentation/userspace-api/media/v4l/metafmt-generic.rst+340−0
@@ -0,0 +1,340 @@
1.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later
2
3********************************************************************************************************************************************************************************************************************************************************************************
4V4L2_META_FMT_GENERIC_8 ('MET8'), V4L2_META_FMT_GENERIC_CSI2_10 ('MC1A'), V4L2_META_FMT_GENERIC_CSI2_12 ('MC1C'), V4L2_META_FMT_GENERIC_CSI2_14 ('MC1E'), V4L2_META_FMT_GENERIC_CSI2_16 ('MC1G'), V4L2_META_FMT_GENERIC_CSI2_20 ('MC1K'), V4L2_META_FMT_GENERIC_CSI2_24 ('MC1O')
5********************************************************************************************************************************************************************************************************************************************************************************
6
7
8Generic line-based metadata formats
9
10
11Description
12===========
13
14These generic line-based metadata formats define the memory layout of the data
15without defining the format or meaning of the metadata itself.
16
17.. _v4l2-meta-fmt-generic-8:
18
19V4L2_META_FMT_GENERIC_8
20-----------------------
21
22The V4L2_META_FMT_GENERIC_8 format is a plain 8-bit metadata format. This format
23is used on CSI-2 for 8 bits per :term:`Data Unit`.
24
25Additionally it is used for 16 bits per Data Unit when two bytes of metadata are
26packed into one 16-bit Data Unit. Otherwise the 16 bits per pixel dataformat is
27:ref:`V4L2_META_FMT_GENERIC_CSI2_16 <v4l2-meta-fmt-generic-csi2-16>`.
28
29**Byte Order Of V4L2_META_FMT_GENERIC_8.**
30Each cell is one byte. "M" denotes a byte of metadata.
31
32.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|
33
34.. flat-table:: Sample 4x2 Metadata Frame
35 :header-rows: 0
36 :stub-columns: 0
37 :widths: 12 8 8 8 8
38
39 * - start + 0:
40 - M\ :sub:`00`
41 - M\ :sub:`10`
42 - M\ :sub:`20`
43 - M\ :sub:`30`
44 * - start + 4:
45 - M\ :sub:`01`
46 - M\ :sub:`11`
47 - M\ :sub:`21`
48 - M\ :sub:`31`
49
50.. _v4l2-meta-fmt-generic-csi2-10:
51
52V4L2_META_FMT_GENERIC_CSI2_10
53-----------------------------
54
55V4L2_META_FMT_GENERIC_CSI2_10 contains 8-bit generic metadata packed in 10-bit
56Data Units, with one padding byte after every four bytes of metadata. This
57format is typically used by CSI-2 receivers with a source that transmits
58MEDIA_BUS_FMT_META_10 and the CSI-2 receiver writes the received data to memory
59as-is.
60
61The packing of the data follows the MIPI CSI-2 specification and the padding of
62the data is defined in the MIPI CCS specification.
63
64This format is also used in conjunction with 20 bits per :term:`Data Unit`
65formats that pack two bytes of metadata into one Data Unit. Otherwise the
6620 bits per pixel dataformat is :ref:`V4L2_META_FMT_GENERIC_CSI2_20
67<v4l2-meta-fmt-generic-csi2-20>`.
68
69This format is little endian.
70
71**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_10.**
72Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
73
74.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{.8cm}|
75
76.. flat-table:: Sample 4x2 Metadata Frame
77 :header-rows: 0
78 :stub-columns: 0
79 :widths: 12 8 8 8 8 8
80
81 * - start + 0:
82 - M\ :sub:`00`
83 - M\ :sub:`10`
84 - M\ :sub:`20`
85 - M\ :sub:`30`
86 - x
87 * - start + 5:
88 - M\ :sub:`01`
89 - M\ :sub:`11`
90 - M\ :sub:`21`
91 - M\ :sub:`31`
92 - x
93
94.. _v4l2-meta-fmt-generic-csi2-12:
95
96V4L2_META_FMT_GENERIC_CSI2_12
97-----------------------------
98
99V4L2_META_FMT_GENERIC_CSI2_12 contains 8-bit generic metadata packed in 12-bit
100Data Units, with one padding byte after every two bytes of metadata. This format
101is typically used by CSI-2 receivers with a source that transmits
102MEDIA_BUS_FMT_META_12 and the CSI-2 receiver writes the received data to memory
103as-is.
104
105The packing of the data follows the MIPI CSI-2 specification and the padding of
106the data is defined in the MIPI CCS specification.
107
108This format is also used in conjunction with 24 bits per :term:`Data Unit`
109formats that pack two bytes of metadata into one Data Unit. Otherwise the
11024 bits per pixel dataformat is :ref:`V4L2_META_FMT_GENERIC_CSI2_24
111<v4l2-meta-fmt-generic-csi2-24>`.
112
113This format is little endian.
114
115**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_12.**
116Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
117
118.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{.8cm}|p{.8cm}|
119
120.. flat-table:: Sample 4x2 Metadata Frame
121 :header-rows: 0
122 :stub-columns: 0
123 :widths: 12 8 8 8 8 8 8
124
125 * - start + 0:
126 - M\ :sub:`00`
127 - M\ :sub:`10`
128 - x
129 - M\ :sub:`20`
130 - M\ :sub:`30`
131 - x
132 * - start + 6:
133 - M\ :sub:`01`
134 - M\ :sub:`11`
135 - x
136 - M\ :sub:`21`
137 - M\ :sub:`31`
138 - x
139
140.. _v4l2-meta-fmt-generic-csi2-14:
141
142V4L2_META_FMT_GENERIC_CSI2_14
143-----------------------------
144
145V4L2_META_FMT_GENERIC_CSI2_14 contains 8-bit generic metadata packed in 14-bit
146Data Units, with three padding bytes after every four bytes of metadata. This
147format is typically used by CSI-2 receivers with a source that transmits
148MEDIA_BUS_FMT_META_14 and the CSI-2 receiver writes the received data to memory
149as-is.
150
151The packing of the data follows the MIPI CSI-2 specification and the padding of
152the data is defined in the MIPI CCS specification.
153
154This format is little endian.
155
156**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_14.**
157Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
158
159.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{.8cm}|p{.8cm}|p{.8cm}|
160
161.. flat-table:: Sample 4x2 Metadata Frame
162 :header-rows: 0
163 :stub-columns: 0
164 :widths: 12 8 8 8 8 8 8 8
165
166 * - start + 0:
167 - M\ :sub:`00`
168 - M\ :sub:`10`
169 - M\ :sub:`20`
170 - M\ :sub:`30`
171 - x
172 - x
173 - x
174 * - start + 7:
175 - M\ :sub:`01`
176 - M\ :sub:`11`
177 - M\ :sub:`21`
178 - M\ :sub:`31`
179 - x
180 - x
181 - x
182
183.. _v4l2-meta-fmt-generic-csi2-16:
184
185V4L2_META_FMT_GENERIC_CSI2_16
186-----------------------------
187
188V4L2_META_FMT_GENERIC_CSI2_16 contains 8-bit generic metadata packed in 16-bit
189Data Units, with one padding byte after every byte of metadata. This format is
190typically used by CSI-2 receivers with a source that transmits
191MEDIA_BUS_FMT_META_16 and the CSI-2 receiver writes the received data to memory
192as-is.
193
194The packing of the data follows the MIPI CSI-2 specification and the padding of
195the data is defined in the MIPI CCS specification.
196
197Some devices support more efficient packing of metadata in conjunction with
19816-bit image data. In that case the dataformat is
199:ref:`V4L2_META_FMT_GENERIC_8 <v4l2-meta-fmt-generic-8>`.
200
201This format is little endian.
202
203**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_16.**
204Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
205
206.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{1.2cm}|p{.8cm}|
207
208.. flat-table:: Sample 4x2 Metadata Frame
209 :header-rows: 0
210 :stub-columns: 0
211 :widths: 12 8 8 8 8 8 8 8 8
212
213 * - start + 0:
214 - M\ :sub:`00`
215 - x
216 - M\ :sub:`10`
217 - x
218 - M\ :sub:`20`
219 - x
220 - M\ :sub:`30`
221 - x
222 * - start + 8:
223 - M\ :sub:`01`
224 - x
225 - M\ :sub:`11`
226 - x
227 - M\ :sub:`21`
228 - x
229 - M\ :sub:`31`
230 - x
231
232.. _v4l2-meta-fmt-generic-csi2-20:
233
234V4L2_META_FMT_GENERIC_CSI2_20
235-----------------------------
236
237V4L2_META_FMT_GENERIC_CSI2_20 contains 8-bit generic metadata packed in 20-bit
238Data Units, with alternating one or two padding bytes after every byte of
239metadata. This format is typically used by CSI-2 receivers with a source that
240transmits MEDIA_BUS_FMT_META_20 and the CSI-2 receiver writes the received data
241to memory as-is.
242
243The packing of the data follows the MIPI CSI-2 specification and the padding of
244the data is defined in the MIPI CCS specification.
245
246Some devices support more efficient packing of metadata in conjunction with
24716-bit image data. In that case the dataformat is
248:ref:`V4L2_META_FMT_GENERIC_CSI2_10 <v4l2-meta-fmt-generic-csi2-10>`.
249
250This format is little endian.
251
252**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_20.**
253Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
254
255.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{.8cm}|
256
257.. flat-table:: Sample 4x2 Metadata Frame
258 :header-rows: 0
259 :stub-columns: 0
260 :widths: 12 8 8 8 8 8 8 8 8 8 8
261
262 * - start + 0:
263 - M\ :sub:`00`
264 - x
265 - M\ :sub:`10`
266 - x
267 - x
268 - M\ :sub:`20`
269 - x
270 - M\ :sub:`30`
271 - x
272 - x
273 * - start + 10:
274 - M\ :sub:`01`
275 - x
276 - M\ :sub:`11`
277 - x
278 - x
279 - M\ :sub:`21`
280 - x
281 - M\ :sub:`31`
282 - x
283 - x
284
285.. _v4l2-meta-fmt-generic-csi2-24:
286
287V4L2_META_FMT_GENERIC_CSI2_24
288-----------------------------
289
290V4L2_META_FMT_GENERIC_CSI2_24 contains 8-bit generic metadata packed in 24-bit
291Data Units, with two padding bytes after every byte of metadata. This format is
292typically used by CSI-2 receivers with a source that transmits
293MEDIA_BUS_FMT_META_24 and the CSI-2 receiver writes the received data to memory
294as-is.
295
296The packing of the data follows the MIPI CSI-2 specification and the padding of
297the data is defined in the MIPI CCS specification.
298
299Some devices support more efficient packing of metadata in conjunction with
30016-bit image data. In that case the dataformat is
301:ref:`V4L2_META_FMT_GENERIC_CSI2_12 <v4l2-meta-fmt-generic-csi2-12>`.
302
303This format is little endian.
304
305**Byte Order Of V4L2_META_FMT_GENERIC_CSI2_24.**
306Each cell is one byte. "M" denotes a byte of metadata and "x" a byte of padding.
307
308.. tabularcolumns:: |p{2.4cm}|p{1.2cm}|p{.8cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{.8cm}|p{1.2cm}|p{.8cm}|p{.8cm}|
309
310.. flat-table:: Sample 4x2 Metadata Frame
311 :header-rows: 0
312 :stub-columns: 0
313 :widths: 12 8 8 8 8 8 8 8 8 8 8 8 8
314
315 * - start + 0:
316 - M\ :sub:`00`
317 - x
318 - x
319 - M\ :sub:`10`
320 - x
321 - x
322 - M\ :sub:`20`
323 - x
324 - x
325 - M\ :sub:`30`
326 - x
327 - x
328 * - start + 12:
329 - M\ :sub:`01`
330 - x
331 - x
332 - M\ :sub:`11`
333 - x
334 - x
335 - M\ :sub:`21`
336 - x
337 - x
338 - M\ :sub:`31`
339 - x
340 - x
Documentation/userspace-api/media/v4l/mmap.rst+1−1
@@ -188,7 +188,7 @@ Example: Mapping buffers in the multi-planar API · 187 unmodified lines
188 buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,188 buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
189 PROT_READ | PROT_WRITE, /* recommended */189 PROT_READ | PROT_WRITE, /* recommended */
190 MAP_SHARED, /* recommended */190 MAP_SHARED, /* recommended */
191 fd, buffer.m.planes[j].m.offset);191 fd, buffer.m.planes[j].m.mem_offset);
192 192
193 if (MAP_FAILED == buffers[i].start[j]) {193 if (MAP_FAILED == buffers[i].start[j]) {
194 /* If you do not exit here you should unmap() and free()194 /* If you do not exit here you should unmap() and free()
Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst+48−0
@@ -36,6 +36,8 @@ are often referred to as greyscale formats. · 35 unmodified lines
36 - Byte 236 - Byte 2
37 - Byte 337 - Byte 3
38 - Byte 438 - Byte 4
39 - Byte 5
40 - Byte 6
39 41
40 * .. _V4L2-PIX-FMT-GREY:42 * .. _V4L2-PIX-FMT-GREY:
41 43
@@ -47,6 +49,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
47 - ...49 - ...
48 - ...50 - ...
49 - ...51 - ...
52 - ...
53 - ...
50 54
51 * .. _V4L2-PIX-FMT-IPU3-Y10:55 * .. _V4L2-PIX-FMT-IPU3-Y10:
52 56
@@ -58,6 +62,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
58 - Y'\ :sub:`2`\ [3:0] Y'\ :sub:`1`\ [9:6]62 - Y'\ :sub:`2`\ [3:0] Y'\ :sub:`1`\ [9:6]
59 - Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [9:4]63 - Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [9:4]
60 - Y'\ :sub:`3`\ [9:2]64 - Y'\ :sub:`3`\ [9:2]
65 - ...
66 - ...
61 67
62 * .. _V4L2-PIX-FMT-Y10:68 * .. _V4L2-PIX-FMT-Y10:
63 69
@@ -69,6 +75,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
69 - ...75 - ...
70 - ...76 - ...
71 - ...77 - ...
78 - ...
79 - ...
72 80
73 * .. _V4L2-PIX-FMT-Y10BPACK:81 * .. _V4L2-PIX-FMT-Y10BPACK:
74 82
@@ -80,6 +88,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
80 - Y'\ :sub:`1`\ [3:0] Y'\ :sub:`2`\ [9:6]88 - Y'\ :sub:`1`\ [3:0] Y'\ :sub:`2`\ [9:6]
81 - Y'\ :sub:`2`\ [5:0] Y'\ :sub:`3`\ [9:8]89 - Y'\ :sub:`2`\ [5:0] Y'\ :sub:`3`\ [9:8]
82 - Y'\ :sub:`3`\ [7:0]90 - Y'\ :sub:`3`\ [7:0]
91 - ...
92 - ...
83 93
84 * .. _V4L2-PIX-FMT-Y10P:94 * .. _V4L2-PIX-FMT-Y10P:
85 95
@@ -91,6 +101,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
91 - Y'\ :sub:`2`\ [9:2]101 - Y'\ :sub:`2`\ [9:2]
92 - Y'\ :sub:`3`\ [9:2]102 - Y'\ :sub:`3`\ [9:2]
93 - Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [1:0] Y'\ :sub:`1`\ [1:0] Y'\ :sub:`0`\ [1:0]103 - Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [1:0] Y'\ :sub:`1`\ [1:0] Y'\ :sub:`0`\ [1:0]
104 - ...
105 - ...
94 106
95 * .. _V4L2-PIX-FMT-Y12:107 * .. _V4L2-PIX-FMT-Y12:
96 108
@@ -102,6 +114,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
102 - ...114 - ...
103 - ...115 - ...
104 - ...116 - ...
117 - ...
118 - ...
105 119
106 * .. _V4L2-PIX-FMT-Y012:120 * .. _V4L2-PIX-FMT-Y012:
107 121
@@ -113,6 +127,21 @@ are often referred to as greyscale formats. · 5 unmodified lines
113 - ...127 - ...
114 - ...128 - ...
115 - ...129 - ...
130 - ...
131 - ...
132
133 * .. _V4L2-PIX-FMT-Y12P:
134
135 - ``V4L2_PIX_FMT_Y12P``
136 - 'Y12P'
137
138 - Y'\ :sub:`0`\ [11:4]
139 - Y'\ :sub:`1`\ [11:4]
140 - Y'\ :sub:`1`\ [3:0] Y'\ :sub:`0`\ [3:0]
141 - ...
142 - ...
143 - ...
144 - ...
116 145
117 * .. _V4L2-PIX-FMT-Y14:146 * .. _V4L2-PIX-FMT-Y14:
118 147
@@ -124,6 +153,21 @@ are often referred to as greyscale formats. · 5 unmodified lines
124 - ...153 - ...
125 - ...154 - ...
126 - ...155 - ...
156 - ...
157 - ...
158
159 * .. _V4L2-PIX-FMT-Y14P:
160
161 - ``V4L2_PIX_FMT_Y14P``
162 - 'Y14P'
163
164 - Y'\ :sub:`0`\ [13:6]
165 - Y'\ :sub:`1`\ [13:6]
166 - Y'\ :sub:`2`\ [13:6]
167 - Y'\ :sub:`3`\ [13:6]
168 - Y'\ :sub:`1`\ [1:0] Y'\ :sub:`0`\ [5:0]
169 - Y'\ :sub:`2`\ [3:0] Y'\ :sub:`1`\ [5:2]
170 - Y'\ :sub:`3`\ [5:0] Y'\ :sub:`2`\ [5:4]
127 171
128 * .. _V4L2-PIX-FMT-Y16:172 * .. _V4L2-PIX-FMT-Y16:
129 173
@@ -135,6 +179,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
135 - ...179 - ...
136 - ...180 - ...
137 - ...181 - ...
182 - ...
183 - ...
138 184
139 * .. _V4L2-PIX-FMT-Y16-BE:185 * .. _V4L2-PIX-FMT-Y16-BE:
140 186
@@ -146,6 +192,8 @@ are often referred to as greyscale formats. · 5 unmodified lines
146 - ...192 - ...
147 - ...193 - ...
148 - ...194 - ...
195 - ...
196 - ...
149 197
150.. raw:: latex198.. raw:: latex
151 199
Documentation/userspace-api/media/v4l/subdev-formats.rst+262−7
@@ -33,7 +33,7 @@ Media Bus Formats · 32 unmodified lines
33 * - __u3233 * - __u32
34 - ``field``34 - ``field``
35 - Field order, from enum :c:type:`v4l2_field`. See35 - Field order, from enum :c:type:`v4l2_field`. See
36 :ref:`field-order` for details.36 :ref:`field-order` for details. Zero for metadata mbus codes.
37 * - __u3237 * - __u32
38 - ``colorspace``38 - ``colorspace``
39 - Image colorspace, from enum :c:type:`v4l2_colorspace`.39 - Image colorspace, from enum :c:type:`v4l2_colorspace`.
@@ -45,7 +45,7 @@ Media Bus Formats · 5 unmodified lines
45 conversion is supported by setting the flag45 conversion is supported by setting the flag
46 V4L2_SUBDEV_MBUS_CODE_CSC_COLORSPACE in the corresponding struct46 V4L2_SUBDEV_MBUS_CODE_CSC_COLORSPACE in the corresponding struct
47 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.47 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.
48 See :ref:`v4l2-subdev-mbus-code-flags`.48 See :ref:`v4l2-subdev-mbus-code-flags`. Zero for metadata mbus codes.
49 * - union {49 * - union {
50 - (anonymous)50 - (anonymous)
51 * - __u1651 * - __u16
@@ -61,7 +61,7 @@ Media Bus Formats · 9 unmodified lines
61 that ycbcr_enc conversion is supported by setting the flag61 that ycbcr_enc conversion is supported by setting the flag
62 V4L2_SUBDEV_MBUS_CODE_CSC_YCBCR_ENC in the corresponding struct62 V4L2_SUBDEV_MBUS_CODE_CSC_YCBCR_ENC in the corresponding struct
63 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.63 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.
64 See :ref:`v4l2-subdev-mbus-code-flags`.64 See :ref:`v4l2-subdev-mbus-code-flags`. Zero for metadata mbus codes.
65 * - __u1665 * - __u16
66 - ``hsv_enc``66 - ``hsv_enc``
67 - HSV encoding, from enum :c:type:`v4l2_hsv_encoding`.67 - HSV encoding, from enum :c:type:`v4l2_hsv_encoding`.
@@ -75,7 +75,7 @@ Media Bus Formats · 7 unmodified lines
75 that hsv_enc conversion is supported by setting the flag75 that hsv_enc conversion is supported by setting the flag
76 V4L2_SUBDEV_MBUS_CODE_CSC_HSV_ENC in the corresponding struct76 V4L2_SUBDEV_MBUS_CODE_CSC_HSV_ENC in the corresponding struct
77 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.77 :c:type:`v4l2_subdev_mbus_code_enum` during enumeration.
78 See :ref:`v4l2-subdev-mbus-code-flags`78 See :ref:`v4l2-subdev-mbus-code-flags`. Zero for metadata mbus codes.
79 * - }79 * - }
80 -80 -
81 * - __u1681 * - __u16
@@ -90,8 +90,8 @@ Media Bus Formats · 8 unmodified lines
90 The driver indicates that quantization conversion is supported by90 The driver indicates that quantization conversion is supported by
91 setting the flag V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION in the91 setting the flag V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION in the
92 corresponding struct :c:type:`v4l2_subdev_mbus_code_enum`92 corresponding struct :c:type:`v4l2_subdev_mbus_code_enum`
93 during enumeration. See :ref:`v4l2-subdev-mbus-code-flags`.93 during enumeration. See :ref:`v4l2-subdev-mbus-code-flags`. Zero for
94 94 metadata mbus codes.
95 * - __u1695 * - __u16
96 - ``xfer_func``96 - ``xfer_func``
97 - Transfer function, from enum :c:type:`v4l2_xfer_func`.97 - Transfer function, from enum :c:type:`v4l2_xfer_func`.
@@ -104,7 +104,8 @@ Media Bus Formats · 6 unmodified lines
104 The driver indicates that the transfer function conversion is supported by104 The driver indicates that the transfer function conversion is supported by
105 setting the flag V4L2_SUBDEV_MBUS_CODE_CSC_XFER_FUNC in the105 setting the flag V4L2_SUBDEV_MBUS_CODE_CSC_XFER_FUNC in the
106 corresponding struct :c:type:`v4l2_subdev_mbus_code_enum`106 corresponding struct :c:type:`v4l2_subdev_mbus_code_enum`
107 during enumeration. See :ref:`v4l2-subdev-mbus-code-flags`.107 during enumeration. See :ref:`v4l2-subdev-mbus-code-flags`. Zero for
108 metadata mbus codes.
108 * - __u16109 * - __u16
109 - ``flags``110 - ``flags``
110 - flags See: :ref:v4l2-mbus-framefmt-flags111 - flags See: :ref:v4l2-mbus-framefmt-flags
@@ -8306,3 +8307,257 @@ The following table lists the existing metadata formats. · 8195 unmodified lines
8306 both sides of the link and the bus format is a fixed8307 both sides of the link and the bus format is a fixed
8307 metadata format that is not configurable from userspace.8308 metadata format that is not configurable from userspace.
8308 Width and height will be set to 0 for this format.8309 Width and height will be set to 0 for this format.
8310
8311Generic Serial Metadata Formats
8312^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8313
8314Generic serial metadata formats are used on serial buses where the actual data
8315content is more or less device specific but the data is transmitted and received
8316by multiple devices that do not process the data in any way, simply writing
8317it to system memory for processing in software at the end of the pipeline.
8318
8319"b" in an array cell signifies a byte of data, followed by the number of the bit
8320and finally the bit number in subscript. "x" indicates a padding bit.
8321
8322.. _media-bus-format-generic-meta:
8323
8324.. cssclass: longtable
8325
8326.. flat-table:: Generic Serial Metadata Formats
8327 :header-rows: 2
8328 :stub-columns: 0
8329
8330 * - Identifier
8331 - Code
8332 -
8333 - :cspan:`23` Data organization within bus :term:`Data Unit`
8334 * -
8335 -
8336 - Bit
8337 - 23
8338 - 22
8339 - 21
8340 - 20
8341 - 19
8342 - 18
8343 - 17
8344 - 16
8345 - 15
8346 - 14
8347 - 13
8348 - 12
8349 - 11
8350 - 10
8351 - 9
8352 - 8
8353 - 7
8354 - 6
8355 - 5
8356 - 4
8357 - 3
8358 - 2
8359 - 1
8360 - 0
8361 * .. _MEDIA-BUS-FMT-META-8:
8362
8363 - MEDIA_BUS_FMT_META_8
8364 - 0x8001
8365 -
8366 -
8367 -
8368 -
8369 -
8370 -
8371 -
8372 -
8373 -
8374 -
8375 -
8376 -
8377 -
8378 -
8379 -
8380 -
8381 -
8382 - b0\ :sub:`7`
8383 - b0\ :sub:`6`
8384 - b0\ :sub:`5`
8385 - b0\ :sub:`4`
8386 - b0\ :sub:`3`
8387 - b0\ :sub:`2`
8388 - b0\ :sub:`1`
8389 - b0\ :sub:`0`
8390 * .. _MEDIA-BUS-FMT-META-10:
8391
8392 - MEDIA_BUS_FMT_META_10
8393 - 0x8002
8394 -
8395 -
8396 -
8397 -
8398 -
8399 -
8400 -
8401 -
8402 -
8403 -
8404 -
8405 -
8406 -
8407 -
8408 -
8409 - b0\ :sub:`7`
8410 - b0\ :sub:`6`
8411 - b0\ :sub:`5`
8412 - b0\ :sub:`4`
8413 - b0\ :sub:`3`
8414 - b0\ :sub:`2`
8415 - b0\ :sub:`1`
8416 - b0\ :sub:`0`
8417 - x
8418 - x
8419 * .. _MEDIA-BUS-FMT-META-12:
8420
8421 - MEDIA_BUS_FMT_META_12
8422 - 0x8003
8423 -
8424 -
8425 -
8426 -
8427 -
8428 -
8429 -
8430 -
8431 -
8432 -
8433 -
8434 -
8435 -
8436 - b0\ :sub:`7`
8437 - b0\ :sub:`6`
8438 - b0\ :sub:`5`
8439 - b0\ :sub:`4`
8440 - b0\ :sub:`3`
8441 - b0\ :sub:`2`
8442 - b0\ :sub:`1`
8443 - b0\ :sub:`0`
8444 - x
8445 - x
8446 - x
8447 - x
8448 * .. _MEDIA-BUS-FMT-META-14:
8449
8450 - MEDIA_BUS_FMT_META_14
8451 - 0x8004
8452 -
8453 -
8454 -
8455 -
8456 -
8457 -
8458 -
8459 -
8460 -
8461 -
8462 -
8463 - b0\ :sub:`7`
8464 - b0\ :sub:`6`
8465 - b0\ :sub:`5`
8466 - b0\ :sub:`4`
8467 - b0\ :sub:`3`
8468 - b0\ :sub:`2`
8469 - b0\ :sub:`1`
8470 - b0\ :sub:`0`
8471 - x
8472 - x
8473 - x
8474 - x
8475 - x
8476 - x
8477 * .. _MEDIA-BUS-FMT-META-16:
8478
8479 - MEDIA_BUS_FMT_META_16
8480 - 0x8005
8481 -
8482 -
8483 -
8484 -
8485 -
8486 -
8487 -
8488 -
8489 -
8490 - b0\ :sub:`7`
8491 - b0\ :sub:`6`
8492 - b0\ :sub:`5`
8493 - b0\ :sub:`4`
8494 - b0\ :sub:`3`
8495 - b0\ :sub:`2`
8496 - b0\ :sub:`1`
8497 - b0\ :sub:`0`
8498 - x
8499 - x
8500 - x
8501 - x
8502 - x
8503 - x
8504 - x
8505 - x
8506 * .. _MEDIA-BUS-FMT-META-20:
8507
8508 - MEDIA_BUS_FMT_META_20
8509 - 0x8006
8510 -
8511 -
8512 -
8513 -
8514 -
8515 - b0\ :sub:`7`
8516 - b0\ :sub:`6`
8517 - b0\ :sub:`5`
8518 - b0\ :sub:`4`
8519 - b0\ :sub:`3`
8520 - b0\ :sub:`2`
8521 - b0\ :sub:`1`
8522 - b0\ :sub:`0`
8523 - x
8524 - x
8525 - x
8526 - x
8527 - x
8528 - x
8529 - x
8530 - x
8531 - x
8532 - x
8533 - x
8534 - x
8535 * .. _MEDIA-BUS-FMT-META-24:
8536
8537 - MEDIA_BUS_FMT_META_24
8538 - 0x8007
8539 -
8540 - b0\ :sub:`7`
8541 - b0\ :sub:`6`
8542 - b0\ :sub:`5`
8543 - b0\ :sub:`4`
8544 - b0\ :sub:`3`
8545 - b0\ :sub:`2`
8546 - b0\ :sub:`1`
8547 - b0\ :sub:`0`
8548 - x
8549 - x
8550 - x
8551 - x
8552 - x
8553 - x
8554 - x
8555 - x
8556 - x
8557 - x
8558 - x
8559 - x
8560 - x
8561 - x
8562 - x
8563 - x
Documentation/userspace-api/media/v4l/user-func.rst+1−0
@@ -62,6 +62,7 @@ Function Reference · 61 unmodified lines
62 vidioc-query-dv-timings62 vidioc-query-dv-timings
63 vidioc-querystd63 vidioc-querystd
64 vidioc-reqbufs64 vidioc-reqbufs
65 vidioc-remove-bufs
65 vidioc-s-hw-freq-seek66 vidioc-s-hw-freq-seek
66 vidioc-streamon67 vidioc-streamon
67 vidioc-subdev-enum-frame-interval68 vidioc-subdev-enum-frame-interval
Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst+7−0
@@ -227,6 +227,13 @@ the ``mbus_code`` field is handled differently: · 226 unmodified lines
227 The application can ask to configure the quantization of the capture227 The application can ask to configure the quantization of the capture
228 device when calling the :ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctl with228 device when calling the :ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctl with
229 :ref:`V4L2_PIX_FMT_FLAG_SET_CSC <v4l2-pix-fmt-flag-set-csc>` set.229 :ref:`V4L2_PIX_FMT_FLAG_SET_CSC <v4l2-pix-fmt-flag-set-csc>` set.
230 * - ``V4L2_FMT_FLAG_META_LINE_BASED``
231 - 0x0200
232 - The metadata format is line-based. In this case the ``width``,
233 ``height`` and ``bytesperline`` fields of :c:type:`v4l2_meta_format` are
234 valid. The buffer consists of ``height`` lines, each having ``width``
235 Data Units of data and the offset (in bytes) between the beginning of
236 each two consecutive lines is ``bytesperline``.
230 237
231Return Value238Return Value
232============239============
Documentation/userspace-api/media/v4l/vidioc-remove-bufs.rst+86−0
@@ -0,0 +1,86 @@
1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
2.. c:namespace:: V4L
3
4.. _VIDIOC_REMOVE_BUFS:
5
6************************
7ioctl VIDIOC_REMOVE_BUFS
8************************
9
10Name
11====
12
13VIDIOC_REMOVE_BUFS - Removes buffers from a queue
14
15Synopsis
16========
17
18.. c:macro:: VIDIOC_REMOVE_BUFS
19
20``int ioctl(int fd, VIDIOC_REMOVE_BUFS, struct v4l2_remove_buffers *argp)``
21
22Arguments
23=========
24
25``fd``
26 File descriptor returned by :c:func:`open()`.
27
28``argp``
29 Pointer to struct :c:type:`v4l2_remove_buffers`.
30
31Description
32===========
33
34Applications can optionally call the :ref:`VIDIOC_REMOVE_BUFS` ioctl to
35remove buffers from a queue.
36:ref:`VIDIOC_CREATE_BUFS` ioctl support is mandatory to enable :ref:`VIDIOC_REMOVE_BUFS`.
37This ioctl is available if the ``V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS`` capability
38is set on the queue when :c:func:`VIDIOC_REQBUFS` or :c:func:`VIDIOC_CREATE_BUFS`
39are invoked.
40
41.. c:type:: v4l2_remove_buffers
42
43.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}|
44
45.. flat-table:: struct v4l2_remove_buffers
46 :header-rows: 0
47 :stub-columns: 0
48 :widths: 1 1 2
49
50 * - __u32
51 - ``index``
52 - The starting buffer index to remove. This field is ignored if count == 0.
53 * - __u32
54 - ``count``
55 - The number of buffers to be removed with indices 'index' until 'index + count - 1'.
56 All buffers in this range must be valid and in DEQUEUED state.
57 :ref:`VIDIOC_REMOVE_BUFS` will always check the validity of ``type`, if it is
58 invalid it returns ``EINVAL`` error code.
59 If count is set to 0 :ref:`VIDIOC_REMOVE_BUFS` will do nothing and return 0.
60 * - __u32
61 - ``type``
62 - Type of the stream or buffers, this is the same as the struct
63 :c:type:`v4l2_format` ``type`` field. See
64 :c:type:`v4l2_buf_type` for valid values.
65 * - __u32
66 - ``reserved``\ [13]
67 - A place holder for future extensions. Drivers and applications
68 must set the array to zero.
69
70Return Value
71============
72
73On success 0 is returned, on error -1 and the ``errno`` variable is set
74appropriately. The generic error codes are described at the
75:ref:`Generic Error Codes <gen-errors>` chapter. If an error occurs, no
76buffers will be freed and one of the error codes below will be returned:
77
78EBUSY
79 File I/O is in progress.
80 One or more of the buffers in the range ``index`` to ``index + count - 1`` are not
81 in DEQUEUED state.
82
83EINVAL
84 One or more of the buffers in the range ``index`` to ``index + count - 1`` do not
85 exist in the queue.
86 The buffer type (``type`` field) is not valid.
Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst+1−0
@@ -121,6 +121,7 @@ aborting or finishing any DMA in progress, an implicit · 120 unmodified lines
121.. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF:121.. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF:
122.. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS:122.. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS:
123.. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS:123.. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS:
124.. _V4L2-BUF-CAP-SUPPORTS-REMOVE-BUFS:
124 125
125.. raw:: latex126.. raw:: latex
126 127
Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst+3−3
@@ -37,9 +37,9 @@ Description · 36 unmodified lines
37 37
38.. note::38.. note::
39 39
40 This is an :ref:`obsolete` interface and may be removed40 This is an :ref:`obsolete` interface and may be removed in the future. It is
41 in the future. It is superseded by41 superseded by :ref:`the selection API <VIDIOC_SUBDEV_G_SELECTION>`. No new
42 :ref:`the selection API <VIDIOC_SUBDEV_G_SELECTION>`.42 extensions to the :c:type:`v4l2_subdev_crop` structure will be accepted.
43 43
44To retrieve the current crop rectangle applications set the ``pad``44To retrieve the current crop rectangle applications set the ``pad``
45field of a struct :c:type:`v4l2_subdev_crop` to the45field of a struct :c:type:`v4l2_subdev_crop` to the
Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst+33−18
@@ -43,23 +43,39 @@ The routing configuration determines the flows of data inside an entity. · 42 unmodified lines
43Drivers report their current routing tables using the43Drivers report their current routing tables using the
44``VIDIOC_SUBDEV_G_ROUTING`` ioctl and application may enable or disable routes44``VIDIOC_SUBDEV_G_ROUTING`` ioctl and application may enable or disable routes
45with the ``VIDIOC_SUBDEV_S_ROUTING`` ioctl, by adding or removing routes and45with the ``VIDIOC_SUBDEV_S_ROUTING`` ioctl, by adding or removing routes and
46setting or clearing flags of the ``flags`` field of a46setting or clearing flags of the ``flags`` field of a struct
47struct :c:type:`v4l2_subdev_route`.47:c:type:`v4l2_subdev_route`. Similarly to ``VIDIOC_SUBDEV_G_ROUTING``, also
48``VIDIOC_SUBDEV_S_ROUTING`` returns the routes back to the user.
48 49
49All stream configurations are reset when ``VIDIOC_SUBDEV_S_ROUTING`` is called. This50All stream configurations are reset when ``VIDIOC_SUBDEV_S_ROUTING`` is called.
50means that the userspace must reconfigure all streams after calling the ioctl51This means that the userspace must reconfigure all stream formats and selections
51with e.g. ``VIDIOC_SUBDEV_S_FMT``.52after calling the ioctl with e.g. ``VIDIOC_SUBDEV_S_FMT``.
52 53
53Only subdevices which have both sink and source pads can support routing.54Only subdevices which have both sink and source pads can support routing.
54 55
55When inspecting routes through ``VIDIOC_SUBDEV_G_ROUTING`` and the application56The ``len_routes`` field indicates the number of routes that can fit in the
56provided ``num_routes`` is not big enough to contain all the available routes57``routes`` array allocated by userspace. It is set by applications for both
57the subdevice exposes, drivers return the ENOSPC error code and adjust the58ioctls to indicate how many routes the kernel can return, and is never modified
58value of the ``num_routes`` field. Application should then reserve enough memory59by the kernel.
59for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again.60
60 61The ``num_routes`` field indicates the number of routes in the routing
61On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the62table. For ``VIDIOC_SUBDEV_S_ROUTING``, it is set by userspace to the number of
62``num_routes`` field to reflect the actual number of routes returned.63routes that the application stored in the ``routes`` array. For both ioctls, it
64is returned by the kernel and indicates how many routes are stored in the
65subdevice routing table. This may be smaller or larger than the value of
66``num_routes`` set by the application for ``VIDIOC_SUBDEV_S_ROUTING``, as
67drivers may adjust the requested routing table.
68
69The kernel can return a ``num_routes`` value larger than ``len_routes`` from
70both ioctls. This indicates thare are more routes in the routing table than fits
71the ``routes`` array. In this case, the ``routes`` array is filled by the kernel
72with the first ``len_routes`` entries of the subdevice routing table. This is
73not considered to be an error, and the ioctl call succeeds. If the applications
74wants to retrieve the missing routes, it can issue a new
75``VIDIOC_SUBDEV_G_ROUTING`` call with a large enough ``routes`` array.
76
77``VIDIOC_SUBDEV_S_ROUTING`` may return more routes than the user provided in
78``num_routes`` field due to e.g. hardware properties.
63 79
64.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|80.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
65 81
@@ -74,6 +90,9 @@ On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the · 8 unmodified lines
74 - ``which``90 - ``which``
75 - Routing table to be accessed, from enum91 - Routing table to be accessed, from enum
76 :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.92 :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
93 * - __u32
94 - ``len_routes``
95 - The length of the array (as in memory reserved for the array)
77 * - struct :c:type:`v4l2_subdev_route`96 * - struct :c:type:`v4l2_subdev_route`
78 - ``routes[]``97 - ``routes[]``
79 - Array of struct :c:type:`v4l2_subdev_route` entries98 - Array of struct :c:type:`v4l2_subdev_route` entries
@@ -81,7 +100,7 @@ On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the · 1 unmodified line
81 - ``num_routes``100 - ``num_routes``
82 - Number of entries of the routes array101 - Number of entries of the routes array
83 * - __u32102 * - __u32
84 - ``reserved``\ [5]103 - ``reserved``\ [11]
85 - Reserved for future extensions. Applications and drivers must set104 - Reserved for future extensions. Applications and drivers must set
86 the array to zero.105 the array to zero.
87 106
@@ -135,10 +154,6 @@ On success 0 is returned, on error -1 and the ``errno`` variable is set · 47 unmodified lines
135appropriately. The generic error codes are described at the154appropriately. The generic error codes are described at the
136:ref:`Generic Error Codes <gen-errors>` chapter.155:ref:`Generic Error Codes <gen-errors>` chapter.
137 156
138ENOSPC
139 The application provided ``num_routes`` is not big enough to contain
140 all the available routes the subdevice exposes.
141
142EINVAL157EINVAL
143 The sink or source pad identifiers reference a non-existing pad or reference158 The sink or source pad identifiers reference a non-existing pad or reference
144 pads of different types (ie. the sink_pad identifiers refers to a source159 pads of different types (ie. the sink_pad identifiers refers to a source
Documentation/userspace-api/media/videodev2.h.rst.exceptions+1−0
@@ -215,6 +215,7 @@ replace define V4L2_FMT_FLAG_CSC_XFER_FUNC fmtdesc-flags · 214 unmodified lines
215replace define V4L2_FMT_FLAG_CSC_YCBCR_ENC fmtdesc-flags215replace define V4L2_FMT_FLAG_CSC_YCBCR_ENC fmtdesc-flags
216replace define V4L2_FMT_FLAG_CSC_HSV_ENC fmtdesc-flags216replace define V4L2_FMT_FLAG_CSC_HSV_ENC fmtdesc-flags
217replace define V4L2_FMT_FLAG_CSC_QUANTIZATION fmtdesc-flags217replace define V4L2_FMT_FLAG_CSC_QUANTIZATION fmtdesc-flags
218replace define V4L2_FMT_FLAG_META_LINE_BASED fmtdesc-flags
218 219
219# V4L2 timecode types220# V4L2 timecode types
220replace define V4L2_TC_TYPE_24FPS timecode-type221replace define V4L2_TC_TYPE_24FPS timecode-type
MAINTAINERS+18−1
@@ -4110,6 +4110,13 @@ N: bcm113* · 4109 unmodified lines
4110N: bcm216*4110N: bcm216*
4111N: kona4111N: kona
4112 4112
4113BROADCOM BCM2835 CAMERA DRIVERS
4114M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
4115L: linux-media@vger.kernel.org
4116S: Maintained
4117F: Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml
4118F: drivers/media/platform/broadcom/bcm2835-unicam*
4119
4113BROADCOM BCM47XX MIPS ARCHITECTURE4120BROADCOM BCM47XX MIPS ARCHITECTURE
4114M: Hauke Mehrtens <hauke@hauke-m.de>4121M: Hauke Mehrtens <hauke@hauke-m.de>
4115M: Rafał Miłecki <zajec5@gmail.com>4122M: Rafał Miłecki <zajec5@gmail.com>
@@ -11091,6 +11098,16 @@ F: Documentation/admin-guide/media/ipu3_rcb.svg · 6975 unmodified lines
11091F: Documentation/userspace-api/media/v4l/metafmt-intel-ipu3.rst11098F: Documentation/userspace-api/media/v4l/metafmt-intel-ipu3.rst
11092F: drivers/staging/media/ipu3/11099F: drivers/staging/media/ipu3/
11093 11100
11101INTEL IPU6 INPUT SYSTEM DRIVER
11102M: Sakari Ailus <sakari.ailus@linux.intel.com>
11103M: Bingbu Cao <bingbu.cao@intel.com>
11104R: Tianshu Qiu <tian.shu.qiu@intel.com>
11105L: linux-media@vger.kernel.org
11106S: Maintained
11107T: git git://linuxtv.org/media_tree.git
11108F: Documentation/admin-guide/media/ipu6-isys.rst
11109F: drivers/media/pci/intel/ipu6/
11110
11094INTEL ISHTP ECLITE DRIVER11111INTEL ISHTP ECLITE DRIVER
11095M: Sumesh K Naduvalath <sumesh.k.naduvalath@intel.com>11112M: Sumesh K Naduvalath <sumesh.k.naduvalath@intel.com>
11096L: platform-driver-x86@vger.kernel.org11113L: platform-driver-x86@vger.kernel.org
@@ -16539,7 +16556,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com> · 5442 unmodified lines
16539L: linux-media@vger.kernel.org16556L: linux-media@vger.kernel.org
16540S: Maintained16557S: Maintained
16541T: git git://linuxtv.org/media_tree.git16558T: git git://linuxtv.org/media_tree.git
16542F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml16559F: Documentation/devicetree/bindings/media/i2c/ovti,ov8856.yaml
16543F: drivers/media/i2c/ov8856.c16560F: drivers/media/i2c/ov8856.c
16544 16561
16545OMNIVISION OV8858 SENSOR DRIVER16562OMNIVISION OV8858 SENSOR DRIVER
drivers/media/cec/core/cec-adap.c+20−4
@@ -490,6 +490,15 @@ int cec_thread_func(void *_adap) · 489 unmodified lines
490 goto unlock;490 goto unlock;
491 }491 }
492 492
493 if (adap->transmit_in_progress &&
494 adap->transmit_in_progress_aborted) {
495 if (adap->transmitting)
496 cec_data_cancel(adap->transmitting,
497 CEC_TX_STATUS_ABORTED, 0);
498 adap->transmit_in_progress = false;
499 adap->transmit_in_progress_aborted = false;
500 goto unlock;
501 }
493 if (adap->transmit_in_progress && timeout) {502 if (adap->transmit_in_progress && timeout) {
494 /*503 /*
495 * If we timeout, then log that. Normally this does504 * If we timeout, then log that. Normally this does
@@ -771,6 +780,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, · 275 unmodified lines
771{780{
772 struct cec_data *data;781 struct cec_data *data;
773 bool is_raw = msg_is_raw(msg);782 bool is_raw = msg_is_raw(msg);
783 int err;
774 784
775 if (adap->devnode.unregistered)785 if (adap->devnode.unregistered)
776 return -ENODEV;786 return -ENODEV;
@@ -935,11 +945,13 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, · 158 unmodified lines
935 * Release the lock and wait, retake the lock afterwards.945 * Release the lock and wait, retake the lock afterwards.
936 */946 */
937 mutex_unlock(&adap->lock);947 mutex_unlock(&adap->lock);
938 wait_for_completion_killable(&data->c);948 err = wait_for_completion_killable(&data->c);
939 if (!data->completed)949 cancel_delayed_work_sync(&data->work);
940 cancel_delayed_work_sync(&data->work);
941 mutex_lock(&adap->lock);950 mutex_lock(&adap->lock);
942 951
952 if (err)
953 adap->transmit_in_progress_aborted = true;
954
943 /* Cancel the transmit if it was interrupted */955 /* Cancel the transmit if it was interrupted */
944 if (!data->completed) {956 if (!data->completed) {
945 if (data->msg.tx_status & CEC_TX_STATUS_OK)957 if (data->msg.tx_status & CEC_TX_STATUS_OK)
@@ -1575,9 +1587,12 @@ unconfigure: · 629 unmodified lines
1575 */1587 */
1576static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)1588static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
1577{1589{
1578 if (WARN_ON(adap->is_configuring || adap->is_configured))1590 if (WARN_ON(adap->is_claiming_log_addrs ||
1591 adap->is_configuring || adap->is_configured))
1579 return;1592 return;
1580 1593
1594 adap->is_claiming_log_addrs = true;
1595
1581 init_completion(&adap->config_completion);1596 init_completion(&adap->config_completion);
1582 1597
1583 /* Ready to kick off the thread */1598 /* Ready to kick off the thread */
@@ -1592,6 +1607,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) · 8 unmodified lines
1592 wait_for_completion(&adap->config_completion);1607 wait_for_completion(&adap->config_completion);
1593 mutex_lock(&adap->lock);1608 mutex_lock(&adap->lock);
1594 }1609 }
1610 adap->is_claiming_log_addrs = false;
1595}1611}
1596 1612
1597/*1613/*
drivers/media/cec/core/cec-api.c+4−1
@@ -178,7 +178,7 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, · 177 unmodified lines
178 CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU |178 CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU |
179 CEC_LOG_ADDRS_FL_CDC_ONLY;179 CEC_LOG_ADDRS_FL_CDC_ONLY;
180 mutex_lock(&adap->lock);180 mutex_lock(&adap->lock);
181 if (!adap->is_configuring &&181 if (!adap->is_claiming_log_addrs && !adap->is_configuring &&
182 (!log_addrs.num_log_addrs || !adap->is_configured) &&182 (!log_addrs.num_log_addrs || !adap->is_configured) &&
183 !cec_is_busy(adap, fh)) {183 !cec_is_busy(adap, fh)) {
184 err = __cec_s_log_addrs(adap, &log_addrs, block);184 err = __cec_s_log_addrs(adap, &log_addrs, block);
@@ -664,6 +664,8 @@ static int cec_release(struct inode *inode, struct file *filp) · 479 unmodified lines
664 list_del_init(&data->xfer_list);664 list_del_init(&data->xfer_list);
665 }665 }
666 mutex_unlock(&adap->lock);666 mutex_unlock(&adap->lock);
667
668 mutex_lock(&fh->lock);
667 while (!list_empty(&fh->msgs)) {669 while (!list_empty(&fh->msgs)) {
668 struct cec_msg_entry *entry =670 struct cec_msg_entry *entry =
669 list_first_entry(&fh->msgs, struct cec_msg_entry, list);671 list_first_entry(&fh->msgs, struct cec_msg_entry, list);
@@ -681,6 +683,7 @@ static int cec_release(struct inode *inode, struct file *filp) · 11 unmodified lines
681 kfree(entry);683 kfree(entry);
682 }684 }
683 }685 }
686 mutex_unlock(&fh->lock);
684 kfree(fh);687 kfree(fh);
685 688
686 cec_put_device(devnode);689 cec_put_device(devnode);
drivers/media/cec/core/cec-core.c+2−2
@@ -62,12 +62,12 @@ int cec_get_device(struct cec_devnode *devnode) · 61 unmodified lines
62 */62 */
63 mutex_lock(&devnode->lock);63 mutex_lock(&devnode->lock);
64 /*64 /*
65 * return ENXIO if the cec device has been removed65 * return ENODEV if the cec device has been removed
66 * already or if it is not registered anymore.66 * already or if it is not registered anymore.
67 */67 */
68 if (!devnode->registered) {68 if (!devnode->registered) {
69 mutex_unlock(&devnode->lock);69 mutex_unlock(&devnode->lock);
70 return -ENXIO;70 return -ENODEV;
71 }71 }
72 /* and increase the device refcount */72 /* and increase the device refcount */
73 get_device(&devnode->dev);73 get_device(&devnode->dev);
drivers/media/cec/platform/cros-ec/cros-ec-cec.c+8−1
@@ -8,6 +8,7 @@ · 7 unmodified lines
8 8
9#include <linux/kernel.h>9#include <linux/kernel.h>
10#include <linux/module.h>10#include <linux/module.h>
11#include <linux/mod_devicetable.h>
11#include <linux/platform_device.h>12#include <linux/platform_device.h>
12#include <linux/dmi.h>13#include <linux/dmi.h>
13#include <linux/pci.h>14#include <linux/pci.h>
@@ -573,6 +574,12 @@ static void cros_ec_cec_remove(struct platform_device *pdev) · 559 unmodified lines
573 }574 }
574}575}
575 576
577static const struct platform_device_id cros_ec_cec_id[] = {
578 { DRV_NAME, 0 },
579 {}
580};
581MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
582
576static struct platform_driver cros_ec_cec_driver = {583static struct platform_driver cros_ec_cec_driver = {
577 .probe = cros_ec_cec_probe,584 .probe = cros_ec_cec_probe,
578 .remove_new = cros_ec_cec_remove,585 .remove_new = cros_ec_cec_remove,
@@ -580,6 +587,7 @@ static struct platform_driver cros_ec_cec_driver = { · 1 unmodified line
580 .name = DRV_NAME,587 .name = DRV_NAME,
581 .pm = &cros_ec_cec_pm_ops,588 .pm = &cros_ec_cec_pm_ops,
582 },589 },
590 .id_table = cros_ec_cec_id,
583};591};
584 592
585module_platform_driver(cros_ec_cec_driver);593module_platform_driver(cros_ec_cec_driver);
@@ -587,4 +595,3 @@ module_platform_driver(cros_ec_cec_driver); · 1 unmodified line
587MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");595MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");
588MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");596MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
589MODULE_LICENSE("GPL");597MODULE_LICENSE("GPL");
590MODULE_ALIAS("platform:" DRV_NAME);
drivers/media/common/saa7146/saa7146_hlp.c+4−4
@@ -122,7 +122,7 @@ static int calculate_h_scale_registers(struct saa7146_dev *dev, · 121 unmodified lines
122 xacm = 0;122 xacm = 0;
123 123
124 /* set horizontal filter parameters (CXY = CXUV) */124 /* set horizontal filter parameters (CXY = CXUV) */
125 cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;125 cxy = hps_h_coeff_tab[min(xpsc - 1, 63)].hps_coeff;
126 cxuv = cxy;126 cxuv = cxy;
127 127
128 /* calculate and set horizontal fine scale (xsci) */128 /* calculate and set horizontal fine scale (xsci) */
@@ -151,7 +151,7 @@ static int calculate_h_scale_registers(struct saa7146_dev *dev, · 22 unmodified lines
151 xacm = 0;151 xacm = 0;
152 /* get best match in the table of attenuations152 /* get best match in the table of attenuations
153 for horizontal scaling */153 for horizontal scaling */
154 h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;154 h_atten = hps_h_coeff_tab[min(xpsc - 1, 63)].weight_sum;
155 155
156 for (i = 0; h_attenuation[i] != 0; i++) {156 for (i = 0; h_attenuation[i] != 0; i++) {
157 if (h_attenuation[i] >= h_atten)157 if (h_attenuation[i] >= h_atten)
@@ -283,10 +283,10 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field · 125 unmodified lines
283 }283 }
284 284
285 /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */285 /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
286 cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;286 cya_cyb = hps_v_coeff_tab[min(yacl, 63)].hps_coeff;
287 287
288 /* get best match in the table of attenuations for vertical scaling */288 /* get best match in the table of attenuations for vertical scaling */
289 v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum;289 v_atten = hps_v_coeff_tab[min(yacl, 63)].weight_sum;
290 290
291 for (i = 0; v_attenuation[i] != 0; i++) {291 for (i = 0; v_attenuation[i] != 0; i++) {
292 if (v_attenuation[i] >= v_atten)292 if (v_attenuation[i] >= v_atten)
drivers/media/common/videobuf2/videobuf2-core.c+163−68
@@ -421,11 +421,12 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) · 420 unmodified lines
421 */421 */
422static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index)422static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index)
423{423{
424 WARN_ON(index >= q->max_num_buffers || q->bufs[index] || vb->vb2_queue);424 WARN_ON(index >= q->max_num_buffers || test_bit(index, q->bufs_bitmap) || vb->vb2_queue);
425 425
426 q->bufs[index] = vb;426 q->bufs[index] = vb;
427 vb->index = index;427 vb->index = index;
428 vb->vb2_queue = q;428 vb->vb2_queue = q;
429 set_bit(index, q->bufs_bitmap);
429}430}
430 431
431/**432/**
@@ -434,6 +435,7 @@ static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, uns · 2 unmodified lines
434 */435 */
435static void vb2_queue_remove_buffer(struct vb2_buffer *vb)436static void vb2_queue_remove_buffer(struct vb2_buffer *vb)
436{437{
438 clear_bit(vb->index, vb->vb2_queue->bufs_bitmap);
437 vb->vb2_queue->bufs[vb->index] = NULL;439 vb->vb2_queue->bufs[vb->index] = NULL;
438 vb->vb2_queue = NULL;440 vb->vb2_queue = NULL;
439}441}
@@ -442,16 +444,19 @@ static void vb2_queue_remove_buffer(struct vb2_buffer *vb) · 2 unmodified lines
442 * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)444 * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
443 * video buffer memory for all buffers/planes on the queue and initializes the445 * video buffer memory for all buffers/planes on the queue and initializes the
444 * queue446 * queue
447 * @first_index: index of the first created buffer, all newly allocated buffers
448 * have indices in the range [first_index..first_index+count-1]
445 *449 *
446 * Returns the number of buffers successfully allocated.450 * Returns the number of buffers successfully allocated.
447 */451 */
448static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,452static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
449 unsigned int num_buffers, unsigned int num_planes,453 unsigned int num_buffers, unsigned int num_planes,
450 const unsigned plane_sizes[VB2_MAX_PLANES])454 const unsigned int plane_sizes[VB2_MAX_PLANES],
455 unsigned int *first_index)
451{456{
452 unsigned int q_num_buffers = vb2_get_num_buffers(q);
453 unsigned int buffer, plane;457 unsigned int buffer, plane;
454 struct vb2_buffer *vb;458 struct vb2_buffer *vb;
459 unsigned long index = q->max_num_buffers;
455 int ret;460 int ret;
456 461
457 /*462 /*
@@ -459,7 +464,25 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line
459 * in the queue is below q->max_num_buffers464 * in the queue is below q->max_num_buffers
460 */465 */
461 num_buffers = min_t(unsigned int, num_buffers,466 num_buffers = min_t(unsigned int, num_buffers,
462 q->max_num_buffers - q_num_buffers);467 q->max_num_buffers - vb2_get_num_buffers(q));
468
469 while (num_buffers) {
470 index = bitmap_find_next_zero_area(q->bufs_bitmap, q->max_num_buffers,
471 0, num_buffers, 0);
472
473 if (index < q->max_num_buffers)
474 break;
475 /* Try to find free space for less buffers */
476 num_buffers--;
477 }
478
479 /* If there is no space left to allocate buffers return 0 to indicate the error */
480 if (!num_buffers) {
481 *first_index = 0;
482 return 0;
483 }
484
485 *first_index = index;
463 486
464 for (buffer = 0; buffer < num_buffers; ++buffer) {487 for (buffer = 0; buffer < num_buffers; ++buffer) {
465 /* Allocate vb2 buffer structures */488 /* Allocate vb2 buffer structures */
@@ -479,7 +502,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 13 unmodified lines
479 vb->planes[plane].min_length = plane_sizes[plane];502 vb->planes[plane].min_length = plane_sizes[plane];
480 }503 }
481 504
482 vb2_queue_add_buffer(q, vb, q_num_buffers + buffer);505 vb2_queue_add_buffer(q, vb, index++);
483 call_void_bufop(q, init_buffer, vb);506 call_void_bufop(q, init_buffer, vb);
484 507
485 /* Allocate video buffer memory for the MMAP type */508 /* Allocate video buffer memory for the MMAP type */
@@ -517,17 +540,16 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 31 unmodified lines
517}540}
518 541
519/*542/*
520 * __vb2_free_mem() - release all video buffer memory for a given queue543 * __vb2_free_mem() - release video buffer memory for a given range of
544 * buffers in a given queue
521 */545 */
522static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)546static void __vb2_free_mem(struct vb2_queue *q, unsigned int start, unsigned int count)
523{547{
524 unsigned int buffer;548 unsigned int i;
525 struct vb2_buffer *vb;549 struct vb2_buffer *vb;
526 unsigned int q_num_buffers = vb2_get_num_buffers(q);
527 550
528 for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;551 for (i = start; i < start + count; i++) {
529 ++buffer) {552 vb = vb2_get_buffer(q, i);
530 vb = vb2_get_buffer(q, buffer);
531 if (!vb)553 if (!vb)
532 continue;554 continue;
533 555
@@ -542,35 +564,33 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) · 8 unmodified lines
542}564}
543 565
544/*566/*
545 * __vb2_queue_free() - free buffers at the end of the queue - video memory and567 * __vb2_queue_free() - free @count buffers from @start index of the queue - video memory and
546 * related information, if no buffers are left return the queue to an568 * related information, if no buffers are left return the queue to an
547 * uninitialized state. Might be called even if the queue has already been freed.569 * uninitialized state. Might be called even if the queue has already been freed.
548 */570 */
549static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)571static void __vb2_queue_free(struct vb2_queue *q, unsigned int start, unsigned int count)
550{572{
551 unsigned int buffer;573 unsigned int i;
552 unsigned int q_num_buffers = vb2_get_num_buffers(q);
553 574
554 lockdep_assert_held(&q->mmap_lock);575 lockdep_assert_held(&q->mmap_lock);
555 576
556 /* Call driver-provided cleanup function for each buffer, if provided */577 /* Call driver-provided cleanup function for each buffer, if provided */
557 for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;578 for (i = start; i < start + count; i++) {
558 ++buffer) {579 struct vb2_buffer *vb = vb2_get_buffer(q, i);
559 struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
560 580
561 if (vb && vb->planes[0].mem_priv)581 if (vb && vb->planes[0].mem_priv)
562 call_void_vb_qop(vb, buf_cleanup, vb);582 call_void_vb_qop(vb, buf_cleanup, vb);
563 }583 }
564 584
565 /* Release video buffer memory */585 /* Release video buffer memory */
566 __vb2_free_mem(q, buffers);586 __vb2_free_mem(q, start, count);
567 587
568#ifdef CONFIG_VIDEO_ADV_DEBUG588#ifdef CONFIG_VIDEO_ADV_DEBUG
569 /*589 /*
570 * Check that all the calls were balanced during the life-time of this590 * Check that all the calls were balanced during the life-time of this
571 * queue. If not then dump the counters to the kernel log.591 * queue. If not then dump the counters to the kernel log.
572 */592 */
573 if (q_num_buffers) {593 if (vb2_get_num_buffers(q)) {
574 bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||594 bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
575 q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||595 q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||
576 q->cnt_wait_prepare != q->cnt_wait_finish;596 q->cnt_wait_prepare != q->cnt_wait_finish;
@@ -596,8 +616,8 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) · 19 unmodified lines
596 q->cnt_stop_streaming = 0;616 q->cnt_stop_streaming = 0;
597 q->cnt_unprepare_streaming = 0;617 q->cnt_unprepare_streaming = 0;
598 }618 }
599 for (buffer = 0; buffer < vb2_get_num_buffers(q); buffer++) {619 for (i = start; i < start + count; i++) {
600 struct vb2_buffer *vb = vb2_get_buffer(q, buffer);620 struct vb2_buffer *vb = vb2_get_buffer(q, i);
601 bool unbalanced;621 bool unbalanced;
602 622
603 if (!vb)623 if (!vb)
@@ -614,7 +634,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) · 10 unmodified lines
614 634
615 if (unbalanced) {635 if (unbalanced) {
616 pr_info("unbalanced counters for queue %p, buffer %d:\n",636 pr_info("unbalanced counters for queue %p, buffer %d:\n",
617 q, buffer);637 q, i);
618 if (vb->cnt_buf_init != vb->cnt_buf_cleanup)638 if (vb->cnt_buf_init != vb->cnt_buf_cleanup)
619 pr_info(" buf_init: %u buf_cleanup: %u\n",639 pr_info(" buf_init: %u buf_cleanup: %u\n",
620 vb->cnt_buf_init, vb->cnt_buf_cleanup);640 vb->cnt_buf_init, vb->cnt_buf_cleanup);
@@ -648,9 +668,8 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) · 27 unmodified lines
648#endif668#endif
649 669
650 /* Free vb2 buffers */670 /* Free vb2 buffers */
651 for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;671 for (i = start; i < start + count; i++) {
652 ++buffer) {672 struct vb2_buffer *vb = vb2_get_buffer(q, i);
653 struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
654 673
655 if (!vb)674 if (!vb)
656 continue;675 continue;
@@ -659,7 +678,6 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) · 2 unmodified lines
659 kfree(vb);678 kfree(vb);
660 }679 }
661 680
662 q->num_buffers -= buffers;
663 if (!vb2_get_num_buffers(q)) {681 if (!vb2_get_num_buffers(q)) {
664 q->memory = VB2_MEMORY_UNKNOWN;682 q->memory = VB2_MEMORY_UNKNOWN;
665 INIT_LIST_HEAD(&q->queued_list);683 INIT_LIST_HEAD(&q->queued_list);
@@ -691,7 +709,7 @@ EXPORT_SYMBOL(vb2_buffer_in_use); · 25 unmodified lines
691static bool __buffers_in_use(struct vb2_queue *q)709static bool __buffers_in_use(struct vb2_queue *q)
692{710{
693 unsigned int buffer;711 unsigned int buffer;
694 for (buffer = 0; buffer < vb2_get_num_buffers(q); ++buffer) {712 for (buffer = 0; buffer < q->max_num_buffers; ++buffer) {
695 struct vb2_buffer *vb = vb2_get_buffer(q, buffer);713 struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
696 714
697 if (!vb)715 if (!vb)
@@ -813,6 +831,32 @@ static bool verify_coherency_flags(struct vb2_queue *q, bool non_coherent_mem) · 115 unmodified lines
813 return true;831 return true;
814}832}
815 833
834static int vb2_core_allocated_buffers_storage(struct vb2_queue *q)
835{
836 if (!q->bufs)
837 q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
838 if (!q->bufs)
839 return -ENOMEM;
840
841 if (!q->bufs_bitmap)
842 q->bufs_bitmap = bitmap_zalloc(q->max_num_buffers, GFP_KERNEL);
843 if (!q->bufs_bitmap) {
844 kfree(q->bufs);
845 q->bufs = NULL;
846 return -ENOMEM;
847 }
848
849 return 0;
850}
851
852static void vb2_core_free_buffers_storage(struct vb2_queue *q)
853{
854 kfree(q->bufs);
855 q->bufs = NULL;
856 bitmap_free(q->bufs_bitmap);
857 q->bufs_bitmap = NULL;
858}
859
816int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,860int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
817 unsigned int flags, unsigned int *count)861 unsigned int flags, unsigned int *count)
818{862{
@@ -820,7 +864,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line
820 unsigned int q_num_bufs = vb2_get_num_buffers(q);864 unsigned int q_num_bufs = vb2_get_num_buffers(q);
821 unsigned plane_sizes[VB2_MAX_PLANES] = { };865 unsigned plane_sizes[VB2_MAX_PLANES] = { };
822 bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;866 bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
823 unsigned int i;867 unsigned int i, first_index;
824 int ret = 0;868 int ret = 0;
825 869
826 if (q->streaming) {870 if (q->streaming) {
@@ -851,9 +895,10 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 24 unmodified lines
851 * queued without ever calling STREAMON.895 * queued without ever calling STREAMON.
852 */896 */
853 __vb2_queue_cancel(q);897 __vb2_queue_cancel(q);
854 __vb2_queue_free(q, q_num_bufs);898 __vb2_queue_free(q, 0, q->max_num_buffers);
855 mutex_unlock(&q->mmap_lock);899 mutex_unlock(&q->mmap_lock);
856 900
901 q->is_busy = 0;
857 /*902 /*
858 * In case of REQBUFS(0) return immediately without calling903 * In case of REQBUFS(0) return immediately without calling
859 * driver's queue_setup() callback and allocating resources.904 * driver's queue_setup() callback and allocating resources.
@@ -865,7 +910,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 5 unmodified lines
865 /*910 /*
866 * Make sure the requested values and current defaults are sane.911 * Make sure the requested values and current defaults are sane.
867 */912 */
868 num_buffers = max_t(unsigned int, *count, q->min_queued_buffers);913 num_buffers = max_t(unsigned int, *count, q->min_reqbufs_allocation);
869 num_buffers = min_t(unsigned int, num_buffers, q->max_num_buffers);914 num_buffers = min_t(unsigned int, num_buffers, q->max_num_buffers);
870 memset(q->alloc_devs, 0, sizeof(q->alloc_devs));915 memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
871 /*916 /*
@@ -873,10 +918,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line
873 * in the queue_setup op.918 * in the queue_setup op.
874 */919 */
875 mutex_lock(&q->mmap_lock);920 mutex_lock(&q->mmap_lock);
876 if (!q->bufs)921 ret = vb2_core_allocated_buffers_storage(q);
877 q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
878 if (!q->bufs)
879 ret = -ENOMEM;
880 q->memory = memory;922 q->memory = memory;
881 mutex_unlock(&q->mmap_lock);923 mutex_unlock(&q->mmap_lock);
882 if (ret)924 if (ret)
@@ -906,8 +948,10 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 23 unmodified lines
906 948
907 /* Finally, allocate buffers and video memory */949 /* Finally, allocate buffers and video memory */
908 allocated_buffers =950 allocated_buffers =
909 __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);951 __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes, &first_index);
910 if (allocated_buffers == 0) {952 if (allocated_buffers == 0) {
953 /* There shouldn't be any buffers allocated, so first_index == 0 */
954 WARN_ON(first_index);
911 dprintk(q, 1, "memory allocation failed\n");955 dprintk(q, 1, "memory allocation failed\n");
912 ret = -ENOMEM;956 ret = -ENOMEM;
913 goto error;957 goto error;
@@ -917,7 +961,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 3 unmodified lines
917 * There is no point in continuing if we can't allocate the minimum961 * There is no point in continuing if we can't allocate the minimum
918 * number of buffers needed by this vb2_queue.962 * number of buffers needed by this vb2_queue.
919 */963 */
920 if (allocated_buffers < q->min_queued_buffers)964 if (allocated_buffers < q->min_reqbufs_allocation)
921 ret = -ENOMEM;965 ret = -ENOMEM;
922 966
923 /*967 /*
@@ -946,7 +990,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 22 unmodified lines
946 }990 }
947 991
948 mutex_lock(&q->mmap_lock);992 mutex_lock(&q->mmap_lock);
949 q->num_buffers = allocated_buffers;
950 993
951 if (ret < 0) {994 if (ret < 0) {
952 /*995 /*
@@ -954,7 +997,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line
954 * from already queued buffers and it will reset q->memory to997 * from already queued buffers and it will reset q->memory to
955 * VB2_MEMORY_UNKNOWN.998 * VB2_MEMORY_UNKNOWN.
956 */999 */
957 __vb2_queue_free(q, allocated_buffers);1000 __vb2_queue_free(q, first_index, allocated_buffers);
958 mutex_unlock(&q->mmap_lock);1001 mutex_unlock(&q->mmap_lock);
959 return ret;1002 return ret;
960 }1003 }
@@ -966,6 +1009,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 5 unmodified lines
966 */1009 */
967 *count = allocated_buffers;1010 *count = allocated_buffers;
968 q->waiting_for_buffers = !q->is_output;1011 q->waiting_for_buffers = !q->is_output;
1012 q->is_busy = 1;
969 1013
970 return 0;1014 return 0;
971 1015
@@ -973,6 +1017,7 @@ error: · 1 unmodified line
973 mutex_lock(&q->mmap_lock);1017 mutex_lock(&q->mmap_lock);
974 q->memory = VB2_MEMORY_UNKNOWN;1018 q->memory = VB2_MEMORY_UNKNOWN;
975 mutex_unlock(&q->mmap_lock);1019 mutex_unlock(&q->mmap_lock);
1020 vb2_core_free_buffers_storage(q);
976 return ret;1021 return ret;
977}1022}
978EXPORT_SYMBOL_GPL(vb2_core_reqbufs);1023EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
@@ -980,7 +1025,8 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs); · 1 unmodified line
980int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,1025int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
981 unsigned int flags, unsigned int *count,1026 unsigned int flags, unsigned int *count,
982 unsigned int requested_planes,1027 unsigned int requested_planes,
983 const unsigned int requested_sizes[])1028 const unsigned int requested_sizes[],
1029 unsigned int *first_index)
984{1030{
985 unsigned int num_planes = 0, num_buffers, allocated_buffers;1031 unsigned int num_planes = 0, num_buffers, allocated_buffers;
986 unsigned plane_sizes[VB2_MAX_PLANES] = { };1032 unsigned plane_sizes[VB2_MAX_PLANES] = { };
@@ -1005,11 +1051,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 18 unmodified lines
1005 * value in the queue_setup op.1051 * value in the queue_setup op.
1006 */1052 */
1007 mutex_lock(&q->mmap_lock);1053 mutex_lock(&q->mmap_lock);
1054 ret = vb2_core_allocated_buffers_storage(q);
1008 q->memory = memory;1055 q->memory = memory;
1009 if (!q->bufs)
1010 q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
1011 if (!q->bufs)
1012 ret = -ENOMEM;
1013 mutex_unlock(&q->mmap_lock);1056 mutex_unlock(&q->mmap_lock);
1014 if (ret)1057 if (ret)
1015 return ret;1058 return ret;
@@ -1042,7 +1085,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 26 unmodified lines
1042 1085
1043 /* Finally, allocate buffers and video memory */1086 /* Finally, allocate buffers and video memory */
1044 allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,1087 allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
1045 num_planes, plane_sizes);1088 num_planes, plane_sizes, first_index);
1046 if (allocated_buffers == 0) {1089 if (allocated_buffers == 0) {
1047 dprintk(q, 1, "memory allocation failed\n");1090 dprintk(q, 1, "memory allocation failed\n");
1048 ret = -ENOMEM;1091 ret = -ENOMEM;
@@ -1072,7 +1115,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 23 unmodified lines
1072 }1115 }
1073 1116
1074 mutex_lock(&q->mmap_lock);1117 mutex_lock(&q->mmap_lock);
1075 q->num_buffers += allocated_buffers;
1076 1118
1077 if (ret < 0) {1119 if (ret < 0) {
1078 /*1120 /*
@@ -1080,7 +1122,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line
1080 * from already queued buffers and it will reset q->memory to1122 * from already queued buffers and it will reset q->memory to
1081 * VB2_MEMORY_UNKNOWN.1123 * VB2_MEMORY_UNKNOWN.
1082 */1124 */
1083 __vb2_queue_free(q, allocated_buffers);1125 __vb2_queue_free(q, *first_index, allocated_buffers);
1084 mutex_unlock(&q->mmap_lock);1126 mutex_unlock(&q->mmap_lock);
1085 return -ENOMEM;1127 return -ENOMEM;
1086 }1128 }
@@ -1091,6 +1133,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 4 unmodified lines
1091 * to the userspace.1133 * to the userspace.
1092 */1134 */
1093 *count = allocated_buffers;1135 *count = allocated_buffers;
1136 q->is_busy = 1;
1094 1137
1095 return 0;1138 return 0;
1096 1139
@@ -1648,6 +1691,44 @@ int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb) · 551 unmodified lines
1648}1691}
1649EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);1692EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
1650 1693
1694int vb2_core_remove_bufs(struct vb2_queue *q, unsigned int start, unsigned int count)
1695{
1696 unsigned int i, ret = 0;
1697 unsigned int q_num_bufs = vb2_get_num_buffers(q);
1698
1699 if (count == 0)
1700 return 0;
1701
1702 if (count > q_num_bufs)
1703 return -EINVAL;
1704
1705 if (start > q->max_num_buffers - count)
1706 return -EINVAL;
1707
1708 mutex_lock(&q->mmap_lock);
1709
1710 /* Check that all buffers in the range exist */
1711 for (i = start; i < start + count; i++) {
1712 struct vb2_buffer *vb = vb2_get_buffer(q, i);
1713
1714 if (!vb) {
1715 ret = -EINVAL;
1716 goto unlock;
1717 }
1718 if (vb->state != VB2_BUF_STATE_DEQUEUED) {
1719 ret = -EBUSY;
1720 goto unlock;
1721 }
1722 }
1723 __vb2_queue_free(q, start, count);
1724 dprintk(q, 2, "%u buffers removed\n", count);
1725
1726unlock:
1727 mutex_unlock(&q->mmap_lock);
1728 return ret;
1729}
1730EXPORT_SYMBOL_GPL(vb2_core_remove_bufs);
1731
1651/*1732/*
1652 * vb2_start_streaming() - Attempt to start streaming.1733 * vb2_start_streaming() - Attempt to start streaming.
1653 * @q: videobuf2 queue1734 * @q: videobuf2 queue
@@ -1694,7 +1775,7 @@ static int vb2_start_streaming(struct vb2_queue *q) · 40 unmodified lines
1694 * Forcefully reclaim buffers if the driver did not1775 * Forcefully reclaim buffers if the driver did not
1695 * correctly return them to vb2.1776 * correctly return them to vb2.
1696 */1777 */
1697 for (i = 0; i < vb2_get_num_buffers(q); ++i) {1778 for (i = 0; i < q->max_num_buffers; ++i) {
1698 vb = vb2_get_buffer(q, i);1779 vb = vb2_get_buffer(q, i);
1699 1780
1700 if (!vb)1781 if (!vb)
@@ -2100,7 +2181,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) · 399 unmodified lines
2100 * to vb2 in stop_streaming().2181 * to vb2 in stop_streaming().
2101 */2182 */
2102 if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {2183 if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
2103 for (i = 0; i < vb2_get_num_buffers(q); i++) {2184 for (i = 0; i < q->max_num_buffers; i++) {
2104 struct vb2_buffer *vb = vb2_get_buffer(q, i);2185 struct vb2_buffer *vb = vb2_get_buffer(q, i);
2105 2186
2106 if (!vb)2187 if (!vb)
@@ -2144,7 +2225,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) · 37 unmodified lines
2144 * call to __fill_user_buffer() after buf_finish(). That order can't2225 * call to __fill_user_buffer() after buf_finish(). That order can't
2145 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().2226 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
2146 */2227 */
2147 for (i = 0; i < vb2_get_num_buffers(q); i++) {2228 for (i = 0; i < q->max_num_buffers; i++) {
2148 struct vb2_buffer *vb;2229 struct vb2_buffer *vb;
2149 struct media_request *req;2230 struct media_request *req;
2150 2231
@@ -2503,7 +2584,7 @@ int vb2_core_queue_init(struct vb2_queue *q) · 352 unmodified lines
2503 WARN_ON(!q->ops->buf_queue))2584 WARN_ON(!q->ops->buf_queue))
2504 return -EINVAL;2585 return -EINVAL;
2505 2586
2506 if (WARN_ON(q->max_num_buffers > MAX_BUFFER_INDEX) ||2587 if (WARN_ON(q->max_num_buffers < VB2_MAX_FRAME) ||
2507 WARN_ON(q->min_queued_buffers > q->max_num_buffers))2588 WARN_ON(q->min_queued_buffers > q->max_num_buffers))
2508 return -EINVAL;2589 return -EINVAL;
2509 2590
@@ -2521,6 +2602,25 @@ int vb2_core_queue_init(struct vb2_queue *q) · 11 unmodified lines
2521 if (WARN_ON(q->supports_requests && q->min_queued_buffers))2602 if (WARN_ON(q->supports_requests && q->min_queued_buffers))
2522 return -EINVAL;2603 return -EINVAL;
2523 2604
2605 /*
2606 * The minimum requirement is 2: one buffer is used
2607 * by the hardware while the other is being processed by userspace.
2608 */
2609 if (q->min_reqbufs_allocation < 2)
2610 q->min_reqbufs_allocation = 2;
2611
2612 /*
2613 * If the driver needs 'min_queued_buffers' in the queue before
2614 * calling start_streaming() then the minimum requirement is
2615 * 'min_queued_buffers + 1' to keep at least one buffer available
2616 * for userspace.
2617 */
2618 if (q->min_reqbufs_allocation < q->min_queued_buffers + 1)
2619 q->min_reqbufs_allocation = q->min_queued_buffers + 1;
2620
2621 if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers))
2622 return -EINVAL;
2623
2524 INIT_LIST_HEAD(&q->queued_list);2624 INIT_LIST_HEAD(&q->queued_list);
2525 INIT_LIST_HEAD(&q->done_list);2625 INIT_LIST_HEAD(&q->done_list);
2526 spin_lock_init(&q->done_lock);2626 spin_lock_init(&q->done_lock);
@@ -2552,9 +2652,9 @@ void vb2_core_queue_release(struct vb2_queue *q) · 25 unmodified lines
2552 __vb2_cleanup_fileio(q);2652 __vb2_cleanup_fileio(q);
2553 __vb2_queue_cancel(q);2653 __vb2_queue_cancel(q);
2554 mutex_lock(&q->mmap_lock);2654 mutex_lock(&q->mmap_lock);
2555 __vb2_queue_free(q, vb2_get_num_buffers(q));2655 __vb2_queue_free(q, 0, q->max_num_buffers);
2556 kfree(q->bufs);2656 vb2_core_free_buffers_storage(q);
2557 q->bufs = NULL;2657 q->is_busy = 0;
2558 mutex_unlock(&q->mmap_lock);2658 mutex_unlock(&q->mmap_lock);
2559}2659}
2560EXPORT_SYMBOL_GPL(vb2_core_queue_release);2660EXPORT_SYMBOL_GPL(vb2_core_queue_release);
@@ -2713,7 +2813,6 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 152 unmodified lines
2713 struct vb2_fileio_data *fileio;2813 struct vb2_fileio_data *fileio;
2714 struct vb2_buffer *vb;2814 struct vb2_buffer *vb;
2715 int i, ret;2815 int i, ret;
2716 unsigned int count = 0;
2717 2816
2718 /*2817 /*
2719 * Sanity check2818 * Sanity check
@@ -2734,18 +2833,8 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 14 unmodified lines
2734 if (q->streaming || vb2_get_num_buffers(q) > 0)2833 if (q->streaming || vb2_get_num_buffers(q) > 0)
2735 return -EBUSY;2834 return -EBUSY;
2736 2835
2737 /*
2738 * Start with q->min_queued_buffers + 1, driver can increase it in
2739 * queue_setup()
2740 *
2741 * 'min_queued_buffers' buffers need to be queued up before you
2742 * can start streaming, plus 1 for userspace (or in this case,
2743 * kernelspace) processing.
2744 */
2745 count = max(2, q->min_queued_buffers + 1);
2746
2747 dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",2836 dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
2748 (read) ? "read" : "write", count, q->fileio_read_once,2837 (read) ? "read" : "write", q->min_reqbufs_allocation, q->fileio_read_once,
2749 q->fileio_write_immediately);2838 q->fileio_write_immediately);
2750 2839
2751 fileio = kzalloc(sizeof(*fileio), GFP_KERNEL);2840 fileio = kzalloc(sizeof(*fileio), GFP_KERNEL);
@@ -2759,13 +2848,19 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 7 unmodified lines
2759 * Request buffers and use MMAP type to force driver2848 * Request buffers and use MMAP type to force driver
2760 * to allocate buffers by itself.2849 * to allocate buffers by itself.
2761 */2850 */
2762 fileio->count = count;2851 fileio->count = q->min_reqbufs_allocation;
2763 fileio->memory = VB2_MEMORY_MMAP;2852 fileio->memory = VB2_MEMORY_MMAP;
2764 fileio->type = q->type;2853 fileio->type = q->type;
2765 q->fileio = fileio;2854 q->fileio = fileio;
2766 ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);2855 ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
2767 if (ret)2856 if (ret)
2768 goto err_kfree;2857 goto err_kfree;
2858 /* vb2_fileio_data supports max VB2_MAX_FRAME buffers */
2859 if (fileio->count > VB2_MAX_FRAME) {
2860 dprintk(q, 1, "fileio: more than VB2_MAX_FRAME buffers requested\n");
2861 ret = -ENOSPC;
2862 goto err_reqbufs;
2863 }
2769 2864
2770 /*2865 /*
2771 * Userspace can never add or delete buffers later, so there2866 * Userspace can never add or delete buffers later, so there
drivers/media/common/videobuf2/videobuf2-v4l2.c+28−6
@@ -685,7 +685,7 @@ static void vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory, · 684 unmodified lines
685 *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;685 *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
686 }686 }
687 687
688 *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;688 *caps |= V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
689 if (q->io_modes & VB2_MMAP)689 if (q->io_modes & VB2_MMAP)
690 *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;690 *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
691 if (q->io_modes & VB2_USERPTR)691 if (q->io_modes & VB2_USERPTR)
@@ -795,11 +795,15 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) · 103 unmodified lines
795 for (i = 0; i < requested_planes; i++)795 for (i = 0; i < requested_planes; i++)
796 if (requested_sizes[i] == 0)796 if (requested_sizes[i] == 0)
797 return -EINVAL;797 return -EINVAL;
798 return ret ? ret : vb2_core_create_bufs(q, create->memory,798 if (ret)
799 create->flags,799 return ret;
800 &create->count,800
801 requested_planes,801 return vb2_core_create_bufs(q, create->memory,
802 requested_sizes);802 create->flags,
803 &create->count,
804 requested_planes,
805 requested_sizes,
806 &create->index);
803}807}
804EXPORT_SYMBOL_GPL(vb2_create_bufs);808EXPORT_SYMBOL_GPL(vb2_create_bufs);
805 809
@@ -997,6 +1001,24 @@ EXPORT_SYMBOL_GPL(vb2_poll); · 191 unmodified lines
997 1001
998/* vb2 ioctl helpers */1002/* vb2 ioctl helpers */
999 1003
1004int vb2_ioctl_remove_bufs(struct file *file, void *priv,
1005 struct v4l2_remove_buffers *d)
1006{
1007 struct video_device *vdev = video_devdata(file);
1008
1009 if (vdev->queue->type != d->type)
1010 return -EINVAL;
1011
1012 if (d->count == 0)
1013 return 0;
1014
1015 if (vb2_queue_is_busy(vdev->queue, file))
1016 return -EBUSY;
1017
1018 return vb2_core_remove_bufs(vdev->queue, d->index, d->count);
1019}
1020EXPORT_SYMBOL_GPL(vb2_ioctl_remove_bufs);
1021
1000int vb2_ioctl_reqbufs(struct file *file, void *priv,1022int vb2_ioctl_reqbufs(struct file *file, void *priv,
1001 struct v4l2_requestbuffers *p)1023 struct v4l2_requestbuffers *p)
1002{1024{
drivers/media/dvb-core/dvbdev.c+1−1
@@ -956,7 +956,7 @@ int dvb_usercopy(struct file *file, · 955 unmodified lines
956 int (*func)(struct file *file,956 int (*func)(struct file *file,
957 unsigned int cmd, void *arg))957 unsigned int cmd, void *arg))
958{958{
959 char sbuf[128];959 char sbuf[128] = {};
960 void *mbuf = NULL;960 void *mbuf = NULL;
961 void *parg = NULL;961 void *parg = NULL;
962 int err = -EINVAL;962 int err = -EINVAL;
drivers/media/dvb-frontends/as102_fe_types.h+1−1
@@ -174,6 +174,6 @@ struct as10x_register_addr { · 173 unmodified lines
174 uint32_t addr;174 uint32_t addr;
175 /* register mode access */175 /* register mode access */
176 uint8_t mode;176 uint8_t mode;
177};177} __packed;
178 178
179#endif179#endif
drivers/media/dvb-frontends/cxd2880/Kconfig+1−1
@@ -5,4 +5,4 @@ config DVB_CXD2880 · 4 unmodified lines
5 depends on DVB_CORE && SPI5 depends on DVB_CORE && SPI
6 default m if !MEDIA_SUBDRV_AUTOSELECT6 default m if !MEDIA_SUBDRV_AUTOSELECT
7 help7 help
8 Say Y when you want to support this frontend.8 Say Y when you want to support this frontend.
drivers/media/dvb-frontends/drx39xyj/drx_driver.h+0−2
@@ -33,7 +33,6 @@ · 32 unmodified lines
33 33
34#include <linux/kernel.h>34#include <linux/kernel.h>
35#include <linux/errno.h>35#include <linux/errno.h>
36#include <linux/firmware.h>
37#include <linux/i2c.h>36#include <linux/i2c.h>
38 37
39/*38/*
@@ -1910,7 +1909,6 @@ struct drx_demod_instance { · 1870 unmodified lines
1910 /* generic demodulator data */1909 /* generic demodulator data */
1911 1910
1912 struct i2c_adapter *i2c;1911 struct i2c_adapter *i2c;
1913 const struct firmware *firmware;
1914};1912};
1915 1913
1916/*-------------------------------------------------------------------------1914/*-------------------------------------------------------------------------
drivers/media/dvb-frontends/drx39xyj/drxj.c+26−32
@@ -56,6 +56,7 @@ INCLUDE FILES · 55 unmodified lines
56#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__56#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
57 57
58#include <linux/module.h>58#include <linux/module.h>
59#include <linux/firmware.h>
59#include <linux/init.h>60#include <linux/init.h>
60#include <linux/string.h>61#include <linux/string.h>
61#include <linux/slab.h>62#include <linux/slab.h>
@@ -1444,8 +1445,7 @@ static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr, · 1382 unmodified lines
1444 1445
1445 /* Read block from I2C **************************************************** */1446 /* Read block from I2C **************************************************** */
1446 do {1447 do {
1447 u16 todo = (datasize < DRXDAP_MAX_RCHUNKSIZE ?1448 u16 todo = min(datasize, DRXDAP_MAX_RCHUNKSIZE);
1448 datasize : DRXDAP_MAX_RCHUNKSIZE);
1449 1449
1450 bufx = 0;1450 bufx = 0;
1451 1451
@@ -1659,7 +1659,7 @@ static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, · 207 unmodified lines
1659 Address must be rewritten because HI is reset after data transport and1659 Address must be rewritten because HI is reset after data transport and
1660 expects an address.1660 expects an address.
1661 */1661 */
1662 todo = (block_size < datasize ? block_size : datasize);1662 todo = min(block_size, datasize);
1663 if (todo == 0) {1663 if (todo == 0) {
1664 u16 overhead_size_i2c_addr = 0;1664 u16 overhead_size_i2c_addr = 0;
1665 u16 data_block_size = 0;1665 u16 data_block_size = 0;
@@ -1681,9 +1681,7 @@ static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, · 15 unmodified lines
1681 first_err = st;1681 first_err = st;
1682 }1682 }
1683 bufx = 0;1683 bufx = 0;
1684 todo =1684 todo = min(data_block_size, datasize);
1685 (data_block_size <
1686 datasize ? data_block_size : datasize);
1687 }1685 }
1688 memcpy(&buf[bufx], data, todo);1686 memcpy(&buf[bufx], data, todo);
1689 /* write (address if can do and) data */1687 /* write (address if can do and) data */
@@ -11750,6 +11748,7 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, · 10060 unmodified lines
11750 u8 *mc_data = NULL;11748 u8 *mc_data = NULL;
11751 unsigned size;11749 unsigned size;
11752 char *mc_file;11750 char *mc_file;
11751 const struct firmware *fw;
11753 11752
11754 /* Check arguments */11753 /* Check arguments */
11755 if (!mc_info || !mc_info->mc_file)11754 if (!mc_info || !mc_info->mc_file)
@@ -11757,28 +11756,22 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, · 1 unmodified line
11757 11756
11758 mc_file = mc_info->mc_file;11757 mc_file = mc_info->mc_file;
11759 11758
11760 if (!demod->firmware) {11759 rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
11761 const struct firmware *fw = NULL;11760 if (rc < 0) {
11762 11761 pr_err("Couldn't read firmware %s\n", mc_file);
11763 rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);11762 return rc;
11764 if (rc < 0) {11763 }
11765 pr_err("Couldn't read firmware %s\n", mc_file);
11766 return rc;
11767 }
11768 demod->firmware = fw;
11769
11770 if (demod->firmware->size < 2 * sizeof(u16)) {
11771 rc = -EINVAL;
11772 pr_err("Firmware is too short!\n");
11773 goto release;
11774 }
11775 11764
11776 pr_info("Firmware %s, size %zu\n",11765 if (fw->size < 2 * sizeof(u16)) {
11777 mc_file, demod->firmware->size);11766 rc = -EINVAL;
11767 pr_err("Firmware is too short!\n");
11768 goto release;
11778 }11769 }
11779 11770
11780 mc_data_init = demod->firmware->data;11771 pr_info("Firmware %s, size %zu\n", mc_file, fw->size);
11781 size = demod->firmware->size;11772
11773 mc_data_init = fw->data;
11774 size = fw->size;
11782 11775
11783 mc_data = (void *)mc_data_init;11776 mc_data = (void *)mc_data_init;
11784 /* Check data */11777 /* Check data */
@@ -11874,7 +11867,8 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, · 89 unmodified lines
11874 0x0000)) {11867 0x0000)) {
11875 pr_err("error reading firmware at pos %zd\n",11868 pr_err("error reading firmware at pos %zd\n",
11876 mc_data - mc_data_init);11869 mc_data - mc_data_init);
11877 return -EIO;11870 rc = -EIO;
11871 goto release;
11878 }11872 }
11879 11873
11880 result = memcmp(curr_ptr, mc_data_buffer,11874 result = memcmp(curr_ptr, mc_data_buffer,
@@ -11883,7 +11877,8 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, · 2 unmodified lines
11883 if (result) {11877 if (result) {
11884 pr_err("error verifying firmware at pos %zd\n",11878 pr_err("error verifying firmware at pos %zd\n",
11885 mc_data - mc_data_init);11879 mc_data - mc_data_init);
11886 return -EIO;11880 rc = -EIO;
11881 goto release;
11887 }11882 }
11888 11883
11889 curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));11884 curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
@@ -11893,17 +11888,17 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, · 3 unmodified lines
11893 break;11888 break;
11894 }11889 }
11895 default:11890 default:
11896 return -EINVAL;11891 rc = -EINVAL;
11892 goto release;
11897 11893
11898 }11894 }
11899 mc_data += mc_block_nr_bytes;11895 mc_data += mc_block_nr_bytes;
11900 }11896 }
11901 11897
11902 return 0;11898 rc = 0;
11903 11899
11904release:11900release:
11905 release_firmware(demod->firmware);11901 release_firmware(fw);
11906 demod->firmware = NULL;
11907 11902
11908 return rc;11903 return rc;
11909}11904}
@@ -12271,7 +12266,6 @@ static void drx39xxj_release(struct dvb_frontend *fe) · 361 unmodified lines
12271 kfree(demod->my_ext_attr);12266 kfree(demod->my_ext_attr);
12272 kfree(demod->my_common_attr);12267 kfree(demod->my_common_attr);
12273 kfree(demod->my_i2c_dev_addr);12268 kfree(demod->my_i2c_dev_addr);
12274 release_firmware(demod->firmware);
12275 kfree(demod);12269 kfree(demod);
12276 kfree(state);12270 kfree(state);
12277}12271}
drivers/media/dvb-frontends/lgdt3306a.c+5−0
@@ -2176,6 +2176,11 @@ static int lgdt3306a_probe(struct i2c_client *client) · 2175 unmodified lines
2176 struct dvb_frontend *fe;2176 struct dvb_frontend *fe;
2177 int ret;2177 int ret;
2178 2178
2179 if (!client->dev.platform_data) {
2180 dev_err(&client->dev, "platform data is mandatory\n");
2181 return -EINVAL;
2182 }
2183
2179 config = kmemdup(client->dev.platform_data,2184 config = kmemdup(client->dev.platform_data,
2180 sizeof(struct lgdt3306a_config), GFP_KERNEL);2185 sizeof(struct lgdt3306a_config), GFP_KERNEL);
2181 if (config == NULL) {2186 if (config == NULL) {
drivers/media/dvb-frontends/m88ds3103.c+7−0
@@ -1000,6 +1000,13 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 999 unmodified lines
1000 if (ret)1000 if (ret)
1001 goto err;1001 goto err;
1002 1002
1003 if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
1004 /* to light up the LOCK led */
1005 ret = m88ds3103_update_bits(dev, 0x11, 0x80, 0x00);
1006 if (ret)
1007 goto err;
1008 }
1009
1003 dev->delivery_system = c->delivery_system;1010 dev->delivery_system = c->delivery_system;
1004 1011
1005 return 0;1012 return 0;
drivers/media/dvb-frontends/mxl5xx.c+11−11
@@ -1381,57 +1381,57 @@ static int config_ts(struct mxl *state, enum MXL_HYDRA_DEMOD_ID_E demod_id, · 1380 unmodified lines
1381 u32 nco_count_min = 0;1381 u32 nco_count_min = 0;
1382 u32 clk_type = 0;1382 u32 clk_type = 0;
1383 1383
1384 struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = {1384 static const struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = {
1385 {0x90700010, 8, 1}, {0x90700010, 9, 1},1385 {0x90700010, 8, 1}, {0x90700010, 9, 1},
1386 {0x90700010, 10, 1}, {0x90700010, 11, 1},1386 {0x90700010, 10, 1}, {0x90700010, 11, 1},
1387 {0x90700010, 12, 1}, {0x90700010, 13, 1},1387 {0x90700010, 12, 1}, {0x90700010, 13, 1},
1388 {0x90700010, 14, 1}, {0x90700010, 15, 1} };1388 {0x90700010, 14, 1}, {0x90700010, 15, 1} };
1389 struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = {1389 static const struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = {
1390 {0x90700010, 16, 1}, {0x90700010, 17, 1},1390 {0x90700010, 16, 1}, {0x90700010, 17, 1},
1391 {0x90700010, 18, 1}, {0x90700010, 19, 1},1391 {0x90700010, 18, 1}, {0x90700010, 19, 1},
1392 {0x90700010, 20, 1}, {0x90700010, 21, 1},1392 {0x90700010, 20, 1}, {0x90700010, 21, 1},
1393 {0x90700010, 22, 1}, {0x90700010, 23, 1} };1393 {0x90700010, 22, 1}, {0x90700010, 23, 1} };
1394 struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = {1394 static const struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = {
1395 {0x90700014, 0, 1}, {0x90700014, 1, 1},1395 {0x90700014, 0, 1}, {0x90700014, 1, 1},
1396 {0x90700014, 2, 1}, {0x90700014, 3, 1},1396 {0x90700014, 2, 1}, {0x90700014, 3, 1},
1397 {0x90700014, 4, 1}, {0x90700014, 5, 1},1397 {0x90700014, 4, 1}, {0x90700014, 5, 1},
1398 {0x90700014, 6, 1}, {0x90700014, 7, 1} };1398 {0x90700014, 6, 1}, {0x90700014, 7, 1} };
1399 struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = {1399 static const struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = {
1400 {0x90700018, 0, 3}, {0x90700018, 4, 3},1400 {0x90700018, 0, 3}, {0x90700018, 4, 3},
1401 {0x90700018, 8, 3}, {0x90700018, 12, 3},1401 {0x90700018, 8, 3}, {0x90700018, 12, 3},
1402 {0x90700018, 16, 3}, {0x90700018, 20, 3},1402 {0x90700018, 16, 3}, {0x90700018, 20, 3},
1403 {0x90700018, 24, 3}, {0x90700018, 28, 3} };1403 {0x90700018, 24, 3}, {0x90700018, 28, 3} };
1404 struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = {1404 static const struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = {
1405 {0x9070000C, 16, 1}, {0x9070000C, 17, 1},1405 {0x9070000C, 16, 1}, {0x9070000C, 17, 1},
1406 {0x9070000C, 18, 1}, {0x9070000C, 19, 1},1406 {0x9070000C, 18, 1}, {0x9070000C, 19, 1},
1407 {0x9070000C, 20, 1}, {0x9070000C, 21, 1},1407 {0x9070000C, 20, 1}, {0x9070000C, 21, 1},
1408 {0x9070000C, 22, 1}, {0x9070000C, 23, 1} };1408 {0x9070000C, 22, 1}, {0x9070000C, 23, 1} };
1409 struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = {1409 static const struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = {
1410 {0x90700010, 0, 1}, {0x90700010, 1, 1},1410 {0x90700010, 0, 1}, {0x90700010, 1, 1},
1411 {0x90700010, 2, 1}, {0x90700010, 3, 1},1411 {0x90700010, 2, 1}, {0x90700010, 3, 1},
1412 {0x90700010, 4, 1}, {0x90700010, 5, 1},1412 {0x90700010, 4, 1}, {0x90700010, 5, 1},
1413 {0x90700010, 6, 1}, {0x90700010, 7, 1} };1413 {0x90700010, 6, 1}, {0x90700010, 7, 1} };
1414 struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = {1414 static const struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = {
1415 {0x9070000C, 0, 1}, {0x9070000C, 1, 1},1415 {0x9070000C, 0, 1}, {0x9070000C, 1, 1},
1416 {0x9070000C, 2, 1}, {0x9070000C, 3, 1},1416 {0x9070000C, 2, 1}, {0x9070000C, 3, 1},
1417 {0x9070000C, 4, 1}, {0x9070000C, 5, 1},1417 {0x9070000C, 4, 1}, {0x9070000C, 5, 1},
1418 {0x9070000C, 6, 1}, {0x9070000C, 7, 1} };1418 {0x9070000C, 6, 1}, {0x9070000C, 7, 1} };
1419 struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = {1419 static const struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = {
1420 {0x9070000C, 24, 1}, {0x9070000C, 25, 1},1420 {0x9070000C, 24, 1}, {0x9070000C, 25, 1},
1421 {0x9070000C, 26, 1}, {0x9070000C, 27, 1},1421 {0x9070000C, 26, 1}, {0x9070000C, 27, 1},
1422 {0x9070000C, 28, 1}, {0x9070000C, 29, 1},1422 {0x9070000C, 28, 1}, {0x9070000C, 29, 1},
1423 {0x9070000C, 30, 1}, {0x9070000C, 31, 1} };1423 {0x9070000C, 30, 1}, {0x9070000C, 31, 1} };
1424 struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = {1424 static const struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = {
1425 {0x90700014, 8, 1}, {0x90700014, 9, 1},1425 {0x90700014, 8, 1}, {0x90700014, 9, 1},
1426 {0x90700014, 10, 1}, {0x90700014, 11, 1},1426 {0x90700014, 10, 1}, {0x90700014, 11, 1},
1427 {0x90700014, 12, 1}, {0x90700014, 13, 1},1427 {0x90700014, 12, 1}, {0x90700014, 13, 1},
1428 {0x90700014, 14, 1}, {0x90700014, 15, 1} };1428 {0x90700014, 14, 1}, {0x90700014, 15, 1} };
1429 struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = {1429 static const struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = {
1430 {0x907001D4, 0, 1}, {0x907001D4, 1, 1},1430 {0x907001D4, 0, 1}, {0x907001D4, 1, 1},
1431 {0x907001D4, 2, 1}, {0x907001D4, 3, 1},1431 {0x907001D4, 2, 1}, {0x907001D4, 3, 1},
1432 {0x907001D4, 4, 1}, {0x907001D4, 5, 1},1432 {0x907001D4, 4, 1}, {0x907001D4, 5, 1},
1433 {0x907001D4, 6, 1}, {0x907001D4, 7, 1} };1433 {0x907001D4, 6, 1}, {0x907001D4, 7, 1} };
1434 struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = {1434 static const struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = {
1435 {0x90700044, 16, 80}, {0x90700044, 16, 81},1435 {0x90700044, 16, 80}, {0x90700044, 16, 81},
1436 {0x90700044, 16, 82}, {0x90700044, 16, 83},1436 {0x90700044, 16, 82}, {0x90700044, 16, 83},
1437 {0x90700044, 16, 84}, {0x90700044, 16, 85},1437 {0x90700044, 16, 84}, {0x90700044, 16, 85},
drivers/media/dvb-frontends/si2165.c+2−4
@@ -513,10 +513,8 @@ static int si2165_upload_firmware(struct si2165_state *state) · 512 unmodified lines
513 ret = 0;513 ret = 0;
514 state->firmware_loaded = true;514 state->firmware_loaded = true;
515error:515error:
516 if (fw) {516 release_firmware(fw);
517 release_firmware(fw);517 fw = NULL;
518 fw = NULL;
519 }
520 518
521 return ret;519 return ret;
522}520}
drivers/media/dvb-frontends/stb0899_drv.c+1−1
@@ -1277,7 +1277,7 @@ static int stb0899_get_dev_id(struct stb0899_state *state) · 1276 unmodified lines
1277 dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);1277 dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);
1278 CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);1278 CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);
1279 fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);1279 fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);
1280 if (! (chip_id > 0)) {1280 if (!chip_id) {
1281 dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");1281 dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");
1282 1282
1283 return -ENODEV;1283 return -ENODEV;
drivers/media/dvb-frontends/tda10048.c+6−3
@@ -410,6 +410,7 @@ static int tda10048_set_if(struct dvb_frontend *fe, u32 bw) · 409 unmodified lines
410 struct tda10048_config *config = &state->config;410 struct tda10048_config *config = &state->config;
411 int i;411 int i;
412 u32 if_freq_khz;412 u32 if_freq_khz;
413 u64 sample_freq;
413 414
414 dprintk(1, "%s(bw = %d)\n", __func__, bw);415 dprintk(1, "%s(bw = %d)\n", __func__, bw);
415 416
@@ -451,9 +452,11 @@ static int tda10048_set_if(struct dvb_frontend *fe, u32 bw) · 35 unmodified lines
451 dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);452 dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
452 453
453 /* Calculate the sample frequency */454 /* Calculate the sample frequency */
454 state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);455 sample_freq = state->xtal_hz;
455 state->sample_freq /= (state->pll_nfactor + 1);456 sample_freq *= state->pll_mfactor + 45;
456 state->sample_freq /= (state->pll_pfactor + 4);457 do_div(sample_freq, state->pll_nfactor + 1);
458 do_div(sample_freq, state->pll_pfactor + 4);
459 state->sample_freq = sample_freq;
457 dprintk(1, "- sample_freq = %d\n", state->sample_freq);460 dprintk(1, "- sample_freq = %d\n", state->sample_freq);
458 461
459 /* Update the I/F */462 /* Update the I/F */
drivers/media/dvb-frontends/tda18271c2dd.c+2−2
@@ -328,7 +328,7 @@ static int CalcMainPLL(struct tda_state *state, u32 freq) · 327 unmodified lines
328 328
329 OscFreq = (u64) freq * (u64) Div;329 OscFreq = (u64) freq * (u64) Div;
330 OscFreq *= (u64) 16384;330 OscFreq *= (u64) 16384;
331 do_div(OscFreq, (u64)16000000);331 do_div(OscFreq, 16000000);
332 MainDiv = OscFreq;332 MainDiv = OscFreq;
333 333
334 state->m_Regs[MPD] = PostDiv & 0x77;334 state->m_Regs[MPD] = PostDiv & 0x77;
@@ -352,7 +352,7 @@ static int CalcCalPLL(struct tda_state *state, u32 freq) · 17 unmodified lines
352 OscFreq = (u64)freq * (u64)Div;352 OscFreq = (u64)freq * (u64)Div;
353 /* CalDiv = u32( OscFreq * 16384 / 16000000 ); */353 /* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
354 OscFreq *= (u64)16384;354 OscFreq *= (u64)16384;
355 do_div(OscFreq, (u64)16000000);355 do_div(OscFreq, 16000000);
356 CalDiv = OscFreq;356 CalDiv = OscFreq;
357 357
358 state->m_Regs[CPD] = PostDiv;358 state->m_Regs[CPD] = PostDiv;
drivers/media/i2c/Kconfig+2−0
@@ -195,6 +195,7 @@ config VIDEO_IMX334 · 194 unmodified lines
195config VIDEO_IMX335195config VIDEO_IMX335
196 tristate "Sony IMX335 sensor support"196 tristate "Sony IMX335 sensor support"
197 depends on OF_GPIO197 depends on OF_GPIO
198 select V4L2_CCI_I2C
198 help199 help
199 This is a Video4Linux2 sensor driver for the Sony200 This is a Video4Linux2 sensor driver for the Sony
200 IMX335 camera.201 IMX335 camera.
@@ -405,6 +406,7 @@ config VIDEO_OV2740 · 204 unmodified lines
405config VIDEO_OV4689406config VIDEO_OV4689
406 tristate "OmniVision OV4689 sensor support"407 tristate "OmniVision OV4689 sensor support"
407 depends on GPIOLIB408 depends on GPIOLIB
409 select V4L2_CCI_I2C
408 help410 help
409 This is a Video4Linux2 sensor-level driver for the OmniVision411 This is a Video4Linux2 sensor-level driver for the OmniVision
410 OV4689 camera.412 OV4689 camera.
drivers/media/i2c/adv7180.c+1−1
@@ -1486,7 +1486,7 @@ static int adv7180_probe(struct i2c_client *client) · 1485 unmodified lines
1486 if (ret)1486 if (ret)
1487 goto err_media_entity_cleanup;1487 goto err_media_entity_cleanup;
1488 1488
1489 if (state->irq) {1489 if (state->irq > 0) {
1490 ret = request_threaded_irq(client->irq, NULL, adv7180_irq,1490 ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
1491 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,1491 IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
1492 KBUILD_MODNAME, state);1492 KBUILD_MODNAME, state);
drivers/media/i2c/adv748x/adv748x-hdmi.c+8−8
@@ -214,7 +214,7 @@ static int adv748x_hdmi_set_video_timings(struct adv748x_state *state, · 213 unmodified lines
214 * v4l2_subdev_video_ops214 * v4l2_subdev_video_ops
215 */215 */
216 216
217static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd,217static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
218 struct v4l2_dv_timings *timings)218 struct v4l2_dv_timings *timings)
219{219{
220 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);220 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -254,7 +254,7 @@ error: · 33 unmodified lines
254 return ret;254 return ret;
255}255}
256 256
257static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd,257static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
258 struct v4l2_dv_timings *timings)258 struct v4l2_dv_timings *timings)
259{259{
260 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);260 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -269,7 +269,7 @@ static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, · 8 unmodified lines
269 return 0;269 return 0;
270}270}
271 271
272static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd,272static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
273 struct v4l2_dv_timings *timings)273 struct v4l2_dv_timings *timings)
274{274{
275 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);275 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -392,9 +392,6 @@ static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd, · 116 unmodified lines
392}392}
393 393
394static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = {394static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = {
395 .s_dv_timings = adv748x_hdmi_s_dv_timings,
396 .g_dv_timings = adv748x_hdmi_g_dv_timings,
397 .query_dv_timings = adv748x_hdmi_query_dv_timings,
398 .g_input_status = adv748x_hdmi_g_input_status,395 .g_input_status = adv748x_hdmi_g_input_status,
399 .s_stream = adv748x_hdmi_s_stream,396 .s_stream = adv748x_hdmi_s_stream,
400 .g_pixelaspect = adv748x_hdmi_g_pixelaspect,397 .g_pixelaspect = adv748x_hdmi_g_pixelaspect,
@@ -413,7 +410,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi) · 12 unmodified lines
413 if (!tx)410 if (!tx)
414 return -ENOLINK;411 return -ENOLINK;
415 412
416 adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings);413 adv748x_hdmi_query_dv_timings(&hdmi->sd, 0, &timings);
417 414
418 return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock);415 return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock);
419}416}
@@ -610,6 +607,9 @@ static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi = { · 190 unmodified lines
610 .get_fmt = adv748x_hdmi_get_format,607 .get_fmt = adv748x_hdmi_get_format,
611 .get_edid = adv748x_hdmi_get_edid,608 .get_edid = adv748x_hdmi_get_edid,
612 .set_edid = adv748x_hdmi_set_edid,609 .set_edid = adv748x_hdmi_set_edid,
610 .s_dv_timings = adv748x_hdmi_s_dv_timings,
611 .g_dv_timings = adv748x_hdmi_g_dv_timings,
612 .query_dv_timings = adv748x_hdmi_query_dv_timings,
613 .dv_timings_cap = adv748x_hdmi_dv_timings_cap,613 .dv_timings_cap = adv748x_hdmi_dv_timings_cap,
614 .enum_dv_timings = adv748x_hdmi_enum_dv_timings,614 .enum_dv_timings = adv748x_hdmi_enum_dv_timings,
615};615};
@@ -734,7 +734,7 @@ int adv748x_hdmi_init(struct adv748x_hdmi *hdmi) · 118 unmodified lines
734 struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30;734 struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30;
735 int ret;735 int ret;
736 736
737 adv748x_hdmi_s_dv_timings(&hdmi->sd, &cea1280x720);737 adv748x_hdmi_s_dv_timings(&hdmi->sd, 0, &cea1280x720);
738 738
739 /* Initialise a default 16:9 aspect ratio */739 /* Initialise a default 16:9 aspect ratio */
740 hdmi->aspect_ratio.numerator = 16;740 hdmi->aspect_ratio.numerator = 16;
drivers/media/i2c/adv7511-v4l2.c+11−5
@@ -995,8 +995,8 @@ static int adv7511_s_stream(struct v4l2_subdev *sd, int enable) · 994 unmodified lines
995 return 0;995 return 0;
996}996}
997 997
998static int adv7511_s_dv_timings(struct v4l2_subdev *sd,998static int adv7511_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
999 struct v4l2_dv_timings *timings)999 struct v4l2_dv_timings *timings)
1000{1000{
1001 struct adv7511_state *state = get_adv7511_state(sd);1001 struct adv7511_state *state = get_adv7511_state(sd);
1002 struct v4l2_bt_timings *bt = &timings->bt;1002 struct v4l2_bt_timings *bt = &timings->bt;
@@ -1004,6 +1004,9 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd, · 1 unmodified line
1004 1004
1005 v4l2_dbg(1, debug, sd, "%s:\n", __func__);1005 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1006 1006
1007 if (pad != 0)
1008 return -EINVAL;
1009
1007 /* quick sanity check */1010 /* quick sanity check */
1008 if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL))1011 if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL))
1009 return -EINVAL;1012 return -EINVAL;
@@ -1042,13 +1045,16 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd, · 32 unmodified lines
1042 return 0;1045 return 0;
1043}1046}
1044 1047
1045static int adv7511_g_dv_timings(struct v4l2_subdev *sd,1048static int adv7511_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1046 struct v4l2_dv_timings *timings)1049 struct v4l2_dv_timings *timings)
1047{1050{
1048 struct adv7511_state *state = get_adv7511_state(sd);1051 struct adv7511_state *state = get_adv7511_state(sd);
1049 1052
1050 v4l2_dbg(1, debug, sd, "%s:\n", __func__);1053 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1051 1054
1055 if (pad != 0)
1056 return -EINVAL;
1057
1052 if (!timings)1058 if (!timings)
1053 return -EINVAL;1059 return -EINVAL;
1054 1060
@@ -1078,8 +1084,6 @@ static int adv7511_dv_timings_cap(struct v4l2_subdev *sd, · 23 unmodified lines
1078 1084
1079static const struct v4l2_subdev_video_ops adv7511_video_ops = {1085static const struct v4l2_subdev_video_ops adv7511_video_ops = {
1080 .s_stream = adv7511_s_stream,1086 .s_stream = adv7511_s_stream,
1081 .s_dv_timings = adv7511_s_dv_timings,
1082 .g_dv_timings = adv7511_g_dv_timings,
1083};1087};
1084 1088
1085/* ------------------------------ AUDIO OPS ------------------------------ */1089/* ------------------------------ AUDIO OPS ------------------------------ */
@@ -1403,6 +1407,8 @@ static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { · 317 unmodified lines
1403 .enum_mbus_code = adv7511_enum_mbus_code,1407 .enum_mbus_code = adv7511_enum_mbus_code,
1404 .get_fmt = adv7511_get_fmt,1408 .get_fmt = adv7511_get_fmt,
1405 .set_fmt = adv7511_set_fmt,1409 .set_fmt = adv7511_set_fmt,
1410 .s_dv_timings = adv7511_s_dv_timings,
1411 .g_dv_timings = adv7511_g_dv_timings,
1406 .enum_dv_timings = adv7511_enum_dv_timings,1412 .enum_dv_timings = adv7511_enum_dv_timings,
1407 .dv_timings_cap = adv7511_dv_timings_cap,1413 .dv_timings_cap = adv7511_dv_timings_cap,
1408};1414};
drivers/media/i2c/adv7604.c+10−10
@@ -1557,8 +1557,8 @@ static unsigned int adv76xx_read_hdmi_pixelclock(struct v4l2_subdev *sd) · 1556 unmodified lines
1557 return freq;1557 return freq;
1558}1558}
1559 1559
1560static int adv76xx_query_dv_timings(struct v4l2_subdev *sd,1560static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1561 struct v4l2_dv_timings *timings)1561 struct v4l2_dv_timings *timings)
1562{1562{
1563 struct adv76xx_state *state = to_state(sd);1563 struct adv76xx_state *state = to_state(sd);
1564 const struct adv76xx_chip_info *info = state->info;1564 const struct adv76xx_chip_info *info = state->info;
@@ -1687,8 +1687,8 @@ found: · 122 unmodified lines
1687 return 0;1687 return 0;
1688}1688}
1689 1689
1690static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,1690static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1691 struct v4l2_dv_timings *timings)1691 struct v4l2_dv_timings *timings)
1692{1692{
1693 struct adv76xx_state *state = to_state(sd);1693 struct adv76xx_state *state = to_state(sd);
1694 struct v4l2_bt_timings *bt;1694 struct v4l2_bt_timings *bt;
@@ -1730,8 +1730,8 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, · 35 unmodified lines
1730 return 0;1730 return 0;
1731}1731}
1732 1732
1733static int adv76xx_g_dv_timings(struct v4l2_subdev *sd,1733static int adv76xx_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1734 struct v4l2_dv_timings *timings)1734 struct v4l2_dv_timings *timings)
1735{1735{
1736 struct adv76xx_state *state = to_state(sd);1736 struct adv76xx_state *state = to_state(sd);
1737 1737
@@ -2607,7 +2607,7 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) · 869 unmodified lines
2607 stdi.lcf, stdi.bl, stdi.lcvs,2607 stdi.lcf, stdi.bl, stdi.lcvs,
2608 stdi.interlaced ? "interlaced" : "progressive",2608 stdi.interlaced ? "interlaced" : "progressive",
2609 stdi.hs_pol, stdi.vs_pol);2609 stdi.hs_pol, stdi.vs_pol);
2610 if (adv76xx_query_dv_timings(sd, &timings))2610 if (adv76xx_query_dv_timings(sd, 0, &timings))
2611 v4l2_info(sd, "No video detected\n");2611 v4l2_info(sd, "No video detected\n");
2612 else2612 else
2613 v4l2_print_dv_timings(sd->name, "Detected format: ",2613 v4l2_print_dv_timings(sd->name, "Detected format: ",
@@ -2726,9 +2726,6 @@ static const struct v4l2_subdev_core_ops adv76xx_core_ops = { · 112 unmodified lines
2726static const struct v4l2_subdev_video_ops adv76xx_video_ops = {2726static const struct v4l2_subdev_video_ops adv76xx_video_ops = {
2727 .s_routing = adv76xx_s_routing,2727 .s_routing = adv76xx_s_routing,
2728 .g_input_status = adv76xx_g_input_status,2728 .g_input_status = adv76xx_g_input_status,
2729 .s_dv_timings = adv76xx_s_dv_timings,
2730 .g_dv_timings = adv76xx_g_dv_timings,
2731 .query_dv_timings = adv76xx_query_dv_timings,
2732};2729};
2733 2730
2734static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = {2731static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = {
@@ -2738,6 +2735,9 @@ static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { · 3 unmodified lines
2738 .set_fmt = adv76xx_set_format,2735 .set_fmt = adv76xx_set_format,
2739 .get_edid = adv76xx_get_edid,2736 .get_edid = adv76xx_get_edid,
2740 .set_edid = adv76xx_set_edid,2737 .set_edid = adv76xx_set_edid,
2738 .s_dv_timings = adv76xx_s_dv_timings,
2739 .g_dv_timings = adv76xx_g_dv_timings,
2740 .query_dv_timings = adv76xx_query_dv_timings,
2741 .dv_timings_cap = adv76xx_dv_timings_cap,2741 .dv_timings_cap = adv76xx_dv_timings_cap,
2742 .enum_dv_timings = adv76xx_enum_dv_timings,2742 .enum_dv_timings = adv76xx_enum_dv_timings,
2743};2743};
drivers/media/i2c/adv7842.c+17−8
@@ -1518,7 +1518,7 @@ static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, · 1517 unmodified lines
1518 timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS;1518 timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS;
1519}1519}
1520 1520
1521static int adv7842_query_dv_timings(struct v4l2_subdev *sd,1521static int adv7842_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1522 struct v4l2_dv_timings *timings)1522 struct v4l2_dv_timings *timings)
1523{1523{
1524 struct adv7842_state *state = to_state(sd);1524 struct adv7842_state *state = to_state(sd);
@@ -1527,6 +1527,9 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, · 2 unmodified lines
1527 1527
1528 v4l2_dbg(1, debug, sd, "%s:\n", __func__);1528 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1529 1529
1530 if (pad != 0)
1531 return -EINVAL;
1532
1530 memset(timings, 0, sizeof(struct v4l2_dv_timings));1533 memset(timings, 0, sizeof(struct v4l2_dv_timings));
1531 1534
1532 /* SDP block */1535 /* SDP block */
@@ -1643,7 +1646,7 @@ found: · 110 unmodified lines
1643 return 0;1646 return 0;
1644}1647}
1645 1648
1646static int adv7842_s_dv_timings(struct v4l2_subdev *sd,1649static int adv7842_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1647 struct v4l2_dv_timings *timings)1650 struct v4l2_dv_timings *timings)
1648{1651{
1649 struct adv7842_state *state = to_state(sd);1652 struct adv7842_state *state = to_state(sd);
@@ -1652,6 +1655,9 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, · 2 unmodified lines
1652 1655
1653 v4l2_dbg(1, debug, sd, "%s:\n", __func__);1656 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1654 1657
1658 if (pad != 0)
1659 return -EINVAL;
1660
1655 if (state->mode == ADV7842_MODE_SDP)1661 if (state->mode == ADV7842_MODE_SDP)
1656 return -ENODATA;1662 return -ENODATA;
1657 1663
@@ -1689,11 +1695,14 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, · 31 unmodified lines
1689 return 0;1695 return 0;
1690}1696}
1691 1697
1692static int adv7842_g_dv_timings(struct v4l2_subdev *sd,1698static int adv7842_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1693 struct v4l2_dv_timings *timings)1699 struct v4l2_dv_timings *timings)
1694{1700{
1695 struct adv7842_state *state = to_state(sd);1701 struct adv7842_state *state = to_state(sd);
1696 1702
1703 if (pad != 0)
1704 return -EINVAL;
1705
1697 if (state->mode == ADV7842_MODE_SDP)1706 if (state->mode == ADV7842_MODE_SDP)
1698 return -ENODATA;1707 return -ENODATA;
1699 *timings = state->timings;1708 *timings = state->timings;
@@ -2780,7 +2789,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) · 1080 unmodified lines
2780 "interlaced" : "progressive",2789 "interlaced" : "progressive",
2781 hs_pol, vs_pol);2790 hs_pol, vs_pol);
2782 }2791 }
2783 if (adv7842_query_dv_timings(sd, &timings))2792 if (adv7842_query_dv_timings(sd, 0, &timings))
2784 v4l2_info(sd, "No video detected\n");2793 v4l2_info(sd, "No video detected\n");
2785 else2794 else
2786 v4l2_print_dv_timings(sd->name, "Detected format: ",2795 v4l2_print_dv_timings(sd->name, "Detected format: ",
@@ -3226,7 +3235,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd) · 439 unmodified lines
3226 3235
3227 memset(&state->timings, 0, sizeof(struct v4l2_dv_timings));3236 memset(&state->timings, 0, sizeof(struct v4l2_dv_timings));
3228 3237
3229 adv7842_s_dv_timings(sd, &timings);3238 adv7842_s_dv_timings(sd, 0, &timings);
3230 3239
3231 return ret;3240 return ret;
3232}3241}
@@ -3298,9 +3307,6 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { · 65 unmodified lines
3298 .s_routing = adv7842_s_routing,3307 .s_routing = adv7842_s_routing,
3299 .querystd = adv7842_querystd,3308 .querystd = adv7842_querystd,
3300 .g_input_status = adv7842_g_input_status,3309 .g_input_status = adv7842_g_input_status,
3301 .s_dv_timings = adv7842_s_dv_timings,
3302 .g_dv_timings = adv7842_g_dv_timings,
3303 .query_dv_timings = adv7842_query_dv_timings,
3304};3310};
3305 3311
3306static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {3312static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {
@@ -3309,6 +3315,9 @@ static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { · 2 unmodified lines
3309 .set_fmt = adv7842_set_format,3315 .set_fmt = adv7842_set_format,
3310 .get_edid = adv7842_get_edid,3316 .get_edid = adv7842_get_edid,
3311 .set_edid = adv7842_set_edid,3317 .set_edid = adv7842_set_edid,
3318 .s_dv_timings = adv7842_s_dv_timings,
3319 .g_dv_timings = adv7842_g_dv_timings,
3320 .query_dv_timings = adv7842_query_dv_timings,
3312 .enum_dv_timings = adv7842_enum_dv_timings,3321 .enum_dv_timings = adv7842_enum_dv_timings,
3313 .dv_timings_cap = adv7842_dv_timings_cap,3322 .dv_timings_cap = adv7842_dv_timings_cap,
3314};3323};
drivers/media/i2c/dw9714.c+3−3
@@ -310,8 +310,8 @@ module_i2c_driver(dw9714_i2c_driver); · 309 unmodified lines
310 310
311MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");311MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
312MODULE_AUTHOR("Jian Xu Zheng");312MODULE_AUTHOR("Jian Xu Zheng");
313MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>");313MODULE_AUTHOR("Yuning Pu");
314MODULE_AUTHOR("Jouni Ukkonen <jouni.ukkonen@intel.com>");314MODULE_AUTHOR("Jouni Ukkonen");
315MODULE_AUTHOR("Tommi Franttila <tommi.franttila@intel.com>");315MODULE_AUTHOR("Tommi Franttila");
316MODULE_DESCRIPTION("DW9714 VCM driver");316MODULE_DESCRIPTION("DW9714 VCM driver");
317MODULE_LICENSE("GPL v2");317MODULE_LICENSE("GPL v2");
drivers/media/i2c/et8ek8/et8ek8_driver.c+2−2
@@ -1475,7 +1475,7 @@ err_mutex: · 1474 unmodified lines
1475 return ret;1475 return ret;
1476}1476}
1477 1477
1478static void __exit et8ek8_remove(struct i2c_client *client)1478static void et8ek8_remove(struct i2c_client *client)
1479{1479{
1480 struct v4l2_subdev *subdev = i2c_get_clientdata(client);1480 struct v4l2_subdev *subdev = i2c_get_clientdata(client);
1481 struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);1481 struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
@@ -1517,7 +1517,7 @@ static struct i2c_driver et8ek8_i2c_driver = { · 35 unmodified lines
1517 .of_match_table = et8ek8_of_table,1517 .of_match_table = et8ek8_of_table,
1518 },1518 },
1519 .probe = et8ek8_probe,1519 .probe = et8ek8_probe,
1520 .remove = __exit_p(et8ek8_remove),1520 .remove = et8ek8_remove,
1521 .id_table = et8ek8_id_table,1521 .id_table = et8ek8_id_table,
1522};1522};
1523 1523
drivers/media/i2c/hi556.c+93−12
@@ -3,10 +3,13 @@ · 2 unmodified lines
3 3
4#include <asm/unaligned.h>4#include <asm/unaligned.h>
5#include <linux/acpi.h>5#include <linux/acpi.h>
6#include <linux/clk.h>
6#include <linux/delay.h>7#include <linux/delay.h>
8#include <linux/gpio/consumer.h>
7#include <linux/i2c.h>9#include <linux/i2c.h>
8#include <linux/module.h>10#include <linux/module.h>
9#include <linux/pm_runtime.h>11#include <linux/pm_runtime.h>
12#include <linux/regulator/consumer.h>
10#include <media/v4l2-ctrls.h>13#include <media/v4l2-ctrls.h>
11#include <media/v4l2-device.h>14#include <media/v4l2-device.h>
12#include <media/v4l2-fwnode.h>15#include <media/v4l2-fwnode.h>
@@ -633,6 +636,11 @@ struct hi556 { · 620 unmodified lines
633 struct v4l2_ctrl *hblank;636 struct v4l2_ctrl *hblank;
634 struct v4l2_ctrl *exposure;637 struct v4l2_ctrl *exposure;
635 638
639 /* GPIOs, clocks, etc. */
640 struct gpio_desc *reset_gpio;
641 struct clk *clk;
642 struct regulator *avdd;
643
636 /* Current mode */644 /* Current mode */
637 const struct hi556_mode *cur_mode;645 const struct hi556_mode *cur_mode;
638 646
@@ -1206,8 +1214,18 @@ static int hi556_check_hwcfg(struct device *dev) · 567 unmodified lines
1206 int ret = 0;1214 int ret = 0;
1207 unsigned int i, j;1215 unsigned int i, j;
1208 1216
1209 if (!fwnode)1217 /*
1210 return -ENXIO;1218 * Sometimes the fwnode graph is initialized by the bridge driver,
1219 * wait for this.
1220 */
1221 ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1222 if (!ep)
1223 return -EPROBE_DEFER;
1224
1225 ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1226 fwnode_handle_put(ep);
1227 if (ret)
1228 return ret;
1211 1229
1212 ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);1230 ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
1213 if (ret) {1231 if (ret) {
@@ -1220,15 +1238,6 @@ static int hi556_check_hwcfg(struct device *dev) · 6 unmodified lines
1220 return -EINVAL;1238 return -EINVAL;
1221 }1239 }
1222 1240
1223 ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1224 if (!ep)
1225 return -ENXIO;
1226
1227 ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1228 fwnode_handle_put(ep);
1229 if (ret)
1230 return ret;
1231
1232 if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) {1241 if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) {
1233 dev_err(dev, "number of CSI2 data lanes %d is not supported",1242 dev_err(dev, "number of CSI2 data lanes %d is not supported",
1234 bus_cfg.bus.mipi_csi2.num_data_lanes);1243 bus_cfg.bus.mipi_csi2.num_data_lanes);
@@ -1275,6 +1284,47 @@ static void hi556_remove(struct i2c_client *client) · 40 unmodified lines
1275 mutex_destroy(&hi556->mutex);1284 mutex_destroy(&hi556->mutex);
1276}1285}
1277 1286
1287static int hi556_suspend(struct device *dev)
1288{
1289 struct v4l2_subdev *sd = dev_get_drvdata(dev);
1290 struct hi556 *hi556 = to_hi556(sd);
1291 int ret;
1292
1293 gpiod_set_value_cansleep(hi556->reset_gpio, 1);
1294
1295 ret = regulator_disable(hi556->avdd);
1296 if (ret) {
1297 dev_err(dev, "failed to disable avdd: %d\n", ret);
1298 gpiod_set_value_cansleep(hi556->reset_gpio, 0);
1299 return ret;
1300 }
1301
1302 clk_disable_unprepare(hi556->clk);
1303 return 0;
1304}
1305
1306static int hi556_resume(struct device *dev)
1307{
1308 struct v4l2_subdev *sd = dev_get_drvdata(dev);
1309 struct hi556 *hi556 = to_hi556(sd);
1310 int ret;
1311
1312 ret = clk_prepare_enable(hi556->clk);
1313 if (ret)
1314 return ret;
1315
1316 ret = regulator_enable(hi556->avdd);
1317 if (ret) {
1318 dev_err(dev, "failed to enable avdd: %d\n", ret);
1319 clk_disable_unprepare(hi556->clk);
1320 return ret;
1321 }
1322
1323 gpiod_set_value_cansleep(hi556->reset_gpio, 0);
1324 usleep_range(5000, 5500);
1325 return 0;
1326}
1327
1278static int hi556_probe(struct i2c_client *client)1328static int hi556_probe(struct i2c_client *client)
1279{1329{
1280 struct hi556 *hi556;1330 struct hi556 *hi556;
@@ -1294,12 +1344,35 @@ static int hi556_probe(struct i2c_client *client) · 13 unmodified lines
1294 1344
1295 v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops);1345 v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops);
1296 1346
1347 hi556->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
1348 GPIOD_OUT_HIGH);
1349 if (IS_ERR(hi556->reset_gpio))
1350 return dev_err_probe(&client->dev, PTR_ERR(hi556->reset_gpio),
1351 "failed to get reset GPIO\n");
1352
1353 hi556->clk = devm_clk_get_optional(&client->dev, "clk");
1354 if (IS_ERR(hi556->clk))
1355 return dev_err_probe(&client->dev, PTR_ERR(hi556->clk),
1356 "failed to get clock\n");
1357
1358 /* The regulator core will provide a "dummy" regulator if necessary */
1359 hi556->avdd = devm_regulator_get(&client->dev, "avdd");
1360 if (IS_ERR(hi556->avdd))
1361 return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd),
1362 "failed to get avdd regulator\n");
1363
1297 full_power = acpi_dev_state_d0(&client->dev);1364 full_power = acpi_dev_state_d0(&client->dev);
1298 if (full_power) {1365 if (full_power) {
1366 /* Ensure non ACPI managed resources are enabled */
1367 ret = hi556_resume(&client->dev);
1368 if (ret)
1369 return dev_err_probe(&client->dev, ret,
1370 "failed to power on sensor\n");
1371
1299 ret = hi556_identify_module(hi556);1372 ret = hi556_identify_module(hi556);
1300 if (ret) {1373 if (ret) {
1301 dev_err(&client->dev, "failed to find sensor: %d", ret);1374 dev_err(&client->dev, "failed to find sensor: %d", ret);
1302 return ret;1375 goto probe_error_power_off;
1303 }1376 }
1304 }1377 }
1305 1378
@@ -1344,9 +1417,16 @@ probe_error_v4l2_ctrl_handler_free: · 38 unmodified lines
1344 v4l2_ctrl_handler_free(hi556->sd.ctrl_handler);1417 v4l2_ctrl_handler_free(hi556->sd.ctrl_handler);
1345 mutex_destroy(&hi556->mutex);1418 mutex_destroy(&hi556->mutex);
1346 1419
1420probe_error_power_off:
1421 if (full_power)
1422 hi556_suspend(&client->dev);
1423
1347 return ret;1424 return ret;
1348}1425}
1349 1426
1427static DEFINE_RUNTIME_DEV_PM_OPS(hi556_pm_ops, hi556_suspend, hi556_resume,
1428 NULL);
1429
1350#ifdef CONFIG_ACPI1430#ifdef CONFIG_ACPI
1351static const struct acpi_device_id hi556_acpi_ids[] = {1431static const struct acpi_device_id hi556_acpi_ids[] = {
1352 {"INT3537"},1432 {"INT3537"},
@@ -1360,6 +1440,7 @@ static struct i2c_driver hi556_i2c_driver = { · 7 unmodified lines
1360 .driver = {1440 .driver = {
1361 .name = "hi556",1441 .name = "hi556",
1362 .acpi_match_table = ACPI_PTR(hi556_acpi_ids),1442 .acpi_match_table = ACPI_PTR(hi556_acpi_ids),
1443 .pm = pm_sleep_ptr(&hi556_pm_ops),
1363 },1444 },
1364 .probe = hi556_probe,1445 .probe = hi556_probe,
1365 .remove = hi556_remove,1446 .remove = hi556_remove,
drivers/media/i2c/imx214.c+1−0
@@ -1114,6 +1114,7 @@ free_ctrl: · 1113 unmodified lines
1114 v4l2_ctrl_handler_free(&imx214->ctrls);1114 v4l2_ctrl_handler_free(&imx214->ctrls);
1115error_power_off:1115error_power_off:
1116 pm_runtime_disable(imx214->dev);1116 pm_runtime_disable(imx214->dev);
1117 regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies);
1117 1118
1118 return ret;1119 return ret;
1119}1120}
drivers/media/i2c/imx219.c+35−42
@@ -551,8 +551,7 @@ static int imx219_init_controls(struct imx219 *imx219) · 550 unmodified lines
551 551
552 if (ctrl_hdlr->error) {552 if (ctrl_hdlr->error) {
553 ret = ctrl_hdlr->error;553 ret = ctrl_hdlr->error;
554 dev_err(&client->dev, "%s control init failed (%d)\n",554 dev_err_probe(&client->dev, ret, "Control init failed\n");
555 __func__, ret);
556 goto error;555 goto error;
557 }556 }
558 557
@@ -1024,17 +1023,15 @@ static int imx219_identify_module(struct imx219 *imx219) · 465 unmodified lines
1024 u64 val;1023 u64 val;
1025 1024
1026 ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL);1025 ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL);
1027 if (ret) {1026 if (ret)
1028 dev_err(&client->dev, "failed to read chip id %x\n",1027 return dev_err_probe(&client->dev, ret,
1029 IMX219_CHIP_ID);1028 "failed to read chip id %x\n",
1030 return ret;1029 IMX219_CHIP_ID);
1031 }
1032 1030
1033 if (val != IMX219_CHIP_ID) {1031 if (val != IMX219_CHIP_ID)
1034 dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",1032 return dev_err_probe(&client->dev, -EIO,
1035 IMX219_CHIP_ID, val);1033 "chip id mismatch: %x!=%llx\n",
1036 return -EIO;1034 IMX219_CHIP_ID, val);
1037 }
1038 1035
1039 return 0;1036 return 0;
1040}1037}
@@ -1048,35 +1045,36 @@ static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) · 7 unmodified lines
1048 int ret = -EINVAL;1045 int ret = -EINVAL;
1049 1046
1050 endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);1047 endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
1051 if (!endpoint) {1048 if (!endpoint)
1052 dev_err(dev, "endpoint node not found\n");1049 return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
1053 return -EINVAL;
1054 }
1055 1050
1056 if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {1051 if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
1057 dev_err(dev, "could not parse endpoint\n");1052 dev_err_probe(dev, -EINVAL, "could not parse endpoint\n");
1058 goto error_out;1053 goto error_out;
1059 }1054 }
1060 1055
1061 /* Check the number of MIPI CSI2 data lanes */1056 /* Check the number of MIPI CSI2 data lanes */
1062 if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 &&1057 if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
1063 ep_cfg.bus.mipi_csi2.num_data_lanes != 4) {1058 ep_cfg.bus.mipi_csi2.num_data_lanes != 4) {
1064 dev_err(dev, "only 2 or 4 data lanes are currently supported\n");1059 dev_err_probe(dev, -EINVAL,
1060 "only 2 or 4 data lanes are currently supported\n");
1065 goto error_out;1061 goto error_out;
1066 }1062 }
1067 imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;1063 imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;
1068 1064
1069 /* Check the link frequency set in device tree */1065 /* Check the link frequency set in device tree */
1070 if (!ep_cfg.nr_of_link_frequencies) {1066 if (!ep_cfg.nr_of_link_frequencies) {
1071 dev_err(dev, "link-frequency property not found in DT\n");1067 dev_err_probe(dev, -EINVAL,
1068 "link-frequency property not found in DT\n");
1072 goto error_out;1069 goto error_out;
1073 }1070 }
1074 1071
1075 if (ep_cfg.nr_of_link_frequencies != 1 ||1072 if (ep_cfg.nr_of_link_frequencies != 1 ||
1076 (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?1073 (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
1077 IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {1074 IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
1078 dev_err(dev, "Link frequency not supported: %lld\n",1075 dev_err_probe(dev, -EINVAL,
1079 ep_cfg.link_frequencies[0]);1076 "Link frequency not supported: %lld\n",
1077 ep_cfg.link_frequencies[0]);
1080 goto error_out;1078 goto error_out;
1081 }1079 }
1082 1080
@@ -1107,31 +1105,25 @@ static int imx219_probe(struct i2c_client *client) · 24 unmodified lines
1107 return -EINVAL;1105 return -EINVAL;
1108 1106
1109 imx219->regmap = devm_cci_regmap_init_i2c(client, 16);1107 imx219->regmap = devm_cci_regmap_init_i2c(client, 16);
1110 if (IS_ERR(imx219->regmap)) {1108 if (IS_ERR(imx219->regmap))
1111 ret = PTR_ERR(imx219->regmap);1109 return dev_err_probe(dev, PTR_ERR(imx219->regmap),
1112 dev_err(dev, "failed to initialize CCI: %d\n", ret);1110 "failed to initialize CCI\n");
1113 return ret;
1114 }
1115 1111
1116 /* Get system clock (xclk) */1112 /* Get system clock (xclk) */
1117 imx219->xclk = devm_clk_get(dev, NULL);1113 imx219->xclk = devm_clk_get(dev, NULL);
1118 if (IS_ERR(imx219->xclk)) {1114 if (IS_ERR(imx219->xclk))
1119 dev_err(dev, "failed to get xclk\n");1115 return dev_err_probe(dev, PTR_ERR(imx219->xclk),
1120 return PTR_ERR(imx219->xclk);1116 "failed to get xclk\n");
1121 }
1122 1117
1123 imx219->xclk_freq = clk_get_rate(imx219->xclk);1118 imx219->xclk_freq = clk_get_rate(imx219->xclk);
1124 if (imx219->xclk_freq != IMX219_XCLK_FREQ) {1119 if (imx219->xclk_freq != IMX219_XCLK_FREQ)
1125 dev_err(dev, "xclk frequency not supported: %d Hz\n",1120 return dev_err_probe(dev, -EINVAL,
1126 imx219->xclk_freq);1121 "xclk frequency not supported: %d Hz\n",
1127 return -EINVAL;1122 imx219->xclk_freq);
1128 }
1129 1123
1130 ret = imx219_get_regulators(imx219);1124 ret = imx219_get_regulators(imx219);
1131 if (ret) {1125 if (ret)
1132 dev_err(dev, "failed to get regulators\n");1126 return dev_err_probe(dev, ret, "failed to get regulators\n");
1133 return ret;
1134 }
1135 1127
1136 /* Request optional enable pin */1128 /* Request optional enable pin */
1137 imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",1129 imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
@@ -1183,20 +1175,21 @@ static int imx219_probe(struct i2c_client *client) · 45 unmodified lines
1183 1175
1184 ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);1176 ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
1185 if (ret) {1177 if (ret) {
1186 dev_err(dev, "failed to init entity pads: %d\n", ret);1178 dev_err_probe(dev, ret, "failed to init entity pads\n");
1187 goto error_handler_free;1179 goto error_handler_free;
1188 }1180 }
1189 1181
1190 imx219->sd.state_lock = imx219->ctrl_handler.lock;1182 imx219->sd.state_lock = imx219->ctrl_handler.lock;
1191 ret = v4l2_subdev_init_finalize(&imx219->sd);1183 ret = v4l2_subdev_init_finalize(&imx219->sd);
1192 if (ret < 0) {1184 if (ret < 0) {
1193 dev_err(dev, "subdev init error: %d\n", ret);1185 dev_err_probe(dev, ret, "subdev init error\n");
1194 goto error_media_entity;1186 goto error_media_entity;
1195 }1187 }
1196 1188
1197 ret = v4l2_async_register_subdev_sensor(&imx219->sd);1189 ret = v4l2_async_register_subdev_sensor(&imx219->sd);
1198 if (ret < 0) {1190 if (ret < 0) {
1199 dev_err(dev, "failed to register sensor sub-device: %d\n", ret);1191 dev_err_probe(dev, ret,
1192 "failed to register sensor sub-device\n");
1200 goto error_subdev_cleanup;1193 goto error_subdev_cleanup;
1201 }1194 }
1202 1195
drivers/media/i2c/imx335.c+304−333
@@ -11,57 +11,108 @@ · 10 unmodified lines
11#include <linux/i2c.h>11#include <linux/i2c.h>
12#include <linux/module.h>12#include <linux/module.h>
13#include <linux/pm_runtime.h>13#include <linux/pm_runtime.h>
14#include <linux/regmap.h>
14 15
16#include <media/v4l2-cci.h>
15#include <media/v4l2-ctrls.h>17#include <media/v4l2-ctrls.h>
16#include <media/v4l2-fwnode.h>18#include <media/v4l2-fwnode.h>
17#include <media/v4l2-subdev.h>19#include <media/v4l2-subdev.h>
18 20
19/* Streaming Mode */21/* Streaming Mode */
20#define IMX335_REG_MODE_SELECT 0x300022#define IMX335_REG_MODE_SELECT CCI_REG8(0x3000)
21#define IMX335_MODE_STANDBY 0x0123#define IMX335_MODE_STANDBY 0x01
22#define IMX335_MODE_STREAMING 0x0024#define IMX335_MODE_STREAMING 0x00
25
26/* Group hold register */
27#define IMX335_REG_HOLD CCI_REG8(0x3001)
28
29#define IMX335_REG_MASTER_MODE CCI_REG8(0x3002)
30#define IMX335_REG_BCWAIT_TIME CCI_REG8(0x300c)
31#define IMX335_REG_CPWAIT_TIME CCI_REG8(0x300d)
32#define IMX335_REG_WINMODE CCI_REG8(0x3018)
33#define IMX335_REG_HTRIMMING_START CCI_REG16_LE(0x302c)
34#define IMX335_REG_HNUM CCI_REG8(0x302e)
23 35
24/* Lines per frame */36/* Lines per frame */
25#define IMX335_REG_LPFR 0x303037#define IMX335_REG_VMAX CCI_REG24_LE(0x3030)
26 38
27/* Chip ID */39#define IMX335_REG_OPB_SIZE_V CCI_REG8(0x304c)
28#define IMX335_REG_ID 0x391240#define IMX335_REG_ADBIT CCI_REG8(0x3050)
29#define IMX335_ID 0x0041#define IMX335_REG_Y_OUT_SIZE CCI_REG16_LE(0x3056)
30
31/* Exposure control */
32#define IMX335_REG_SHUTTER 0x3058
33#define IMX335_EXPOSURE_MIN 1
34#define IMX335_EXPOSURE_OFFSET 9
35#define IMX335_EXPOSURE_STEP 1
36#define IMX335_EXPOSURE_DEFAULT 0x0648
37
38/* Analog gain control */
39#define IMX335_REG_AGAIN 0x30e8
40#define IMX335_AGAIN_MIN 0
41#define IMX335_AGAIN_MAX 240
42#define IMX335_AGAIN_STEP 1
43#define IMX335_AGAIN_DEFAULT 0
44 42
45/* Group hold register */43#define IMX335_REG_SHUTTER CCI_REG24_LE(0x3058)
46#define IMX335_REG_HOLD 0x300144#define IMX335_EXPOSURE_MIN 1
45#define IMX335_EXPOSURE_OFFSET 9
46#define IMX335_EXPOSURE_STEP 1
47#define IMX335_EXPOSURE_DEFAULT 0x0648
48
49#define IMX335_REG_AREA3_ST_ADR_1 CCI_REG16_LE(0x3074)
50#define IMX335_REG_AREA3_WIDTH_1 CCI_REG16_LE(0x3076)
51
52/* Analog and Digital gain control */
53#define IMX335_REG_GAIN CCI_REG8(0x30e8)
54#define IMX335_AGAIN_MIN 0
55#define IMX335_AGAIN_MAX 100
56#define IMX335_AGAIN_STEP 1
57#define IMX335_AGAIN_DEFAULT 0
58
59#define IMX335_REG_TPG_TESTCLKEN CCI_REG8(0x3148)
60
61#define IMX335_REG_INCLKSEL1 CCI_REG16_LE(0x314c)
62#define IMX335_REG_INCLKSEL2 CCI_REG8(0x315a)
63#define IMX335_REG_INCLKSEL3 CCI_REG8(0x3168)
64#define IMX335_REG_INCLKSEL4 CCI_REG8(0x316a)
65
66#define IMX335_REG_MDBIT CCI_REG8(0x319d)
67#define IMX335_REG_SYSMODE CCI_REG8(0x319e)
68
69#define IMX335_REG_XVS_XHS_DRV CCI_REG8(0x31a1)
47 70
48/* Test pattern generator */71/* Test pattern generator */
49#define IMX335_REG_TPG 0x329e72#define IMX335_REG_TPG_DIG_CLP_MODE CCI_REG8(0x3280)
50#define IMX335_TPG_ALL_000 073#define IMX335_REG_TPG_EN_DUOUT CCI_REG8(0x329c)
51#define IMX335_TPG_ALL_FFF 174#define IMX335_REG_TPG CCI_REG8(0x329e)
52#define IMX335_TPG_ALL_555 275#define IMX335_TPG_ALL_000 0
53#define IMX335_TPG_ALL_AAA 376#define IMX335_TPG_ALL_FFF 1
54#define IMX335_TPG_TOG_555_AAA 477#define IMX335_TPG_ALL_555 2
55#define IMX335_TPG_TOG_AAA_555 578#define IMX335_TPG_ALL_AAA 3
56#define IMX335_TPG_TOG_000_555 679#define IMX335_TPG_TOG_555_AAA 4
57#define IMX335_TPG_TOG_555_000 780#define IMX335_TPG_TOG_AAA_555 5
58#define IMX335_TPG_TOG_000_FFF 881#define IMX335_TPG_TOG_000_555 6
59#define IMX335_TPG_TOG_FFF_000 982#define IMX335_TPG_TOG_555_000 7
60#define IMX335_TPG_H_COLOR_BARS 1083#define IMX335_TPG_TOG_000_FFF 8
61#define IMX335_TPG_V_COLOR_BARS 1184#define IMX335_TPG_TOG_FFF_000 9
85#define IMX335_TPG_H_COLOR_BARS 10
86#define IMX335_TPG_V_COLOR_BARS 11
87#define IMX335_REG_TPG_COLORWIDTH CCI_REG8(0x32a0)
88
89#define IMX335_REG_BLKLEVEL CCI_REG16_LE(0x3302)
90
91#define IMX335_REG_WRJ_OPEN CCI_REG8(0x336c)
92
93#define IMX335_REG_ADBIT1 CCI_REG16_LE(0x341c)
94
95/* Chip ID */
96#define IMX335_REG_ID CCI_REG8(0x3912)
97#define IMX335_ID 0x00
98
99/* Data Lanes */
100#define IMX335_REG_LANEMODE CCI_REG8(0x3a01)
101#define IMX335_2LANE 1
102#define IMX335_4LANE 3
103
104#define IMX335_REG_TCLKPOST CCI_REG16_LE(0x3a18)
105#define IMX335_REG_TCLKPREPARE CCI_REG16_LE(0x3a1a)
106#define IMX335_REG_TCLK_TRAIL CCI_REG16_LE(0x3a1c)
107#define IMX335_REG_TCLK_ZERO CCI_REG16_LE(0x3a1e)
108#define IMX335_REG_THS_PREPARE CCI_REG16_LE(0x3a20)
109#define IMX335_REG_THS_ZERO CCI_REG16_LE(0x3a22)
110#define IMX335_REG_THS_TRAIL CCI_REG16_LE(0x3a24)
111#define IMX335_REG_THS_EXIT CCI_REG16_LE(0x3a26)
112#define IMX335_REG_TPLX CCI_REG16_LE(0x3a28)
62 113
63/* Input clock rate */114/* Input clock rate */
64#define IMX335_INCLK_RATE 24000000115#define IMX335_INCLK_RATE 24000000
65 116
66/* CSI2 HW configuration */117/* CSI2 HW configuration */
67#define IMX335_LINK_FREQ_594MHz 594000000LL118#define IMX335_LINK_FREQ_594MHz 594000000LL
@@ -69,9 +120,6 @@ · 1 unmodified line
69 120
70#define IMX335_NUM_DATA_LANES 4121#define IMX335_NUM_DATA_LANES 4
71 122
72#define IMX335_REG_MIN 0x00
73#define IMX335_REG_MAX 0xfffff
74
75/* IMX335 native and active pixel array size. */123/* IMX335 native and active pixel array size. */
76#define IMX335_NATIVE_WIDTH 2616U124#define IMX335_NATIVE_WIDTH 2616U
77#define IMX335_NATIVE_HEIGHT 1964U125#define IMX335_NATIVE_HEIGHT 1964U
@@ -80,16 +128,6 @@ · 2 unmodified lines
80#define IMX335_PIXEL_ARRAY_WIDTH 2592U128#define IMX335_PIXEL_ARRAY_WIDTH 2592U
81#define IMX335_PIXEL_ARRAY_HEIGHT 1944U129#define IMX335_PIXEL_ARRAY_HEIGHT 1944U
82 130
83/**
84 * struct imx335_reg - imx335 sensor register
85 * @address: Register address
86 * @val: Register value
87 */
88struct imx335_reg {
89 u16 address;
90 u8 val;
91};
92
93/**131/**
94 * struct imx335_reg_list - imx335 sensor register list132 * struct imx335_reg_list - imx335 sensor register list
95 * @num_of_regs: Number of registers in the list133 * @num_of_regs: Number of registers in the list
@@ -97,7 +135,7 @@ struct imx335_reg { · 1 unmodified line
97 */135 */
98struct imx335_reg_list {136struct imx335_reg_list {
99 u32 num_of_regs;137 u32 num_of_regs;
100 const struct imx335_reg *regs;138 const struct cci_reg_sequence *regs;
101};139};
102 140
103static const char * const imx335_supply_name[] = {141static const char * const imx335_supply_name[] = {
@@ -138,6 +176,7 @@ struct imx335_mode { · 34 unmodified lines
138 * @pad: Media pad. Only one pad supported176 * @pad: Media pad. Only one pad supported
139 * @reset_gpio: Sensor reset gpio177 * @reset_gpio: Sensor reset gpio
140 * @supplies: Regulator supplies to handle power control178 * @supplies: Regulator supplies to handle power control
179 * @cci: CCI register map
141 * @inclk: Sensor input clock180 * @inclk: Sensor input clock
142 * @ctrl_handler: V4L2 control handler181 * @ctrl_handler: V4L2 control handler
143 * @link_freq_ctrl: Pointer to link frequency control182 * @link_freq_ctrl: Pointer to link frequency control
@@ -147,6 +186,7 @@ struct imx335_mode { · 3 unmodified lines
147 * @exp_ctrl: Pointer to exposure control186 * @exp_ctrl: Pointer to exposure control
148 * @again_ctrl: Pointer to analog gain control187 * @again_ctrl: Pointer to analog gain control
149 * @vblank: Vertical blanking in lines188 * @vblank: Vertical blanking in lines
189 * @lane_mode: Mode for number of connected data lanes
150 * @cur_mode: Pointer to current selected sensor mode190 * @cur_mode: Pointer to current selected sensor mode
151 * @mutex: Mutex for serializing sensor controls191 * @mutex: Mutex for serializing sensor controls
152 * @link_freq_bitmap: Menu bitmap for link_freq_ctrl192 * @link_freq_bitmap: Menu bitmap for link_freq_ctrl
@@ -159,6 +199,7 @@ struct imx335 { · 6 unmodified lines
159 struct media_pad pad;199 struct media_pad pad;
160 struct gpio_desc *reset_gpio;200 struct gpio_desc *reset_gpio;
161 struct regulator_bulk_data supplies[ARRAY_SIZE(imx335_supply_name)];201 struct regulator_bulk_data supplies[ARRAY_SIZE(imx335_supply_name)];
202 struct regmap *cci;
162 203
163 struct clk *inclk;204 struct clk *inclk;
164 struct v4l2_ctrl_handler ctrl_handler;205 struct v4l2_ctrl_handler ctrl_handler;
@@ -171,6 +212,7 @@ struct imx335 { · 6 unmodified lines
171 struct v4l2_ctrl *again_ctrl;212 struct v4l2_ctrl *again_ctrl;
172 };213 };
173 u32 vblank;214 u32 vblank;
215 u32 lane_mode;
174 const struct imx335_mode *cur_mode;216 const struct imx335_mode *cur_mode;
175 struct mutex mutex;217 struct mutex mutex;
176 unsigned long link_freq_bitmap;218 unsigned long link_freq_bitmap;
@@ -210,140 +252,135 @@ static const int imx335_tpg_val[] = { · 33 unmodified lines
210};252};
211 253
212/* Sensor mode registers */254/* Sensor mode registers */
213static const struct imx335_reg mode_2592x1940_regs[] = {255static const struct cci_reg_sequence mode_2592x1940_regs[] = {
214 {0x3000, 0x01},256 { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY },
215 {0x3002, 0x00},257 { IMX335_REG_MASTER_MODE, 0x00 },
216 {0x3018, 0x04},258 { IMX335_REG_WINMODE, 0x04 },
217 {0x302c, 0x3c},259 { IMX335_REG_HTRIMMING_START, 48 },
218 {0x302e, 0x20},260 { IMX335_REG_HNUM, 2592 },
219 {0x3056, 0x94},261 { IMX335_REG_Y_OUT_SIZE, 1944 },
220 {0x3074, 0xc8},262 { IMX335_REG_AREA3_ST_ADR_1, 176 },
221 {0x3076, 0x28},263 { IMX335_REG_AREA3_WIDTH_1, 3928 },
222 {0x304c, 0x00},264 { IMX335_REG_OPB_SIZE_V, 0 },
223 {0x31a1, 0x00},265 { IMX335_REG_XVS_XHS_DRV, 0x00 },
224 {0x3288, 0x21},266 { CCI_REG8(0x3288), 0x21 },
225 {0x328a, 0x02},267 { CCI_REG8(0x328a), 0x02 },
226 {0x3414, 0x05},268 { CCI_REG8(0x3414), 0x05 },
227 {0x3416, 0x18},269 { CCI_REG8(0x3416), 0x18 },
228 {0x3648, 0x01},270 { CCI_REG8(0x3648), 0x01 },
229 {0x364a, 0x04},271 { CCI_REG8(0x364a), 0x04 },
230 {0x364c, 0x04},272 { CCI_REG8(0x364c), 0x04 },
231 {0x3678, 0x01},273 { CCI_REG8(0x3678), 0x01 },
232 {0x367c, 0x31},274 { CCI_REG8(0x367c), 0x31 },
233 {0x367e, 0x31},275 { CCI_REG8(0x367e), 0x31 },
234 {0x3706, 0x10},276 { CCI_REG8(0x3706), 0x10 },
235 {0x3708, 0x03},277 { CCI_REG8(0x3708), 0x03 },
236 {0x3714, 0x02},278 { CCI_REG8(0x3714), 0x02 },
237 {0x3715, 0x02},279 { CCI_REG8(0x3715), 0x02 },
238 {0x3716, 0x01},280 { CCI_REG8(0x3716), 0x01 },
239 {0x3717, 0x03},281 { CCI_REG8(0x3717), 0x03 },
240 {0x371c, 0x3d},282 { CCI_REG8(0x371c), 0x3d },
241 {0x371d, 0x3f},283 { CCI_REG8(0x371d), 0x3f },
242 {0x372c, 0x00},284 { CCI_REG8(0x372c), 0x00 },
243 {0x372d, 0x00},285 { CCI_REG8(0x372d), 0x00 },
244 {0x372e, 0x46},286 { CCI_REG8(0x372e), 0x46 },
245 {0x372f, 0x00},287 { CCI_REG8(0x372f), 0x00 },
246 {0x3730, 0x89},288 { CCI_REG8(0x3730), 0x89 },
247 {0x3731, 0x00},289 { CCI_REG8(0x3731), 0x00 },
248 {0x3732, 0x08},290 { CCI_REG8(0x3732), 0x08 },
249 {0x3733, 0x01},291 { CCI_REG8(0x3733), 0x01 },
250 {0x3734, 0xfe},292 { CCI_REG8(0x3734), 0xfe },
251 {0x3735, 0x05},293 { CCI_REG8(0x3735), 0x05 },
252 {0x3740, 0x02},294 { CCI_REG8(0x3740), 0x02 },
253 {0x375d, 0x00},295 { CCI_REG8(0x375d), 0x00 },
254 {0x375e, 0x00},296 { CCI_REG8(0x375e), 0x00 },
255 {0x375f, 0x11},297 { CCI_REG8(0x375f), 0x11 },
256 {0x3760, 0x01},298 { CCI_REG8(0x3760), 0x01 },
257 {0x3768, 0x1b},299 { CCI_REG8(0x3768), 0x1b },
258 {0x3769, 0x1b},300 { CCI_REG8(0x3769), 0x1b },
259 {0x376a, 0x1b},301 { CCI_REG8(0x376a), 0x1b },
260 {0x376b, 0x1b},302 { CCI_REG8(0x376b), 0x1b },
261 {0x376c, 0x1a},303 { CCI_REG8(0x376c), 0x1a },
262 {0x376d, 0x17},304 { CCI_REG8(0x376d), 0x17 },
263 {0x376e, 0x0f},305 { CCI_REG8(0x376e), 0x0f },
264 {0x3776, 0x00},306 { CCI_REG8(0x3776), 0x00 },
265 {0x3777, 0x00},307 { CCI_REG8(0x3777), 0x00 },
266 {0x3778, 0x46},308 { CCI_REG8(0x3778), 0x46 },
267 {0x3779, 0x00},309 { CCI_REG8(0x3779), 0x00 },
268 {0x377a, 0x89},310 { CCI_REG8(0x377a), 0x89 },
269 {0x377b, 0x00},311 { CCI_REG8(0x377b), 0x00 },
270 {0x377c, 0x08},312 { CCI_REG8(0x377c), 0x08 },
271 {0x377d, 0x01},313 { CCI_REG8(0x377d), 0x01 },
272 {0x377e, 0x23},314 { CCI_REG8(0x377e), 0x23 },
273 {0x377f, 0x02},315 { CCI_REG8(0x377f), 0x02 },
274 {0x3780, 0xd9},316 { CCI_REG8(0x3780), 0xd9 },
275 {0x3781, 0x03},317 { CCI_REG8(0x3781), 0x03 },
276 {0x3782, 0xf5},318 { CCI_REG8(0x3782), 0xf5 },
277 {0x3783, 0x06},319 { CCI_REG8(0x3783), 0x06 },
278 {0x3784, 0xa5},320 { CCI_REG8(0x3784), 0xa5 },
279 {0x3788, 0x0f},321 { CCI_REG8(0x3788), 0x0f },
280 {0x378a, 0xd9},322 { CCI_REG8(0x378a), 0xd9 },
281 {0x378b, 0x03},323 { CCI_REG8(0x378b), 0x03 },
282 {0x378c, 0xeb},324 { CCI_REG8(0x378c), 0xeb },
283 {0x378d, 0x05},325 { CCI_REG8(0x378d), 0x05 },
284 {0x378e, 0x87},326 { CCI_REG8(0x378e), 0x87 },
285 {0x378f, 0x06},327 { CCI_REG8(0x378f), 0x06 },
286 {0x3790, 0xf5},328 { CCI_REG8(0x3790), 0xf5 },
287 {0x3792, 0x43},329 { CCI_REG8(0x3792), 0x43 },
288 {0x3794, 0x7a},330 { CCI_REG8(0x3794), 0x7a },
289 {0x3796, 0xa1},331 { CCI_REG8(0x3796), 0xa1 },
290 {0x37b0, 0x36},332 { CCI_REG8(0x37b0), 0x36 },
291 {0x3a00, 0x00},333 { CCI_REG8(0x3a00), 0x00 },
292};334};
293 335
294static const struct imx335_reg raw10_framefmt_regs[] = {336static const struct cci_reg_sequence raw10_framefmt_regs[] = {
295 {0x3050, 0x00},337 { IMX335_REG_ADBIT, 0x00 },
296 {0x319d, 0x00},338 { IMX335_REG_MDBIT, 0x00 },
297 {0x341c, 0xff},339 { IMX335_REG_ADBIT1, 0x1ff },
298 {0x341d, 0x01},
299};340};
300 341
301static const struct imx335_reg raw12_framefmt_regs[] = {342static const struct cci_reg_sequence raw12_framefmt_regs[] = {
302 {0x3050, 0x01},343 { IMX335_REG_ADBIT, 0x01 },
303 {0x319d, 0x01},344 { IMX335_REG_MDBIT, 0x01 },
304 {0x341c, 0x47},345 { IMX335_REG_ADBIT1, 0x47 },
305 {0x341d, 0x00},
306};346};
307 347
308static const struct imx335_reg mipi_data_rate_1188Mbps[] = {348static const struct cci_reg_sequence mipi_data_rate_1188Mbps[] = {
309 {0x300c, 0x3b},349 { IMX335_REG_BCWAIT_TIME, 0x3b },
310 {0x300d, 0x2a},350 { IMX335_REG_CPWAIT_TIME, 0x2a },
311 {0x314c, 0xc6},351 { IMX335_REG_INCLKSEL1, 0x00c6 },
312 {0x314d, 0x00},352 { IMX335_REG_INCLKSEL2, 0x02 },
313 {0x315a, 0x02},353 { IMX335_REG_INCLKSEL3, 0xa0 },
314 {0x3168, 0xa0},354 { IMX335_REG_INCLKSEL4, 0x7e },
315 {0x316a, 0x7e},355 { IMX335_REG_SYSMODE, 0x01 },
316 {0x319e, 0x01},356 { IMX335_REG_TCLKPOST, 0x8f },
317 {0x3a18, 0x8f},357 { IMX335_REG_TCLKPREPARE, 0x4f },
318 {0x3a1a, 0x4f},358 { IMX335_REG_TCLK_TRAIL, 0x47 },
319 {0x3a1c, 0x47},359 { IMX335_REG_TCLK_ZERO, 0x0137 },
320 {0x3a1e, 0x37},360 { IMX335_REG_THS_PREPARE, 0x4f },
321 {0x3a1f, 0x01},361 { IMX335_REG_THS_ZERO, 0x87 },
322 {0x3a20, 0x4f},362 { IMX335_REG_THS_TRAIL, 0x4f },
323 {0x3a22, 0x87},363 { IMX335_REG_THS_EXIT, 0x7f },
324 {0x3a24, 0x4f},364 { IMX335_REG_TPLX, 0x3f },
325 {0x3a26, 0x7f},
326 {0x3a28, 0x3f},
327};365};
328 366
329static const struct imx335_reg mipi_data_rate_891Mbps[] = {367static const struct cci_reg_sequence mipi_data_rate_891Mbps[] = {
330 {0x300c, 0x3b},368 { IMX335_REG_BCWAIT_TIME, 0x3b },
331 {0x300d, 0x2a},369 { IMX335_REG_CPWAIT_TIME, 0x2a },
332 {0x314c, 0x29},370 { IMX335_REG_INCLKSEL1, 0x0129 },
333 {0x314d, 0x01},371 { IMX335_REG_INCLKSEL2, 0x06 },
334 {0x315a, 0x06},372 { IMX335_REG_INCLKSEL3, 0xa0 },
335 {0x3168, 0xa0},373 { IMX335_REG_INCLKSEL4, 0x7e },
336 {0x316a, 0x7e},374 { IMX335_REG_SYSMODE, 0x02 },
337 {0x319e, 0x02},375 { IMX335_REG_TCLKPOST, 0x7f },
338 {0x3a18, 0x7f},376 { IMX335_REG_TCLKPREPARE, 0x37 },
339 {0x3a1a, 0x37},377 { IMX335_REG_TCLK_TRAIL, 0x37 },
340 {0x3a1c, 0x37},378 { IMX335_REG_TCLK_ZERO, 0xf7 },
341 {0x3a1e, 0xf7},379 { IMX335_REG_THS_PREPARE, 0x3f },
342 {0x3a20, 0x3f},380 { IMX335_REG_THS_ZERO, 0x6f },
343 {0x3a22, 0x6f},381 { IMX335_REG_THS_TRAIL, 0x3f },
344 {0x3a24, 0x3f},382 { IMX335_REG_THS_EXIT, 0x5f },
345 {0x3a26, 0x5f},383 { IMX335_REG_TPLX, 0x2f },
346 {0x3a28, 0x2f},
347};384};
348 385
349static const s64 link_freq[] = {386static const s64 link_freq[] = {
@@ -372,10 +409,10 @@ static const u32 imx335_mbus_codes[] = { · 22 unmodified lines
372/* Supported sensor mode configurations */409/* Supported sensor mode configurations */
373static const struct imx335_mode supported_mode = {410static const struct imx335_mode supported_mode = {
374 .width = 2592,411 .width = 2592,
375 .height = 1940,412 .height = 1944,
376 .hblank = 342,413 .hblank = 342,
377 .vblank = 2560,414 .vblank = 2556,
378 .vblank_min = 2560,415 .vblank_min = 2556,
379 .vblank_max = 133060,416 .vblank_max = 133060,
380 .pclk = 396000000,417 .pclk = 396000000,
381 .reg_list = {418 .reg_list = {
@@ -395,101 +432,6 @@ static inline struct imx335 *to_imx335(struct v4l2_subdev *subdev) · 13 unmodified lines
395 return container_of(subdev, struct imx335, sd);432 return container_of(subdev, struct imx335, sd);
396}433}
397 434
398/**
399 * imx335_read_reg() - Read registers.
400 * @imx335: pointer to imx335 device
401 * @reg: register address
402 * @len: length of bytes to read. Max supported bytes is 4
403 * @val: pointer to register value to be filled.
404 *
405 * Big endian register addresses with little endian values.
406 *
407 * Return: 0 if successful, error code otherwise.
408 */
409static int imx335_read_reg(struct imx335 *imx335, u16 reg, u32 len, u32 *val)
410{
411 struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd);
412 struct i2c_msg msgs[2] = {0};
413 u8 addr_buf[2] = {0};
414 u8 data_buf[4] = {0};
415 int ret;
416
417 if (WARN_ON(len > 4))
418 return -EINVAL;
419
420 put_unaligned_be16(reg, addr_buf);
421
422 /* Write register address */
423 msgs[0].addr = client->addr;
424 msgs[0].flags = 0;
425 msgs[0].len = ARRAY_SIZE(addr_buf);
426 msgs[0].buf = addr_buf;
427
428 /* Read data from register */
429 msgs[1].addr = client->addr;
430 msgs[1].flags = I2C_M_RD;
431 msgs[1].len = len;
432 msgs[1].buf = data_buf;
433
434 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
435 if (ret != ARRAY_SIZE(msgs))
436 return -EIO;
437
438 *val = get_unaligned_le32(data_buf);
439
440 return 0;
441}
442
443/**
444 * imx335_write_reg() - Write register
445 * @imx335: pointer to imx335 device
446 * @reg: register address
447 * @len: length of bytes. Max supported bytes is 4
448 * @val: register value
449 *
450 * Big endian register addresses with little endian values.
451 *
452 * Return: 0 if successful, error code otherwise.
453 */
454static int imx335_write_reg(struct imx335 *imx335, u16 reg, u32 len, u32 val)
455{
456 struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd);
457 u8 buf[6] = {0};
458
459 if (WARN_ON(len > 4))
460 return -EINVAL;
461
462 put_unaligned_be16(reg, buf);
463 put_unaligned_le32(val, buf + 2);
464 if (i2c_master_send(client, buf, len + 2) != len + 2)
465 return -EIO;
466
467 return 0;
468}
469
470/**
471 * imx335_write_regs() - Write a list of registers
472 * @imx335: pointer to imx335 device
473 * @regs: list of registers to be written
474 * @len: length of registers array
475 *
476 * Return: 0 if successful. error code otherwise.
477 */
478static int imx335_write_regs(struct imx335 *imx335,
479 const struct imx335_reg *regs, u32 len)
480{
481 unsigned int i;
482 int ret;
483
484 for (i = 0; i < len; i++) {
485 ret = imx335_write_reg(imx335, regs[i].address, 1, regs[i].val);
486 if (ret)
487 return ret;
488 }
489
490 return 0;
491}
492
493/**435/**
494 * imx335_update_controls() - Update control ranges based on streaming mode436 * imx335_update_controls() - Update control ranges based on streaming mode
495 * @imx335: pointer to imx335 device437 * @imx335: pointer to imx335 device
@@ -526,7 +468,8 @@ static int imx335_update_controls(struct imx335 *imx335, · 30 unmodified lines
526static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain)468static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain)
527{469{
528 u32 lpfr, shutter;470 u32 lpfr, shutter;
529 int ret;471 int ret_hold;
472 int ret = 0;
530 473
531 lpfr = imx335->vblank + imx335->cur_mode->height;474 lpfr = imx335->vblank + imx335->cur_mode->height;
532 shutter = lpfr - exposure;475 shutter = lpfr - exposure;
@@ -534,64 +477,55 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) · 1 unmodified line
534 dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u\n",477 dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u\n",
535 exposure, gain, shutter, lpfr);478 exposure, gain, shutter, lpfr);
536 479
537 ret = imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 1);480 cci_write(imx335->cci, IMX335_REG_HOLD, 1, &ret);
538 if (ret)481 cci_write(imx335->cci, IMX335_REG_VMAX, lpfr, &ret);
539 return ret;482 cci_write(imx335->cci, IMX335_REG_SHUTTER, shutter, &ret);
540 483 cci_write(imx335->cci, IMX335_REG_GAIN, gain, &ret);
541 ret = imx335_write_reg(imx335, IMX335_REG_LPFR, 3, lpfr);484 /*
542 if (ret)485 * Unconditionally attempt to release the hold, but track the
543 goto error_release_group_hold;486 * error if the unhold itself fails.
544 487 */
545 ret = imx335_write_reg(imx335, IMX335_REG_SHUTTER, 3, shutter);488 ret_hold = cci_write(imx335->cci, IMX335_REG_HOLD, 0, NULL);
546 if (ret)489 if (ret_hold)
547 goto error_release_group_hold;490 ret = ret_hold;
548
549 ret = imx335_write_reg(imx335, IMX335_REG_AGAIN, 2, gain);
550
551error_release_group_hold:
552 imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 0);
553 491
554 return ret;492 return ret;
555}493}
556 494
557static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index)495static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index)
558{496{
559 int ret;497 int ret = 0;
560 498
561 if (pattern_index >= ARRAY_SIZE(imx335_tpg_val))499 if (pattern_index >= ARRAY_SIZE(imx335_tpg_val))
562 return -EINVAL;500 return -EINVAL;
563 501
564 if (pattern_index) {502 if (pattern_index) {
565 const struct imx335_reg tpg_enable_regs[] = {503 const struct cci_reg_sequence tpg_enable_regs[] = {
566 { 0x3148, 0x10 },504 { IMX335_REG_TPG_TESTCLKEN, 0x10 },
567 { 0x3280, 0x00 },505 { IMX335_REG_TPG_DIG_CLP_MODE, 0x00 },
568 { 0x329c, 0x01 },506 { IMX335_REG_TPG_EN_DUOUT, 0x01 },
569 { 0x32a0, 0x11 },507 { IMX335_REG_TPG_COLORWIDTH, 0x11 },
570 { 0x3302, 0x00 },508 { IMX335_REG_BLKLEVEL, 0x00 },
571 { 0x3303, 0x00 },509 { IMX335_REG_WRJ_OPEN, 0x00 },
572 { 0x336c, 0x00 },
573 };510 };
574 511
575 ret = imx335_write_reg(imx335, IMX335_REG_TPG, 1,512 cci_write(imx335->cci, IMX335_REG_TPG,
576 imx335_tpg_val[pattern_index]);513 imx335_tpg_val[pattern_index], &ret);
577 if (ret)
578 return ret;
579 514
580 ret = imx335_write_regs(imx335, tpg_enable_regs,515 cci_multi_reg_write(imx335->cci, tpg_enable_regs,
581 ARRAY_SIZE(tpg_enable_regs));516 ARRAY_SIZE(tpg_enable_regs), &ret);
582 } else {517 } else {
583 const struct imx335_reg tpg_disable_regs[] = {518 const struct cci_reg_sequence tpg_disable_regs[] = {
584 { 0x3148, 0x00 },519 { IMX335_REG_TPG_TESTCLKEN, 0x00 },
585 { 0x3280, 0x01 },520 { IMX335_REG_TPG_DIG_CLP_MODE, 0x01 },
586 { 0x329c, 0x00 },521 { IMX335_REG_TPG_EN_DUOUT, 0x00 },
587 { 0x32a0, 0x10 },522 { IMX335_REG_TPG_COLORWIDTH, 0x10 },
588 { 0x3302, 0x32 },523 { IMX335_REG_BLKLEVEL, 0x32 },
589 { 0x3303, 0x00 },524 { IMX335_REG_WRJ_OPEN, 0x01 },
590 { 0x336c, 0x01 },
591 };525 };
592 526
593 ret = imx335_write_regs(imx335, tpg_disable_regs,527 cci_multi_reg_write(imx335->cci, tpg_disable_regs,
594 ARRAY_SIZE(tpg_disable_regs));528 ARRAY_SIZE(tpg_disable_regs), &ret);
595 }529 }
596 530
597 return ret;531 return ret;
@@ -890,12 +824,14 @@ static int imx335_set_framefmt(struct imx335 *imx335) · 292 unmodified lines
890{824{
891 switch (imx335->cur_mbus_code) {825 switch (imx335->cur_mbus_code) {
892 case MEDIA_BUS_FMT_SRGGB10_1X10:826 case MEDIA_BUS_FMT_SRGGB10_1X10:
893 return imx335_write_regs(imx335, raw10_framefmt_regs,827 return cci_multi_reg_write(imx335->cci, raw10_framefmt_regs,
894 ARRAY_SIZE(raw10_framefmt_regs));828 ARRAY_SIZE(raw10_framefmt_regs),
829 NULL);
895 830
896 case MEDIA_BUS_FMT_SRGGB12_1X12:831 case MEDIA_BUS_FMT_SRGGB12_1X12:
897 return imx335_write_regs(imx335, raw12_framefmt_regs,832 return cci_multi_reg_write(imx335->cci, raw12_framefmt_regs,
898 ARRAY_SIZE(raw12_framefmt_regs));833 ARRAY_SIZE(raw12_framefmt_regs),
834 NULL);
899 }835 }
900 836
901 return -EINVAL;837 return -EINVAL;
@@ -914,7 +850,8 @@ static int imx335_start_streaming(struct imx335 *imx335) · 12 unmodified lines
914 850
915 /* Setup PLL */851 /* Setup PLL */
916 reg_list = &link_freq_reglist[__ffs(imx335->link_freq_bitmap)];852 reg_list = &link_freq_reglist[__ffs(imx335->link_freq_bitmap)];
917 ret = imx335_write_regs(imx335, reg_list->regs, reg_list->num_of_regs);853 ret = cci_multi_reg_write(imx335->cci, reg_list->regs,
854 reg_list->num_of_regs, NULL);
918 if (ret) {855 if (ret) {
919 dev_err(imx335->dev, "%s failed to set plls\n", __func__);856 dev_err(imx335->dev, "%s failed to set plls\n", __func__);
920 return ret;857 return ret;
@@ -922,8 +859,8 @@ static int imx335_start_streaming(struct imx335 *imx335) · 1 unmodified line
922 859
923 /* Write sensor mode registers */860 /* Write sensor mode registers */
924 reg_list = &imx335->cur_mode->reg_list;861 reg_list = &imx335->cur_mode->reg_list;
925 ret = imx335_write_regs(imx335, reg_list->regs,862 ret = cci_multi_reg_write(imx335->cci, reg_list->regs,
926 reg_list->num_of_regs);863 reg_list->num_of_regs, NULL);
927 if (ret) {864 if (ret) {
928 dev_err(imx335->dev, "fail to write initial registers\n");865 dev_err(imx335->dev, "fail to write initial registers\n");
929 return ret;866 return ret;
@@ -936,6 +873,12 @@ static int imx335_start_streaming(struct imx335 *imx335) · 6 unmodified lines
936 return ret;873 return ret;
937 }874 }
938 875
876 /* Configure lanes */
877 ret = cci_write(imx335->cci, IMX335_REG_LANEMODE,
878 imx335->lane_mode, NULL);
879 if (ret)
880 return ret;
881
939 /* Setup handler will write actual exposure and gain */882 /* Setup handler will write actual exposure and gain */
940 ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler);883 ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler);
941 if (ret) {884 if (ret) {
@@ -944,8 +887,8 @@ static int imx335_start_streaming(struct imx335 *imx335) · 2 unmodified lines
944 }887 }
945 888
946 /* Start streaming */889 /* Start streaming */
947 ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT,890 ret = cci_write(imx335->cci, IMX335_REG_MODE_SELECT,
948 1, IMX335_MODE_STREAMING);891 IMX335_MODE_STREAMING, NULL);
949 if (ret) {892 if (ret) {
950 dev_err(imx335->dev, "fail to start streaming\n");893 dev_err(imx335->dev, "fail to start streaming\n");
951 return ret;894 return ret;
@@ -965,8 +908,8 @@ static int imx335_start_streaming(struct imx335 *imx335) · 13 unmodified lines
965 */908 */
966static int imx335_stop_streaming(struct imx335 *imx335)909static int imx335_stop_streaming(struct imx335 *imx335)
967{910{
968 return imx335_write_reg(imx335, IMX335_REG_MODE_SELECT,911 return cci_write(imx335->cci, IMX335_REG_MODE_SELECT,
969 1, IMX335_MODE_STANDBY);912 IMX335_MODE_STANDBY, NULL);
970}913}
971 914
972/**915/**
@@ -1017,14 +960,14 @@ error_unlock: · 44 unmodified lines
1017static int imx335_detect(struct imx335 *imx335)960static int imx335_detect(struct imx335 *imx335)
1018{961{
1019 int ret;962 int ret;
1020 u32 val;963 u64 val;
1021 964
1022 ret = imx335_read_reg(imx335, IMX335_REG_ID, 2, &val);965 ret = cci_read(imx335->cci, IMX335_REG_ID, &val, NULL);
1023 if (ret)966 if (ret)
1024 return ret;967 return ret;
1025 968
1026 if (val != IMX335_ID) {969 if (val != IMX335_ID) {
1027 dev_err(imx335->dev, "chip id mismatch: %x!=%x\n",970 dev_err(imx335->dev, "chip id mismatch: %x!=%llx\n",
1028 IMX335_ID, val);971 IMX335_ID, val);
1029 return -ENXIO;972 return -ENXIO;
1030 }973 }
@@ -1096,7 +1039,14 @@ static int imx335_parse_hw_config(struct imx335 *imx335) · 65 unmodified lines
1096 if (ret)1039 if (ret)
1097 return ret;1040 return ret;
1098 1041
1099 if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) {1042 switch (bus_cfg.bus.mipi_csi2.num_data_lanes) {
1043 case 2:
1044 imx335->lane_mode = IMX335_2LANE;
1045 break;
1046 case 4:
1047 imx335->lane_mode = IMX335_4LANE;
1048 break;
1049 default:
1100 dev_err(imx335->dev,1050 dev_err(imx335->dev,
1101 "number of CSI2 data lanes %d is not supported\n",1051 "number of CSI2 data lanes %d is not supported\n",
1102 bus_cfg.bus.mipi_csi2.num_data_lanes);1052 bus_cfg.bus.mipi_csi2.num_data_lanes);
@@ -1208,10 +1158,16 @@ static int imx335_init_controls(struct imx335 *imx335) · 105 unmodified lines
1208{1158{
1209 struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler;1159 struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler;
1210 const struct imx335_mode *mode = imx335->cur_mode;1160 const struct imx335_mode *mode = imx335->cur_mode;
1161 struct v4l2_fwnode_device_properties props;
1211 u32 lpfr;1162 u32 lpfr;
1212 int ret;1163 int ret;
1213 1164
1214 ret = v4l2_ctrl_handler_init(ctrl_hdlr, 7);1165 ret = v4l2_fwnode_device_parse(imx335->dev, &props);
1166 if (ret)
1167 return ret;
1168
1169 /* v4l2_fwnode_device_properties can add two more controls */
1170 ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
1215 if (ret)1171 if (ret)
1216 return ret;1172 return ret;
1217 1173
@@ -1228,6 +1184,14 @@ static int imx335_init_controls(struct imx335 *imx335) · 10 unmodified lines
1228 IMX335_EXPOSURE_STEP,1184 IMX335_EXPOSURE_STEP,
1229 IMX335_EXPOSURE_DEFAULT);1185 IMX335_EXPOSURE_DEFAULT);
1230 1186
1187 /*
1188 * The sensor has an analog gain and a digital gain, both controlled
1189 * through a single gain value, expressed in 0.3dB increments. Values
1190 * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
1191 * up to 72.0dB (240) add further digital gain. Limit the range to
1192 * analog gain only, support for digital gain can be added separately
1193 * if needed.
1194 */
1231 imx335->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,1195 imx335->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
1232 &imx335_ctrl_ops,1196 &imx335_ctrl_ops,
1233 V4L2_CID_ANALOGUE_GAIN,1197 V4L2_CID_ANALOGUE_GAIN,
@@ -1276,6 +1240,8 @@ static int imx335_init_controls(struct imx335 *imx335) · 42 unmodified lines
1276 if (imx335->hblank_ctrl)1240 if (imx335->hblank_ctrl)
1277 imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;1241 imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1278 1242
1243 v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx335_ctrl_ops, &props);
1244
1279 if (ctrl_hdlr->error) {1245 if (ctrl_hdlr->error) {
1280 dev_err(imx335->dev, "control init failed: %d\n",1246 dev_err(imx335->dev, "control init failed: %d\n",
1281 ctrl_hdlr->error);1247 ctrl_hdlr->error);
@@ -1304,6 +1270,11 @@ static int imx335_probe(struct i2c_client *client) · 22 unmodified lines
1304 return -ENOMEM;1270 return -ENOMEM;
1305 1271
1306 imx335->dev = &client->dev;1272 imx335->dev = &client->dev;
1273 imx335->cci = devm_cci_regmap_init_i2c(client, 16);
1274 if (IS_ERR(imx335->cci)) {
1275 dev_err(imx335->dev, "Unable to initialize I2C\n");
1276 return -ENODEV;
1277 }
1307 1278
1308 /* Initialize subdev */1279 /* Initialize subdev */
1309 v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops);1280 v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops);
drivers/media/i2c/max9271.h+5−0
@@ -8,6 +8,9 @@ · 7 unmodified lines
8 * Copyright (C) 2015 Cogent Embedded, Inc.8 * Copyright (C) 2015 Cogent Embedded, Inc.
9 */9 */
10 10
11#ifndef __MEDIA_I2C_MAX9271_H__
12#define __MEDIA_I2C_MAX9271_H__
13
11#include <linux/i2c.h>14#include <linux/i2c.h>
12 15
13#define MAX9271_DEFAULT_ADDR 0x4016#define MAX9271_DEFAULT_ADDR 0x40
@@ -231,3 +234,5 @@ int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr); · 217 unmodified lines
231 * Return 0 on success or a negative error code on failure234 * Return 0 on success or a negative error code on failure
232 */235 */
233int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest);236int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest);
237
238#endif /* __MEDIA_I2C_MAX9271_H__ */
drivers/media/i2c/ov2680.c+77−26
@@ -75,6 +75,8 @@ · 74 unmodified lines
75#define OV2680_ACTIVE_START_TOP 875#define OV2680_ACTIVE_START_TOP 8
76#define OV2680_MIN_CROP_WIDTH 276#define OV2680_MIN_CROP_WIDTH 2
77#define OV2680_MIN_CROP_HEIGHT 277#define OV2680_MIN_CROP_HEIGHT 2
78#define OV2680_MIN_VBLANK 4
79#define OV2680_MAX_VBLANK 0xffff
78 80
79/* Fixed pre-div of 1/2 */81/* Fixed pre-div of 1/2 */
80#define OV2680_PLL_PREDIV0 282#define OV2680_PLL_PREDIV0 2
@@ -84,10 +86,7 @@ · 3 unmodified lines
84 86
85/* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */87/* 66MHz pixel clock: 66MHz / 1704 * 1294 = 30fps */
86#define OV2680_PIXELS_PER_LINE 170488#define OV2680_PIXELS_PER_LINE 1704
87#define OV2680_LINES_PER_FRAME 129489#define OV2680_LINES_PER_FRAME_30FPS 1294
88
89/* If possible send 16 extra rows / lines to the ISP as padding */
90#define OV2680_END_MARGIN 16
91 90
92/* Max exposure time is VTS - 8 */91/* Max exposure time is VTS - 8 */
93#define OV2680_INTEGRATION_TIME_MARGIN 892#define OV2680_INTEGRATION_TIME_MARGIN 8
@@ -130,6 +129,8 @@ struct ov2680_ctrls { · 36 unmodified lines
130 struct v4l2_ctrl *test_pattern;129 struct v4l2_ctrl *test_pattern;
131 struct v4l2_ctrl *link_freq;130 struct v4l2_ctrl *link_freq;
132 struct v4l2_ctrl *pixel_rate;131 struct v4l2_ctrl *pixel_rate;
132 struct v4l2_ctrl *vblank;
133 struct v4l2_ctrl *hblank;
133};134};
134 135
135struct ov2680_mode {136struct ov2680_mode {
@@ -143,8 +144,6 @@ struct ov2680_mode { · 7 unmodified lines
143 u16 v_end;144 u16 v_end;
144 u16 h_output_size;145 u16 h_output_size;
145 u16 v_output_size;146 u16 v_output_size;
146 u16 hts;
147 u16 vts;
148};147};
149 148
150struct ov2680_dev {149struct ov2680_dev {
@@ -359,15 +358,11 @@ static void ov2680_calc_mode(struct ov2680_dev *sensor) · 208 unmodified lines
359 sensor->mode.v_start = (sensor->mode.crop.top +358 sensor->mode.v_start = (sensor->mode.crop.top +
360 (sensor->mode.crop.height - height) / 2) & ~1;359 (sensor->mode.crop.height - height) / 2) & ~1;
361 sensor->mode.h_end =360 sensor->mode.h_end =
362 min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1,361 min(sensor->mode.h_start + width - 1, OV2680_NATIVE_WIDTH - 1);
363 OV2680_NATIVE_WIDTH - 1);
364 sensor->mode.v_end =362 sensor->mode.v_end =
365 min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1,363 min(sensor->mode.v_start + height - 1, OV2680_NATIVE_HEIGHT - 1);
366 OV2680_NATIVE_HEIGHT - 1);
367 sensor->mode.h_output_size = orig_width;364 sensor->mode.h_output_size = orig_width;
368 sensor->mode.v_output_size = orig_height;365 sensor->mode.v_output_size = orig_height;
369 sensor->mode.hts = OV2680_PIXELS_PER_LINE;
370 sensor->mode.vts = OV2680_LINES_PER_FRAME;
371}366}
372 367
373static int ov2680_set_mode(struct ov2680_dev *sensor)368static int ov2680_set_mode(struct ov2680_dev *sensor)
@@ -402,9 +397,8 @@ static int ov2680_set_mode(struct ov2680_dev *sensor) · 28 unmodified lines
402 cci_write(sensor->regmap, OV2680_REG_VERTICAL_OUTPUT_SIZE,397 cci_write(sensor->regmap, OV2680_REG_VERTICAL_OUTPUT_SIZE,
403 sensor->mode.v_output_size, &ret);398 sensor->mode.v_output_size, &ret);
404 cci_write(sensor->regmap, OV2680_REG_TIMING_HTS,399 cci_write(sensor->regmap, OV2680_REG_TIMING_HTS,
405 sensor->mode.hts, &ret);400 OV2680_PIXELS_PER_LINE, &ret);
406 cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,401 /* VTS gets set by the vblank ctrl */
407 sensor->mode.vts, &ret);
408 cci_write(sensor->regmap, OV2680_REG_ISP_X_WIN, 0, &ret);402 cci_write(sensor->regmap, OV2680_REG_ISP_X_WIN, 0, &ret);
409 cci_write(sensor->regmap, OV2680_REG_ISP_Y_WIN, 0, &ret);403 cci_write(sensor->regmap, OV2680_REG_ISP_Y_WIN, 0, &ret);
410 cci_write(sensor->regmap, OV2680_REG_X_INC, inc, &ret);404 cci_write(sensor->regmap, OV2680_REG_X_INC, inc, &ret);
@@ -478,6 +472,15 @@ static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp) · 67 unmodified lines
478 NULL);472 NULL);
479}473}
480 474
475static int ov2680_exposure_update_range(struct ov2680_dev *sensor)
476{
477 int exp_max = sensor->mode.fmt.height + sensor->ctrls.vblank->val -
478 OV2680_INTEGRATION_TIME_MARGIN;
479
480 return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max,
481 1, exp_max);
482}
483
481static int ov2680_stream_enable(struct ov2680_dev *sensor)484static int ov2680_stream_enable(struct ov2680_dev *sensor)
482{485{
483 int ret;486 int ret;
@@ -644,7 +647,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, · 160 unmodified lines
644 struct v4l2_mbus_framefmt *try_fmt;647 struct v4l2_mbus_framefmt *try_fmt;
645 const struct v4l2_rect *crop;648 const struct v4l2_rect *crop;
646 unsigned int width, height;649 unsigned int width, height;
647 int ret = 0;650 int def, max, ret = 0;
648 651
649 crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad,652 crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad,
650 format->which);653 format->which);
@@ -673,6 +676,27 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, · 22 unmodified lines
673 sensor->mode.fmt = format->format;676 sensor->mode.fmt = format->format;
674 ov2680_calc_mode(sensor);677 ov2680_calc_mode(sensor);
675 678
679 /* vblank range is height dependent adjust and reset to default */
680 max = OV2680_MAX_VBLANK - height;
681 def = OV2680_LINES_PER_FRAME_30FPS - height;
682 ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV2680_MIN_VBLANK,
683 max, 1, def);
684 if (ret)
685 goto unlock;
686
687 ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, def);
688 if (ret)
689 goto unlock;
690
691 /* exposure range depends on vts which may have changed */
692 ret = ov2680_exposure_update_range(sensor);
693 if (ret)
694 goto unlock;
695
696 /* adjust hblank value for new width */
697 def = OV2680_PIXELS_PER_LINE - width;
698 ret = __v4l2_ctrl_modify_range(sensor->ctrls.hblank, def, def, 1, def);
699
676unlock:700unlock:
677 mutex_unlock(&sensor->lock);701 mutex_unlock(&sensor->lock);
678 702
@@ -842,6 +866,13 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) · 163 unmodified lines
842 struct ov2680_dev *sensor = to_ov2680_dev(sd);866 struct ov2680_dev *sensor = to_ov2680_dev(sd);
843 int ret;867 int ret;
844 868
869 /* Update exposure range on vblank changes */
870 if (ctrl->id == V4L2_CID_VBLANK) {
871 ret = ov2680_exposure_update_range(sensor);
872 if (ret)
873 return ret;
874 }
875
845 /* Only apply changes to the controls if the device is powered up */876 /* Only apply changes to the controls if the device is powered up */
846 if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {877 if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {
847 ov2680_set_bayer_order(sensor, &sensor->mode.fmt);878 ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
@@ -864,6 +895,10 @@ static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) · 16 unmodified lines
864 case V4L2_CID_TEST_PATTERN:895 case V4L2_CID_TEST_PATTERN:
865 ret = ov2680_test_pattern_set(sensor, ctrl->val);896 ret = ov2680_test_pattern_set(sensor, ctrl->val);
866 break;897 break;
898 case V4L2_CID_VBLANK:
899 ret = cci_write(sensor->regmap, OV2680_REG_TIMING_VTS,
900 sensor->mode.fmt.height + ctrl->val, NULL);
901 break;
867 default:902 default:
868 ret = -EINVAL;903 ret = -EINVAL;
869 break;904 break;
@@ -922,8 +957,8 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) · 52 unmodified lines
922 const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;957 const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
923 struct ov2680_ctrls *ctrls = &sensor->ctrls;958 struct ov2680_ctrls *ctrls = &sensor->ctrls;
924 struct v4l2_ctrl_handler *hdl = &ctrls->handler;959 struct v4l2_ctrl_handler *hdl = &ctrls->handler;
925 int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN;960 struct v4l2_fwnode_device_properties props;
926 int ret = 0;961 int def, max, ret = 0;
927 962
928 v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops);963 v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops);
929 sensor->sd.internal_ops = &ov2680_internal_ops;964 sensor->sd.internal_ops = &ov2680_internal_ops;
@@ -948,8 +983,9 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) · 18 unmodified lines
948 ARRAY_SIZE(test_pattern_menu) - 1,983 ARRAY_SIZE(test_pattern_menu) - 1,
949 0, 0, test_pattern_menu);984 0, 0, test_pattern_menu);
950 985
986 max = OV2680_LINES_PER_FRAME_30FPS - OV2680_INTEGRATION_TIME_MARGIN;
951 ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,987 ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
952 0, exp_max, 1, exp_max);988 0, max, 1, max);
953 989
954 ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,990 ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
955 0, 1023, 1, 250);991 0, 1023, 1, 250);
@@ -960,6 +996,21 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) · 4 unmodified lines
960 0, sensor->pixel_rate,996 0, sensor->pixel_rate,
961 1, sensor->pixel_rate);997 1, sensor->pixel_rate);
962 998
999 max = OV2680_MAX_VBLANK - OV2680_DEFAULT_HEIGHT;
1000 def = OV2680_LINES_PER_FRAME_30FPS - OV2680_DEFAULT_HEIGHT;
1001 ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
1002 OV2680_MIN_VBLANK, max, 1, def);
1003
1004 def = OV2680_PIXELS_PER_LINE - OV2680_DEFAULT_WIDTH;
1005 ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
1006 def, def, 1, def);
1007
1008 ret = v4l2_fwnode_device_parse(sensor->dev, &props);
1009 if (ret)
1010 goto cleanup_entity;
1011
1012 v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
1013
963 if (hdl->error) {1014 if (hdl->error) {
964 ret = hdl->error;1015 ret = hdl->error;
965 goto cleanup_entity;1016 goto cleanup_entity;
@@ -968,6 +1019,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) · 2 unmodified lines
968 ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;1019 ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
969 ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;1020 ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
970 ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;1021 ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1022 ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
971 1023
972 sensor->sd.ctrl_handler = hdl;1024 sensor->sd.ctrl_handler = hdl;
973 1025
@@ -1116,25 +1168,24 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) · 142 unmodified lines
1116 sensor->pixel_rate = sensor->link_freq[0] * 2;1168 sensor->pixel_rate = sensor->link_freq[0] * 2;
1117 do_div(sensor->pixel_rate, 10);1169 do_div(sensor->pixel_rate, 10);
1118 1170
1119 /* Verify bus cfg */1171 if (!bus_cfg.nr_of_link_frequencies) {
1120 if (bus_cfg.bus.mipi_csi2.num_data_lanes != 1) {1172 dev_warn(dev, "Consider passing 'link-frequencies' in DT\n");
1121 ret = dev_err_probe(dev, -EINVAL,1173 goto skip_link_freq_validation;
1122 "only a 1-lane CSI2 config is supported");
1123 goto out_free_bus_cfg;
1124 }1174 }
1125 1175
1126 for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)1176 for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
1127 if (bus_cfg.link_frequencies[i] == sensor->link_freq[0])1177 if (bus_cfg.link_frequencies[i] == sensor->link_freq[0])
1128 break;1178 break;
1129 1179
1130 if (bus_cfg.nr_of_link_frequencies == 0 ||1180 if (bus_cfg.nr_of_link_frequencies == i) {
1131 bus_cfg.nr_of_link_frequencies == i) {
1132 ret = dev_err_probe(dev, -EINVAL,1181 ret = dev_err_probe(dev, -EINVAL,
1133 "supported link freq %lld not found\n",1182 "supported link freq %lld not found\n",
1134 sensor->link_freq[0]);1183 sensor->link_freq[0]);
1135 goto out_free_bus_cfg;1184 goto out_free_bus_cfg;
1136 }1185 }
1137 1186
1187skip_link_freq_validation:
1188 ret = 0;
1138out_free_bus_cfg:1189out_free_bus_cfg:
1139 v4l2_fwnode_endpoint_free(&bus_cfg);1190 v4l2_fwnode_endpoint_free(&bus_cfg);
1140 return ret;1191 return ret;
drivers/media/i2c/ov2740.c+14−6
@@ -768,14 +768,15 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 767 unmodified lines
768 cur_mode = ov2740->cur_mode;768 cur_mode = ov2740->cur_mode;
769 size = ARRAY_SIZE(link_freq_menu_items);769 size = ARRAY_SIZE(link_freq_menu_items);
770 770
771 ov2740->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops,771 ov2740->link_freq =
772 V4L2_CID_LINK_FREQ,772 v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops,
773 size - 1, 0,773 V4L2_CID_LINK_FREQ, size - 1,
774 link_freq_menu_items);774 ov2740->supported_modes->link_freq_index,
775 link_freq_menu_items);
775 if (ov2740->link_freq)776 if (ov2740->link_freq)
776 ov2740->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;777 ov2740->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
777 778
778 pixel_rate = to_pixel_rate(OV2740_LINK_FREQ_360MHZ_INDEX);779 pixel_rate = to_pixel_rate(ov2740->supported_modes->link_freq_index);
779 ov2740->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,780 ov2740->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
780 V4L2_CID_PIXEL_RATE, 0,781 V4L2_CID_PIXEL_RATE, 0,
781 pixel_rate, 1, pixel_rate);782 pixel_rate, 1, pixel_rate);
@@ -1332,9 +1333,16 @@ static int ov2740_probe(struct i2c_client *client) · 550 unmodified lines
1332 return dev_err_probe(dev, ret, "failed to check HW configuration\n");1333 return dev_err_probe(dev, ret, "failed to check HW configuration\n");
1333 1334
1334 ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);1335 ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
1335 if (IS_ERR(ov2740->reset_gpio))1336 if (IS_ERR(ov2740->reset_gpio)) {
1336 return dev_err_probe(dev, PTR_ERR(ov2740->reset_gpio),1337 return dev_err_probe(dev, PTR_ERR(ov2740->reset_gpio),
1337 "failed to get reset GPIO\n");1338 "failed to get reset GPIO\n");
1339 } else if (ov2740->reset_gpio) {
1340 /*
1341 * Ensure reset is asserted for at least 20 ms before
1342 * ov2740_resume() deasserts it.
1343 */
1344 msleep(20);
1345 }
1338 1346
1339 ov2740->clk = devm_clk_get_optional(dev, "clk");1347 ov2740->clk = devm_clk_get_optional(dev, "clk");
1340 if (IS_ERR(ov2740->clk))1348 if (IS_ERR(ov2740->clk))
drivers/media/i2c/ov4689.c+359−314
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 * ov4689 driver3 * ov4689 driver
4 *4 *
5 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.5 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
6 * Copyright (C) 2022 Mikhail Rudenko6 * Copyright (C) 2022, 2024 Mikhail Rudenko
7 */7 */
8 8
9#include <linux/clk.h>9#include <linux/clk.h>
@@ -15,45 +15,86 @@ · 5 unmodified lines
15#include <linux/regulator/consumer.h>15#include <linux/regulator/consumer.h>
16#include <media/media-entity.h>16#include <media/media-entity.h>
17#include <media/v4l2-async.h>17#include <media/v4l2-async.h>
18#include <media/v4l2-cci.h>
18#include <media/v4l2-ctrls.h>19#include <media/v4l2-ctrls.h>
19#include <media/v4l2-subdev.h>20#include <media/v4l2-subdev.h>
20#include <media/v4l2-fwnode.h>21#include <media/v4l2-fwnode.h>
21 22
22#define CHIP_ID 0x00468823#define OV4689_REG_CTRL_MODE CCI_REG8(0x0100)
23#define OV4689_REG_CHIP_ID 0x300a
24
25#define OV4689_XVCLK_FREQ 24000000
26
27#define OV4689_REG_CTRL_MODE 0x0100
28#define OV4689_MODE_SW_STANDBY 0x024#define OV4689_MODE_SW_STANDBY 0x0
29#define OV4689_MODE_STREAMING BIT(0)25#define OV4689_MODE_STREAMING BIT(0)
30 26
31#define OV4689_REG_EXPOSURE 0x350027#define OV4689_REG_CHIP_ID CCI_REG16(0x300a)
28#define CHIP_ID 0x004688
29
30#define OV4689_REG_EXPOSURE CCI_REG24(0x3500)
32#define OV4689_EXPOSURE_MIN 431#define OV4689_EXPOSURE_MIN 4
33#define OV4689_EXPOSURE_STEP 132#define OV4689_EXPOSURE_STEP 1
34#define OV4689_VTS_MAX 0x7fff
35 33
36#define OV4689_REG_GAIN_H 0x350834#define OV4689_REG_GAIN CCI_REG16(0x3508)
37#define OV4689_REG_GAIN_L 0x3509
38#define OV4689_GAIN_H_MASK 0x07
39#define OV4689_GAIN_H_SHIFT 8
40#define OV4689_GAIN_L_MASK 0xff
41#define OV4689_GAIN_STEP 135#define OV4689_GAIN_STEP 1
42#define OV4689_GAIN_DEFAULT 0x8036#define OV4689_GAIN_DEFAULT 0x80
43 37
44#define OV4689_REG_TEST_PATTERN 0x504038#define OV4689_REG_DIG_GAIN CCI_REG16(0x352a)
45#define OV4689_TEST_PATTERN_ENABLE 0x8039#define OV4689_DIG_GAIN_MIN 1
46#define OV4689_TEST_PATTERN_DISABLE 0x040#define OV4689_DIG_GAIN_MAX 0x7fff
41#define OV4689_DIG_GAIN_STEP 1
42#define OV4689_DIG_GAIN_DEFAULT 0x800
47 43
48#define OV4689_REG_VTS 0x380e44#define OV4689_REG_H_CROP_START CCI_REG16(0x3800)
45#define OV4689_REG_V_CROP_START CCI_REG16(0x3802)
46#define OV4689_REG_H_CROP_END CCI_REG16(0x3804)
47#define OV4689_REG_V_CROP_END CCI_REG16(0x3806)
48#define OV4689_REG_H_OUTPUT_SIZE CCI_REG16(0x3808)
49#define OV4689_REG_V_OUTPUT_SIZE CCI_REG16(0x380a)
49 50
50#define REG_NULL 0xFFFF51#define OV4689_REG_HTS CCI_REG16(0x380c)
52#define OV4689_HTS_DIVIDER 4
53#define OV4689_HTS_MAX 0x7fff
51 54
52#define OV4689_REG_VALUE_08BIT 155#define OV4689_REG_VTS CCI_REG16(0x380e)
53#define OV4689_REG_VALUE_16BIT 256#define OV4689_VTS_MAX 0x7fff
54#define OV4689_REG_VALUE_24BIT 357
58#define OV4689_REG_H_WIN_OFF CCI_REG16(0x3810)
59#define OV4689_REG_V_WIN_OFF CCI_REG16(0x3812)
60
61#define OV4689_REG_TIMING_FORMAT1 CCI_REG8(0x3820) /* Vertical */
62#define OV4689_REG_TIMING_FORMAT2 CCI_REG8(0x3821) /* Horizontal */
63#define OV4689_TIMING_FLIP_MASK GENMASK(2, 1)
64#define OV4689_TIMING_FLIP_ARRAY BIT(1)
65#define OV4689_TIMING_FLIP_DIGITAL BIT(2)
66#define OV4689_TIMING_FLIP_BOTH (OV4689_TIMING_FLIP_ARRAY |\
67 OV4689_TIMING_FLIP_DIGITAL)
68
69#define OV4689_REG_ANCHOR_LEFT_START CCI_REG16(0x4020)
70#define OV4689_ANCHOR_LEFT_START_DEF 576
71#define OV4689_REG_ANCHOR_LEFT_END CCI_REG16(0x4022)
72#define OV4689_ANCHOR_LEFT_END_DEF 831
73#define OV4689_REG_ANCHOR_RIGHT_START CCI_REG16(0x4024)
74#define OV4689_ANCHOR_RIGHT_START_DEF 1984
75#define OV4689_REG_ANCHOR_RIGHT_END CCI_REG16(0x4026)
76#define OV4689_ANCHOR_RIGHT_END_DEF 2239
77
78#define OV4689_REG_VFIFO_CTRL_01 CCI_REG8(0x4601)
79
80#define OV4689_REG_WB_GAIN_RED CCI_REG16(0x500c)
81#define OV4689_REG_WB_GAIN_BLUE CCI_REG16(0x5010)
82#define OV4689_WB_GAIN_MIN 1
83#define OV4689_WB_GAIN_MAX 0xfff
84#define OV4689_WB_GAIN_STEP 1
85#define OV4689_WB_GAIN_DEFAULT 0x400
86
87#define OV4689_REG_TEST_PATTERN CCI_REG8(0x5040)
88#define OV4689_TEST_PATTERN_ENABLE 0x80
89#define OV4689_TEST_PATTERN_DISABLE 0x0
55 90
56#define OV4689_LANES 491#define OV4689_LANES 4
92#define OV4689_XVCLK_FREQ 24000000
93
94#define OV4689_PIXEL_ARRAY_WIDTH 2720
95#define OV4689_PIXEL_ARRAY_HEIGHT 1536
96#define OV4689_DUMMY_ROWS 8 /* 8 dummy rows on each side */
97#define OV4689_DUMMY_COLUMNS 16 /* 16 dummy columns on each side */
57 98
58static const char *const ov4689_supply_names[] = {99static const char *const ov4689_supply_names[] = {
59 "avdd", /* Analog power */100 "avdd", /* Analog power */
@@ -61,11 +102,6 @@ static const char *const ov4689_supply_names[] = { · 1 unmodified line
61 "dvdd", /* Digital core power */102 "dvdd", /* Digital core power */
62};103};
63 104
64struct regval {
65 u16 addr;
66 u8 val;
67};
68
69enum ov4689_mode_id {105enum ov4689_mode_id {
70 OV4689_MODE_2688_1520 = 0,106 OV4689_MODE_2688_1520 = 0,
71 OV4689_NUM_MODES,107 OV4689_NUM_MODES,
@@ -75,20 +111,18 @@ struct ov4689_mode { · 3 unmodified lines
75 enum ov4689_mode_id id;111 enum ov4689_mode_id id;
76 u32 width;112 u32 width;
77 u32 height;113 u32 height;
78 u32 max_fps;
79 u32 hts_def;114 u32 hts_def;
115 u32 hts_min;
80 u32 vts_def;116 u32 vts_def;
81 u32 exp_def;117 u32 exp_def;
82 u32 pixel_rate;118 u32 pixel_rate;
83 u32 sensor_width;119 const struct cci_reg_sequence *reg_list;
84 u32 sensor_height;120 unsigned int num_regs;
85 u32 crop_top;
86 u32 crop_left;
87 const struct regval *reg_list;
88};121};
89 122
90struct ov4689 {123struct ov4689 {
91 struct i2c_client *client;124 struct device *dev;
125 struct regmap *regmap;
92 struct clk *xvclk;126 struct clk *xvclk;
93 struct gpio_desc *reset_gpio;127 struct gpio_desc *reset_gpio;
94 struct gpio_desc *pwdn_gpio;128 struct gpio_desc *pwdn_gpio;
@@ -99,7 +133,6 @@ struct ov4689 { · 4 unmodified lines
99 133
100 u32 clock_rate;134 u32 clock_rate;
101 135
102 struct mutex mutex; /* lock to protect ctrls and cur_mode */
103 struct v4l2_ctrl_handler ctrl_handler;136 struct v4l2_ctrl_handler ctrl_handler;
104 struct v4l2_ctrl *exposure;137 struct v4l2_ctrl *exposure;
105 138
@@ -119,95 +152,108 @@ struct ov4689_gain_range { · 13 unmodified lines
119 152
120/*153/*
121 * Xclk 24Mhz154 * Xclk 24Mhz
122 * max_framerate 30fps155 * max_framerate 90fps
123 * mipi_datarate per lane 1008Mbps156 * mipi_datarate per lane 1008Mbps
124 */157 */
125static const struct regval ov4689_2688x1520_regs[] = {158static const struct cci_reg_sequence ov4689_2688x1520_regs[] = {
126 {0x0103, 0x01}, {0x3638, 0x00}, {0x0300, 0x00},159 /* System control*/
127 {0x0302, 0x2a}, {0x0303, 0x00}, {0x0304, 0x03},160 { CCI_REG8(0x0103), 0x01 }, /* SC_CTRL0103 software_reset = 1 */
128 {0x030b, 0x00}, {0x030d, 0x1e}, {0x030e, 0x04},161 { CCI_REG8(0x3000), 0x20 }, /* SC_CMMN_PAD_OEN0 FSIN_output_enable = 1 */
129 {0x030f, 0x01}, {0x0312, 0x01}, {0x031e, 0x00},162 { CCI_REG8(0x3021), 0x03 }, /*
130 {0x3000, 0x20}, {0x3002, 0x00}, {0x3018, 0x72},163 * SC_CMMN_MISC_CTRL fst_stby_ctr = 0,
131 {0x3020, 0x93}, {0x3021, 0x03}, {0x3022, 0x01},164 * sleep_no_latch_enable = 0
132 {0x3031, 0x0a}, {0x303f, 0x0c}, {0x3305, 0xf1},165 */
133 {0x3307, 0x04}, {0x3309, 0x29}, {0x3500, 0x00},166
134 {0x3501, 0x60}, {0x3502, 0x00}, {0x3503, 0x04},167 /* AEC PK */
135 {0x3504, 0x00}, {0x3505, 0x00}, {0x3506, 0x00},168 { CCI_REG8(0x3503), 0x04 }, /* AEC_MANUAL gain_input_as_sensor_gain_format = 1 */
136 {0x3507, 0x00}, {0x3508, 0x00}, {0x3509, 0x80},169
137 {0x350a, 0x00}, {0x350b, 0x00}, {0x350c, 0x00},170 /* ADC and analog control*/
138 {0x350d, 0x00}, {0x350e, 0x00}, {0x350f, 0x80},171 { CCI_REG8(0x3603), 0x40 },
139 {0x3510, 0x00}, {0x3511, 0x00}, {0x3512, 0x00},172 { CCI_REG8(0x3604), 0x02 },
140 {0x3513, 0x00}, {0x3514, 0x00}, {0x3515, 0x80},173 { CCI_REG8(0x3609), 0x12 },
141 {0x3516, 0x00}, {0x3517, 0x00}, {0x3518, 0x00},174 { CCI_REG8(0x360c), 0x08 },
142 {0x3519, 0x00}, {0x351a, 0x00}, {0x351b, 0x80},175 { CCI_REG8(0x360f), 0xe5 },
143 {0x351c, 0x00}, {0x351d, 0x00}, {0x351e, 0x00},176 { CCI_REG8(0x3608), 0x8f },
144 {0x351f, 0x00}, {0x3520, 0x00}, {0x3521, 0x80},177 { CCI_REG8(0x3611), 0x00 },
145 {0x3522, 0x08}, {0x3524, 0x08}, {0x3526, 0x08},178 { CCI_REG8(0x3613), 0xf7 },
146 {0x3528, 0x08}, {0x352a, 0x08}, {0x3602, 0x00},179 { CCI_REG8(0x3616), 0x58 },
147 {0x3603, 0x40}, {0x3604, 0x02}, {0x3605, 0x00},180 { CCI_REG8(0x3619), 0x99 },
148 {0x3606, 0x00}, {0x3607, 0x00}, {0x3609, 0x12},181 { CCI_REG8(0x361b), 0x60 },
149 {0x360a, 0x40}, {0x360c, 0x08}, {0x360f, 0xe5},182 { CCI_REG8(0x361e), 0x79 },
150 {0x3608, 0x8f}, {0x3611, 0x00}, {0x3613, 0xf7},183 { CCI_REG8(0x3634), 0x10 },
151 {0x3616, 0x58}, {0x3619, 0x99}, {0x361b, 0x60},184 { CCI_REG8(0x3635), 0x10 },
152 {0x361c, 0x7a}, {0x361e, 0x79}, {0x361f, 0x02},185 { CCI_REG8(0x3636), 0x15 },
153 {0x3632, 0x00}, {0x3633, 0x10}, {0x3634, 0x10},186 { CCI_REG8(0x3646), 0x86 },
154 {0x3635, 0x10}, {0x3636, 0x15}, {0x3646, 0x86},187 { CCI_REG8(0x364a), 0x0b },
155 {0x364a, 0x0b}, {0x3700, 0x17}, {0x3701, 0x22},188
156 {0x3703, 0x10}, {0x370a, 0x37}, {0x3705, 0x00},189 /* Sensor control */
157 {0x3706, 0x63}, {0x3709, 0x3c}, {0x370b, 0x01},190 { CCI_REG8(0x3700), 0x17 },
158 {0x370c, 0x30}, {0x3710, 0x24}, {0x3711, 0x0c},191 { CCI_REG8(0x3701), 0x22 },
159 {0x3716, 0x00}, {0x3720, 0x28}, {0x3729, 0x7b},192 { CCI_REG8(0x3703), 0x10 },
160 {0x372a, 0x84}, {0x372b, 0xbd}, {0x372c, 0xbc},193 { CCI_REG8(0x370a), 0x37 },
161 {0x372e, 0x52}, {0x373c, 0x0e}, {0x373e, 0x33},194 { CCI_REG8(0x3706), 0x63 },
162 {0x3743, 0x10}, {0x3744, 0x88}, {0x3745, 0xc0},195 { CCI_REG8(0x3709), 0x3c },
163 {0x374a, 0x43}, {0x374c, 0x00}, {0x374e, 0x23},196 { CCI_REG8(0x370c), 0x30 },
164 {0x3751, 0x7b}, {0x3752, 0x84}, {0x3753, 0xbd},197 { CCI_REG8(0x3710), 0x24 },
165 {0x3754, 0xbc}, {0x3756, 0x52}, {0x375c, 0x00},198 { CCI_REG8(0x3720), 0x28 },
166 {0x3760, 0x00}, {0x3761, 0x00}, {0x3762, 0x00},199 { CCI_REG8(0x3729), 0x7b },
167 {0x3763, 0x00}, {0x3764, 0x00}, {0x3767, 0x04},200 { CCI_REG8(0x372b), 0xbd },
168 {0x3768, 0x04}, {0x3769, 0x08}, {0x376a, 0x08},201 { CCI_REG8(0x372c), 0xbc },
169 {0x376b, 0x20}, {0x376c, 0x00}, {0x376d, 0x00},202 { CCI_REG8(0x372e), 0x52 },
170 {0x376e, 0x00}, {0x3773, 0x00}, {0x3774, 0x51},203 { CCI_REG8(0x373c), 0x0e },
171 {0x3776, 0xbd}, {0x3777, 0xbd}, {0x3781, 0x18},204 { CCI_REG8(0x373e), 0x33 },
172 {0x3783, 0x25}, {0x3798, 0x1b}, {0x3800, 0x00},205 { CCI_REG8(0x3743), 0x10 },
173 {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x04},206 { CCI_REG8(0x3744), 0x88 },
174 {0x3804, 0x0a}, {0x3805, 0x97}, {0x3806, 0x05},207 { CCI_REG8(0x3745), 0xc0 },
175 {0x3807, 0xfb}, {0x3808, 0x0a}, {0x3809, 0x80},208 { CCI_REG8(0x374c), 0x00 },
176 {0x380a, 0x05}, {0x380b, 0xf0}, {0x380c, 0x0a},209 { CCI_REG8(0x374e), 0x23 },
177 {0x380d, 0x0e}, {0x380e, 0x06}, {0x380f, 0x12},210 { CCI_REG8(0x3751), 0x7b },
178 {0x3810, 0x00}, {0x3811, 0x08}, {0x3812, 0x00},211 { CCI_REG8(0x3753), 0xbd },
179 {0x3813, 0x04}, {0x3814, 0x01}, {0x3815, 0x01},212 { CCI_REG8(0x3754), 0xbc },
180 {0x3819, 0x01}, {0x3820, 0x00}, {0x3821, 0x06},213 { CCI_REG8(0x3756), 0x52 },
181 {0x3829, 0x00}, {0x382a, 0x01}, {0x382b, 0x01},214 { CCI_REG8(0x376b), 0x20 },
182 {0x382d, 0x7f}, {0x3830, 0x04}, {0x3836, 0x01},215 { CCI_REG8(0x3774), 0x51 },
183 {0x3837, 0x00}, {0x3841, 0x02}, {0x3846, 0x08},216 { CCI_REG8(0x3776), 0xbd },
184 {0x3847, 0x07}, {0x3d85, 0x36}, {0x3d8c, 0x71},217 { CCI_REG8(0x3777), 0xbd },
185 {0x3d8d, 0xcb}, {0x3f0a, 0x00}, {0x4000, 0xf1},218 { CCI_REG8(0x3781), 0x18 },
186 {0x4001, 0x40}, {0x4002, 0x04}, {0x4003, 0x14},219 { CCI_REG8(0x3783), 0x25 },
187 {0x400e, 0x00}, {0x4011, 0x00}, {0x401a, 0x00},220 { CCI_REG8(0x3798), 0x1b },
188 {0x401b, 0x00}, {0x401c, 0x00}, {0x401d, 0x00},221
189 {0x401f, 0x00}, {0x4020, 0x00}, {0x4021, 0x10},222 /* Timing control */
190 {0x4022, 0x07}, {0x4023, 0xcf}, {0x4024, 0x09},223 { CCI_REG8(0x3819), 0x01 }, /* VSYNC_END_L vsync_end_point[7:0] = 0x01 */
191 {0x4025, 0x60}, {0x4026, 0x09}, {0x4027, 0x6f},224
192 {0x4028, 0x00}, {0x4029, 0x02}, {0x402a, 0x06},225 /* OTP control */
193 {0x402b, 0x04}, {0x402c, 0x02}, {0x402d, 0x02},226 { CCI_REG8(0x3d85), 0x36 }, /* OTP_REG85 OTP_power_up_load_setting_enable = 1,
194 {0x402e, 0x0e}, {0x402f, 0x04}, {0x4302, 0xff},227 * OTP_power_up_load_data_enable = 1,
195 {0x4303, 0xff}, {0x4304, 0x00}, {0x4305, 0x00},228 * OTP_bist_select = 1 (compare with zero)
196 {0x4306, 0x00}, {0x4308, 0x02}, {0x4500, 0x6c},229 */
197 {0x4501, 0xc4}, {0x4502, 0x40}, {0x4503, 0x01},230 { CCI_REG8(0x3d8c), 0x71 }, /* OTP_SETTING_STT_ADDRESS_H */
198 {0x4601, 0xa7}, {0x4800, 0x04}, {0x4813, 0x08},231 { CCI_REG8(0x3d8d), 0xcb }, /* OTP_SETTING_STT_ADDRESS_L */
199 {0x481f, 0x40}, {0x4829, 0x78}, {0x4837, 0x10},232
200 {0x4b00, 0x2a}, {0x4b0d, 0x00}, {0x4d00, 0x04},233 /* BLC registers*/
201 {0x4d01, 0x42}, {0x4d02, 0xd1}, {0x4d03, 0x93},234 { CCI_REG8(0x4001), 0x40 }, /* DEBUG_MODE */
202 {0x4d04, 0xf5}, {0x4d05, 0xc1}, {0x5000, 0xf3},235 { CCI_REG8(0x401b), 0x00 }, /* DEBUG_MODE */
203 {0x5001, 0x11}, {0x5004, 0x00}, {0x500a, 0x00},236 { CCI_REG8(0x401d), 0x00 }, /* DEBUG_MODE */
204 {0x500b, 0x00}, {0x5032, 0x00}, {0x5040, 0x00},237 { CCI_REG8(0x401f), 0x00 }, /* DEBUG_MODE */
205 {0x5050, 0x0c}, {0x5500, 0x00}, {0x5501, 0x10},238
206 {0x5502, 0x01}, {0x5503, 0x0f}, {0x8000, 0x00},239 /* ADC sync control */
207 {0x8001, 0x00}, {0x8002, 0x00}, {0x8003, 0x00},240 { CCI_REG8(0x4500), 0x6c }, /* ADC_SYNC_CTRL */
208 {0x8004, 0x00}, {0x8005, 0x00}, {0x8006, 0x00},241 { CCI_REG8(0x4503), 0x01 }, /* ADC_SYNC_CTRL */
209 {0x8007, 0x00}, {0x8008, 0x00}, {0x3638, 0x00},242
210 {REG_NULL, 0x00},243 /* Temperature monitor */
244 { CCI_REG8(0x4d00), 0x04 }, /* TPM_CTRL_00 tmp_slope[15:8] = 0x04 */
245 { CCI_REG8(0x4d01), 0x42 }, /* TPM_CTRL_01 tmp_slope[7:0] = 0x42 */
246 { CCI_REG8(0x4d02), 0xd1 }, /* TPM_CTRL_02 tpm_offset[31:24] = 0xd1 */
247 { CCI_REG8(0x4d03), 0x93 }, /* TPM_CTRL_03 tpm_offset[23:16] = 0x93 */
248 { CCI_REG8(0x4d04), 0xf5 }, /* TPM_CTRL_04 tpm_offset[15:8] = 0xf5 */
249 { CCI_REG8(0x4d05), 0xc1 }, /* TPM_CTRL_05 tpm_offset[7:0] = 0xc1 */
250
251 /* pre-ISP control */
252 { CCI_REG8(0x5050), 0x0c }, /* DEBUG_MODE */
253
254 /* OTP-DPC control */
255 { CCI_REG8(0x5501), 0x10 }, /* OTP_DPC_START_L otp_start_address[7:0] = 0x10 */
256 { CCI_REG8(0x5503), 0x0f }, /* OTP_DPC_END_L otp_end_address[7:0] = 0x0f */
211};257};
212 258
213static const struct ov4689_mode supported_modes[] = {259static const struct ov4689_mode supported_modes[] = {
@@ -215,16 +261,13 @@ static const struct ov4689_mode supported_modes[] = { · 1 unmodified line
215 .id = OV4689_MODE_2688_1520,261 .id = OV4689_MODE_2688_1520,
216 .width = 2688,262 .width = 2688,
217 .height = 1520,263 .height = 1520,
218 .sensor_width = 2720,
219 .sensor_height = 1536,
220 .crop_top = 8,
221 .crop_left = 16,
222 .max_fps = 30,
223 .exp_def = 1536,264 .exp_def = 1536,
224 .hts_def = 4 * 2574,265 .hts_def = 10296,
266 .hts_min = 3432,
225 .vts_def = 1554,267 .vts_def = 1554,
226 .pixel_rate = 480000000,268 .pixel_rate = 480000000,
227 .reg_list = ov4689_2688x1520_regs,269 .reg_list = ov4689_2688x1520_regs,
270 .num_regs = ARRAY_SIZE(ov4689_2688x1520_regs),
228 },271 },
229};272};
230 273
@@ -277,83 +320,6 @@ static const struct ov4689_gain_range ov4689_gain_ranges[] = { · 46 unmodified lines
277 },320 },
278};321};
279 322
280/* Write registers up to 4 at a time */
281static int ov4689_write_reg(struct i2c_client *client, u16 reg, u32 len,
282 u32 val)
283{
284 u32 buf_i, val_i;
285 __be32 val_be;
286 u8 *val_p;
287 u8 buf[6];
288
289 if (len > 4)
290 return -EINVAL;
291
292 buf[0] = reg >> 8;
293 buf[1] = reg & 0xff;
294
295 val_be = cpu_to_be32(val);
296 val_p = (u8 *)&val_be;
297 buf_i = 2;
298 val_i = 4 - len;
299
300 while (val_i < 4)
301 buf[buf_i++] = val_p[val_i++];
302
303 if (i2c_master_send(client, buf, len + 2) != len + 2)
304 return -EIO;
305
306 return 0;
307}
308
309static int ov4689_write_array(struct i2c_client *client,
310 const struct regval *regs)
311{
312 int ret = 0;
313 u32 i;
314
315 for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
316 ret = ov4689_write_reg(client, regs[i].addr,
317 OV4689_REG_VALUE_08BIT, regs[i].val);
318
319 return ret;
320}
321
322/* Read registers up to 4 at a time */
323static int ov4689_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
324 u32 *val)
325{
326 __be16 reg_addr_be = cpu_to_be16(reg);
327 struct i2c_msg msgs[2];
328 __be32 data_be = 0;
329 u8 *data_be_p;
330 int ret;
331
332 if (len > 4 || !len)
333 return -EINVAL;
334
335 data_be_p = (u8 *)&data_be;
336 /* Write register address */
337 msgs[0].addr = client->addr;
338 msgs[0].flags = 0;
339 msgs[0].len = 2;
340 msgs[0].buf = (u8 *)&reg_addr_be;
341
342 /* Read data from register */
343 msgs[1].addr = client->addr;
344 msgs[1].flags = I2C_M_RD;
345 msgs[1].len = len;
346 msgs[1].buf = &data_be_p[4 - len];
347
348 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
349 if (ret != ARRAY_SIZE(msgs))
350 return -EIO;
351
352 *val = be32_to_cpu(data_be);
353
354 return 0;
355}
356
357static void ov4689_fill_fmt(const struct ov4689_mode *mode,323static void ov4689_fill_fmt(const struct ov4689_mode *mode,
358 struct v4l2_mbus_framefmt *fmt)324 struct v4l2_mbus_framefmt *fmt)
359{325{
@@ -376,19 +342,6 @@ static int ov4689_set_fmt(struct v4l2_subdev *sd, · 16 unmodified lines
376 return 0;342 return 0;
377}343}
378 344
379static int ov4689_get_fmt(struct v4l2_subdev *sd,
380 struct v4l2_subdev_state *sd_state,
381 struct v4l2_subdev_format *fmt)
382{
383 struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
384 struct ov4689 *ov4689 = to_ov4689(sd);
385
386 /* only one mode supported for now */
387 ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt);
388
389 return 0;
390}
391
392static int ov4689_enum_mbus_code(struct v4l2_subdev *sd,345static int ov4689_enum_mbus_code(struct v4l2_subdev *sd,
393 struct v4l2_subdev_state *sd_state,346 struct v4l2_subdev_state *sd_state,
394 struct v4l2_subdev_mbus_code_enum *code)347 struct v4l2_subdev_mbus_code_enum *code)
@@ -427,16 +380,14 @@ static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern) · 32 unmodified lines
427 else380 else
428 val = OV4689_TEST_PATTERN_DISABLE;381 val = OV4689_TEST_PATTERN_DISABLE;
429 382
430 return ov4689_write_reg(ov4689->client, OV4689_REG_TEST_PATTERN,383 return cci_write(ov4689->regmap, OV4689_REG_TEST_PATTERN,
431 OV4689_REG_VALUE_08BIT, val);384 val, NULL);
432}385}
433 386
434static int ov4689_get_selection(struct v4l2_subdev *sd,387static int ov4689_get_selection(struct v4l2_subdev *sd,
435 struct v4l2_subdev_state *state,388 struct v4l2_subdev_state *state,
436 struct v4l2_subdev_selection *sel)389 struct v4l2_subdev_selection *sel)
437{390{
438 const struct ov4689_mode *mode = to_ov4689(sd)->cur_mode;
439
440 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)391 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
441 return -EINVAL;392 return -EINVAL;
442 393
@@ -444,63 +395,114 @@ static int ov4689_get_selection(struct v4l2_subdev *sd, · 1 unmodified line
444 case V4L2_SEL_TGT_CROP_BOUNDS:395 case V4L2_SEL_TGT_CROP_BOUNDS:
445 sel->r.top = 0;396 sel->r.top = 0;
446 sel->r.left = 0;397 sel->r.left = 0;
447 sel->r.width = mode->sensor_width;398 sel->r.width = OV4689_PIXEL_ARRAY_WIDTH;
448 sel->r.height = mode->sensor_height;399 sel->r.height = OV4689_PIXEL_ARRAY_HEIGHT;
449 return 0;400 return 0;
450 case V4L2_SEL_TGT_CROP:401 case V4L2_SEL_TGT_CROP:
451 case V4L2_SEL_TGT_CROP_DEFAULT:402 case V4L2_SEL_TGT_CROP_DEFAULT:
452 sel->r.top = mode->crop_top;403 sel->r.top = OV4689_DUMMY_ROWS;
453 sel->r.left = mode->crop_left;404 sel->r.left = OV4689_DUMMY_COLUMNS;
454 sel->r.width = mode->width;405 sel->r.width =
455 sel->r.height = mode->height;406 OV4689_PIXEL_ARRAY_WIDTH - 2 * OV4689_DUMMY_COLUMNS;
407 sel->r.height =
408 OV4689_PIXEL_ARRAY_HEIGHT - 2 * OV4689_DUMMY_ROWS;
456 return 0;409 return 0;
457 }410 }
458 411
459 return -EINVAL;412 return -EINVAL;
460}413}
461 414
415static int ov4689_setup_timings(struct ov4689 *ov4689)
416{
417 const struct ov4689_mode *mode = ov4689->cur_mode;
418 struct regmap *rm = ov4689->regmap;
419 int ret = 0;
420
421 cci_write(rm, OV4689_REG_H_CROP_START, 8, &ret);
422 cci_write(rm, OV4689_REG_V_CROP_START, 8, &ret);
423 cci_write(rm, OV4689_REG_H_CROP_END, 2711, &ret);
424 cci_write(rm, OV4689_REG_V_CROP_END, 1531, &ret);
425
426 cci_write(rm, OV4689_REG_H_OUTPUT_SIZE, mode->width, &ret);
427 cci_write(rm, OV4689_REG_V_OUTPUT_SIZE, mode->height, &ret);
428
429 cci_write(rm, OV4689_REG_H_WIN_OFF, 8, &ret);
430 cci_write(rm, OV4689_REG_V_WIN_OFF, 4, &ret);
431
432 cci_write(rm, OV4689_REG_VFIFO_CTRL_01, 167, &ret);
433
434 return ret;
435}
436
437static int ov4689_setup_blc_anchors(struct ov4689 *ov4689)
438{
439 struct regmap *rm = ov4689->regmap;
440 int ret = 0;
441
442 cci_write(rm, OV4689_REG_ANCHOR_LEFT_START, 16, &ret);
443 cci_write(rm, OV4689_REG_ANCHOR_LEFT_END, 1999, &ret);
444 cci_write(rm, OV4689_REG_ANCHOR_RIGHT_START, 2400, &ret);
445 cci_write(rm, OV4689_REG_ANCHOR_RIGHT_END, 2415, &ret);
446
447 return ret;
448}
449
462static int ov4689_s_stream(struct v4l2_subdev *sd, int on)450static int ov4689_s_stream(struct v4l2_subdev *sd, int on)
463{451{
464 struct ov4689 *ov4689 = to_ov4689(sd);452 struct ov4689 *ov4689 = to_ov4689(sd);
465 struct i2c_client *client = ov4689->client;453 struct v4l2_subdev_state *sd_state;
454 struct device *dev = ov4689->dev;
466 int ret = 0;455 int ret = 0;
467 456
468 mutex_lock(&ov4689->mutex);457 sd_state = v4l2_subdev_lock_and_get_active_state(&ov4689->subdev);
469 458
470 if (on) {459 if (on) {
471 ret = pm_runtime_resume_and_get(&client->dev);460 ret = pm_runtime_resume_and_get(dev);
472 if (ret < 0)461 if (ret < 0)
473 goto unlock_and_return;462 goto unlock_and_return;
474 463
475 ret = ov4689_write_array(ov4689->client,464 ret = cci_multi_reg_write(ov4689->regmap,
476 ov4689->cur_mode->reg_list);465 ov4689->cur_mode->reg_list,
466 ov4689->cur_mode->num_regs,
467 NULL);
468 if (ret) {
469 pm_runtime_put(dev);
470 goto unlock_and_return;
471 }
472
473 ret = ov4689_setup_timings(ov4689);
477 if (ret) {474 if (ret) {
478 pm_runtime_put(&client->dev);475 pm_runtime_put(dev);
476 goto unlock_and_return;
477 }
478
479 ret = ov4689_setup_blc_anchors(ov4689);
480 if (ret) {
481 pm_runtime_put(dev);
479 goto unlock_and_return;482 goto unlock_and_return;
480 }483 }
481 484
482 ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler);485 ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler);
483 if (ret) {486 if (ret) {
484 pm_runtime_put(&client->dev);487 pm_runtime_put(dev);
485 goto unlock_and_return;488 goto unlock_and_return;
486 }489 }
487 490
488 ret = ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,491 ret = cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE,
489 OV4689_REG_VALUE_08BIT,492 OV4689_MODE_STREAMING, NULL);
490 OV4689_MODE_STREAMING);
491 if (ret) {493 if (ret) {
492 pm_runtime_put(&client->dev);494 pm_runtime_put(dev);
493 goto unlock_and_return;495 goto unlock_and_return;
494 }496 }
495 } else {497 } else {
496 ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,498 cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE,
497 OV4689_REG_VALUE_08BIT,499 OV4689_MODE_SW_STANDBY, NULL);
498 OV4689_MODE_SW_STANDBY);500 pm_runtime_mark_last_busy(dev);
499 pm_runtime_put(&client->dev);501 pm_runtime_put_autosuspend(dev);
500 }502 }
501 503
502unlock_and_return:504unlock_and_return:
503 mutex_unlock(&ov4689->mutex);505 v4l2_subdev_unlock_state(sd_state);
504 506
505 return ret;507 return ret;
506}508}
@@ -563,18 +565,13 @@ static int __maybe_unused ov4689_power_off(struct device *dev) · 56 unmodified lines
563 return 0;565 return 0;
564}566}
565 567
566static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)568static int ov4689_init_state(struct v4l2_subdev *sd,
569 struct v4l2_subdev_state *sd_state)
567{570{
568 struct ov4689 *ov4689 = to_ov4689(sd);571 struct v4l2_mbus_framefmt *fmt =
569 struct v4l2_mbus_framefmt *try_fmt;572 v4l2_subdev_state_get_format(sd_state, 0);
570
571 mutex_lock(&ov4689->mutex);
572
573 try_fmt = v4l2_subdev_state_get_format(fh->state, 0);
574 /* Initialize try_fmt */
575 ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt);
576 573
577 mutex_unlock(&ov4689->mutex);574 ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], fmt);
578 575
579 return 0;576 return 0;
580}577}
@@ -583,10 +580,6 @@ static const struct dev_pm_ops ov4689_pm_ops = { · 2 unmodified lines
583 SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL)580 SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL)
584};581};
585 582
586static const struct v4l2_subdev_internal_ops ov4689_internal_ops = {
587 .open = ov4689_open,
588};
589
590static const struct v4l2_subdev_video_ops ov4689_video_ops = {583static const struct v4l2_subdev_video_ops ov4689_video_ops = {
591 .s_stream = ov4689_s_stream,584 .s_stream = ov4689_s_stream,
592};585};
@@ -594,11 +587,15 @@ static const struct v4l2_subdev_video_ops ov4689_video_ops = { · 1 unmodified line
594static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {587static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {
595 .enum_mbus_code = ov4689_enum_mbus_code,588 .enum_mbus_code = ov4689_enum_mbus_code,
596 .enum_frame_size = ov4689_enum_frame_sizes,589 .enum_frame_size = ov4689_enum_frame_sizes,
597 .get_fmt = ov4689_get_fmt,590 .get_fmt = v4l2_subdev_get_fmt,
598 .set_fmt = ov4689_set_fmt,591 .set_fmt = ov4689_set_fmt,
599 .get_selection = ov4689_get_selection,592 .get_selection = ov4689_get_selection,
600};593};
601 594
595static const struct v4l2_subdev_internal_ops ov4689_internal_ops = {
596 .init_state = ov4689_init_state,
597};
598
602static const struct v4l2_subdev_ops ov4689_subdev_ops = {599static const struct v4l2_subdev_ops ov4689_subdev_ops = {
603 .video = &ov4689_video_ops,600 .video = &ov4689_video_ops,
604 .pad = &ov4689_pad_ops,601 .pad = &ov4689_pad_ops,
@@ -610,7 +607,6 @@ static const struct v4l2_subdev_ops ov4689_subdev_ops = { · 5 unmodified lines
610 */607 */
611static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result)608static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result)
612{609{
613 const struct device *dev = &ov4689->client->dev;
614 const struct ov4689_gain_range *range;610 const struct ov4689_gain_range *range;
615 unsigned int n;611 unsigned int n;
616 612
@@ -621,7 +617,8 @@ static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result) · 4 unmodified lines
621 }617 }
622 618
623 if (n == ARRAY_SIZE(ov4689_gain_ranges)) {619 if (n == ARRAY_SIZE(ov4689_gain_ranges)) {
624 dev_warn_ratelimited(dev, "no mapping found for gain %d\n",620 dev_warn_ratelimited(ov4689->dev,
621 "no mapping found for gain %d\n",
625 logical_gain);622 logical_gain);
626 return -EINVAL;623 return -EINVAL;
627 }624 }
@@ -637,10 +634,11 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) · 9 unmodified lines
637{634{
638 struct ov4689 *ov4689 =635 struct ov4689 *ov4689 =
639 container_of(ctrl->handler, struct ov4689, ctrl_handler);636 container_of(ctrl->handler, struct ov4689, ctrl_handler);
640 struct i2c_client *client = ov4689->client;637 struct regmap *regmap = ov4689->regmap;
641 int sensor_gain;638 struct device *dev = ov4689->dev;
639 int sensor_gain = 0;
642 s64 max_expo;640 s64 max_expo;
643 int ret;641 int ret = 0;
644 642
645 /* Propagate change of current control to all related controls */643 /* Propagate change of current control to all related controls */
646 switch (ctrl->id) {644 switch (ctrl->id) {
@@ -654,44 +652,58 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) · 7 unmodified lines
654 break;652 break;
655 }653 }
656 654
657 if (!pm_runtime_get_if_in_use(&client->dev))655 if (!pm_runtime_get_if_in_use(dev))
658 return 0;656 return 0;
659 657
660 switch (ctrl->id) {658 switch (ctrl->id) {
661 case V4L2_CID_EXPOSURE:659 case V4L2_CID_EXPOSURE:
662 /* 4 least significant bits of expsoure are fractional part */660 /* 4 least significant bits of exposure are fractional part */
663 ret = ov4689_write_reg(ov4689->client, OV4689_REG_EXPOSURE,661 cci_write(regmap, OV4689_REG_EXPOSURE, ctrl->val << 4, &ret);
664 OV4689_REG_VALUE_24BIT, ctrl->val << 4);
665 break;662 break;
666 case V4L2_CID_ANALOGUE_GAIN:663 case V4L2_CID_ANALOGUE_GAIN:
667 ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain);664 ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain);
668 665 cci_write(regmap, OV4689_REG_GAIN, sensor_gain, &ret);
669 ret = ret ?:
670 ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_H,
671 OV4689_REG_VALUE_08BIT,
672 (sensor_gain >> OV4689_GAIN_H_SHIFT) &
673 OV4689_GAIN_H_MASK);
674 ret = ret ?:
675 ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_L,
676 OV4689_REG_VALUE_08BIT,
677 sensor_gain & OV4689_GAIN_L_MASK);
678 break;666 break;
679 case V4L2_CID_VBLANK:667 case V4L2_CID_VBLANK:
680 ret = ov4689_write_reg(ov4689->client, OV4689_REG_VTS,668 cci_write(regmap, OV4689_REG_VTS,
681 OV4689_REG_VALUE_16BIT,669 ctrl->val + ov4689->cur_mode->height, &ret);
682 ctrl->val + ov4689->cur_mode->height);
683 break;670 break;
684 case V4L2_CID_TEST_PATTERN:671 case V4L2_CID_TEST_PATTERN:
685 ret = ov4689_enable_test_pattern(ov4689, ctrl->val);672 ret = ov4689_enable_test_pattern(ov4689, ctrl->val);
686 break;673 break;
674 case V4L2_CID_HBLANK:
675 cci_write(regmap, OV4689_REG_HTS,
676 (ctrl->val + ov4689->cur_mode->width) /
677 OV4689_HTS_DIVIDER, &ret);
678 break;
679 case V4L2_CID_VFLIP:
680 cci_update_bits(regmap, OV4689_REG_TIMING_FORMAT1,
681 OV4689_TIMING_FLIP_MASK,
682 ctrl->val ? OV4689_TIMING_FLIP_BOTH : 0, &ret);
683 break;
684 case V4L2_CID_HFLIP:
685 cci_update_bits(regmap, OV4689_REG_TIMING_FORMAT2,
686 OV4689_TIMING_FLIP_MASK,
687 ctrl->val ? 0 : OV4689_TIMING_FLIP_BOTH, &ret);
688 break;
689 case V4L2_CID_DIGITAL_GAIN:
690 cci_write(regmap, OV4689_REG_DIG_GAIN, ctrl->val, &ret);
691 break;
692 case V4L2_CID_RED_BALANCE:
693 cci_write(regmap, OV4689_REG_WB_GAIN_RED, ctrl->val, &ret);
694 break;
695 case V4L2_CID_BLUE_BALANCE:
696 cci_write(regmap, OV4689_REG_WB_GAIN_BLUE, ctrl->val, &ret);
697 break;
687 default:698 default:
688 dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",699 dev_warn(dev, "%s Unhandled id:0x%x, val:0x%x\n",
689 __func__, ctrl->id, ctrl->val);700 __func__, ctrl->id, ctrl->val);
690 ret = -EINVAL;701 ret = -EINVAL;
691 break;702 break;
692 }703 }
693 704
694 pm_runtime_put(&client->dev);705 pm_runtime_mark_last_busy(dev);
706 pm_runtime_put_autosuspend(dev);
695 707
696 return ret;708 return ret;
697}709}
@@ -707,16 +719,15 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) · 9 unmodified lines
707 struct v4l2_ctrl_handler *handler;719 struct v4l2_ctrl_handler *handler;
708 const struct ov4689_mode *mode;720 const struct ov4689_mode *mode;
709 s64 exposure_max, vblank_def;721 s64 exposure_max, vblank_def;
722 s64 hblank_def, hblank_min;
710 struct v4l2_ctrl *ctrl;723 struct v4l2_ctrl *ctrl;
711 s64 h_blank_def;
712 int ret;724 int ret;
713 725
714 handler = &ov4689->ctrl_handler;726 handler = &ov4689->ctrl_handler;
715 mode = ov4689->cur_mode;727 mode = ov4689->cur_mode;
716 ret = v4l2_ctrl_handler_init(handler, 10);728 ret = v4l2_ctrl_handler_init(handler, 15);
717 if (ret)729 if (ret)
718 return ret;730 return ret;
719 handler->lock = &ov4689->mutex;
720 731
721 ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0,732 ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0,
722 link_freq_menu_items);733 link_freq_menu_items);
@@ -726,11 +737,11 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) · 3 unmodified lines
726 v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0,737 v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0,
727 mode->pixel_rate, 1, mode->pixel_rate);738 mode->pixel_rate, 1, mode->pixel_rate);
728 739
729 h_blank_def = mode->hts_def - mode->width;740 hblank_def = mode->hts_def - mode->width;
730 ctrl = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank_def,741 hblank_min = mode->hts_min - mode->width;
731 h_blank_def, 1, h_blank_def);742 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_HBLANK,
732 if (ctrl)743 hblank_min, OV4689_HTS_MAX - mode->width,
733 ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;744 OV4689_HTS_DIVIDER, hblank_def);
734 745
735 vblank_def = mode->vts_def - mode->height;746 vblank_def = mode->vts_def - mode->height;
736 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK,747 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK,
@@ -754,10 +765,24 @@ static int ov4689_initialize_controls(struct ov4689 *ov4689) · 17 unmodified lines
754 ARRAY_SIZE(ov4689_test_pattern_menu) - 1,765 ARRAY_SIZE(ov4689_test_pattern_menu) - 1,
755 0, 0, ov4689_test_pattern_menu);766 0, 0, ov4689_test_pattern_menu);
756 767
768 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
769 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
770
771 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
772 OV4689_DIG_GAIN_MIN, OV4689_DIG_GAIN_MAX,
773 OV4689_DIG_GAIN_STEP, OV4689_DIG_GAIN_DEFAULT);
774
775 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_RED_BALANCE,
776 OV4689_WB_GAIN_MIN, OV4689_WB_GAIN_MAX,
777 OV4689_WB_GAIN_STEP, OV4689_WB_GAIN_DEFAULT);
778
779 v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_BLUE_BALANCE,
780 OV4689_WB_GAIN_MIN, OV4689_WB_GAIN_MAX,
781 OV4689_WB_GAIN_STEP, OV4689_WB_GAIN_DEFAULT);
782
757 if (handler->error) {783 if (handler->error) {
758 ret = handler->error;784 ret = handler->error;
759 dev_err(&ov4689->client->dev, "Failed to init controls(%d)\n",785 dev_err(ov4689->dev, "Failed to init controls(%d)\n", ret);
760 ret);
761 goto err_free_handler;786 goto err_free_handler;
762 }787 }
763 788
@@ -783,19 +808,18 @@ err_free_handler: · 19 unmodified lines
783static int ov4689_check_sensor_id(struct ov4689 *ov4689,808static int ov4689_check_sensor_id(struct ov4689 *ov4689,
784 struct i2c_client *client)809 struct i2c_client *client)
785{810{
786 struct device *dev = &ov4689->client->dev;811 struct device *dev = ov4689->dev;
787 u32 id = 0;812 u64 id = 0;
788 int ret;813 int ret;
789 814
790 ret = ov4689_read_reg(client, OV4689_REG_CHIP_ID,815 ret = cci_read(ov4689->regmap, OV4689_REG_CHIP_ID, &id, NULL);
791 OV4689_REG_VALUE_16BIT, &id);
792 if (ret) {816 if (ret) {
793 dev_err(dev, "Cannot read sensor ID\n");817 dev_err(dev, "Cannot read sensor ID\n");
794 return ret;818 return ret;
795 }819 }
796 820
797 if (id != CHIP_ID) {821 if (id != CHIP_ID) {
798 dev_err(dev, "Unexpected sensor ID %06x, expected %06x\n",822 dev_err(dev, "Unexpected sensor ID %06llx, expected %06x\n",
799 id, CHIP_ID);823 id, CHIP_ID);
800 return -ENODEV;824 return -ENODEV;
801 }825 }
@@ -812,7 +836,7 @@ static int ov4689_configure_regulators(struct ov4689 *ov4689) · 10 unmodified lines
812 for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++)836 for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++)
813 ov4689->supplies[i].supply = ov4689_supply_names[i];837 ov4689->supplies[i].supply = ov4689_supply_names[i];
814 838
815 return devm_regulator_bulk_get(&ov4689->client->dev,839 return devm_regulator_bulk_get(ov4689->dev,
816 ARRAY_SIZE(ov4689_supply_names),840 ARRAY_SIZE(ov4689_supply_names),
817 ov4689->supplies);841 ov4689->supplies);
818}842}
@@ -881,7 +905,8 @@ static int ov4689_probe(struct i2c_client *client) · 62 unmodified lines
881 if (!ov4689)905 if (!ov4689)
882 return -ENOMEM;906 return -ENOMEM;
883 907
884 ov4689->client = client;908 ov4689->dev = dev;
909
885 ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520];910 ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520];
886 911
887 ov4689->xvclk = devm_clk_get_optional(dev, NULL);912 ov4689->xvclk = devm_clk_get_optional(dev, NULL);
@@ -905,6 +930,13 @@ static int ov4689_probe(struct i2c_client *client) · 17 unmodified lines
905 return -EINVAL;930 return -EINVAL;
906 }931 }
907 932
933 ov4689->regmap = devm_cci_regmap_init_i2c(client, 16);
934 if (IS_ERR(ov4689->regmap)) {
935 ret = PTR_ERR(ov4689->regmap);
936 dev_err(dev, "failed to initialize CCI: %d\n", ret);
937 return ret;
938 }
939
908 ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset",940 ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset",
909 GPIOD_OUT_LOW);941 GPIOD_OUT_LOW);
910 if (IS_ERR(ov4689->reset_gpio)) {942 if (IS_ERR(ov4689->reset_gpio)) {
@@ -923,13 +955,15 @@ static int ov4689_probe(struct i2c_client *client) · 12 unmodified lines
923 return dev_err_probe(dev, ret,955 return dev_err_probe(dev, ret,
924 "Failed to get power regulators\n");956 "Failed to get power regulators\n");
925 957
926 mutex_init(&ov4689->mutex);
927
928 sd = &ov4689->subdev;958 sd = &ov4689->subdev;
929 v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops);959 v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops);
960 sd->internal_ops = &ov4689_internal_ops;
961 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
930 ret = ov4689_initialize_controls(ov4689);962 ret = ov4689_initialize_controls(ov4689);
931 if (ret)963 if (ret) {
932 goto err_destroy_mutex;964 dev_err(dev, "Failed to initialize controls\n");
965 return ret;
966 }
933 967
934 ret = ov4689_power_on(dev);968 ret = ov4689_power_on(dev);
935 if (ret)969 if (ret)
@@ -939,35 +973,47 @@ static int ov4689_probe(struct i2c_client *client) · 3 unmodified lines
939 if (ret)973 if (ret)
940 goto err_power_off;974 goto err_power_off;
941 975
942 sd->internal_ops = &ov4689_internal_ops;
943 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
944 976
945 ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;
946 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;977 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
978 ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;
947 ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad);979 ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad);
948 if (ret < 0)980 if (ret < 0)
949 goto err_power_off;981 goto err_power_off;
950 982
951 ret = v4l2_async_register_subdev_sensor(sd);983 sd->state_lock = ov4689->ctrl_handler.lock;
984 ret = v4l2_subdev_init_finalize(sd);
952 if (ret) {985 if (ret) {
953 dev_err(dev, "v4l2 async register subdev failed\n");986 dev_err(dev, "Could not register v4l2 device\n");
954 goto err_clean_entity;987 goto err_clean_entity;
955 }988 }
956 989
957 pm_runtime_set_active(dev);990 pm_runtime_set_active(dev);
991 pm_runtime_get_noresume(dev);
958 pm_runtime_enable(dev);992 pm_runtime_enable(dev);
959 pm_runtime_idle(dev);993 pm_runtime_set_autosuspend_delay(dev, 1000);
994 pm_runtime_use_autosuspend(dev);
995
996 ret = v4l2_async_register_subdev_sensor(sd);
997 if (ret) {
998 dev_err(dev, "v4l2 async register subdev failed\n");
999 goto err_clean_subdev_pm;
1000 }
1001
1002 pm_runtime_mark_last_busy(dev);
1003 pm_runtime_put_autosuspend(dev);
960 1004
961 return 0;1005 return 0;
962 1006
1007err_clean_subdev_pm:
1008 pm_runtime_disable(dev);
1009 pm_runtime_put_noidle(dev);
1010 v4l2_subdev_cleanup(sd);
963err_clean_entity:1011err_clean_entity:
964 media_entity_cleanup(&sd->entity);1012 media_entity_cleanup(&sd->entity);
965err_power_off:1013err_power_off:
966 ov4689_power_off(dev);1014 ov4689_power_off(dev);
967err_free_handler:1015err_free_handler:
968 v4l2_ctrl_handler_free(&ov4689->ctrl_handler);1016 v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
969err_destroy_mutex:
970 mutex_destroy(&ov4689->mutex);
971 1017
972 return ret;1018 return ret;
973}1019}
@@ -979,9 +1025,8 @@ static void ov4689_remove(struct i2c_client *client) · 5 unmodified lines
979 1025
980 v4l2_async_unregister_subdev(sd);1026 v4l2_async_unregister_subdev(sd);
981 media_entity_cleanup(&sd->entity);1027 media_entity_cleanup(&sd->entity);
982 1028 v4l2_subdev_cleanup(sd);
983 v4l2_ctrl_handler_free(&ov4689->ctrl_handler);1029 v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
984 mutex_destroy(&ov4689->mutex);
985 1030
986 pm_runtime_disable(&client->dev);1031 pm_runtime_disable(&client->dev);
987 if (!pm_runtime_status_suspended(&client->dev))1032 if (!pm_runtime_status_suspended(&client->dev))
drivers/media/i2c/rdacm20.c+2−2
@@ -463,8 +463,8 @@ static int rdacm20_initialize(struct rdacm20_device *dev) · 462 unmodified lines
463 return ret;463 return ret;
464 464
465 /*465 /*
466 * Ensure that we have a good link configuration before attempting to466 * Ensure that we have a good link configuration before attempting to
467 * identify the device.467 * identify the device.
468 */468 */
469 ret = max9271_configure_i2c(&dev->serializer,469 ret = max9271_configure_i2c(&dev->serializer,
470 MAX9271_I2CSLVSH_469NS_234NS |470 MAX9271_I2CSLVSH_469NS_234NS |
drivers/media/i2c/st-mipid02.c+1−1
@@ -326,7 +326,7 @@ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge, · 325 unmodified lines
326 }326 }
327 327
328 dev_dbg(&client->dev, "detect link_freq = %lld Hz", link_freq);328 dev_dbg(&client->dev, "detect link_freq = %lld Hz", link_freq);
329 do_div(ui_4, link_freq);329 ui_4 = div64_u64(ui_4, link_freq);
330 bridge->r.clk_lane_reg1 |= ui_4 << 2;330 bridge->r.clk_lane_reg1 |= ui_4 << 2;
331 331
332 return 0;332 return 0;
drivers/media/i2c/tc358743.c+17−8
@@ -1521,11 +1521,14 @@ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) · 1520 unmodified lines
1521 return 0;1521 return 0;
1522}1522}
1523 1523
1524static int tc358743_s_dv_timings(struct v4l2_subdev *sd,1524static int tc358743_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1525 struct v4l2_dv_timings *timings)1525 struct v4l2_dv_timings *timings)
1526{1526{
1527 struct tc358743_state *state = to_state(sd);1527 struct tc358743_state *state = to_state(sd);
1528 1528
1529 if (pad != 0)
1530 return -EINVAL;
1531
1529 if (!timings)1532 if (!timings)
1530 return -EINVAL;1533 return -EINVAL;
1531 1534
@@ -1553,11 +1556,14 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd, · 21 unmodified lines
1553 return 0;1556 return 0;
1554}1557}
1555 1558
1556static int tc358743_g_dv_timings(struct v4l2_subdev *sd,1559static int tc358743_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1557 struct v4l2_dv_timings *timings)1560 struct v4l2_dv_timings *timings)
1558{1561{
1559 struct tc358743_state *state = to_state(sd);1562 struct tc358743_state *state = to_state(sd);
1560 1563
1564 if (pad != 0)
1565 return -EINVAL;
1566
1561 *timings = state->timings;1567 *timings = state->timings;
1562 1568
1563 return 0;1569 return 0;
@@ -1573,11 +1579,14 @@ static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, · 9 unmodified lines
1573 &tc358743_timings_cap, NULL, NULL);1579 &tc358743_timings_cap, NULL, NULL);
1574}1580}
1575 1581
1576static int tc358743_query_dv_timings(struct v4l2_subdev *sd,1582static int tc358743_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1577 struct v4l2_dv_timings *timings)1583 struct v4l2_dv_timings *timings)
1578{1584{
1579 int ret;1585 int ret;
1580 1586
1587 if (pad != 0)
1588 return -EINVAL;
1589
1581 ret = tc358743_get_detected_timings(sd, timings);1590 ret = tc358743_get_detected_timings(sd, timings);
1582 if (ret)1591 if (ret)
1583 return ret;1592 return ret;
@@ -1822,9 +1831,6 @@ static const struct v4l2_subdev_core_ops tc358743_core_ops = { · 238 unmodified lines
1822 1831
1823static const struct v4l2_subdev_video_ops tc358743_video_ops = {1832static const struct v4l2_subdev_video_ops tc358743_video_ops = {
1824 .g_input_status = tc358743_g_input_status,1833 .g_input_status = tc358743_g_input_status,
1825 .s_dv_timings = tc358743_s_dv_timings,
1826 .g_dv_timings = tc358743_g_dv_timings,
1827 .query_dv_timings = tc358743_query_dv_timings,
1828 .s_stream = tc358743_s_stream,1834 .s_stream = tc358743_s_stream,
1829};1835};
1830 1836
@@ -1834,6 +1840,9 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { · 3 unmodified lines
1834 .get_fmt = tc358743_get_fmt,1840 .get_fmt = tc358743_get_fmt,
1835 .get_edid = tc358743_g_edid,1841 .get_edid = tc358743_g_edid,
1836 .set_edid = tc358743_s_edid,1842 .set_edid = tc358743_s_edid,
1843 .s_dv_timings = tc358743_s_dv_timings,
1844 .g_dv_timings = tc358743_g_dv_timings,
1845 .query_dv_timings = tc358743_query_dv_timings,
1837 .enum_dv_timings = tc358743_enum_dv_timings,1846 .enum_dv_timings = tc358743_enum_dv_timings,
1838 .dv_timings_cap = tc358743_dv_timings_cap,1847 .dv_timings_cap = tc358743_dv_timings_cap,
1839 .get_mbus_config = tc358743_get_mbus_config,1848 .get_mbus_config = tc358743_get_mbus_config,
@@ -2110,7 +2119,7 @@ static int tc358743_probe(struct i2c_client *client) · 270 unmodified lines
2110 2119
2111 tc358743_initial_setup(sd);2120 tc358743_initial_setup(sd);
2112 2121
2113 tc358743_s_dv_timings(sd, &default_timing);2122 tc358743_s_dv_timings(sd, 0, &default_timing);
2114 2123
2115 tc358743_set_csi_color_space(sd);2124 tc358743_set_csi_color_space(sd);
2116 2125
drivers/media/i2c/tc358746.c+1−2
@@ -844,8 +844,7 @@ static unsigned long tc358746_find_pll_settings(struct tc358746 *tc358746, · 843 unmodified lines
844 continue;844 continue;
845 845
846 tmp = fout * postdiv;846 tmp = fout * postdiv;
847 do_div(tmp, fin);847 mul = div64_ul(tmp, fin);
848 mul = tmp;
849 if (mul > 511)848 if (mul > 511)
850 continue;849 continue;
851 850
drivers/media/i2c/tda1997x.c+7−7
@@ -1669,8 +1669,8 @@ tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status) · 1668 unmodified lines
1669 return 0;1669 return 0;
1670};1670};
1671 1671
1672static int tda1997x_s_dv_timings(struct v4l2_subdev *sd,1672static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1673 struct v4l2_dv_timings *timings)1673 struct v4l2_dv_timings *timings)
1674{1674{
1675 struct tda1997x_state *state = to_state(sd);1675 struct tda1997x_state *state = to_state(sd);
1676 1676
@@ -1694,7 +1694,7 @@ static int tda1997x_s_dv_timings(struct v4l2_subdev *sd, · 17 unmodified lines
1694 return 0;1694 return 0;
1695}1695}
1696 1696
1697static int tda1997x_g_dv_timings(struct v4l2_subdev *sd,1697static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1698 struct v4l2_dv_timings *timings)1698 struct v4l2_dv_timings *timings)
1699{1699{
1700 struct tda1997x_state *state = to_state(sd);1700 struct tda1997x_state *state = to_state(sd);
@@ -1707,7 +1707,7 @@ static int tda1997x_g_dv_timings(struct v4l2_subdev *sd, · 6 unmodified lines
1707 return 0;1707 return 0;
1708}1708}
1709 1709
1710static int tda1997x_query_dv_timings(struct v4l2_subdev *sd,1710static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1711 struct v4l2_dv_timings *timings)1711 struct v4l2_dv_timings *timings)
1712{1712{
1713 struct tda1997x_state *state = to_state(sd);1713 struct tda1997x_state *state = to_state(sd);
@@ -1724,9 +1724,6 @@ static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, · 10 unmodified lines
1724 1724
1725static const struct v4l2_subdev_video_ops tda1997x_video_ops = {1725static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
1726 .g_input_status = tda1997x_g_input_status,1726 .g_input_status = tda1997x_g_input_status,
1727 .s_dv_timings = tda1997x_s_dv_timings,
1728 .g_dv_timings = tda1997x_g_dv_timings,
1729 .query_dv_timings = tda1997x_query_dv_timings,
1730};1727};
1731 1728
1732 1729
@@ -1930,6 +1927,9 @@ static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = { · 197 unmodified lines
1930 .set_fmt = tda1997x_set_format,1927 .set_fmt = tda1997x_set_format,
1931 .get_edid = tda1997x_get_edid,1928 .get_edid = tda1997x_get_edid,
1932 .set_edid = tda1997x_set_edid,1929 .set_edid = tda1997x_set_edid,
1930 .s_dv_timings = tda1997x_s_dv_timings,
1931 .g_dv_timings = tda1997x_g_dv_timings,
1932 .query_dv_timings = tda1997x_query_dv_timings,
1933 .dv_timings_cap = tda1997x_get_dv_timings_cap,1933 .dv_timings_cap = tda1997x_get_dv_timings_cap,
1934 .enum_dv_timings = tda1997x_enum_dv_timings,1934 .enum_dv_timings = tda1997x_enum_dv_timings,
1935};1935};
drivers/media/i2c/ths7303.c+7−3
@@ -193,8 +193,8 @@ static int ths7303_s_stream(struct v4l2_subdev *sd, int enable) · 192 unmodified lines
193}193}
194 194
195/* for setting filter for HD output */195/* for setting filter for HD output */
196static int ths7303_s_dv_timings(struct v4l2_subdev *sd,196static int ths7303_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
197 struct v4l2_dv_timings *dv_timings)197 struct v4l2_dv_timings *dv_timings)
198{198{
199 struct ths7303_state *state = to_state(sd);199 struct ths7303_state *state = to_state(sd);
200 200
@@ -210,7 +210,6 @@ static int ths7303_s_dv_timings(struct v4l2_subdev *sd, · 9 unmodified lines
210static const struct v4l2_subdev_video_ops ths7303_video_ops = {210static const struct v4l2_subdev_video_ops ths7303_video_ops = {
211 .s_stream = ths7303_s_stream,211 .s_stream = ths7303_s_stream,
212 .s_std_output = ths7303_s_std_output,212 .s_std_output = ths7303_s_std_output,
213 .s_dv_timings = ths7303_s_dv_timings,
214};213};
215 214
216#ifdef CONFIG_VIDEO_ADV_DEBUG215#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -317,9 +316,14 @@ static const struct v4l2_subdev_core_ops ths7303_core_ops = { · 100 unmodified lines
317#endif316#endif
318};317};
319 318
319static const struct v4l2_subdev_pad_ops ths7303_pad_ops = {
320 .s_dv_timings = ths7303_s_dv_timings,
321};
322
320static const struct v4l2_subdev_ops ths7303_ops = {323static const struct v4l2_subdev_ops ths7303_ops = {
321 .core = &ths7303_core_ops,324 .core = &ths7303_core_ops,
322 .video = &ths7303_video_ops,325 .video = &ths7303_video_ops,
326 .pad = &ths7303_pad_ops,
323};327};
324 328
325static int ths7303_probe(struct i2c_client *client)329static int ths7303_probe(struct i2c_client *client)
drivers/media/i2c/ths8200.c+10−4
@@ -358,13 +358,16 @@ static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt) · 357 unmodified lines
358 bt->hsync, bt->vsync);358 bt->hsync, bt->vsync);
359}359}
360 360
361static int ths8200_s_dv_timings(struct v4l2_subdev *sd,361static int ths8200_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
362 struct v4l2_dv_timings *timings)362 struct v4l2_dv_timings *timings)
363{363{
364 struct ths8200_state *state = to_state(sd);364 struct ths8200_state *state = to_state(sd);
365 365
366 v4l2_dbg(1, debug, sd, "%s:\n", __func__);366 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
367 367
368 if (pad != 0)
369 return -EINVAL;
370
368 if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap,371 if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap,
369 NULL, NULL))372 NULL, NULL))
370 return -EINVAL;373 return -EINVAL;
@@ -385,13 +388,16 @@ static int ths8200_s_dv_timings(struct v4l2_subdev *sd, · 14 unmodified lines
385 return 0;388 return 0;
386}389}
387 390
388static int ths8200_g_dv_timings(struct v4l2_subdev *sd,391static int ths8200_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
389 struct v4l2_dv_timings *timings)392 struct v4l2_dv_timings *timings)
390{393{
391 struct ths8200_state *state = to_state(sd);394 struct ths8200_state *state = to_state(sd);
392 395
393 v4l2_dbg(1, debug, sd, "%s:\n", __func__);396 v4l2_dbg(1, debug, sd, "%s:\n", __func__);
394 397
398 if (pad != 0)
399 return -EINVAL;
400
395 *timings = state->dv_timings;401 *timings = state->dv_timings;
396 402
397 return 0;403 return 0;
@@ -420,11 +426,11 @@ static int ths8200_dv_timings_cap(struct v4l2_subdev *sd, · 22 unmodified lines
420/* Specific video subsystem operation handlers */426/* Specific video subsystem operation handlers */
421static const struct v4l2_subdev_video_ops ths8200_video_ops = {427static const struct v4l2_subdev_video_ops ths8200_video_ops = {
422 .s_stream = ths8200_s_stream,428 .s_stream = ths8200_s_stream,
423 .s_dv_timings = ths8200_s_dv_timings,
424 .g_dv_timings = ths8200_g_dv_timings,
425};429};
426 430
427static const struct v4l2_subdev_pad_ops ths8200_pad_ops = {431static const struct v4l2_subdev_pad_ops ths8200_pad_ops = {
432 .s_dv_timings = ths8200_s_dv_timings,
433 .g_dv_timings = ths8200_g_dv_timings,
428 .enum_dv_timings = ths8200_enum_dv_timings,434 .enum_dv_timings = ths8200_enum_dv_timings,
429 .dv_timings_cap = ths8200_dv_timings_cap,435 .dv_timings_cap = ths8200_dv_timings_cap,
430};436};
drivers/media/i2c/tvp7002.c+21−11
@@ -546,13 +546,16 @@ static int tvp7002_write_inittab(struct v4l2_subdev *sd, · 545 unmodified lines
546 return error;546 return error;
547}547}
548 548
549static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,549static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
550 struct v4l2_dv_timings *dv_timings)550 struct v4l2_dv_timings *dv_timings)
551{551{
552 struct tvp7002 *device = to_tvp7002(sd);552 struct tvp7002 *device = to_tvp7002(sd);
553 const struct v4l2_bt_timings *bt = &dv_timings->bt;553 const struct v4l2_bt_timings *bt = &dv_timings->bt;
554 int i;554 int i;
555 555
556 if (pad != 0)
557 return -EINVAL;
558
556 if (dv_timings->type != V4L2_DV_BT_656_1120)559 if (dv_timings->type != V4L2_DV_BT_656_1120)
557 return -EINVAL;560 return -EINVAL;
558 for (i = 0; i < NUM_TIMINGS; i++) {561 for (i = 0; i < NUM_TIMINGS; i++) {
@@ -566,11 +569,14 @@ static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, · 7 unmodified lines
566 return -EINVAL;569 return -EINVAL;
567}570}
568 571
569static int tvp7002_g_dv_timings(struct v4l2_subdev *sd,572static int tvp7002_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
570 struct v4l2_dv_timings *dv_timings)573 struct v4l2_dv_timings *dv_timings)
571{574{
572 struct tvp7002 *device = to_tvp7002(sd);575 struct tvp7002 *device = to_tvp7002(sd);
573 576
577 if (pad != 0)
578 return -EINVAL;
579
574 *dv_timings = device->current_timings->timings;580 *dv_timings = device->current_timings->timings;
575 return 0;581 return 0;
576}582}
@@ -659,12 +665,16 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) · 82 unmodified lines
659 return 0;665 return 0;
660}666}
661 667
662static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,668static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
663 struct v4l2_dv_timings *timings)669 struct v4l2_dv_timings *timings)
664{670{
665 int index;671 int index;
666 int err = tvp7002_query_dv(sd, &index);672 int err;
673
674 if (pad != 0)
675 return -EINVAL;
667 676
677 err = tvp7002_query_dv(sd, &index);
668 if (err)678 if (err)
669 return err;679 return err;
670 *timings = tvp7002_timings[index].timings;680 *timings = tvp7002_timings[index].timings;
@@ -861,9 +871,6 @@ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { · 190 unmodified lines
861 871
862/* Specific video subsystem operation handlers */872/* Specific video subsystem operation handlers */
863static const struct v4l2_subdev_video_ops tvp7002_video_ops = {873static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
864 .g_dv_timings = tvp7002_g_dv_timings,
865 .s_dv_timings = tvp7002_s_dv_timings,
866 .query_dv_timings = tvp7002_query_dv_timings,
867 .s_stream = tvp7002_s_stream,874 .s_stream = tvp7002_s_stream,
868};875};
869 876
@@ -872,6 +879,9 @@ static const struct v4l2_subdev_pad_ops tvp7002_pad_ops = { · 2 unmodified lines
872 .enum_mbus_code = tvp7002_enum_mbus_code,879 .enum_mbus_code = tvp7002_enum_mbus_code,
873 .get_fmt = tvp7002_get_pad_format,880 .get_fmt = tvp7002_get_pad_format,
874 .set_fmt = tvp7002_set_pad_format,881 .set_fmt = tvp7002_set_pad_format,
882 .g_dv_timings = tvp7002_g_dv_timings,
883 .s_dv_timings = tvp7002_s_dv_timings,
884 .query_dv_timings = tvp7002_query_dv_timings,
875 .enum_dv_timings = tvp7002_enum_dv_timings,885 .enum_dv_timings = tvp7002_enum_dv_timings,
876};886};
877 887
@@ -1001,7 +1011,7 @@ static int tvp7002_probe(struct i2c_client *c) · 123 unmodified lines
1001 1011
1002 /* Set registers according to default video mode */1012 /* Set registers according to default video mode */
1003 timings = device->current_timings->timings;1013 timings = device->current_timings->timings;
1004 error = tvp7002_s_dv_timings(sd, &timings);1014 error = tvp7002_s_dv_timings(sd, 0, &timings);
1005 1015
1006#if defined(CONFIG_MEDIA_CONTROLLER)1016#if defined(CONFIG_MEDIA_CONTROLLER)
1007 device->pad.flags = MEDIA_PAD_FL_SOURCE;1017 device->pad.flags = MEDIA_PAD_FL_SOURCE;
drivers/media/mc/mc-devnode.c+2−3
@@ -245,15 +245,14 @@ int __must_check media_devnode_register(struct media_device *mdev, · 244 unmodified lines
245 kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor);245 kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor);
246 246
247 /* Part 3: Add the media and char device */247 /* Part 3: Add the media and char device */
248 set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
248 ret = cdev_device_add(&devnode->cdev, &devnode->dev);249 ret = cdev_device_add(&devnode->cdev, &devnode->dev);
249 if (ret < 0) {250 if (ret < 0) {
251 clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
250 pr_err("%s: cdev_device_add failed\n", __func__);252 pr_err("%s: cdev_device_add failed\n", __func__);
251 goto cdev_add_error;253 goto cdev_add_error;
252 }254 }
253 255
254 /* Part 4: Activate this minor. The char device can now be used. */
255 set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
256
257 return 0;256 return 0;
258 257
259cdev_add_error:258cdev_add_error:
drivers/media/mc/mc-entity.c+6−0
@@ -619,6 +619,12 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe, · 618 unmodified lines
619 link = list_entry(entry->links, typeof(*link), list);619 link = list_entry(entry->links, typeof(*link), list);
620 last_link = media_pipeline_walk_pop(walk);620 last_link = media_pipeline_walk_pop(walk);
621 621
622 if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
623 dev_dbg(walk->mdev->dev,
624 "media pipeline: skipping link (not data-link)\n");
625 return 0;
626 }
627
622 dev_dbg(walk->mdev->dev,628 dev_dbg(walk->mdev->dev,
623 "media pipeline: exploring link '%s':%u -> '%s':%u\n",629 "media pipeline: exploring link '%s':%u -> '%s':%u\n",
624 link->source->entity->name, link->source->index,630 link->source->entity->name, link->source->index,
drivers/media/mmc/siano/smssdio.c+1−24
@@ -344,30 +344,7 @@ static struct sdio_driver smssdio_driver = { · 343 unmodified lines
344 .probe = smssdio_probe,344 .probe = smssdio_probe,
345 .remove = smssdio_remove,345 .remove = smssdio_remove,
346};346};
347 347module_sdio_driver(smssdio_driver);
348/*******************************************************************/
349/* Module functions */
350/*******************************************************************/
351
352static int __init smssdio_module_init(void)
353{
354 int ret = 0;
355
356 printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
357 printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
358
359 ret = sdio_register_driver(&smssdio_driver);
360
361 return ret;
362}
363
364static void __exit smssdio_module_exit(void)
365{
366 sdio_unregister_driver(&smssdio_driver);
367}
368
369module_init(smssdio_module_init);
370module_exit(smssdio_module_exit);
371 348
372MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");349MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
373MODULE_AUTHOR("Pierre Ossman");350MODULE_AUTHOR("Pierre Ossman");
drivers/media/pci/cobalt/cobalt-v4l2.c+6−6
@@ -633,7 +633,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, · 632 unmodified lines
633 return -EBUSY;633 return -EBUSY;
634 634
635 err = v4l2_subdev_call(s->sd,635 err = v4l2_subdev_call(s->sd,
636 video, s_dv_timings, timings);636 pad, s_dv_timings, 0, timings);
637 if (!err) {637 if (!err) {
638 s->timings = *timings;638 s->timings = *timings;
639 s->width = timings->bt.width;639 s->width = timings->bt.width;
@@ -653,7 +653,7 @@ static int cobalt_g_dv_timings(struct file *file, void *priv_fh, · 13 unmodified lines
653 return 0;653 return 0;
654 }654 }
655 return v4l2_subdev_call(s->sd,655 return v4l2_subdev_call(s->sd,
656 video, g_dv_timings, timings);656 pad, g_dv_timings, 0, timings);
657}657}
658 658
659static int cobalt_query_dv_timings(struct file *file, void *priv_fh,659static int cobalt_query_dv_timings(struct file *file, void *priv_fh,
@@ -666,7 +666,7 @@ static int cobalt_query_dv_timings(struct file *file, void *priv_fh, · 6 unmodified lines
666 return 0;666 return 0;
667 }667 }
668 return v4l2_subdev_call(s->sd,668 return v4l2_subdev_call(s->sd,
669 video, query_dv_timings, timings);669 pad, query_dv_timings, 0, timings);
670}670}
671 671
672static int cobalt_dv_timings_cap(struct file *file, void *priv_fh,672static int cobalt_dv_timings_cap(struct file *file, void *priv_fh,
@@ -1080,7 +1080,7 @@ static int cobalt_g_pixelaspect(struct file *file, void *fh, · 407 unmodified lines
1080 if (s->input == 1)1080 if (s->input == 1)
1081 timings = cea1080p60;1081 timings = cea1080p60;
1082 else1082 else
1083 err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);1083 err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);
1084 if (!err)1084 if (!err)
1085 *f = v4l2_dv_timings_aspect_ratio(&timings);1085 *f = v4l2_dv_timings_aspect_ratio(&timings);
1086 return err;1086 return err;
@@ -1099,7 +1099,7 @@ static int cobalt_g_selection(struct file *file, void *fh, · 12 unmodified lines
1099 if (s->input == 1)1099 if (s->input == 1)
1100 timings = cea1080p60;1100 timings = cea1080p60;
1101 else1101 else
1102 err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);1102 err = v4l2_subdev_call(s->sd, pad, g_dv_timings, 0, &timings);
1103 1103
1104 if (err)1104 if (err)
1105 return err;1105 return err;
@@ -1243,7 +1243,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) · 137 unmodified lines
1243 if (s->sd)1243 if (s->sd)
1244 vdev->ctrl_handler = s->sd->ctrl_handler;1244 vdev->ctrl_handler = s->sd->ctrl_handler;
1245 s->timings = dv1080p60;1245 s->timings = dv1080p60;
1246 v4l2_subdev_call(s->sd, video, s_dv_timings, &s->timings);1246 v4l2_subdev_call(s->sd, pad, s_dv_timings, 0, &s->timings);
1247 if (!s->is_output && s->sd)1247 if (!s->is_output && s->sd)
1248 cobalt_enable_input(s);1248 cobalt_enable_input(s);
1249 vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops :1249 vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops :
drivers/media/pci/intel/Kconfig+3−1
@@ -1,11 +1,13 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2 2
3source "drivers/media/pci/intel/ipu3/Kconfig"3source "drivers/media/pci/intel/ipu3/Kconfig"
4source "drivers/media/pci/intel/ipu6/Kconfig"
4source "drivers/media/pci/intel/ivsc/Kconfig"5source "drivers/media/pci/intel/ivsc/Kconfig"
5 6
6config IPU_BRIDGE7config IPU_BRIDGE
7 tristate "Intel IPU Bridge"8 tristate "Intel IPU Bridge"
8 depends on I2C && ACPI9 depends on ACPI || COMPILE_TEST
10 depends on I2C
9 help11 help
10 The IPU bridge is a helper library for Intel IPU drivers to12 The IPU bridge is a helper library for Intel IPU drivers to
11 function on systems shipped with Windows.13 function on systems shipped with Windows.
drivers/media/pci/intel/Makefile+1−0
@@ -5,3 +5,4 @@ · 4 unmodified lines
5obj-$(CONFIG_IPU_BRIDGE) += ipu-bridge.o5obj-$(CONFIG_IPU_BRIDGE) += ipu-bridge.o
6obj-y += ipu3/6obj-y += ipu3/
7obj-y += ivsc/7obj-y += ivsc/
8obj-$(CONFIG_VIDEO_INTEL_IPU6) += ipu6/
drivers/media/pci/intel/ipu-bridge.c+47−19
@@ -15,6 +15,8 @@ · 14 unmodified lines
15#include <media/ipu-bridge.h>15#include <media/ipu-bridge.h>
16#include <media/v4l2-fwnode.h>16#include <media/v4l2-fwnode.h>
17 17
18#define ADEV_DEV(adev) ACPI_PTR(&((adev)->dev))
19
18/*20/*
19 * 92335fcf-3203-4472-af93-7b4453ac29da21 * 92335fcf-3203-4472-af93-7b4453ac29da
20 *22 *
@@ -87,6 +89,7 @@ static const char * const ipu_vcm_types[] = { · 66 unmodified lines
87 "lc898212axb",89 "lc898212axb",
88};90};
89 91
92#if IS_ENABLED(CONFIG_ACPI)
90/*93/*
91 * Used to figure out IVSC acpi device by ipu_bridge_get_ivsc_acpi_dev()94 * Used to figure out IVSC acpi device by ipu_bridge_get_ivsc_acpi_dev()
92 * instead of device and driver match to probe IVSC device.95 * instead of device and driver match to probe IVSC device.
@@ -100,13 +103,13 @@ static const struct acpi_device_id ivsc_acpi_ids[] = { · 7 unmodified lines
100 103
101static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev)104static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev)
102{105{
103 acpi_handle handle = acpi_device_handle(adev);
104 struct acpi_device *consumer, *ivsc_adev;
105 unsigned int i;106 unsigned int i;
106 107
107 for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) {108 for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) {
108 const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i];109 const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i];
110 struct acpi_device *consumer, *ivsc_adev;
109 111
112 acpi_handle handle = acpi_device_handle(adev);
110 for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1)113 for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1)
111 /* camera sensor depends on IVSC in DSDT if exist */114 /* camera sensor depends on IVSC in DSDT if exist */
112 for_each_acpi_consumer_dev(ivsc_adev, consumer)115 for_each_acpi_consumer_dev(ivsc_adev, consumer)
@@ -118,6 +121,12 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev · 5 unmodified lines
118 121
119 return NULL;122 return NULL;
120}123}
124#else
125static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev)
126{
127 return NULL;
128}
129#endif
121 130
122static int ipu_bridge_match_ivsc_dev(struct device *dev, const void *adev)131static int ipu_bridge_match_ivsc_dev(struct device *dev, const void *adev)
123{132{
@@ -163,7 +172,7 @@ static int ipu_bridge_check_ivsc_dev(struct ipu_sensor *sensor, · 39 unmodified lines
163 csi_dev = ipu_bridge_get_ivsc_csi_dev(adev);172 csi_dev = ipu_bridge_get_ivsc_csi_dev(adev);
164 if (!csi_dev) {173 if (!csi_dev) {
165 acpi_dev_put(adev);174 acpi_dev_put(adev);
166 dev_err(&adev->dev, "Failed to find MEI CSI dev\n");175 dev_err(ADEV_DEV(adev), "Failed to find MEI CSI dev\n");
167 return -ENODEV;176 return -ENODEV;
168 }177 }
169 178
@@ -182,24 +191,25 @@ static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, · 12 unmodified lines
182 acpi_status status;191 acpi_status status;
183 int ret = 0;192 int ret = 0;
184 193
185 status = acpi_evaluate_object(adev->handle, id, NULL, &buffer);194 status = acpi_evaluate_object(ACPI_PTR(adev->handle),
195 id, NULL, &buffer);
186 if (ACPI_FAILURE(status))196 if (ACPI_FAILURE(status))
187 return -ENODEV;197 return -ENODEV;
188 198
189 obj = buffer.pointer;199 obj = buffer.pointer;
190 if (!obj) {200 if (!obj) {
191 dev_err(&adev->dev, "Couldn't locate ACPI buffer\n");201 dev_err(ADEV_DEV(adev), "Couldn't locate ACPI buffer\n");
192 return -ENODEV;202 return -ENODEV;
193 }203 }
194 204
195 if (obj->type != ACPI_TYPE_BUFFER) {205 if (obj->type != ACPI_TYPE_BUFFER) {
196 dev_err(&adev->dev, "Not an ACPI buffer\n");206 dev_err(ADEV_DEV(adev), "Not an ACPI buffer\n");
197 ret = -ENODEV;207 ret = -ENODEV;
198 goto out_free_buff;208 goto out_free_buff;
199 }209 }
200 210
201 if (obj->buffer.length > size) {211 if (obj->buffer.length > size) {
202 dev_err(&adev->dev, "Given buffer is too small\n");212 dev_err(ADEV_DEV(adev), "Given buffer is too small\n");
203 ret = -EINVAL;213 ret = -EINVAL;
204 goto out_free_buff;214 goto out_free_buff;
205 }215 }
@@ -220,7 +230,7 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, · 14 unmodified lines
220 case IPU_SENSOR_ROTATION_INVERTED:230 case IPU_SENSOR_ROTATION_INVERTED:
221 return 180;231 return 180;
222 default:232 default:
223 dev_warn(&adev->dev,233 dev_warn(ADEV_DEV(adev),
224 "Unknown rotation %d. Assume 0 degree rotation\n",234 "Unknown rotation %d. Assume 0 degree rotation\n",
225 ssdb->degree);235 ssdb->degree);
226 return 0;236 return 0;
@@ -230,12 +240,14 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, · 3 unmodified lines
230static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)240static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
231{241{
232 enum v4l2_fwnode_orientation orientation;242 enum v4l2_fwnode_orientation orientation;
233 struct acpi_pld_info *pld;243 struct acpi_pld_info *pld = NULL;
234 acpi_status status;244 acpi_status status = AE_ERROR;
235 245
246#if IS_ENABLED(CONFIG_ACPI)
236 status = acpi_get_physical_device_location(adev->handle, &pld);247 status = acpi_get_physical_device_location(adev->handle, &pld);
248#endif
237 if (ACPI_FAILURE(status)) {249 if (ACPI_FAILURE(status)) {
238 dev_warn(&adev->dev, "_PLD call failed, using default orientation\n");250 dev_warn(ADEV_DEV(adev), "_PLD call failed, using default orientation\n");
239 return V4L2_FWNODE_ORIENTATION_EXTERNAL;251 return V4L2_FWNODE_ORIENTATION_EXTERNAL;
240 }252 }
241 253
@@ -253,7 +265,8 @@ static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_dev · 11 unmodified lines
253 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;265 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
254 break;266 break;
255 default:267 default:
256 dev_warn(&adev->dev, "Unknown _PLD panel val %d\n", pld->panel);268 dev_warn(ADEV_DEV(adev), "Unknown _PLD panel val %d\n",
269 pld->panel);
257 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;270 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
258 break;271 break;
259 }272 }
@@ -272,12 +285,12 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor) · 12 unmodified lines
272 return ret;285 return ret;
273 286
274 if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {287 if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {
275 dev_warn(&adev->dev, "Unknown VCM type %d\n", ssdb.vcmtype);288 dev_warn(ADEV_DEV(adev), "Unknown VCM type %d\n", ssdb.vcmtype);
276 ssdb.vcmtype = 0;289 ssdb.vcmtype = 0;
277 }290 }
278 291
279 if (ssdb.lanes > IPU_MAX_LANES) {292 if (ssdb.lanes > IPU_MAX_LANES) {
280 dev_err(&adev->dev, "Number of lanes in SSDB is invalid\n");293 dev_err(ADEV_DEV(adev), "Number of lanes in SSDB is invalid\n");
281 return -EINVAL;294 return -EINVAL;
282 }295 }
283 296
@@ -465,8 +478,14 @@ static void ipu_bridge_create_connection_swnodes(struct ipu_bridge *bridge, · 181 unmodified lines
465 sensor->ipu_properties);478 sensor->ipu_properties);
466 479
467 if (sensor->csi_dev) {480 if (sensor->csi_dev) {
481 const char *device_hid = "";
482
483#if IS_ENABLED(CONFIG_ACPI)
484 device_hid = acpi_device_hid(sensor->ivsc_adev);
485#endif
486
468 snprintf(sensor->ivsc_name, sizeof(sensor->ivsc_name), "%s-%u",487 snprintf(sensor->ivsc_name, sizeof(sensor->ivsc_name), "%s-%u",
469 acpi_device_hid(sensor->ivsc_adev), sensor->link);488 device_hid, sensor->link);
470 489
471 nodes[SWNODE_IVSC_HID] = NODE_SENSOR(sensor->ivsc_name,490 nodes[SWNODE_IVSC_HID] = NODE_SENSOR(sensor->ivsc_name,
472 sensor->ivsc_properties);491 sensor->ivsc_properties);
@@ -631,11 +650,15 @@ static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg, · 158 unmodified lines
631{650{
632 struct fwnode_handle *fwnode, *primary;651 struct fwnode_handle *fwnode, *primary;
633 struct ipu_sensor *sensor;652 struct ipu_sensor *sensor;
634 struct acpi_device *adev;653 struct acpi_device *adev = NULL;
635 int ret;654 int ret;
636 655
656#if IS_ENABLED(CONFIG_ACPI)
637 for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {657 for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
638 if (!adev->status.enabled)658#else
659 while (true) {
660#endif
661 if (!ACPI_PTR(adev->status.enabled))
639 continue;662 continue;
640 663
641 if (bridge->n_sensors >= IPU_MAX_PORTS) {664 if (bridge->n_sensors >= IPU_MAX_PORTS) {
@@ -671,7 +694,7 @@ static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg, · 29 unmodified lines
671 goto err_free_swnodes;694 goto err_free_swnodes;
672 }695 }
673 696
674 sensor->adev = acpi_dev_get(adev);697 sensor->adev = ACPI_PTR(acpi_dev_get(adev));
675 698
676 primary = acpi_fwnode_handle(adev);699 primary = acpi_fwnode_handle(adev);
677 primary->secondary = fwnode;700 primary->secondary = fwnode;
@@ -727,11 +750,16 @@ static int ipu_bridge_ivsc_is_ready(void) · 49 unmodified lines
727 unsigned int i;750 unsigned int i;
728 751
729 for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) {752 for (i = 0; i < ARRAY_SIZE(ipu_supported_sensors); i++) {
753#if IS_ENABLED(CONFIG_ACPI)
730 const struct ipu_sensor_config *cfg =754 const struct ipu_sensor_config *cfg =
731 &ipu_supported_sensors[i];755 &ipu_supported_sensors[i];
732 756
733 for_each_acpi_dev_match(sensor_adev, cfg->hid, NULL, -1) {757 for_each_acpi_dev_match(sensor_adev, cfg->hid, NULL, -1) {
734 if (!sensor_adev->status.enabled)758#else
759 while (true) {
760 sensor_adev = NULL;
761#endif
762 if (!ACPI_PTR(sensor_adev->status.enabled))
735 continue;763 continue;
736 764
737 adev = ipu_bridge_get_ivsc_acpi_dev(sensor_adev);765 adev = ipu_bridge_get_ivsc_acpi_dev(sensor_adev);
drivers/media/pci/intel/ipu3/ipu3-cio2.c+9−20
@@ -4,9 +4,9 @@ · 3 unmodified lines
4 *4 *
5 * Based partially on Intel IPU4 driver written by5 * Based partially on Intel IPU4 driver written by
6 * Sakari Ailus <sakari.ailus@linux.intel.com>6 * Sakari Ailus <sakari.ailus@linux.intel.com>
7 * Samu Onkalo <samu.onkalo@intel.com>7 * Samu Onkalo
8 * Jouni Högander <jouni.hogander@intel.com>8 * Jouni Högander <jouni.hogander@intel.com>
9 * Jouni Ukkonen <jouni.ukkonen@intel.com>9 * Jouni Ukkonen
10 * Antti Laakso <antti.laakso@intel.com>10 * Antti Laakso <antti.laakso@intel.com>
11 * et al.11 * et al.
12 */12 */
@@ -1752,11 +1752,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, · 1739 unmodified lines
1752 1752
1753 v4l2_async_nf_init(&cio2->notifier, &cio2->v4l2_dev);1753 v4l2_async_nf_init(&cio2->notifier, &cio2->v4l2_dev);
1754 1754
1755 /* Register notifier for subdevices we care */
1756 r = cio2_parse_firmware(cio2);
1757 if (r)
1758 goto fail_clean_notifier;
1759
1760 r = devm_request_irq(dev, pci_dev->irq, cio2_irq, IRQF_SHARED,1755 r = devm_request_irq(dev, pci_dev->irq, cio2_irq, IRQF_SHARED,
1761 CIO2_NAME, cio2);1756 CIO2_NAME, cio2);
1762 if (r) {1757 if (r) {
@@ -1764,6 +1759,11 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, · 1 unmodified line
1764 goto fail_clean_notifier;1759 goto fail_clean_notifier;
1765 }1760 }
1766 1761
1762 /* Register notifier for subdevices we care */
1763 r = cio2_parse_firmware(cio2);
1764 if (r)
1765 goto fail_clean_notifier;
1766
1767 pm_runtime_put_noidle(dev);1767 pm_runtime_put_noidle(dev);
1768 pm_runtime_allow(dev);1768 pm_runtime_allow(dev);
1769 1769
@@ -1807,16 +1807,10 @@ static int __maybe_unused cio2_runtime_suspend(struct device *dev) · 37 unmodified lines
1807 struct pci_dev *pci_dev = to_pci_dev(dev);1807 struct pci_dev *pci_dev = to_pci_dev(dev);
1808 struct cio2_device *cio2 = pci_get_drvdata(pci_dev);1808 struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
1809 void __iomem *const base = cio2->base;1809 void __iomem *const base = cio2->base;
1810 u16 pm;
1811 1810
1812 writel(CIO2_D0I3C_I3, base + CIO2_REG_D0I3C);1811 writel(CIO2_D0I3C_I3, base + CIO2_REG_D0I3C);
1813 dev_dbg(dev, "cio2 runtime suspend.\n");1812 dev_dbg(dev, "cio2 runtime suspend.\n");
1814 1813
1815 pci_read_config_word(pci_dev, pci_dev->pm_cap + CIO2_PMCSR_OFFSET, &pm);
1816 pm = (pm >> CIO2_PMCSR_D0D3_SHIFT) << CIO2_PMCSR_D0D3_SHIFT;
1817 pm |= CIO2_PMCSR_D3;
1818 pci_write_config_word(pci_dev, pci_dev->pm_cap + CIO2_PMCSR_OFFSET, pm);
1819
1820 return 0;1814 return 0;
1821}1815}
1822 1816
@@ -1825,15 +1819,10 @@ static int __maybe_unused cio2_runtime_resume(struct device *dev) · 2 unmodified lines
1825 struct pci_dev *pci_dev = to_pci_dev(dev);1819 struct pci_dev *pci_dev = to_pci_dev(dev);
1826 struct cio2_device *cio2 = pci_get_drvdata(pci_dev);1820 struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
1827 void __iomem *const base = cio2->base;1821 void __iomem *const base = cio2->base;
1828 u16 pm;
1829 1822
1830 writel(CIO2_D0I3C_RR, base + CIO2_REG_D0I3C);1823 writel(CIO2_D0I3C_RR, base + CIO2_REG_D0I3C);
1831 dev_dbg(dev, "cio2 runtime resume.\n");1824 dev_dbg(dev, "cio2 runtime resume.\n");
1832 1825
1833 pci_read_config_word(pci_dev, pci_dev->pm_cap + CIO2_PMCSR_OFFSET, &pm);
1834 pm = (pm >> CIO2_PMCSR_D0D3_SHIFT) << CIO2_PMCSR_D0D3_SHIFT;
1835 pci_write_config_word(pci_dev, pci_dev->pm_cap + CIO2_PMCSR_OFFSET, pm);
1836
1837 return 0;1826 return 0;
1838}1827}
1839 1828
@@ -2006,10 +1995,10 @@ static struct pci_driver cio2_pci_driver = { · 166 unmodified lines
2006 1995
2007module_pci_driver(cio2_pci_driver);1996module_pci_driver(cio2_pci_driver);
2008 1997
2009MODULE_AUTHOR("Tuukka Toivonen <tuukka.toivonen@intel.com>");1998MODULE_AUTHOR("Tuukka Toivonen");
2010MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");1999MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
2011MODULE_AUTHOR("Jian Xu Zheng");2000MODULE_AUTHOR("Jian Xu Zheng");
2012MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>");2001MODULE_AUTHOR("Yuning Pu");
2013MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");2002MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
2014MODULE_LICENSE("GPL v2");2003MODULE_LICENSE("GPL v2");
2015MODULE_DESCRIPTION("IPU3 CIO2 driver");2004MODULE_DESCRIPTION("IPU3 CIO2 driver");
drivers/media/pci/intel/ipu3/ipu3-cio2.h+0−4
@@ -320,10 +320,6 @@ struct pci_dev; · 319 unmodified lines
320#define CIO2_CSIRX_DLY_CNT_TERMEN_DEFAULT 0x4320#define CIO2_CSIRX_DLY_CNT_TERMEN_DEFAULT 0x4
321#define CIO2_CSIRX_DLY_CNT_SETTLE_DEFAULT 0x570321#define CIO2_CSIRX_DLY_CNT_SETTLE_DEFAULT 0x570
322 322
323#define CIO2_PMCSR_OFFSET 4U
324#define CIO2_PMCSR_D0D3_SHIFT 2U
325#define CIO2_PMCSR_D3 0x3
326
327struct cio2_csi2_timing {323struct cio2_csi2_timing {
328 s32 clk_termen;324 s32 clk_termen;
329 s32 clk_settle;325 s32 clk_settle;
drivers/media/pci/intel/ipu6/Kconfig+18−0
@@ -0,0 +1,18 @@
1config VIDEO_INTEL_IPU6
2 tristate "Intel IPU6 driver"
3 depends on ACPI || COMPILE_TEST
4 depends on VIDEO_DEV
5 depends on X86 && X86_64 && HAS_DMA
6 select DMA_OPS
7 select IOMMU_IOVA
8 select VIDEO_V4L2_SUBDEV_API
9 select MEDIA_CONTROLLER
10 select VIDEOBUF2_DMA_CONTIG
11 select V4L2_FWNODE
12 select IPU_BRIDGE
13 help
14 This is the 6th Gen Intel Image Processing Unit, found in Intel SoCs
15 and used for capturing images and video from camera sensors.
16
17 To compile this driver, say Y here! It contains 2 modules -
18 intel_ipu6 and intel_ipu6_isys.
drivers/media/pci/intel/ipu6/Makefile+23−0
@@ -0,0 +1,23 @@
1# SPDX-License-Identifier: GPL-2.0-only
2
3intel-ipu6-y := ipu6.o \
4 ipu6-bus.o \
5 ipu6-dma.o \
6 ipu6-mmu.o \
7 ipu6-buttress.o \
8 ipu6-cpd.o \
9 ipu6-fw-com.o
10
11obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6.o
12
13intel-ipu6-isys-y := ipu6-isys.o \
14 ipu6-isys-csi2.o \
15 ipu6-fw-isys.o \
16 ipu6-isys-video.o \
17 ipu6-isys-queue.o \
18 ipu6-isys-subdev.o \
19 ipu6-isys-mcd-phy.o \
20 ipu6-isys-jsl-phy.o \
21 ipu6-isys-dwc-phy.o
22
23obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-isys.o
drivers/media/pci/intel/ipu6/ipu6-bus.c+165−0
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013 - 2024 Intel Corporation
4 */
5
6#include <linux/auxiliary_bus.h>
7#include <linux/device.h>
8#include <linux/dma-mapping.h>
9#include <linux/err.h>
10#include <linux/list.h>
11#include <linux/mutex.h>
12#include <linux/pci.h>
13#include <linux/pm_domain.h>
14#include <linux/pm_runtime.h>
15#include <linux/slab.h>
16
17#include "ipu6.h"
18#include "ipu6-bus.h"
19#include "ipu6-buttress.h"
20#include "ipu6-dma.h"
21
22static int bus_pm_runtime_suspend(struct device *dev)
23{
24 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
25 int ret;
26
27 ret = pm_generic_runtime_suspend(dev);
28 if (ret)
29 return ret;
30
31 ret = ipu6_buttress_power(dev, adev->ctrl, false);
32 if (!ret)
33 return 0;
34
35 dev_err(dev, "power down failed!\n");
36
37 /* Powering down failed, attempt to resume device now */
38 ret = pm_generic_runtime_resume(dev);
39 if (!ret)
40 return -EBUSY;
41
42 return -EIO;
43}
44
45static int bus_pm_runtime_resume(struct device *dev)
46{
47 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
48 int ret;
49
50 ret = ipu6_buttress_power(dev, adev->ctrl, true);
51 if (ret)
52 return ret;
53
54 ret = pm_generic_runtime_resume(dev);
55 if (ret)
56 goto out_err;
57
58 return 0;
59
60out_err:
61 ipu6_buttress_power(dev, adev->ctrl, false);
62
63 return -EBUSY;
64}
65
66static struct dev_pm_domain ipu6_bus_pm_domain = {
67 .ops = {
68 .runtime_suspend = bus_pm_runtime_suspend,
69 .runtime_resume = bus_pm_runtime_resume,
70 },
71};
72
73static DEFINE_MUTEX(ipu6_bus_mutex);
74
75static void ipu6_bus_release(struct device *dev)
76{
77 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
78
79 kfree(adev->pdata);
80 kfree(adev);
81}
82
83struct ipu6_bus_device *
84ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
85 void *pdata, struct ipu6_buttress_ctrl *ctrl,
86 char *name)
87{
88 struct auxiliary_device *auxdev;
89 struct ipu6_bus_device *adev;
90 struct ipu6_device *isp = pci_get_drvdata(pdev);
91 int ret;
92
93 adev = kzalloc(sizeof(*adev), GFP_KERNEL);
94 if (!adev)
95 return ERR_PTR(-ENOMEM);
96
97 adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS :
98 IPU6_MMU_ADDR_BITS_NON_SECURE);
99 adev->isp = isp;
100 adev->ctrl = ctrl;
101 adev->pdata = pdata;
102 auxdev = &adev->auxdev;
103 auxdev->name = name;
104 auxdev->id = (pci_domain_nr(pdev->bus) << 16) |
105 PCI_DEVID(pdev->bus->number, pdev->devfn);
106
107 auxdev->dev.parent = parent;
108 auxdev->dev.release = ipu6_bus_release;
109 auxdev->dev.dma_ops = &ipu6_dma_ops;
110 auxdev->dev.dma_mask = &adev->dma_mask;
111 auxdev->dev.dma_parms = pdev->dev.dma_parms;
112 auxdev->dev.coherent_dma_mask = adev->dma_mask;
113
114 ret = auxiliary_device_init(auxdev);
115 if (ret < 0) {
116 dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n",
117 ret);
118 kfree(adev);
119 return ERR_PTR(ret);
120 }
121
122 dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);
123
124 pm_runtime_forbid(&adev->auxdev.dev);
125 pm_runtime_enable(&adev->auxdev.dev);
126
127 return adev;
128}
129
130int ipu6_bus_add_device(struct ipu6_bus_device *adev)
131{
132 struct auxiliary_device *auxdev = &adev->auxdev;
133 int ret;
134
135 ret = auxiliary_device_add(auxdev);
136 if (ret) {
137 auxiliary_device_uninit(auxdev);
138 return ret;
139 }
140
141 mutex_lock(&ipu6_bus_mutex);
142 list_add(&adev->list, &adev->isp->devices);
143 mutex_unlock(&ipu6_bus_mutex);
144
145 pm_runtime_allow(&auxdev->dev);
146
147 return 0;
148}
149
150void ipu6_bus_del_devices(struct pci_dev *pdev)
151{
152 struct ipu6_device *isp = pci_get_drvdata(pdev);
153 struct ipu6_bus_device *adev, *save;
154
155 mutex_lock(&ipu6_bus_mutex);
156
157 list_for_each_entry_safe(adev, save, &isp->devices, list) {
158 pm_runtime_disable(&adev->auxdev.dev);
159 list_del(&adev->list);
160 auxiliary_device_delete(&adev->auxdev);
161 auxiliary_device_uninit(&adev->auxdev);
162 }
163
164 mutex_unlock(&ipu6_bus_mutex);
165}
drivers/media/pci/intel/ipu6/ipu6-bus.h+58−0
@@ -0,0 +1,58 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013 - 2024 Intel Corporation */
3
4#ifndef IPU6_BUS_H
5#define IPU6_BUS_H
6
7#include <linux/auxiliary_bus.h>
8#include <linux/container_of.h>
9#include <linux/device.h>
10#include <linux/irqreturn.h>
11#include <linux/list.h>
12#include <linux/scatterlist.h>
13#include <linux/types.h>
14
15struct firmware;
16struct pci_dev;
17
18#define IPU6_BUS_NAME IPU6_NAME "-bus"
19
20struct ipu6_buttress_ctrl;
21
22struct ipu6_bus_device {
23 struct auxiliary_device auxdev;
24 struct auxiliary_driver *auxdrv;
25 const struct ipu6_auxdrv_data *auxdrv_data;
26 struct list_head list;
27 void *pdata;
28 struct ipu6_mmu *mmu;
29 struct ipu6_device *isp;
30 struct ipu6_buttress_ctrl *ctrl;
31 u64 dma_mask;
32 const struct firmware *fw;
33 struct sg_table fw_sgt;
34 u64 *pkg_dir;
35 dma_addr_t pkg_dir_dma_addr;
36 unsigned int pkg_dir_size;
37};
38
39struct ipu6_auxdrv_data {
40 irqreturn_t (*isr)(struct ipu6_bus_device *adev);
41 irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
42 bool wake_isr_thread;
43};
44
45#define to_ipu6_bus_device(_dev) \
46 container_of(to_auxiliary_dev(_dev), struct ipu6_bus_device, auxdev)
47#define auxdev_to_adev(_auxdev) \
48 container_of(_auxdev, struct ipu6_bus_device, auxdev)
49#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
50
51struct ipu6_bus_device *
52ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
53 void *pdata, struct ipu6_buttress_ctrl *ctrl,
54 char *name);
55int ipu6_bus_add_device(struct ipu6_bus_device *adev);
56void ipu6_bus_del_devices(struct pci_dev *pdev);
57
58#endif
drivers/media/pci/intel/ipu6/ipu6-buttress.c+917−0
@@ -0,0 +1,917 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/completion.h>
9#include <linux/delay.h>
10#include <linux/device.h>
11#include <linux/dma-mapping.h>
12#include <linux/firmware.h>
13#include <linux/interrupt.h>
14#include <linux/iopoll.h>
15#include <linux/math64.h>
16#include <linux/mm.h>
17#include <linux/mutex.h>
18#include <linux/pci.h>
19#include <linux/pfn.h>
20#include <linux/pm_runtime.h>
21#include <linux/scatterlist.h>
22#include <linux/slab.h>
23#include <linux/time64.h>
24
25#include "ipu6.h"
26#include "ipu6-bus.h"
27#include "ipu6-buttress.h"
28#include "ipu6-platform-buttress-regs.h"
29
30#define BOOTLOADER_STATUS_OFFSET 0x15c
31
32#define BOOTLOADER_MAGIC_KEY 0xb00710ad
33
34#define ENTRY BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1
35#define EXIT BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2
36#define QUERY BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE
37
38#define BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX 10
39
40#define BUTTRESS_POWER_TIMEOUT_US (200 * USEC_PER_MSEC)
41
42#define BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US (5 * USEC_PER_SEC)
43#define BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US (10 * USEC_PER_SEC)
44#define BUTTRESS_CSE_FWRESET_TIMEOUT_US (100 * USEC_PER_MSEC)
45
46#define BUTTRESS_IPC_TX_TIMEOUT_MS MSEC_PER_SEC
47#define BUTTRESS_IPC_RX_TIMEOUT_MS MSEC_PER_SEC
48#define BUTTRESS_IPC_VALIDITY_TIMEOUT_US (1 * USEC_PER_SEC)
49#define BUTTRESS_TSC_SYNC_TIMEOUT_US (5 * USEC_PER_MSEC)
50
51#define BUTTRESS_IPC_RESET_RETRY 2000
52#define BUTTRESS_CSE_IPC_RESET_RETRY 4
53#define BUTTRESS_IPC_CMD_SEND_RETRY 1
54
55#define BUTTRESS_MAX_CONSECUTIVE_IRQS 100
56
57static const u32 ipu6_adev_irq_mask[2] = {
58 BUTTRESS_ISR_IS_IRQ,
59 BUTTRESS_ISR_PS_IRQ
60};
61
62int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
63 struct ipu6_buttress_ipc *ipc)
64{
65 unsigned int retries = BUTTRESS_IPC_RESET_RETRY;
66 struct ipu6_buttress *b = &isp->buttress;
67 u32 val = 0, csr_in_clr;
68
69 if (!isp->secure_mode) {
70 dev_dbg(&isp->pdev->dev, "Skip IPC reset for non-secure mode");
71 return 0;
72 }
73
74 mutex_lock(&b->ipc_mutex);
75
76 /* Clear-by-1 CSR (all bits), corresponding internal states. */
77 val = readl(isp->base + ipc->csr_in);
78 writel(val, isp->base + ipc->csr_in);
79
80 /* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */
81 writel(ENTRY, isp->base + ipc->csr_out);
82 /*
83 * Clear-by-1 all CSR bits EXCEPT following
84 * bits:
85 * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1.
86 * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2.
87 * C. Possibly custom bits, depending on
88 * their role.
89 */
90 csr_in_clr = BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ |
91 BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID |
92 BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ | QUERY;
93
94 do {
95 usleep_range(400, 500);
96 val = readl(isp->base + ipc->csr_in);
97 switch (val) {
98 case ENTRY | EXIT:
99 case ENTRY | EXIT | QUERY:
100 /*
101 * 1) Clear-by-1 CSR bits
102 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
103 * IPC_PEER_COMP_ACTIONS_RST_PHASE2).
104 * 2) Set peer CSR bit
105 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
106 */
107 writel(ENTRY | EXIT, isp->base + ipc->csr_in);
108 writel(QUERY, isp->base + ipc->csr_out);
109 break;
110 case ENTRY:
111 case ENTRY | QUERY:
112 /*
113 * 1) Clear-by-1 CSR bits
114 * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
115 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE).
116 * 2) Set peer CSR bit
117 * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
118 */
119 writel(ENTRY | QUERY, isp->base + ipc->csr_in);
120 writel(ENTRY, isp->base + ipc->csr_out);
121 break;
122 case EXIT:
123 case EXIT | QUERY:
124 /*
125 * Clear-by-1 CSR bit
126 * IPC_PEER_COMP_ACTIONS_RST_PHASE2.
127 * 1) Clear incoming doorbell.
128 * 2) Clear-by-1 all CSR bits EXCEPT following
129 * bits:
130 * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1.
131 * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2.
132 * C. Possibly custom bits, depending on
133 * their role.
134 * 3) Set peer CSR bit
135 * IPC_PEER_COMP_ACTIONS_RST_PHASE2.
136 */
137 writel(EXIT, isp->base + ipc->csr_in);
138 writel(0, isp->base + ipc->db0_in);
139 writel(csr_in_clr, isp->base + ipc->csr_in);
140 writel(EXIT, isp->base + ipc->csr_out);
141
142 /*
143 * Read csr_in again to make sure if RST_PHASE2 is done.
144 * If csr_in is QUERY, it should be handled again.
145 */
146 usleep_range(200, 300);
147 val = readl(isp->base + ipc->csr_in);
148 if (val & QUERY) {
149 dev_dbg(&isp->pdev->dev,
150 "RST_PHASE2 retry csr_in = %x\n", val);
151 break;
152 }
153 mutex_unlock(&b->ipc_mutex);
154 return 0;
155 case QUERY:
156 /*
157 * 1) Clear-by-1 CSR bit
158 * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
159 * 2) Set peer CSR bit
160 * IPC_PEER_COMP_ACTIONS_RST_PHASE1
161 */
162 writel(QUERY, isp->base + ipc->csr_in);
163 writel(ENTRY, isp->base + ipc->csr_out);
164 break;
165 default:
166 dev_warn_ratelimited(&isp->pdev->dev,
167 "Unexpected CSR 0x%x\n", val);
168 break;
169 }
170 } while (retries--);
171
172 mutex_unlock(&b->ipc_mutex);
173 dev_err(&isp->pdev->dev, "Timed out while waiting for CSE\n");
174
175 return -ETIMEDOUT;
176}
177
178static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp,
179 struct ipu6_buttress_ipc *ipc)
180{
181 writel(BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ,
182 isp->base + ipc->csr_out);
183}
184
185static int
186ipu6_buttress_ipc_validity_open(struct ipu6_device *isp,
187 struct ipu6_buttress_ipc *ipc)
188{
189 unsigned int mask = BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID;
190 void __iomem *addr;
191 int ret;
192 u32 val;
193
194 writel(BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ,
195 isp->base + ipc->csr_out);
196
197 addr = isp->base + ipc->csr_in;
198 ret = readl_poll_timeout(addr, val, val & mask, 200,
199 BUTTRESS_IPC_VALIDITY_TIMEOUT_US);
200 if (ret) {
201 dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val);
202 ipu6_buttress_ipc_validity_close(isp, ipc);
203 }
204
205 return ret;
206}
207
208static void ipu6_buttress_ipc_recv(struct ipu6_device *isp,
209 struct ipu6_buttress_ipc *ipc, u32 *ipc_msg)
210{
211 if (ipc_msg)
212 *ipc_msg = readl(isp->base + ipc->data0_in);
213 writel(0, isp->base + ipc->db0_in);
214}
215
216static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
217 enum ipu6_buttress_ipc_domain ipc_domain,
218 struct ipu6_ipc_buttress_bulk_msg *msgs,
219 u32 size)
220{
221 unsigned long tx_timeout_jiffies, rx_timeout_jiffies;
222 unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
223 struct ipu6_buttress *b = &isp->buttress;
224 struct ipu6_buttress_ipc *ipc;
225 u32 val;
226 int ret;
227 int tout;
228
229 ipc = ipc_domain == IPU6_BUTTRESS_IPC_CSE ? &b->cse : &b->ish;
230
231 mutex_lock(&b->ipc_mutex);
232
233 ret = ipu6_buttress_ipc_validity_open(isp, ipc);
234 if (ret) {
235 dev_err(&isp->pdev->dev, "IPC validity open failed\n");
236 goto out;
237 }
238
239 tx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_TX_TIMEOUT_MS);
240 rx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_RX_TIMEOUT_MS);
241
242 for (i = 0; i < size; i++) {
243 reinit_completion(&ipc->send_complete);
244 if (msgs[i].require_resp)
245 reinit_completion(&ipc->recv_complete);
246
247 dev_dbg(&isp->pdev->dev, "bulk IPC command: 0x%x\n",
248 msgs[i].cmd);
249 writel(msgs[i].cmd, isp->base + ipc->data0_out);
250 val = BUTTRESS_IU2CSEDB0_BUSY | msgs[i].cmd_size;
251 writel(val, isp->base + ipc->db0_out);
252
253 tout = wait_for_completion_timeout(&ipc->send_complete,
254 tx_timeout_jiffies);
255 if (!tout) {
256 dev_err(&isp->pdev->dev, "send IPC response timeout\n");
257 if (!retry--) {
258 ret = -ETIMEDOUT;
259 goto out;
260 }
261
262 /* Try again if CSE is not responding on first try */
263 writel(0, isp->base + ipc->db0_out);
264 i--;
265 continue;
266 }
267
268 retry = BUTTRESS_IPC_CMD_SEND_RETRY;
269
270 if (!msgs[i].require_resp)
271 continue;
272
273 tout = wait_for_completion_timeout(&ipc->recv_complete,
274 rx_timeout_jiffies);
275 if (!tout) {
276 dev_err(&isp->pdev->dev, "recv IPC response timeout\n");
277 ret = -ETIMEDOUT;
278 goto out;
279 }
280
281 if (ipc->nack_mask &&
282 (ipc->recv_data & ipc->nack_mask) == ipc->nack) {
283 dev_err(&isp->pdev->dev,
284 "IPC NACK for cmd 0x%x\n", msgs[i].cmd);
285 ret = -EIO;
286 goto out;
287 }
288
289 if (ipc->recv_data != msgs[i].expected_resp) {
290 dev_err(&isp->pdev->dev,
291 "expected resp: 0x%x, IPC response: 0x%x ",
292 msgs[i].expected_resp, ipc->recv_data);
293 ret = -EIO;
294 goto out;
295 }
296 }
297
298 dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n");
299
300out:
301 ipu6_buttress_ipc_validity_close(isp, ipc);
302 mutex_unlock(&b->ipc_mutex);
303 return ret;
304}
305
306static int
307ipu6_buttress_ipc_send(struct ipu6_device *isp,
308 enum ipu6_buttress_ipc_domain ipc_domain,
309 u32 ipc_msg, u32 size, bool require_resp,
310 u32 expected_resp)
311{
312 struct ipu6_ipc_buttress_bulk_msg msg = {
313 .cmd = ipc_msg,
314 .cmd_size = size,
315 .require_resp = require_resp,
316 .expected_resp = expected_resp,
317 };
318
319 return ipu6_buttress_ipc_send_bulk(isp, ipc_domain, &msg, 1);
320}
321
322static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev)
323{
324 irqreturn_t ret = IRQ_WAKE_THREAD;
325
326 if (!adev || !adev->auxdrv || !adev->auxdrv_data)
327 return IRQ_NONE;
328
329 if (adev->auxdrv_data->isr)
330 ret = adev->auxdrv_data->isr(adev);
331
332 if (ret == IRQ_WAKE_THREAD && !adev->auxdrv_data->isr_threaded)
333 ret = IRQ_NONE;
334
335 return ret;
336}
337
338irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
339{
340 struct ipu6_device *isp = isp_ptr;
341 struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
342 struct ipu6_buttress *b = &isp->buttress;
343 u32 reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
344 irqreturn_t ret = IRQ_NONE;
345 u32 disable_irqs = 0;
346 u32 irq_status;
347 u32 i, count = 0;
348
349 pm_runtime_get_noresume(&isp->pdev->dev);
350
351 irq_status = readl(isp->base + reg_irq_sts);
352 if (!irq_status) {
353 pm_runtime_put_noidle(&isp->pdev->dev);
354 return IRQ_NONE;
355 }
356
357 do {
358 writel(irq_status, isp->base + BUTTRESS_REG_ISR_CLEAR);
359
360 for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask); i++) {
361 irqreturn_t r = ipu6_buttress_call_isr(adev[i]);
362
363 if (!(irq_status & ipu6_adev_irq_mask[i]))
364 continue;
365
366 if (r == IRQ_WAKE_THREAD) {
367 ret = IRQ_WAKE_THREAD;
368 disable_irqs |= ipu6_adev_irq_mask[i];
369 } else if (ret == IRQ_NONE && r == IRQ_HANDLED) {
370 ret = IRQ_HANDLED;
371 }
372 }
373
374 if ((irq_status & BUTTRESS_EVENT) && ret == IRQ_NONE)
375 ret = IRQ_HANDLED;
376
377 if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
378 dev_dbg(&isp->pdev->dev,
379 "BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
380 ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data);
381 complete(&b->cse.recv_complete);
382 }
383
384 if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) {
385 dev_dbg(&isp->pdev->dev,
386 "BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n");
387 ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data);
388 complete(&b->ish.recv_complete);
389 }
390
391 if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
392 dev_dbg(&isp->pdev->dev,
393 "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
394 complete(&b->cse.send_complete);
395 }
396
397 if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) {
398 dev_dbg(&isp->pdev->dev,
399 "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
400 complete(&b->ish.send_complete);
401 }
402
403 if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
404 ipu6_buttress_get_secure_mode(isp))
405 dev_err(&isp->pdev->dev,
406 "BUTTRESS_ISR_SAI_VIOLATION\n");
407
408 if (irq_status & (BUTTRESS_ISR_IS_FATAL_MEM_ERR |
409 BUTTRESS_ISR_PS_FATAL_MEM_ERR))
410 dev_err(&isp->pdev->dev,
411 "BUTTRESS_ISR_FATAL_MEM_ERR\n");
412
413 if (irq_status & BUTTRESS_ISR_UFI_ERROR)
414 dev_err(&isp->pdev->dev, "BUTTRESS_ISR_UFI_ERROR\n");
415
416 if (++count == BUTTRESS_MAX_CONSECUTIVE_IRQS) {
417 dev_err(&isp->pdev->dev, "too many consecutive IRQs\n");
418 ret = IRQ_NONE;
419 break;
420 }
421
422 irq_status = readl(isp->base + reg_irq_sts);
423 } while (irq_status);
424
425 if (disable_irqs)
426 writel(BUTTRESS_IRQS & ~disable_irqs,
427 isp->base + BUTTRESS_REG_ISR_ENABLE);
428
429 pm_runtime_put(&isp->pdev->dev);
430
431 return ret;
432}
433
434irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
435{
436 struct ipu6_device *isp = isp_ptr;
437 struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
438 const struct ipu6_auxdrv_data *drv_data = NULL;
439 irqreturn_t ret = IRQ_NONE;
440 unsigned int i;
441
442 for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask) && adev[i]; i++) {
443 drv_data = adev[i]->auxdrv_data;
444 if (!drv_data)
445 continue;
446
447 if (drv_data->wake_isr_thread &&
448 drv_data->isr_threaded(adev[i]) == IRQ_HANDLED)
449 ret = IRQ_HANDLED;
450 }
451
452 writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
453
454 return ret;
455}
456
457int ipu6_buttress_power(struct device *dev, struct ipu6_buttress_ctrl *ctrl,
458 bool on)
459{
460 struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
461 u32 pwr_sts, val;
462 int ret;
463
464 if (!ctrl)
465 return 0;
466
467 mutex_lock(&isp->buttress.power_mutex);
468
469 if (!on) {
470 val = 0;
471 pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift;
472 } else {
473 val = BUTTRESS_FREQ_CTL_START |
474 FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK,
475 ctrl->ratio) |
476 FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK,
477 ctrl->qos_floor) |
478 BUTTRESS_FREQ_CTL_ICCMAX_LEVEL;
479
480 pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift;
481 }
482
483 writel(val, isp->base + ctrl->freq_ctl);
484
485 ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE,
486 val, (val & ctrl->pwr_sts_mask) == pwr_sts,
487 100, BUTTRESS_POWER_TIMEOUT_US);
488 if (ret)
489 dev_err(&isp->pdev->dev,
490 "Change power status timeout with 0x%x\n", val);
491
492 ctrl->started = !ret && on;
493
494 mutex_unlock(&isp->buttress.power_mutex);
495
496 return ret;
497}
498
499bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp)
500{
501 u32 val;
502
503 val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
504
505 return val & BUTTRESS_SECURITY_CTL_FW_SECURE_MODE;
506}
507
508bool ipu6_buttress_auth_done(struct ipu6_device *isp)
509{
510 u32 val;
511
512 if (!isp->secure_mode)
513 return true;
514
515 val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
516 val = FIELD_GET(BUTTRESS_SECURITY_CTL_FW_SETUP_MASK, val);
517
518 return val == BUTTRESS_SECURITY_CTL_AUTH_DONE;
519}
520EXPORT_SYMBOL_NS_GPL(ipu6_buttress_auth_done, INTEL_IPU6);
521
522int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
523{
524 int ret;
525 u32 val;
526
527 if (!isp->secure_mode) {
528 dev_dbg(&isp->pdev->dev, "Skip auth for non-secure mode\n");
529 return 0;
530 }
531
532 writel(BUTTRESS_FW_RESET_CTL_START, isp->base +
533 BUTTRESS_REG_FW_RESET_CTL);
534
535 ret = readl_poll_timeout(isp->base + BUTTRESS_REG_FW_RESET_CTL, val,
536 val & BUTTRESS_FW_RESET_CTL_DONE, 500,
537 BUTTRESS_CSE_FWRESET_TIMEOUT_US);
538 if (ret) {
539 dev_err(&isp->pdev->dev,
540 "Time out while resetting authentication state\n");
541 return ret;
542 }
543
544 dev_dbg(&isp->pdev->dev, "FW reset for authentication done\n");
545 writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL);
546 /* leave some time for HW restore */
547 usleep_range(800, 1000);
548
549 return 0;
550}
551
552int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
553 const struct firmware *fw, struct sg_table *sgt)
554{
555 bool is_vmalloc = is_vmalloc_addr(fw->data);
556 struct page **pages;
557 const void *addr;
558 unsigned long n_pages;
559 unsigned int i;
560 int ret;
561
562 if (!is_vmalloc && !virt_addr_valid(fw->data))
563 return -EDOM;
564
565 n_pages = PHYS_PFN(PAGE_ALIGN(fw->size));
566
567 pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL);
568 if (!pages)
569 return -ENOMEM;
570
571 addr = fw->data;
572 for (i = 0; i < n_pages; i++) {
573 struct page *p = is_vmalloc ?
574 vmalloc_to_page(addr) : virt_to_page(addr);
575
576 if (!p) {
577 ret = -ENOMEM;
578 goto out;
579 }
580 pages[i] = p;
581 addr += PAGE_SIZE;
582 }
583
584 ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, fw->size,
585 GFP_KERNEL);
586 if (ret) {
587 ret = -ENOMEM;
588 goto out;
589 }
590
591 ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
592 if (ret < 0) {
593 ret = -ENOMEM;
594 sg_free_table(sgt);
595 goto out;
596 }
597
598 dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE);
599
600out:
601 kfree(pages);
602
603 return ret;
604}
605EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6);
606
607void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
608 struct sg_table *sgt)
609{
610 dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
611 sg_free_table(sgt);
612}
613EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6);
614
615int ipu6_buttress_authenticate(struct ipu6_device *isp)
616{
617 struct ipu6_buttress *b = &isp->buttress;
618 struct ipu6_psys_pdata *psys_pdata;
619 u32 data, mask, done, fail;
620 int ret;
621
622 if (!isp->secure_mode) {
623 dev_dbg(&isp->pdev->dev, "Skip auth for non-secure mode\n");
624 return 0;
625 }
626
627 psys_pdata = isp->psys->pdata;
628
629 mutex_lock(&b->auth_mutex);
630
631 if (ipu6_buttress_auth_done(isp)) {
632 ret = 0;
633 goto out_unlock;
634 }
635
636 /*
637 * Write address of FIT table to FW_SOURCE register
638 * Let's use fw address. I.e. not using FIT table yet
639 */
640 data = lower_32_bits(isp->psys->pkg_dir_dma_addr);
641 writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO);
642
643 data = upper_32_bits(isp->psys->pkg_dir_dma_addr);
644 writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI);
645
646 /*
647 * Write boot_load into IU2CSEDATA0
648 * Write sizeof(boot_load) | 0x2 << CLIENT_ID to
649 * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as
650 */
651 dev_info(&isp->pdev->dev, "Sending BOOT_LOAD to CSE\n");
652
653 ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE,
654 BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD,
655 1, true,
656 BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE);
657 if (ret) {
658 dev_err(&isp->pdev->dev, "CSE boot_load failed\n");
659 goto out_unlock;
660 }
661
662 mask = BUTTRESS_SECURITY_CTL_FW_SETUP_MASK;
663 done = BUTTRESS_SECURITY_CTL_FW_SETUP_DONE;
664 fail = BUTTRESS_SECURITY_CTL_AUTH_FAILED;
665 ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
666 ((data & mask) == done ||
667 (data & mask) == fail), 500,
668 BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
669 if (ret) {
670 dev_err(&isp->pdev->dev, "CSE boot_load timeout\n");
671 goto out_unlock;
672 }
673
674 if ((data & mask) == fail) {
675 dev_err(&isp->pdev->dev, "CSE auth failed\n");
676 ret = -EINVAL;
677 goto out_unlock;
678 }
679
680 ret = readl_poll_timeout(psys_pdata->base + BOOTLOADER_STATUS_OFFSET,
681 data, data == BOOTLOADER_MAGIC_KEY, 500,
682 BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
683 if (ret) {
684 dev_err(&isp->pdev->dev, "Unexpected magic number 0x%x\n",
685 data);
686 goto out_unlock;
687 }
688
689 /*
690 * Write authenticate_run into IU2CSEDATA0
691 * Write sizeof(boot_load) | 0x2 << CLIENT_ID to
692 * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as
693 */
694 dev_info(&isp->pdev->dev, "Sending AUTHENTICATE_RUN to CSE\n");
695 ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE,
696 BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN,
697 1, true,
698 BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE);
699 if (ret) {
700 dev_err(&isp->pdev->dev, "CSE authenticate_run failed\n");
701 goto out_unlock;
702 }
703
704 done = BUTTRESS_SECURITY_CTL_AUTH_DONE;
705 ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
706 ((data & mask) == done ||
707 (data & mask) == fail), 500,
708 BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US);
709 if (ret) {
710 dev_err(&isp->pdev->dev, "CSE authenticate timeout\n");
711 goto out_unlock;
712 }
713
714 if ((data & mask) == fail) {
715 dev_err(&isp->pdev->dev, "CSE boot_load failed\n");
716 ret = -EINVAL;
717 goto out_unlock;
718 }
719
720 dev_info(&isp->pdev->dev, "CSE authenticate_run done\n");
721
722out_unlock:
723 mutex_unlock(&b->auth_mutex);
724
725 return ret;
726}
727
728static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
729{
730 u32 val, mask, done;
731 int ret;
732
733 mask = BUTTRESS_PWR_STATE_HH_STATUS_MASK;
734
735 writel(BUTTRESS_FABRIC_CMD_START_TSC_SYNC,
736 isp->base + BUTTRESS_REG_FABRIC_CMD);
737
738 val = readl(isp->base + BUTTRESS_REG_PWR_STATE);
739 val = FIELD_GET(mask, val);
740 if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) {
741 dev_err(&isp->pdev->dev, "Start tsc sync failed\n");
742 return -EINVAL;
743 }
744
745 done = BUTTRESS_PWR_STATE_HH_STATE_DONE;
746 ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE, val,
747 FIELD_GET(mask, val) == done, 500,
748 BUTTRESS_TSC_SYNC_TIMEOUT_US);
749 if (ret)
750 dev_err(&isp->pdev->dev, "Start tsc sync timeout\n");
751
752 return ret;
753}
754
755int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
756{
757 unsigned int i;
758
759 for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
760 u32 val;
761 int ret;
762
763 ret = ipu6_buttress_send_tsc_request(isp);
764 if (ret != -ETIMEDOUT)
765 return ret;
766
767 val = readl(isp->base + BUTTRESS_REG_TSW_CTL);
768 val = val | BUTTRESS_TSW_CTL_SOFT_RESET;
769 writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
770 val = val & ~BUTTRESS_TSW_CTL_SOFT_RESET;
771 writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
772 }
773
774 dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n");
775
776 return -ETIMEDOUT;
777}
778EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, INTEL_IPU6);
779
780void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val)
781{
782 u32 tsc_hi_1, tsc_hi_2, tsc_lo;
783 unsigned long flags;
784
785 local_irq_save(flags);
786 tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI);
787 tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO);
788 tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI);
789 if (tsc_hi_1 == tsc_hi_2) {
790 *val = (u64)tsc_hi_1 << 32 | tsc_lo;
791 } else {
792 /* Check if TSC has rolled over */
793 if (tsc_lo & BIT(31))
794 *val = (u64)tsc_hi_1 << 32 | tsc_lo;
795 else
796 *val = (u64)tsc_hi_2 << 32 | tsc_lo;
797 }
798 local_irq_restore(flags);
799}
800EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_read, INTEL_IPU6);
801
802u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp)
803{
804 u64 ns = ticks * 10000;
805
806 /*
807 * converting TSC tick count to ns is calculated by:
808 * Example (TSC clock frequency is 19.2MHz):
809 * ns = ticks * 1000 000 000 / 19.2Mhz
810 * = ticks * 1000 000 000 / 19200000Hz
811 * = ticks * 10000 / 192 ns
812 */
813 return div_u64(ns, isp->buttress.ref_clk);
814}
815EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, INTEL_IPU6);
816
817void ipu6_buttress_restore(struct ipu6_device *isp)
818{
819 struct ipu6_buttress *b = &isp->buttress;
820
821 writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
822 writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
823 writel(b->wdt_cached_value, isp->base + BUTTRESS_REG_WDT);
824}
825
826int ipu6_buttress_init(struct ipu6_device *isp)
827{
828 int ret, ipc_reset_retry = BUTTRESS_CSE_IPC_RESET_RETRY;
829 struct ipu6_buttress *b = &isp->buttress;
830 u32 val;
831
832 mutex_init(&b->power_mutex);
833 mutex_init(&b->auth_mutex);
834 mutex_init(&b->cons_mutex);
835 mutex_init(&b->ipc_mutex);
836 init_completion(&b->ish.send_complete);
837 init_completion(&b->cse.send_complete);
838 init_completion(&b->ish.recv_complete);
839 init_completion(&b->cse.recv_complete);
840
841 b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
842 b->cse.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
843 b->cse.csr_in = BUTTRESS_REG_CSE2IUCSR;
844 b->cse.csr_out = BUTTRESS_REG_IU2CSECSR;
845 b->cse.db0_in = BUTTRESS_REG_CSE2IUDB0;
846 b->cse.db0_out = BUTTRESS_REG_IU2CSEDB0;
847 b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0;
848 b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0;
849
850 /* no ISH on IPU6 */
851 memset(&b->ish, 0, sizeof(b->ish));
852 INIT_LIST_HEAD(&b->constraints);
853
854 isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
855 dev_info(&isp->pdev->dev, "IPU6 in %s mode touch 0x%x mask 0x%x\n",
856 isp->secure_mode ? "secure" : "non-secure",
857 readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
858 readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
859
860 b->wdt_cached_value = readl(isp->base + BUTTRESS_REG_WDT);
861 writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
862 writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
863
864 /* get ref_clk frequency by reading the indication in btrs control */
865 val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
866 val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
867
868 switch (val) {
869 case 0x0:
870 b->ref_clk = 240;
871 break;
872 case 0x1:
873 b->ref_clk = 192;
874 break;
875 case 0x2:
876 b->ref_clk = 384;
877 break;
878 default:
879 dev_warn(&isp->pdev->dev,
880 "Unsupported ref clock, use 19.2Mhz by default.\n");
881 b->ref_clk = 192;
882 break;
883 }
884
885 /* Retry couple of times in case of CSE initialization is delayed */
886 do {
887 ret = ipu6_buttress_ipc_reset(isp, &b->cse);
888 if (ret) {
889 dev_warn(&isp->pdev->dev,
890 "IPC reset protocol failed, retrying\n");
891 } else {
892 dev_dbg(&isp->pdev->dev, "IPC reset done\n");
893 return 0;
894 }
895 } while (ipc_reset_retry--);
896
897 dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
898
899 mutex_destroy(&b->power_mutex);
900 mutex_destroy(&b->auth_mutex);
901 mutex_destroy(&b->cons_mutex);
902 mutex_destroy(&b->ipc_mutex);
903
904 return ret;
905}
906
907void ipu6_buttress_exit(struct ipu6_device *isp)
908{
909 struct ipu6_buttress *b = &isp->buttress;
910
911 writel(0, isp->base + BUTTRESS_REG_ISR_ENABLE);
912
913 mutex_destroy(&b->power_mutex);
914 mutex_destroy(&b->auth_mutex);
915 mutex_destroy(&b->cons_mutex);
916 mutex_destroy(&b->ipc_mutex);
917}
drivers/media/pci/intel/ipu6/ipu6-buttress.h+92−0
@@ -0,0 +1,92 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_BUTTRESS_H
5#define IPU6_BUTTRESS_H
6
7#include <linux/completion.h>
8#include <linux/irqreturn.h>
9#include <linux/list.h>
10#include <linux/mutex.h>
11
12struct device;
13struct firmware;
14struct ipu6_device;
15struct ipu6_bus_device;
16
17#define BUTTRESS_PS_FREQ_STEP 25U
18#define BUTTRESS_MIN_FORCE_PS_FREQ (BUTTRESS_PS_FREQ_STEP * 8)
19#define BUTTRESS_MAX_FORCE_PS_FREQ (BUTTRESS_PS_FREQ_STEP * 32)
20
21#define BUTTRESS_IS_FREQ_STEP 25U
22#define BUTTRESS_MIN_FORCE_IS_FREQ (BUTTRESS_IS_FREQ_STEP * 8)
23#define BUTTRESS_MAX_FORCE_IS_FREQ (BUTTRESS_IS_FREQ_STEP * 22)
24
25struct ipu6_buttress_ctrl {
26 u32 freq_ctl, pwr_sts_shift, pwr_sts_mask, pwr_sts_on, pwr_sts_off;
27 unsigned int ratio;
28 unsigned int qos_floor;
29 bool started;
30};
31
32struct ipu6_buttress_ipc {
33 struct completion send_complete;
34 struct completion recv_complete;
35 u32 nack;
36 u32 nack_mask;
37 u32 recv_data;
38 u32 csr_out;
39 u32 csr_in;
40 u32 db0_in;
41 u32 db0_out;
42 u32 data0_out;
43 u32 data0_in;
44};
45
46struct ipu6_buttress {
47 struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
48 struct ipu6_buttress_ipc cse;
49 struct ipu6_buttress_ipc ish;
50 struct list_head constraints;
51 u32 wdt_cached_value;
52 bool force_suspend;
53 u32 ref_clk;
54};
55
56enum ipu6_buttress_ipc_domain {
57 IPU6_BUTTRESS_IPC_CSE,
58 IPU6_BUTTRESS_IPC_ISH,
59};
60
61struct ipu6_ipc_buttress_bulk_msg {
62 u32 cmd;
63 u32 expected_resp;
64 bool require_resp;
65 u8 cmd_size;
66};
67
68int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
69 struct ipu6_buttress_ipc *ipc);
70int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
71 const struct firmware *fw,
72 struct sg_table *sgt);
73void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
74 struct sg_table *sgt);
75int ipu6_buttress_power(struct device *dev, struct ipu6_buttress_ctrl *ctrl,
76 bool on);
77bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp);
78int ipu6_buttress_authenticate(struct ipu6_device *isp);
79int ipu6_buttress_reset_authentication(struct ipu6_device *isp);
80bool ipu6_buttress_auth_done(struct ipu6_device *isp);
81int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp);
82void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val);
83u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp);
84
85irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr);
86irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr);
87int ipu6_buttress_init(struct ipu6_device *isp);
88void ipu6_buttress_exit(struct ipu6_device *isp);
89void ipu6_buttress_csi_port_config(struct ipu6_device *isp,
90 u32 legacy, u32 combo);
91void ipu6_buttress_restore(struct ipu6_device *isp);
92#endif /* IPU6_BUTTRESS_H */
drivers/media/pci/intel/ipu6/ipu6-cpd.c+362−0
@@ -0,0 +1,362 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/err.h>
9#include <linux/dma-mapping.h>
10#include <linux/gfp_types.h>
11#include <linux/math64.h>
12#include <linux/sizes.h>
13#include <linux/types.h>
14
15#include "ipu6.h"
16#include "ipu6-bus.h"
17#include "ipu6-cpd.h"
18
19/* 15 entries + header*/
20#define MAX_PKG_DIR_ENT_CNT 16
21/* 2 qword per entry/header */
22#define PKG_DIR_ENT_LEN 2
23/* PKG_DIR size in bytes */
24#define PKG_DIR_SIZE ((MAX_PKG_DIR_ENT_CNT) * \
25 (PKG_DIR_ENT_LEN) * sizeof(u64))
26/* _IUPKDR_ */
27#define PKG_DIR_HDR_MARK 0x5f4955504b44525fULL
28
29/* $CPD */
30#define CPD_HDR_MARK 0x44504324
31
32#define MAX_MANIFEST_SIZE (SZ_2K * sizeof(u32))
33#define MAX_METADATA_SIZE SZ_64K
34
35#define MAX_COMPONENT_ID 127
36#define MAX_COMPONENT_VERSION 0xffff
37
38#define MANIFEST_IDX 0
39#define METADATA_IDX 1
40#define MODULEDATA_IDX 2
41/*
42 * PKG_DIR Entry (type == id)
43 * 63:56 55 54:48 47:32 31:24 23:0
44 * Rsvd Rsvd Type Version Rsvd Size
45 */
46#define PKG_DIR_SIZE_MASK GENMASK(23, 0)
47#define PKG_DIR_VERSION_MASK GENMASK(47, 32)
48#define PKG_DIR_TYPE_MASK GENMASK(54, 48)
49
50static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd,
51 u8 idx)
52{
53 const struct ipu6_cpd_hdr *cpd_hdr = cpd;
54 const struct ipu6_cpd_ent *ent;
55
56 ent = (const struct ipu6_cpd_ent *)((const u8 *)cpd + cpd_hdr->hdr_len);
57 return ent + idx;
58}
59
60#define ipu6_cpd_get_manifest(cpd) ipu6_cpd_get_entry(cpd, MANIFEST_IDX)
61#define ipu6_cpd_get_metadata(cpd) ipu6_cpd_get_entry(cpd, METADATA_IDX)
62#define ipu6_cpd_get_moduledata(cpd) ipu6_cpd_get_entry(cpd, MODULEDATA_IDX)
63
64static const struct ipu6_cpd_metadata_cmpnt_hdr *
65ipu6_cpd_metadata_get_cmpnt(struct ipu6_device *isp, const void *metadata,
66 unsigned int metadata_size, u8 idx)
67{
68 size_t extn_size = sizeof(struct ipu6_cpd_metadata_extn);
69 size_t cmpnt_count = metadata_size - extn_size;
70
71 cmpnt_count = div_u64(cmpnt_count, isp->cpd_metadata_cmpnt_size);
72
73 if (idx > MAX_COMPONENT_ID || idx >= cmpnt_count) {
74 dev_err(&isp->pdev->dev, "Component index out of range (%d)\n",
75 idx);
76 return ERR_PTR(-EINVAL);
77 }
78
79 return metadata + extn_size + idx * isp->cpd_metadata_cmpnt_size;
80}
81
82static u32 ipu6_cpd_metadata_cmpnt_version(struct ipu6_device *isp,
83 const void *metadata,
84 unsigned int metadata_size, u8 idx)
85{
86 const struct ipu6_cpd_metadata_cmpnt_hdr *cmpnt;
87
88 cmpnt = ipu6_cpd_metadata_get_cmpnt(isp, metadata, metadata_size, idx);
89 if (IS_ERR(cmpnt))
90 return PTR_ERR(cmpnt);
91
92 return cmpnt->ver;
93}
94
95static int ipu6_cpd_metadata_get_cmpnt_id(struct ipu6_device *isp,
96 const void *metadata,
97 unsigned int metadata_size, u8 idx)
98{
99 const struct ipu6_cpd_metadata_cmpnt_hdr *cmpnt;
100
101 cmpnt = ipu6_cpd_metadata_get_cmpnt(isp, metadata, metadata_size, idx);
102 if (IS_ERR(cmpnt))
103 return PTR_ERR(cmpnt);
104
105 return cmpnt->id;
106}
107
108static int ipu6_cpd_parse_module_data(struct ipu6_device *isp,
109 const void *module_data,
110 unsigned int module_data_size,
111 dma_addr_t dma_addr_module_data,
112 u64 *pkg_dir, const void *metadata,
113 unsigned int metadata_size)
114{
115 const struct ipu6_cpd_module_data_hdr *module_data_hdr;
116 const struct ipu6_cpd_hdr *dir_hdr;
117 const struct ipu6_cpd_ent *dir_ent;
118 unsigned int i;
119 u8 len;
120
121 if (!module_data)
122 return -EINVAL;
123
124 module_data_hdr = module_data;
125 dir_hdr = module_data + module_data_hdr->hdr_len;
126 len = dir_hdr->hdr_len;
127 dir_ent = (const struct ipu6_cpd_ent *)(((u8 *)dir_hdr) + len);
128
129 pkg_dir[0] = PKG_DIR_HDR_MARK;
130 /* pkg_dir entry count = component count + pkg_dir header */
131 pkg_dir[1] = dir_hdr->ent_cnt + 1;
132
133 for (i = 0; i < dir_hdr->ent_cnt; i++, dir_ent++) {
134 u64 *p = &pkg_dir[PKG_DIR_ENT_LEN * (1 + i)];
135 int ver, id;
136
137 *p++ = dma_addr_module_data + dir_ent->offset;
138 id = ipu6_cpd_metadata_get_cmpnt_id(isp, metadata,
139 metadata_size, i);
140 if (id < 0 || id > MAX_COMPONENT_ID) {
141 dev_err(&isp->pdev->dev, "Invalid CPD component id\n");
142 return -EINVAL;
143 }
144
145 ver = ipu6_cpd_metadata_cmpnt_version(isp, metadata,
146 metadata_size, i);
147 if (ver < 0 || ver > MAX_COMPONENT_VERSION) {
148 dev_err(&isp->pdev->dev,
149 "Invalid CPD component version\n");
150 return -EINVAL;
151 }
152
153 *p = FIELD_PREP(PKG_DIR_SIZE_MASK, dir_ent->len) |
154 FIELD_PREP(PKG_DIR_TYPE_MASK, id) |
155 FIELD_PREP(PKG_DIR_VERSION_MASK, ver);
156 }
157
158 return 0;
159}
160
161int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
162{
163 dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl);
164 const struct ipu6_cpd_ent *ent, *man_ent, *met_ent;
165 struct device *dev = &adev->auxdev.dev;
166 struct ipu6_device *isp = adev->isp;
167 unsigned int man_sz, met_sz;
168 void *pkg_dir_pos;
169 int ret;
170
171 man_ent = ipu6_cpd_get_manifest(src);
172 man_sz = man_ent->len;
173
174 met_ent = ipu6_cpd_get_metadata(src);
175 met_sz = met_ent->len;
176
177 adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz;
178 adev->pkg_dir = dma_alloc_attrs(dev, adev->pkg_dir_size,
179 &adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
180 if (!adev->pkg_dir)
181 return -ENOMEM;
182
183 /*
184 * pkg_dir entry/header:
185 * qword | 63:56 | 55 | 54:48 | 47:32 | 31:24 | 23:0
186 * N Address/Offset/"_IUPKDR_"
187 * N + 1 | rsvd | rsvd | type | ver | rsvd | size
188 *
189 * We can ignore other fields that size in N + 1 qword as they
190 * are 0 anyway. Just setting size for now.
191 */
192
193 ent = ipu6_cpd_get_moduledata(src);
194
195 ret = ipu6_cpd_parse_module_data(isp, src + ent->offset,
196 ent->len, dma_addr_src + ent->offset,
197 adev->pkg_dir, src + met_ent->offset,
198 met_ent->len);
199 if (ret) {
200 dev_err(&isp->pdev->dev, "Failed to parse module data\n");
201 dma_free_attrs(dev, adev->pkg_dir_size,
202 adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
203 return ret;
204 }
205
206 /* Copy manifest after pkg_dir */
207 pkg_dir_pos = adev->pkg_dir + PKG_DIR_ENT_LEN * MAX_PKG_DIR_ENT_CNT;
208 memcpy(pkg_dir_pos, src + man_ent->offset, man_sz);
209
210 /* Copy metadata after manifest */
211 pkg_dir_pos += man_sz;
212 memcpy(pkg_dir_pos, src + met_ent->offset, met_sz);
213
214 dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr,
215 0, adev->pkg_dir_size, DMA_TO_DEVICE);
216
217 return 0;
218}
219EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, INTEL_IPU6);
220
221void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
222{
223 dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir,
224 adev->pkg_dir_dma_addr, 0);
225}
226EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6);
227
228static int ipu6_cpd_validate_cpd(struct ipu6_device *isp, const void *cpd,
229 unsigned long cpd_size,
230 unsigned long data_size)
231{
232 const struct ipu6_cpd_hdr *cpd_hdr = cpd;
233 const struct ipu6_cpd_ent *ent;
234 unsigned int i;
235 u8 len;
236
237 len = cpd_hdr->hdr_len;
238
239 /* Ensure cpd hdr is within moduledata */
240 if (cpd_size < len) {
241 dev_err(&isp->pdev->dev, "Invalid CPD moduledata size\n");
242 return -EINVAL;
243 }
244
245 /* Sanity check for CPD header */
246 if ((cpd_size - len) / sizeof(*ent) < cpd_hdr->ent_cnt) {
247 dev_err(&isp->pdev->dev, "Invalid CPD header\n");
248 return -EINVAL;
249 }
250
251 /* Ensure that all entries are within moduledata */
252 ent = (const struct ipu6_cpd_ent *)(((const u8 *)cpd_hdr) + len);
253 for (i = 0; i < cpd_hdr->ent_cnt; i++, ent++) {
254 if (data_size < ent->offset ||
255 data_size - ent->offset < ent->len) {
256 dev_err(&isp->pdev->dev, "Invalid CPD entry (%d)\n", i);
257 return -EINVAL;
258 }
259 }
260
261 return 0;
262}
263
264static int ipu6_cpd_validate_moduledata(struct ipu6_device *isp,
265 const void *moduledata,
266 u32 moduledata_size)
267{
268 const struct ipu6_cpd_module_data_hdr *mod_hdr = moduledata;
269 int ret;
270
271 /* Ensure moduledata hdr is within moduledata */
272 if (moduledata_size < sizeof(*mod_hdr) ||
273 moduledata_size < mod_hdr->hdr_len) {
274 dev_err(&isp->pdev->dev, "Invalid CPD moduledata size\n");
275 return -EINVAL;
276 }
277
278 dev_info(&isp->pdev->dev, "FW version: %x\n", mod_hdr->fw_pkg_date);
279 ret = ipu6_cpd_validate_cpd(isp, moduledata + mod_hdr->hdr_len,
280 moduledata_size - mod_hdr->hdr_len,
281 moduledata_size);
282 if (ret) {
283 dev_err(&isp->pdev->dev, "Invalid CPD in moduledata\n");
284 return ret;
285 }
286
287 return 0;
288}
289
290static int ipu6_cpd_validate_metadata(struct ipu6_device *isp,
291 const void *metadata, u32 meta_size)
292{
293 const struct ipu6_cpd_metadata_extn *extn = metadata;
294
295 /* Sanity check for metadata size */
296 if (meta_size < sizeof(*extn) || meta_size > MAX_METADATA_SIZE) {
297 dev_err(&isp->pdev->dev, "Invalid CPD metadata\n");
298 return -EINVAL;
299 }
300
301 /* Validate extension and image types */
302 if (extn->extn_type != IPU6_CPD_METADATA_EXTN_TYPE_IUNIT ||
303 extn->img_type != IPU6_CPD_METADATA_IMAGE_TYPE_MAIN_FIRMWARE) {
304 dev_err(&isp->pdev->dev,
305 "Invalid CPD metadata descriptor img_type (%d)\n",
306 extn->img_type);
307 return -EINVAL;
308 }
309
310 /* Validate metadata size multiple of metadata components */
311 if ((meta_size - sizeof(*extn)) % isp->cpd_metadata_cmpnt_size) {
312 dev_err(&isp->pdev->dev, "Invalid CPD metadata size\n");
313 return -EINVAL;
314 }
315
316 return 0;
317}
318
319int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
320 unsigned long cpd_file_size)
321{
322 const struct ipu6_cpd_hdr *hdr = cpd_file;
323 const struct ipu6_cpd_ent *ent;
324 int ret;
325
326 ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
327 cpd_file_size);
328 if (ret) {
329 dev_err(&isp->pdev->dev, "Invalid CPD in file\n");
330 return ret;
331 }
332
333 /* Check for CPD file marker */
334 if (hdr->hdr_mark != CPD_HDR_MARK) {
335 dev_err(&isp->pdev->dev, "Invalid CPD header\n");
336 return -EINVAL;
337 }
338
339 /* Sanity check for manifest size */
340 ent = ipu6_cpd_get_manifest(cpd_file);
341 if (ent->len > MAX_MANIFEST_SIZE) {
342 dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
343 return -EINVAL;
344 }
345
346 /* Validate metadata */
347 ent = ipu6_cpd_get_metadata(cpd_file);
348 ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
349 if (ret) {
350 dev_err(&isp->pdev->dev, "Invalid CPD metadata\n");
351 return ret;
352 }
353
354 /* Validate moduledata */
355 ent = ipu6_cpd_get_moduledata(cpd_file);
356 ret = ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
357 ent->len);
358 if (ret)
359 dev_err(&isp->pdev->dev, "Invalid CPD moduledata\n");
360
361 return ret;
362}
drivers/media/pci/intel/ipu6/ipu6-cpd.h+105−0
@@ -0,0 +1,105 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2015--2024 Intel Corporation */
3
4#ifndef IPU6_CPD_H
5#define IPU6_CPD_H
6
7struct ipu6_device;
8struct ipu6_bus_device;
9
10#define IPU6_CPD_SIZE_OF_FW_ARCH_VERSION 7
11#define IPU6_CPD_SIZE_OF_SYSTEM_VERSION 11
12#define IPU6_CPD_SIZE_OF_COMPONENT_NAME 12
13
14#define IPU6_CPD_METADATA_EXTN_TYPE_IUNIT 0x10
15
16#define IPU6_CPD_METADATA_IMAGE_TYPE_RESERVED 0
17#define IPU6_CPD_METADATA_IMAGE_TYPE_BOOTLOADER 1
18#define IPU6_CPD_METADATA_IMAGE_TYPE_MAIN_FIRMWARE 2
19
20#define IPU6_CPD_PKG_DIR_PSYS_SERVER_IDX 0
21#define IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX 1
22
23#define IPU6_CPD_PKG_DIR_CLIENT_PG_TYPE 3
24
25#define IPU6_CPD_METADATA_HASH_KEY_SIZE 48
26#define IPU6SE_CPD_METADATA_HASH_KEY_SIZE 32
27
28struct ipu6_cpd_module_data_hdr {
29 u32 hdr_len;
30 u32 endian;
31 u32 fw_pkg_date;
32 u32 hive_sdk_date;
33 u32 compiler_date;
34 u32 target_platform_type;
35 u8 sys_ver[IPU6_CPD_SIZE_OF_SYSTEM_VERSION];
36 u8 fw_arch_ver[IPU6_CPD_SIZE_OF_FW_ARCH_VERSION];
37 u8 rsvd[2];
38} __packed;
39
40/*
41 * ipu6_cpd_hdr structure updated as the chksum and
42 * sub_partition_name is unused on host side
43 * CSE layout version 1.6 for IPU6SE (hdr_len = 0x10)
44 * CSE layout version 1.7 for IPU6 (hdr_len = 0x14)
45 */
46struct ipu6_cpd_hdr {
47 u32 hdr_mark;
48 u32 ent_cnt;
49 u8 hdr_ver;
50 u8 ent_ver;
51 u8 hdr_len;
52} __packed;
53
54struct ipu6_cpd_ent {
55 u8 name[IPU6_CPD_SIZE_OF_COMPONENT_NAME];
56 u32 offset;
57 u32 len;
58 u8 rsvd[4];
59} __packed;
60
61struct ipu6_cpd_metadata_cmpnt_hdr {
62 u32 id;
63 u32 size;
64 u32 ver;
65} __packed;
66
67struct ipu6_cpd_metadata_cmpnt {
68 struct ipu6_cpd_metadata_cmpnt_hdr hdr;
69 u8 sha2_hash[IPU6_CPD_METADATA_HASH_KEY_SIZE];
70 u32 entry_point;
71 u32 icache_base_offs;
72 u8 attrs[16];
73} __packed;
74
75struct ipu6se_cpd_metadata_cmpnt {
76 struct ipu6_cpd_metadata_cmpnt_hdr hdr;
77 u8 sha2_hash[IPU6SE_CPD_METADATA_HASH_KEY_SIZE];
78 u32 entry_point;
79 u32 icache_base_offs;
80 u8 attrs[16];
81} __packed;
82
83struct ipu6_cpd_metadata_extn {
84 u32 extn_type;
85 u32 len;
86 u32 img_type;
87 u8 rsvd[16];
88} __packed;
89
90struct ipu6_cpd_client_pkg_hdr {
91 u32 prog_list_offs;
92 u32 prog_list_size;
93 u32 prog_desc_offs;
94 u32 prog_desc_size;
95 u32 pg_manifest_offs;
96 u32 pg_manifest_size;
97 u32 prog_bin_offs;
98 u32 prog_bin_size;
99} __packed;
100
101int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src);
102void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev);
103int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
104 unsigned long cpd_file_size);
105#endif /* IPU6_CPD_H */
drivers/media/pci/intel/ipu6/ipu6-dma.c+502−0
@@ -0,0 +1,502 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/cacheflush.h>
7#include <linux/dma-mapping.h>
8#include <linux/iova.h>
9#include <linux/list.h>
10#include <linux/mm.h>
11#include <linux/vmalloc.h>
12#include <linux/scatterlist.h>
13#include <linux/slab.h>
14#include <linux/types.h>
15
16#include "ipu6.h"
17#include "ipu6-bus.h"
18#include "ipu6-dma.h"
19#include "ipu6-mmu.h"
20
21struct vm_info {
22 struct list_head list;
23 struct page **pages;
24 dma_addr_t ipu6_iova;
25 void *vaddr;
26 unsigned long size;
27};
28
29static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova)
30{
31 struct vm_info *info, *save;
32
33 list_for_each_entry_safe(info, save, &mmu->vma_list, list) {
34 if (iova >= info->ipu6_iova &&
35 iova < (info->ipu6_iova + info->size))
36 return info;
37 }
38
39 return NULL;
40}
41
42static void __dma_clear_buffer(struct page *page, size_t size,
43 unsigned long attrs)
44{
45 void *ptr;
46
47 if (!page)
48 return;
49 /*
50 * Ensure that the allocated pages are zeroed, and that any data
51 * lurking in the kernel direct-mapped region is invalidated.
52 */
53 ptr = page_address(page);
54 memset(ptr, 0, size);
55 if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
56 clflush_cache_range(ptr, size);
57}
58
59static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
60 gfp_t gfp, unsigned long attrs)
61{
62 int count = PHYS_PFN(size);
63 int array_size = count * sizeof(struct page *);
64 struct page **pages;
65 int i = 0;
66
67 pages = kvzalloc(array_size, GFP_KERNEL);
68 if (!pages)
69 return NULL;
70
71 gfp |= __GFP_NOWARN;
72
73 while (count) {
74 int j, order = __fls(count);
75
76 pages[i] = alloc_pages(gfp, order);
77 while (!pages[i] && order)
78 pages[i] = alloc_pages(gfp, --order);
79 if (!pages[i])
80 goto error;
81
82 if (order) {
83 split_page(pages[i], order);
84 j = 1 << order;
85 while (j--)
86 pages[i + j] = pages[i] + j;
87 }
88
89 __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs);
90 i += 1 << order;
91 count -= 1 << order;
92 }
93
94 return pages;
95error:
96 while (i--)
97 if (pages[i])
98 __free_pages(pages[i], 0);
99 kvfree(pages);
100 return NULL;
101}
102
103static void __dma_free_buffer(struct device *dev, struct page **pages,
104 size_t size, unsigned long attrs)
105{
106 int count = PHYS_PFN(size);
107 unsigned int i;
108
109 for (i = 0; i < count && pages[i]; i++) {
110 __dma_clear_buffer(pages[i], PAGE_SIZE, attrs);
111 __free_pages(pages[i], 0);
112 }
113
114 kvfree(pages);
115}
116
117static void ipu6_dma_sync_single_for_cpu(struct device *dev,
118 dma_addr_t dma_handle,
119 size_t size,
120 enum dma_data_direction dir)
121{
122 void *vaddr;
123 u32 offset;
124 struct vm_info *info;
125 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
126
127 info = get_vm_info(mmu, dma_handle);
128 if (WARN_ON(!info))
129 return;
130
131 offset = dma_handle - info->ipu6_iova;
132 if (WARN_ON(size > (info->size - offset)))
133 return;
134
135 vaddr = info->vaddr + offset;
136 clflush_cache_range(vaddr, size);
137}
138
139static void ipu6_dma_sync_sg_for_cpu(struct device *dev,
140 struct scatterlist *sglist,
141 int nents, enum dma_data_direction dir)
142{
143 struct scatterlist *sg;
144 int i;
145
146 for_each_sg(sglist, sg, nents, i)
147 clflush_cache_range(page_to_virt(sg_page(sg)), sg->length);
148}
149
150static void *ipu6_dma_alloc(struct device *dev, size_t size,
151 dma_addr_t *dma_handle, gfp_t gfp,
152 unsigned long attrs)
153{
154 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
155 struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
156 dma_addr_t pci_dma_addr, ipu6_iova;
157 struct vm_info *info;
158 unsigned long count;
159 struct page **pages;
160 struct iova *iova;
161 unsigned int i;
162 int ret;
163
164 info = kzalloc(sizeof(*info), GFP_KERNEL);
165 if (!info)
166 return NULL;
167
168 size = PAGE_ALIGN(size);
169 count = PHYS_PFN(size);
170
171 iova = alloc_iova(&mmu->dmap->iovad, count,
172 PHYS_PFN(dma_get_mask(dev)), 0);
173 if (!iova)
174 goto out_kfree;
175
176 pages = __dma_alloc_buffer(dev, size, gfp, attrs);
177 if (!pages)
178 goto out_free_iova;
179
180 dev_dbg(dev, "dma_alloc: size %zu iova low pfn %lu, high pfn %lu\n",
181 size, iova->pfn_lo, iova->pfn_hi);
182 for (i = 0; iova->pfn_lo + i <= iova->pfn_hi; i++) {
183 pci_dma_addr = dma_map_page_attrs(&pdev->dev, pages[i], 0,
184 PAGE_SIZE, DMA_BIDIRECTIONAL,
185 attrs);
186 dev_dbg(dev, "dma_alloc: mapped pci_dma_addr %pad\n",
187 &pci_dma_addr);
188 if (dma_mapping_error(&pdev->dev, pci_dma_addr)) {
189 dev_err(dev, "pci_dma_mapping for page[%d] failed", i);
190 goto out_unmap;
191 }
192
193 ret = ipu6_mmu_map(mmu->dmap->mmu_info,
194 PFN_PHYS(iova->pfn_lo + i), pci_dma_addr,
195 PAGE_SIZE);
196 if (ret) {
197 dev_err(dev, "ipu6_mmu_map for pci_dma[%d] %pad failed",
198 i, &pci_dma_addr);
199 dma_unmap_page_attrs(&pdev->dev, pci_dma_addr,
200 PAGE_SIZE, DMA_BIDIRECTIONAL,
201 attrs);
202 goto out_unmap;
203 }
204 }
205
206 info->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL);
207 if (!info->vaddr)
208 goto out_unmap;
209
210 *dma_handle = PFN_PHYS(iova->pfn_lo);
211
212 info->pages = pages;
213 info->ipu6_iova = *dma_handle;
214 info->size = size;
215 list_add(&info->list, &mmu->vma_list);
216
217 return info->vaddr;
218
219out_unmap:
220 while (i--) {
221 ipu6_iova = PFN_PHYS(iova->pfn_lo + i);
222 pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
223 ipu6_iova);
224 dma_unmap_page_attrs(&pdev->dev, pci_dma_addr, PAGE_SIZE,
225 DMA_BIDIRECTIONAL, attrs);
226
227 ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE);
228 }
229
230 __dma_free_buffer(dev, pages, size, attrs);
231
232out_free_iova:
233 __free_iova(&mmu->dmap->iovad, iova);
234out_kfree:
235 kfree(info);
236
237 return NULL;
238}
239
240static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
241 dma_addr_t dma_handle,
242 unsigned long attrs)
243{
244 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
245 struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
246 struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle));
247 dma_addr_t pci_dma_addr, ipu6_iova;
248 struct vm_info *info;
249 struct page **pages;
250 unsigned int i;
251
252 if (WARN_ON(!iova))
253 return;
254
255 info = get_vm_info(mmu, dma_handle);
256 if (WARN_ON(!info))
257 return;
258
259 if (WARN_ON(!info->vaddr))
260 return;
261
262 if (WARN_ON(!info->pages))
263 return;
264
265 list_del(&info->list);
266
267 size = PAGE_ALIGN(size);
268
269 pages = info->pages;
270
271 vunmap(vaddr);
272
273 for (i = 0; i < PHYS_PFN(size); i++) {
274 ipu6_iova = PFN_PHYS(iova->pfn_lo + i);
275 pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
276 ipu6_iova);
277 dma_unmap_page_attrs(&pdev->dev, pci_dma_addr, PAGE_SIZE,
278 DMA_BIDIRECTIONAL, attrs);
279 }
280
281 ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
282 PFN_PHYS(iova_size(iova)));
283
284 __dma_free_buffer(dev, pages, size, attrs);
285
286 mmu->tlb_invalidate(mmu);
287
288 __free_iova(&mmu->dmap->iovad, iova);
289
290 kfree(info);
291}
292
293static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
294 void *addr, dma_addr_t iova, size_t size,
295 unsigned long attrs)
296{
297 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
298 size_t count = PHYS_PFN(PAGE_ALIGN(size));
299 struct vm_info *info;
300 size_t i;
301 int ret;
302
303 info = get_vm_info(mmu, iova);
304 if (!info)
305 return -EFAULT;
306
307 if (!info->vaddr)
308 return -EFAULT;
309
310 if (vma->vm_start & ~PAGE_MASK)
311 return -EINVAL;
312
313 if (size > info->size)
314 return -EFAULT;
315
316 for (i = 0; i < count; i++) {
317 ret = vm_insert_page(vma, vma->vm_start + PFN_PHYS(i),
318 info->pages[i]);
319 if (ret < 0)
320 return ret;
321 }
322
323 return 0;
324}
325
326static void ipu6_dma_unmap_sg(struct device *dev,
327 struct scatterlist *sglist,
328 int nents, enum dma_data_direction dir,
329 unsigned long attrs)
330{
331 struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
332 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
333 struct iova *iova = find_iova(&mmu->dmap->iovad,
334 PHYS_PFN(sg_dma_address(sglist)));
335 int i, npages, count;
336 struct scatterlist *sg;
337 dma_addr_t pci_dma_addr;
338
339 if (!nents)
340 return;
341
342 if (WARN_ON(!iova))
343 return;
344
345 if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
346 ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
347
348 /* get the nents as orig_nents given by caller */
349 count = 0;
350 npages = iova_size(iova);
351 for_each_sg(sglist, sg, nents, i) {
352 if (sg_dma_len(sg) == 0 ||
353 sg_dma_address(sg) == DMA_MAPPING_ERROR)
354 break;
355
356 npages -= PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
357 count++;
358 if (npages <= 0)
359 break;
360 }
361
362 /*
363 * Before IPU6 mmu unmap, return the pci dma address back to sg
364 * assume the nents is less than orig_nents as the least granule
365 * is 1 SZ_4K page
366 */
367 dev_dbg(dev, "trying to unmap concatenated %u ents\n", count);
368 for_each_sg(sglist, sg, count, i) {
369 dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg));
370 pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
371 sg_dma_address(sg));
372 dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n",
373 &pci_dma_addr, i);
374 sg_dma_address(sg) = pci_dma_addr;
375 }
376
377 dev_dbg(dev, "ipu6_mmu_unmap low pfn %lu high pfn %lu\n",
378 iova->pfn_lo, iova->pfn_hi);
379 ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
380 PFN_PHYS(iova_size(iova)));
381
382 mmu->tlb_invalidate(mmu);
383
384 dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
385
386 __free_iova(&mmu->dmap->iovad, iova);
387}
388
389static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
390 int nents, enum dma_data_direction dir,
391 unsigned long attrs)
392{
393 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
394 struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
395 struct scatterlist *sg;
396 struct iova *iova;
397 size_t npages = 0;
398 unsigned long iova_addr;
399 int i, count;
400
401 for_each_sg(sglist, sg, nents, i) {
402 if (sg->offset) {
403 dev_err(dev, "Unsupported non-zero sg[%d].offset %x\n",
404 i, sg->offset);
405 return -EFAULT;
406 }
407 }
408
409 dev_dbg(dev, "pci_dma_map_sg trying to map %d ents\n", nents);
410 count = dma_map_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
411 if (count <= 0) {
412 dev_err(dev, "pci_dma_map_sg %d ents failed\n", nents);
413 return 0;
414 }
415
416 dev_dbg(dev, "pci_dma_map_sg %d ents mapped\n", count);
417
418 for_each_sg(sglist, sg, count, i)
419 npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
420
421 iova = alloc_iova(&mmu->dmap->iovad, npages,
422 PHYS_PFN(dma_get_mask(dev)), 0);
423 if (!iova)
424 return 0;
425
426 dev_dbg(dev, "dmamap: iova low pfn %lu, high pfn %lu\n", iova->pfn_lo,
427 iova->pfn_hi);
428
429 iova_addr = iova->pfn_lo;
430 for_each_sg(sglist, sg, count, i) {
431 int ret;
432
433 dev_dbg(dev, "mapping entry %d: iova 0x%llx phy %pad size %d\n",
434 i, PFN_PHYS(iova_addr), &sg_dma_address(sg),
435 sg_dma_len(sg));
436
437 ret = ipu6_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr),
438 sg_dma_address(sg),
439 PAGE_ALIGN(sg_dma_len(sg)));
440 if (ret)
441 goto out_fail;
442
443 sg_dma_address(sg) = PFN_PHYS(iova_addr);
444
445 iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
446 }
447
448 if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
449 ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
450
451 return count;
452
453out_fail:
454 ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs);
455
456 return 0;
457}
458
459/*
460 * Create scatter-list for the already allocated DMA buffer
461 */
462static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
463 void *cpu_addr, dma_addr_t handle, size_t size,
464 unsigned long attrs)
465{
466 struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
467 struct vm_info *info;
468 int n_pages;
469 int ret = 0;
470
471 info = get_vm_info(mmu, handle);
472 if (!info)
473 return -EFAULT;
474
475 if (!info->vaddr)
476 return -EFAULT;
477
478 if (WARN_ON(!info->pages))
479 return -ENOMEM;
480
481 n_pages = PHYS_PFN(PAGE_ALIGN(size));
482
483 ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size,
484 GFP_KERNEL);
485 if (ret)
486 dev_warn(dev, "IPU6 get sgt table failed\n");
487
488 return ret;
489}
490
491const struct dma_map_ops ipu6_dma_ops = {
492 .alloc = ipu6_dma_alloc,
493 .free = ipu6_dma_free,
494 .mmap = ipu6_dma_mmap,
495 .map_sg = ipu6_dma_map_sg,
496 .unmap_sg = ipu6_dma_unmap_sg,
497 .sync_single_for_cpu = ipu6_dma_sync_single_for_cpu,
498 .sync_single_for_device = ipu6_dma_sync_single_for_cpu,
499 .sync_sg_for_cpu = ipu6_dma_sync_sg_for_cpu,
500 .sync_sg_for_device = ipu6_dma_sync_sg_for_cpu,
501 .get_sgtable = ipu6_dma_get_sgtable,
502};
drivers/media/pci/intel/ipu6/ipu6-dma.h+19−0
@@ -0,0 +1,19 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_DMA_H
5#define IPU6_DMA_H
6
7#include <linux/dma-map-ops.h>
8#include <linux/iova.h>
9
10struct ipu6_mmu_info;
11
12struct ipu6_dma_mapping {
13 struct ipu6_mmu_info *mmu_info;
14 struct iova_domain iovad;
15};
16
17extern const struct dma_map_ops ipu6_dma_ops;
18
19#endif /* IPU6_DMA_H */
drivers/media/pci/intel/ipu6/ipu6-fw-com.c+413−0
@@ -0,0 +1,413 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/device.h>
7#include <linux/dma-mapping.h>
8#include <linux/io.h>
9#include <linux/math.h>
10#include <linux/overflow.h>
11#include <linux/slab.h>
12#include <linux/types.h>
13
14#include "ipu6-bus.h"
15#include "ipu6-fw-com.h"
16
17/*
18 * FWCOM layer is a shared resource between FW and driver. It consist
19 * of token queues to both send and receive directions. Queue is simply
20 * an array of structures with read and write indexes to the queue.
21 * There are 1...n queues to both directions. Queues locates in
22 * system RAM and are mapped to ISP MMU so that both CPU and ISP can
23 * see the same buffer. Indexes are located in ISP DMEM so that FW code
24 * can poll those with very low latency and cost. CPU access to indexes is
25 * more costly but that happens only at message sending time and
26 * interrupt triggered message handling. CPU doesn't need to poll indexes.
27 * wr_reg / rd_reg are offsets to those dmem location. They are not
28 * the indexes itself.
29 */
30
31/* Shared structure between driver and FW - do not modify */
32struct ipu6_fw_sys_queue {
33 u64 host_address;
34 u32 vied_address;
35 u32 size;
36 u32 token_size;
37 u32 wr_reg; /* reg number in subsystem's regmem */
38 u32 rd_reg;
39 u32 _align;
40} __packed;
41
42struct ipu6_fw_sys_queue_res {
43 u64 host_address;
44 u32 vied_address;
45 u32 reg;
46} __packed;
47
48enum syscom_state {
49 /* Program load or explicit host setting should init to this */
50 SYSCOM_STATE_UNINIT = 0x57a7e000,
51 /* SP Syscom sets this when it is ready for use */
52 SYSCOM_STATE_READY = 0x57a7e001,
53 /* SP Syscom sets this when no more syscom accesses will happen */
54 SYSCOM_STATE_INACTIVE = 0x57a7e002,
55};
56
57enum syscom_cmd {
58 /* Program load or explicit host setting should init to this */
59 SYSCOM_COMMAND_UNINIT = 0x57a7f000,
60 /* Host Syscom requests syscom to become inactive */
61 SYSCOM_COMMAND_INACTIVE = 0x57a7f001,
62};
63
64/* firmware config: data that sent from the host to SP via DDR */
65/* Cell copies data into a context */
66
67struct ipu6_fw_syscom_config {
68 u32 firmware_address;
69
70 u32 num_input_queues;
71 u32 num_output_queues;
72
73 /* ISP pointers to an array of ipu6_fw_sys_queue structures */
74 u32 input_queue;
75 u32 output_queue;
76
77 /* ISYS / PSYS private data */
78 u32 specific_addr;
79 u32 specific_size;
80};
81
82struct ipu6_fw_com_context {
83 struct ipu6_bus_device *adev;
84 void __iomem *dmem_addr;
85 int (*cell_ready)(struct ipu6_bus_device *adev);
86 void (*cell_start)(struct ipu6_bus_device *adev);
87
88 void *dma_buffer;
89 dma_addr_t dma_addr;
90 unsigned int dma_size;
91 unsigned long attrs;
92
93 struct ipu6_fw_sys_queue *input_queue; /* array of host to SP queues */
94 struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */
95
96 u32 config_vied_addr;
97
98 unsigned int buttress_boot_offset;
99 void __iomem *base_addr;
100};
101
102#define FW_COM_WR_REG 0
103#define FW_COM_RD_REG 4
104
105#define REGMEM_OFFSET 0
106#define TUNIT_MAGIC_PATTERN 0x5a5a5a5a
107
108enum regmem_id {
109 /* pass pkg_dir address to SPC in non-secure mode */
110 PKG_DIR_ADDR_REG = 0,
111 /* Tunit CFG blob for secure - provided by host.*/
112 TUNIT_CFG_DWR_REG = 1,
113 /* syscom commands - modified by the host */
114 SYSCOM_COMMAND_REG = 2,
115 /* Store interrupt status - updated by SP */
116 SYSCOM_IRQ_REG = 3,
117 /* first syscom queue pointer register */
118 SYSCOM_QPR_BASE_REG = 4
119};
120
121#define BUTTRESS_FW_BOOT_PARAMS_0 0x4000
122#define BUTTRESS_FW_BOOT_PARAM_REG(base, offset, id) \
123 ((base) + BUTTRESS_FW_BOOT_PARAMS_0 + ((offset) + (id)) * 4)
124
125enum buttress_syscom_id {
126 /* pass syscom configuration to SPC */
127 SYSCOM_CONFIG_ID = 0,
128 /* syscom state - modified by SP */
129 SYSCOM_STATE_ID = 1,
130 /* syscom vtl0 addr mask */
131 SYSCOM_VTL0_ADDR_MASK_ID = 2,
132 SYSCOM_ID_MAX
133};
134
135static void ipu6_sys_queue_init(struct ipu6_fw_sys_queue *q, unsigned int size,
136 unsigned int token_size,
137 struct ipu6_fw_sys_queue_res *res)
138{
139 unsigned int buf_size = (size + 1) * token_size;
140
141 q->size = size + 1;
142 q->token_size = token_size;
143
144 /* acquire the shared buffer space */
145 q->host_address = res->host_address;
146 res->host_address += buf_size;
147 q->vied_address = res->vied_address;
148 res->vied_address += buf_size;
149
150 /* acquire the shared read and writer pointers */
151 q->wr_reg = res->reg;
152 res->reg++;
153 q->rd_reg = res->reg;
154 res->reg++;
155}
156
157void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
158 struct ipu6_bus_device *adev, void __iomem *base)
159{
160 size_t conf_size, inq_size, outq_size, specific_size;
161 struct ipu6_fw_syscom_config *config_host_addr;
162 unsigned int sizeinput = 0, sizeoutput = 0;
163 struct ipu6_fw_sys_queue_res res;
164 struct ipu6_fw_com_context *ctx;
165 struct device *dev = &adev->auxdev.dev;
166 size_t sizeall, offset;
167 unsigned long attrs = 0;
168 void *specific_host_addr;
169 unsigned int i;
170
171 if (!cfg || !cfg->cell_start || !cfg->cell_ready)
172 return NULL;
173
174 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
175 if (!ctx)
176 return NULL;
177 ctx->dmem_addr = base + cfg->dmem_addr + REGMEM_OFFSET;
178 ctx->adev = adev;
179 ctx->cell_start = cfg->cell_start;
180 ctx->cell_ready = cfg->cell_ready;
181 ctx->buttress_boot_offset = cfg->buttress_boot_offset;
182 ctx->base_addr = base;
183
184 /*
185 * Allocate DMA mapped memory. Allocate one big chunk.
186 */
187 /* Base cfg for FW */
188 conf_size = roundup(sizeof(struct ipu6_fw_syscom_config), 8);
189 /* Descriptions of the queues */
190 inq_size = size_mul(cfg->num_input_queues,
191 sizeof(struct ipu6_fw_sys_queue));
192 outq_size = size_mul(cfg->num_output_queues,
193 sizeof(struct ipu6_fw_sys_queue));
194 /* FW specific information structure */
195 specific_size = roundup(cfg->specific_size, 8);
196
197 sizeall = conf_size + inq_size + outq_size + specific_size;
198
199 for (i = 0; i < cfg->num_input_queues; i++)
200 sizeinput += size_mul(cfg->input[i].queue_size + 1,
201 cfg->input[i].token_size);
202
203 for (i = 0; i < cfg->num_output_queues; i++)
204 sizeoutput += size_mul(cfg->output[i].queue_size + 1,
205 cfg->output[i].token_size);
206
207 sizeall += sizeinput + sizeoutput;
208
209 ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr,
210 GFP_KERNEL, attrs);
211 ctx->attrs = attrs;
212 if (!ctx->dma_buffer) {
213 dev_err(dev, "failed to allocate dma memory\n");
214 kfree(ctx);
215 return NULL;
216 }
217
218 ctx->dma_size = sizeall;
219
220 config_host_addr = ctx->dma_buffer;
221 ctx->config_vied_addr = ctx->dma_addr;
222
223 offset = conf_size;
224 ctx->input_queue = ctx->dma_buffer + offset;
225 config_host_addr->input_queue = ctx->dma_addr + offset;
226 config_host_addr->num_input_queues = cfg->num_input_queues;
227
228 offset += inq_size;
229 ctx->output_queue = ctx->dma_buffer + offset;
230 config_host_addr->output_queue = ctx->dma_addr + offset;
231 config_host_addr->num_output_queues = cfg->num_output_queues;
232
233 /* copy firmware specific data */
234 offset += outq_size;
235 specific_host_addr = ctx->dma_buffer + offset;
236 config_host_addr->specific_addr = ctx->dma_addr + offset;
237 config_host_addr->specific_size = cfg->specific_size;
238 if (cfg->specific_addr && cfg->specific_size)
239 memcpy(specific_host_addr, cfg->specific_addr,
240 cfg->specific_size);
241
242 /* initialize input queues */
243 offset += specific_size;
244 res.reg = SYSCOM_QPR_BASE_REG;
245 res.host_address = (u64)(ctx->dma_buffer + offset);
246 res.vied_address = ctx->dma_addr + offset;
247 for (i = 0; i < cfg->num_input_queues; i++)
248 ipu6_sys_queue_init(ctx->input_queue + i,
249 cfg->input[i].queue_size,
250 cfg->input[i].token_size, &res);
251
252 /* initialize output queues */
253 offset += sizeinput;
254 res.host_address = (u64)(ctx->dma_buffer + offset);
255 res.vied_address = ctx->dma_addr + offset;
256 for (i = 0; i < cfg->num_output_queues; i++) {
257 ipu6_sys_queue_init(ctx->output_queue + i,
258 cfg->output[i].queue_size,
259 cfg->output[i].token_size, &res);
260 }
261
262 return ctx;
263}
264EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_prepare, INTEL_IPU6);
265
266int ipu6_fw_com_open(struct ipu6_fw_com_context *ctx)
267{
268 /* write magic pattern to disable the tunit trace */
269 writel(TUNIT_MAGIC_PATTERN, ctx->dmem_addr + TUNIT_CFG_DWR_REG * 4);
270 /* Check if SP is in valid state */
271 if (!ctx->cell_ready(ctx->adev))
272 return -EIO;
273
274 /* store syscom uninitialized command */
275 writel(SYSCOM_COMMAND_UNINIT, ctx->dmem_addr + SYSCOM_COMMAND_REG * 4);
276
277 /* store syscom uninitialized state */
278 writel(SYSCOM_STATE_UNINIT,
279 BUTTRESS_FW_BOOT_PARAM_REG(ctx->base_addr,
280 ctx->buttress_boot_offset,
281 SYSCOM_STATE_ID));
282
283 /* store firmware configuration address */
284 writel(ctx->config_vied_addr,
285 BUTTRESS_FW_BOOT_PARAM_REG(ctx->base_addr,
286 ctx->buttress_boot_offset,
287 SYSCOM_CONFIG_ID));
288 ctx->cell_start(ctx->adev);
289
290 return 0;
291}
292EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_open, INTEL_IPU6);
293
294int ipu6_fw_com_close(struct ipu6_fw_com_context *ctx)
295{
296 int state;
297
298 state = readl(BUTTRESS_FW_BOOT_PARAM_REG(ctx->base_addr,
299 ctx->buttress_boot_offset,
300 SYSCOM_STATE_ID));
301 if (state != SYSCOM_STATE_READY)
302 return -EBUSY;
303
304 /* set close request flag */
305 writel(SYSCOM_COMMAND_INACTIVE, ctx->dmem_addr +
306 SYSCOM_COMMAND_REG * 4);
307
308 return 0;
309}
310EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_close, INTEL_IPU6);
311
312int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force)
313{
314 /* check if release is forced, an verify cell state if it is not */
315 if (!force && !ctx->cell_ready(ctx->adev))
316 return -EBUSY;
317
318 dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size,
319 ctx->dma_buffer, ctx->dma_addr, ctx->attrs);
320 kfree(ctx);
321 return 0;
322}
323EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_release, INTEL_IPU6);
324
325bool ipu6_fw_com_ready(struct ipu6_fw_com_context *ctx)
326{
327 int state;
328
329 state = readl(BUTTRESS_FW_BOOT_PARAM_REG(ctx->base_addr,
330 ctx->buttress_boot_offset,
331 SYSCOM_STATE_ID));
332
333 return state == SYSCOM_STATE_READY;
334}
335EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_ready, INTEL_IPU6);
336
337void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr)
338{
339 struct ipu6_fw_sys_queue *q = &ctx->input_queue[q_nbr];
340 void __iomem *q_dmem = ctx->dmem_addr + q->wr_reg * 4;
341 unsigned int wr, rd;
342 unsigned int packets;
343 unsigned int index;
344
345 wr = readl(q_dmem + FW_COM_WR_REG);
346 rd = readl(q_dmem + FW_COM_RD_REG);
347
348 if (WARN_ON_ONCE(wr >= q->size || rd >= q->size))
349 return NULL;
350
351 if (wr < rd)
352 packets = rd - wr - 1;
353 else
354 packets = q->size - (wr - rd + 1);
355
356 if (!packets)
357 return NULL;
358
359 index = readl(q_dmem + FW_COM_WR_REG);
360
361 return (void *)(q->host_address + index * q->token_size);
362}
363EXPORT_SYMBOL_NS_GPL(ipu6_send_get_token, INTEL_IPU6);
364
365void ipu6_send_put_token(struct ipu6_fw_com_context *ctx, int q_nbr)
366{
367 struct ipu6_fw_sys_queue *q = &ctx->input_queue[q_nbr];
368 void __iomem *q_dmem = ctx->dmem_addr + q->wr_reg * 4;
369 unsigned int wr = readl(q_dmem + FW_COM_WR_REG) + 1;
370
371 if (wr >= q->size)
372 wr = 0;
373
374 writel(wr, q_dmem + FW_COM_WR_REG);
375}
376EXPORT_SYMBOL_NS_GPL(ipu6_send_put_token, INTEL_IPU6);
377
378void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr)
379{
380 struct ipu6_fw_sys_queue *q = &ctx->output_queue[q_nbr];
381 void __iomem *q_dmem = ctx->dmem_addr + q->wr_reg * 4;
382 unsigned int wr, rd;
383 unsigned int packets;
384
385 wr = readl(q_dmem + FW_COM_WR_REG);
386 rd = readl(q_dmem + FW_COM_RD_REG);
387
388 if (WARN_ON_ONCE(wr >= q->size || rd >= q->size))
389 return NULL;
390
391 if (wr < rd)
392 wr += q->size;
393
394 packets = wr - rd;
395 if (!packets)
396 return NULL;
397
398 return (void *)(q->host_address + rd * q->token_size);
399}
400EXPORT_SYMBOL_NS_GPL(ipu6_recv_get_token, INTEL_IPU6);
401
402void ipu6_recv_put_token(struct ipu6_fw_com_context *ctx, int q_nbr)
403{
404 struct ipu6_fw_sys_queue *q = &ctx->output_queue[q_nbr];
405 void __iomem *q_dmem = ctx->dmem_addr + q->wr_reg * 4;
406 unsigned int rd = readl(q_dmem + FW_COM_RD_REG) + 1;
407
408 if (rd >= q->size)
409 rd = 0;
410
411 writel(rd, q_dmem + FW_COM_RD_REG);
412}
413EXPORT_SYMBOL_NS_GPL(ipu6_recv_put_token, INTEL_IPU6);
drivers/media/pci/intel/ipu6/ipu6-fw-com.h+47−0
@@ -0,0 +1,47 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_FW_COM_H
5#define IPU6_FW_COM_H
6
7struct ipu6_fw_com_context;
8struct ipu6_bus_device;
9
10struct ipu6_fw_syscom_queue_config {
11 unsigned int queue_size; /* tokens per queue */
12 unsigned int token_size; /* bytes per token */
13};
14
15#define SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET 0
16
17struct ipu6_fw_com_cfg {
18 unsigned int num_input_queues;
19 unsigned int num_output_queues;
20 struct ipu6_fw_syscom_queue_config *input;
21 struct ipu6_fw_syscom_queue_config *output;
22
23 unsigned int dmem_addr;
24
25 /* firmware-specific configuration data */
26 void *specific_addr;
27 unsigned int specific_size;
28 int (*cell_ready)(struct ipu6_bus_device *adev);
29 void (*cell_start)(struct ipu6_bus_device *adev);
30
31 unsigned int buttress_boot_offset;
32};
33
34void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
35 struct ipu6_bus_device *adev, void __iomem *base);
36
37int ipu6_fw_com_open(struct ipu6_fw_com_context *ctx);
38bool ipu6_fw_com_ready(struct ipu6_fw_com_context *ctx);
39int ipu6_fw_com_close(struct ipu6_fw_com_context *ctx);
40int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force);
41
42void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr);
43void ipu6_recv_put_token(struct ipu6_fw_com_context *ctx, int q_nbr);
44void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr);
45void ipu6_send_put_token(struct ipu6_fw_com_context *ctx, int q_nbr);
46
47#endif
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c+487−0
@@ -0,0 +1,487 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/cacheflush.h>
7#include <linux/delay.h>
8#include <linux/device.h>
9#include <linux/io.h>
10#include <linux/spinlock.h>
11#include <linux/types.h>
12
13#include "ipu6-bus.h"
14#include "ipu6-fw-com.h"
15#include "ipu6-isys.h"
16#include "ipu6-platform-isys-csi2-reg.h"
17#include "ipu6-platform-regs.h"
18
19static const char send_msg_types[N_IPU6_FW_ISYS_SEND_TYPE][32] = {
20 "STREAM_OPEN",
21 "STREAM_START",
22 "STREAM_START_AND_CAPTURE",
23 "STREAM_CAPTURE",
24 "STREAM_STOP",
25 "STREAM_FLUSH",
26 "STREAM_CLOSE"
27};
28
29static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
30{
31 struct device *dev = &isys->adev->auxdev.dev;
32 struct ipu6_fw_isys_proxy_resp_info_abi *resp;
33 int ret;
34
35 resp = ipu6_recv_get_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
36 if (!resp)
37 return 1;
38
39 dev_dbg(dev, "Proxy response: id %u, error %u, details %u\n",
40 resp->request_id, resp->error_info.error,
41 resp->error_info.error_details);
42
43 ret = req_id == resp->request_id ? 0 : -EIO;
44
45 ipu6_recv_put_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
46
47 return ret;
48}
49
50int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
51 unsigned int req_id,
52 unsigned int index,
53 unsigned int offset, u32 value)
54{
55 struct ipu6_fw_com_context *ctx = isys->fwcom;
56 struct device *dev = &isys->adev->auxdev.dev;
57 struct ipu6_fw_proxy_send_queue_token *token;
58 unsigned int timeout = 1000;
59 int ret;
60
61 dev_dbg(dev,
62 "proxy send: req_id 0x%x, index %d, offset 0x%x, value 0x%x\n",
63 req_id, index, offset, value);
64
65 token = ipu6_send_get_token(ctx, IPU6_BASE_PROXY_SEND_QUEUES);
66 if (!token)
67 return -EBUSY;
68
69 token->request_id = req_id;
70 token->region_index = index;
71 token->offset = offset;
72 token->value = value;
73 ipu6_send_put_token(ctx, IPU6_BASE_PROXY_SEND_QUEUES);
74
75 do {
76 usleep_range(100, 110);
77 ret = handle_proxy_response(isys, req_id);
78 if (!ret)
79 break;
80 if (ret == -EIO) {
81 dev_err(dev, "Proxy respond with unexpected id\n");
82 break;
83 }
84 timeout--;
85 } while (ret && timeout);
86
87 if (!timeout)
88 dev_err(dev, "Proxy response timed out\n");
89
90 return ret;
91}
92
93int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
94 const unsigned int stream_handle,
95 void *cpu_mapped_buf,
96 dma_addr_t dma_mapped_buf,
97 size_t size, u16 send_type)
98{
99 struct ipu6_fw_com_context *ctx = isys->fwcom;
100 struct device *dev = &isys->adev->auxdev.dev;
101 struct ipu6_fw_send_queue_token *token;
102
103 if (send_type >= N_IPU6_FW_ISYS_SEND_TYPE)
104 return -EINVAL;
105
106 dev_dbg(dev, "send_token: %s\n", send_msg_types[send_type]);
107
108 /*
109 * Time to flush cache in case we have some payload. Not all messages
110 * have that
111 */
112 if (cpu_mapped_buf)
113 clflush_cache_range(cpu_mapped_buf, size);
114
115 token = ipu6_send_get_token(ctx,
116 stream_handle + IPU6_BASE_MSG_SEND_QUEUES);
117 if (!token)
118 return -EBUSY;
119
120 token->payload = dma_mapped_buf;
121 token->buf_handle = (unsigned long)cpu_mapped_buf;
122 token->send_type = send_type;
123
124 ipu6_send_put_token(ctx, stream_handle + IPU6_BASE_MSG_SEND_QUEUES);
125
126 return 0;
127}
128
129int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
130 const unsigned int stream_handle, u16 send_type)
131{
132 return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
133 send_type);
134}
135
136int ipu6_fw_isys_close(struct ipu6_isys *isys)
137{
138 struct device *dev = &isys->adev->auxdev.dev;
139 int retry = IPU6_ISYS_CLOSE_RETRY;
140 unsigned long flags;
141 void *fwcom;
142 int ret;
143
144 /*
145 * Stop the isys fw. Actual close takes
146 * some time as the FW must stop its actions including code fetch
147 * to SP icache.
148 * spinlock to wait the interrupt handler to be finished
149 */
150 spin_lock_irqsave(&isys->power_lock, flags);
151 ret = ipu6_fw_com_close(isys->fwcom);
152 fwcom = isys->fwcom;
153 isys->fwcom = NULL;
154 spin_unlock_irqrestore(&isys->power_lock, flags);
155 if (ret)
156 dev_err(dev, "Device close failure: %d\n", ret);
157
158 /* release probably fails if the close failed. Let's try still */
159 do {
160 usleep_range(400, 500);
161 ret = ipu6_fw_com_release(fwcom, 0);
162 retry--;
163 } while (ret && retry);
164
165 if (ret) {
166 dev_err(dev, "Device release time out %d\n", ret);
167 spin_lock_irqsave(&isys->power_lock, flags);
168 isys->fwcom = fwcom;
169 spin_unlock_irqrestore(&isys->power_lock, flags);
170 }
171
172 return ret;
173}
174
175void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
176{
177 int ret;
178
179 ret = ipu6_fw_com_release(isys->fwcom, 1);
180 if (ret < 0)
181 dev_warn(&isys->adev->auxdev.dev,
182 "Device busy, fw_com release failed.");
183 isys->fwcom = NULL;
184}
185
186static void start_sp(struct ipu6_bus_device *adev)
187{
188 struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
189 void __iomem *spc_regs_base = isys->pdata->base +
190 isys->pdata->ipdata->hw_variant.spc_offset;
191 u32 val = IPU6_ISYS_SPC_STATUS_START |
192 IPU6_ISYS_SPC_STATUS_RUN |
193 IPU6_ISYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
194
195 val |= isys->icache_prefetch ? IPU6_ISYS_SPC_STATUS_ICACHE_PREFETCH : 0;
196
197 writel(val, spc_regs_base + IPU6_ISYS_REG_SPC_STATUS_CTRL);
198}
199
200static int query_sp(struct ipu6_bus_device *adev)
201{
202 struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
203 void __iomem *spc_regs_base = isys->pdata->base +
204 isys->pdata->ipdata->hw_variant.spc_offset;
205 u32 val;
206
207 val = readl(spc_regs_base + IPU6_ISYS_REG_SPC_STATUS_CTRL);
208 /* return true when READY == 1, START == 0 */
209 val &= IPU6_ISYS_SPC_STATUS_READY | IPU6_ISYS_SPC_STATUS_START;
210
211 return val == IPU6_ISYS_SPC_STATUS_READY;
212}
213
214static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
215 struct ipu6_fw_com_cfg *fwcom,
216 unsigned int num_streams)
217{
218 unsigned int max_send_queues, max_sram_blocks, max_devq_size;
219 struct ipu6_fw_syscom_queue_config *input_queue_cfg;
220 struct ipu6_fw_syscom_queue_config *output_queue_cfg;
221 struct device *dev = &isys->adev->auxdev.dev;
222 int type_proxy = IPU6_FW_ISYS_QUEUE_TYPE_PROXY;
223 int type_dev = IPU6_FW_ISYS_QUEUE_TYPE_DEV;
224 int type_msg = IPU6_FW_ISYS_QUEUE_TYPE_MSG;
225 int base_dev_send = IPU6_BASE_DEV_SEND_QUEUES;
226 int base_msg_send = IPU6_BASE_MSG_SEND_QUEUES;
227 int base_msg_recv = IPU6_BASE_MSG_RECV_QUEUES;
228 struct ipu6_fw_isys_fw_config *isys_fw_cfg;
229 u32 num_in_message_queues;
230 unsigned int max_streams;
231 unsigned int size;
232 unsigned int i;
233
234 max_streams = isys->pdata->ipdata->max_streams;
235 max_send_queues = isys->pdata->ipdata->max_send_queues;
236 max_sram_blocks = isys->pdata->ipdata->max_sram_blocks;
237 max_devq_size = isys->pdata->ipdata->max_devq_size;
238 num_in_message_queues = clamp(num_streams, 1U, max_streams);
239 isys_fw_cfg = devm_kzalloc(dev, sizeof(*isys_fw_cfg), GFP_KERNEL);
240 if (!isys_fw_cfg)
241 return -ENOMEM;
242
243 isys_fw_cfg->num_send_queues[type_proxy] = IPU6_N_MAX_PROXY_SEND_QUEUES;
244 isys_fw_cfg->num_send_queues[type_dev] = IPU6_N_MAX_DEV_SEND_QUEUES;
245 isys_fw_cfg->num_send_queues[type_msg] = num_in_message_queues;
246 isys_fw_cfg->num_recv_queues[type_proxy] = IPU6_N_MAX_PROXY_RECV_QUEUES;
247 /* Common msg/dev return queue */
248 isys_fw_cfg->num_recv_queues[type_dev] = 0;
249 isys_fw_cfg->num_recv_queues[type_msg] = 1;
250
251 size = sizeof(*input_queue_cfg) * max_send_queues;
252 input_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
253 if (!input_queue_cfg)
254 return -ENOMEM;
255
256 size = sizeof(*output_queue_cfg) * IPU6_N_MAX_RECV_QUEUES;
257 output_queue_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
258 if (!output_queue_cfg)
259 return -ENOMEM;
260
261 fwcom->input = input_queue_cfg;
262 fwcom->output = output_queue_cfg;
263
264 fwcom->num_input_queues = isys_fw_cfg->num_send_queues[type_proxy] +
265 isys_fw_cfg->num_send_queues[type_dev] +
266 isys_fw_cfg->num_send_queues[type_msg];
267
268 fwcom->num_output_queues = isys_fw_cfg->num_recv_queues[type_proxy] +
269 isys_fw_cfg->num_recv_queues[type_dev] +
270 isys_fw_cfg->num_recv_queues[type_msg];
271
272 /* SRAM partitioning. Equal partitioning is set. */
273 for (i = 0; i < max_sram_blocks; i++) {
274 if (i < num_in_message_queues)
275 isys_fw_cfg->buffer_partition.num_gda_pages[i] =
276 (IPU6_DEVICE_GDA_NR_PAGES *
277 IPU6_DEVICE_GDA_VIRT_FACTOR) /
278 num_in_message_queues;
279 else
280 isys_fw_cfg->buffer_partition.num_gda_pages[i] = 0;
281 }
282
283 /* FW assumes proxy interface at fwcom queue 0 */
284 for (i = 0; i < isys_fw_cfg->num_send_queues[type_proxy]; i++) {
285 input_queue_cfg[i].token_size =
286 sizeof(struct ipu6_fw_proxy_send_queue_token);
287 input_queue_cfg[i].queue_size = IPU6_ISYS_SIZE_PROXY_SEND_QUEUE;
288 }
289
290 for (i = 0; i < isys_fw_cfg->num_send_queues[type_dev]; i++) {
291 input_queue_cfg[base_dev_send + i].token_size =
292 sizeof(struct ipu6_fw_send_queue_token);
293 input_queue_cfg[base_dev_send + i].queue_size = max_devq_size;
294 }
295
296 for (i = 0; i < isys_fw_cfg->num_send_queues[type_msg]; i++) {
297 input_queue_cfg[base_msg_send + i].token_size =
298 sizeof(struct ipu6_fw_send_queue_token);
299 input_queue_cfg[base_msg_send + i].queue_size =
300 IPU6_ISYS_SIZE_SEND_QUEUE;
301 }
302
303 for (i = 0; i < isys_fw_cfg->num_recv_queues[type_proxy]; i++) {
304 output_queue_cfg[i].token_size =
305 sizeof(struct ipu6_fw_proxy_resp_queue_token);
306 output_queue_cfg[i].queue_size =
307 IPU6_ISYS_SIZE_PROXY_RECV_QUEUE;
308 }
309 /* There is no recv DEV queue */
310 for (i = 0; i < isys_fw_cfg->num_recv_queues[type_msg]; i++) {
311 output_queue_cfg[base_msg_recv + i].token_size =
312 sizeof(struct ipu6_fw_resp_queue_token);
313 output_queue_cfg[base_msg_recv + i].queue_size =
314 IPU6_ISYS_SIZE_RECV_QUEUE;
315 }
316
317 fwcom->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
318 fwcom->specific_addr = isys_fw_cfg;
319 fwcom->specific_size = sizeof(*isys_fw_cfg);
320
321 return 0;
322}
323
324int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
325{
326 struct device *dev = &isys->adev->auxdev.dev;
327 int retry = IPU6_ISYS_OPEN_RETRY;
328 struct ipu6_fw_com_cfg fwcom = {
329 .cell_start = start_sp,
330 .cell_ready = query_sp,
331 .buttress_boot_offset = SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET,
332 };
333 int ret;
334
335 ipu6_isys_fwcom_cfg_init(isys, &fwcom, num_streams);
336
337 isys->fwcom = ipu6_fw_com_prepare(&fwcom, isys->adev,
338 isys->pdata->base);
339 if (!isys->fwcom) {
340 dev_err(dev, "isys fw com prepare failed\n");
341 return -EIO;
342 }
343
344 ret = ipu6_fw_com_open(isys->fwcom);
345 if (ret) {
346 dev_err(dev, "isys fw com open failed %d\n", ret);
347 return ret;
348 }
349
350 do {
351 usleep_range(400, 500);
352 if (ipu6_fw_com_ready(isys->fwcom))
353 break;
354 retry--;
355 } while (retry > 0);
356
357 if (!retry) {
358 dev_err(dev, "isys port open ready failed %d\n", ret);
359 ipu6_fw_isys_close(isys);
360 ret = -EIO;
361 }
362
363 return ret;
364}
365
366struct ipu6_fw_isys_resp_info_abi *
367ipu6_fw_isys_get_resp(void *context, unsigned int queue)
368{
369 return ipu6_recv_get_token(context, queue);
370}
371
372void ipu6_fw_isys_put_resp(void *context, unsigned int queue)
373{
374 ipu6_recv_put_token(context, queue);
375}
376
377void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
378 struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
379{
380 unsigned int i;
381
382 dev_dbg(dev, "-----------------------------------------------------\n");
383 dev_dbg(dev, "IPU6_FW_ISYS_STREAM_CFG_DATA\n");
384
385 dev_dbg(dev, "compfmt = %d\n", cfg->vc);
386 dev_dbg(dev, "src = %d\n", cfg->src);
387 dev_dbg(dev, "vc = %d\n", cfg->vc);
388 dev_dbg(dev, "isl_use = %d\n", cfg->isl_use);
389 dev_dbg(dev, "sensor_type = %d\n", cfg->sensor_type);
390
391 dev_dbg(dev, "send_irq_sof_discarded = %d\n",
392 cfg->send_irq_sof_discarded);
393 dev_dbg(dev, "send_irq_eof_discarded = %d\n",
394 cfg->send_irq_eof_discarded);
395 dev_dbg(dev, "send_resp_sof_discarded = %d\n",
396 cfg->send_resp_sof_discarded);
397 dev_dbg(dev, "send_resp_eof_discarded = %d\n",
398 cfg->send_resp_eof_discarded);
399
400 dev_dbg(dev, "crop:\n");
401 dev_dbg(dev, "\t.left_top = [%d, %d]\n", cfg->crop.left_offset,
402 cfg->crop.top_offset);
403 dev_dbg(dev, "\t.right_bottom = [%d, %d]\n", cfg->crop.right_offset,
404 cfg->crop.bottom_offset);
405
406 dev_dbg(dev, "nof_input_pins = %d\n", cfg->nof_input_pins);
407 for (i = 0; i < cfg->nof_input_pins; i++) {
408 dev_dbg(dev, "input pin[%d]:\n", i);
409 dev_dbg(dev, "\t.dt = 0x%0x\n", cfg->input_pins[i].dt);
410 dev_dbg(dev, "\t.mipi_store_mode = %d\n",
411 cfg->input_pins[i].mipi_store_mode);
412 dev_dbg(dev, "\t.bits_per_pix = %d\n",
413 cfg->input_pins[i].bits_per_pix);
414 dev_dbg(dev, "\t.mapped_dt = 0x%0x\n",
415 cfg->input_pins[i].mapped_dt);
416 dev_dbg(dev, "\t.input_res = %dx%d\n",
417 cfg->input_pins[i].input_res.width,
418 cfg->input_pins[i].input_res.height);
419 dev_dbg(dev, "\t.mipi_decompression = %d\n",
420 cfg->input_pins[i].mipi_decompression);
421 dev_dbg(dev, "\t.capture_mode = %d\n",
422 cfg->input_pins[i].capture_mode);
423 }
424
425 dev_dbg(dev, "nof_output_pins = %d\n", cfg->nof_output_pins);
426 for (i = 0; i < cfg->nof_output_pins; i++) {
427 dev_dbg(dev, "output_pin[%d]:\n", i);
428 dev_dbg(dev, "\t.input_pin_id = %d\n",
429 cfg->output_pins[i].input_pin_id);
430 dev_dbg(dev, "\t.output_res = %dx%d\n",
431 cfg->output_pins[i].output_res.width,
432 cfg->output_pins[i].output_res.height);
433 dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride);
434 dev_dbg(dev, "\t.pt = %d\n", cfg->output_pins[i].pt);
435 dev_dbg(dev, "\t.payload_buf_size = %d\n",
436 cfg->output_pins[i].payload_buf_size);
437 dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft);
438 dev_dbg(dev, "\t.watermark_in_lines = %d\n",
439 cfg->output_pins[i].watermark_in_lines);
440 dev_dbg(dev, "\t.send_irq = %d\n",
441 cfg->output_pins[i].send_irq);
442 dev_dbg(dev, "\t.reserve_compression = %d\n",
443 cfg->output_pins[i].reserve_compression);
444 dev_dbg(dev, "\t.snoopable = %d\n",
445 cfg->output_pins[i].snoopable);
446 dev_dbg(dev, "\t.error_handling_enable = %d\n",
447 cfg->output_pins[i].error_handling_enable);
448 dev_dbg(dev, "\t.sensor_type = %d\n",
449 cfg->output_pins[i].sensor_type);
450 }
451 dev_dbg(dev, "-----------------------------------------------------\n");
452}
453
454void
455ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
456 struct ipu6_fw_isys_frame_buff_set_abi *buf,
457 unsigned int outputs)
458{
459 unsigned int i;
460
461 dev_dbg(dev, "-----------------------------------------------------\n");
462 dev_dbg(dev, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
463
464 for (i = 0; i < outputs; i++) {
465 dev_dbg(dev, "output_pin[%d]:\n", i);
466 dev_dbg(dev, "\t.out_buf_id = %llu\n",
467 buf->output_pins[i].out_buf_id);
468 dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr);
469 dev_dbg(dev, "\t.compress = %d\n",
470 buf->output_pins[i].compress);
471 }
472
473 dev_dbg(dev, "send_irq_sof = 0x%x\n", buf->send_irq_sof);
474 dev_dbg(dev, "send_irq_eof = 0x%x\n", buf->send_irq_eof);
475 dev_dbg(dev, "send_resp_sof = 0x%x\n", buf->send_resp_sof);
476 dev_dbg(dev, "send_resp_eof = 0x%x\n", buf->send_resp_eof);
477 dev_dbg(dev, "send_irq_capture_ack = 0x%x\n",
478 buf->send_irq_capture_ack);
479 dev_dbg(dev, "send_irq_capture_done = 0x%x\n",
480 buf->send_irq_capture_done);
481 dev_dbg(dev, "send_resp_capture_ack = 0x%x\n",
482 buf->send_resp_capture_ack);
483 dev_dbg(dev, "send_resp_capture_done = 0x%x\n",
484 buf->send_resp_capture_done);
485
486 dev_dbg(dev, "-----------------------------------------------------\n");
487}
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h+596−0
@@ -0,0 +1,596 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_FW_ISYS_H
5#define IPU6_FW_ISYS_H
6
7#include <linux/types.h>
8
9struct device;
10struct ipu6_isys;
11
12/* Max number of Input/Output Pins */
13#define IPU6_MAX_IPINS 4
14
15#define IPU6_MAX_OPINS ((IPU6_MAX_IPINS) + 1)
16
17#define IPU6_STREAM_ID_MAX 16
18#define IPU6_NONSECURE_STREAM_ID_MAX 12
19#define IPU6_DEV_SEND_QUEUE_SIZE (IPU6_STREAM_ID_MAX)
20#define IPU6_NOF_SRAM_BLOCKS_MAX (IPU6_STREAM_ID_MAX)
21#define IPU6_N_MAX_MSG_SEND_QUEUES (IPU6_STREAM_ID_MAX)
22#define IPU6SE_STREAM_ID_MAX 8
23#define IPU6SE_NONSECURE_STREAM_ID_MAX 4
24#define IPU6SE_DEV_SEND_QUEUE_SIZE (IPU6SE_STREAM_ID_MAX)
25#define IPU6SE_NOF_SRAM_BLOCKS_MAX (IPU6SE_STREAM_ID_MAX)
26#define IPU6SE_N_MAX_MSG_SEND_QUEUES (IPU6SE_STREAM_ID_MAX)
27
28/* Single return queue for all streams/commands type */
29#define IPU6_N_MAX_MSG_RECV_QUEUES 1
30/* Single device queue for high priority commands (bypass in-order queue) */
31#define IPU6_N_MAX_DEV_SEND_QUEUES 1
32/* Single dedicated send queue for proxy interface */
33#define IPU6_N_MAX_PROXY_SEND_QUEUES 1
34/* Single dedicated recv queue for proxy interface */
35#define IPU6_N_MAX_PROXY_RECV_QUEUES 1
36/* Send queues layout */
37#define IPU6_BASE_PROXY_SEND_QUEUES 0
38#define IPU6_BASE_DEV_SEND_QUEUES \
39 (IPU6_BASE_PROXY_SEND_QUEUES + IPU6_N_MAX_PROXY_SEND_QUEUES)
40#define IPU6_BASE_MSG_SEND_QUEUES \
41 (IPU6_BASE_DEV_SEND_QUEUES + IPU6_N_MAX_DEV_SEND_QUEUES)
42/* Recv queues layout */
43#define IPU6_BASE_PROXY_RECV_QUEUES 0
44#define IPU6_BASE_MSG_RECV_QUEUES \
45 (IPU6_BASE_PROXY_RECV_QUEUES + IPU6_N_MAX_PROXY_RECV_QUEUES)
46#define IPU6_N_MAX_RECV_QUEUES \
47 (IPU6_BASE_MSG_RECV_QUEUES + IPU6_N_MAX_MSG_RECV_QUEUES)
48
49#define IPU6_N_MAX_SEND_QUEUES \
50 (IPU6_BASE_MSG_SEND_QUEUES + IPU6_N_MAX_MSG_SEND_QUEUES)
51#define IPU6SE_N_MAX_SEND_QUEUES \
52 (IPU6_BASE_MSG_SEND_QUEUES + IPU6SE_N_MAX_MSG_SEND_QUEUES)
53
54/* Max number of planes for frame formats supported by the FW */
55#define IPU6_PIN_PLANES_MAX 4
56
57#define IPU6_FW_ISYS_SENSOR_TYPE_START 14
58#define IPU6_FW_ISYS_SENSOR_TYPE_END 19
59#define IPU6SE_FW_ISYS_SENSOR_TYPE_START 6
60#define IPU6SE_FW_ISYS_SENSOR_TYPE_END 11
61/*
62 * Device close takes some time from last ack message to actual stopping
63 * of the SP processor. As long as the SP processor runs we can't proceed with
64 * clean up of resources.
65 */
66#define IPU6_ISYS_OPEN_RETRY 2000
67#define IPU6_ISYS_CLOSE_RETRY 2000
68#define IPU6_FW_CALL_TIMEOUT_JIFFIES msecs_to_jiffies(2000)
69
70enum ipu6_fw_isys_resp_type {
71 IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE = 0,
72 IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK,
73 IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
74 IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK,
75 IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK,
76 IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK,
77 IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK,
78 IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY,
79 IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_WATERMARK,
80 IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF,
81 IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF,
82 IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
83 IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE,
84 IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_SKIPPED,
85 IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_SKIPPED,
86 IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF_DISCARDED,
87 IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF_DISCARDED,
88 IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY,
89 N_IPU6_FW_ISYS_RESP_TYPE
90};
91
92enum ipu6_fw_isys_send_type {
93 IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN = 0,
94 IPU6_FW_ISYS_SEND_TYPE_STREAM_START,
95 IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE,
96 IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE,
97 IPU6_FW_ISYS_SEND_TYPE_STREAM_STOP,
98 IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH,
99 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE,
100 N_IPU6_FW_ISYS_SEND_TYPE
101};
102
103enum ipu6_fw_isys_queue_type {
104 IPU6_FW_ISYS_QUEUE_TYPE_PROXY = 0,
105 IPU6_FW_ISYS_QUEUE_TYPE_DEV,
106 IPU6_FW_ISYS_QUEUE_TYPE_MSG,
107 N_IPU6_FW_ISYS_QUEUE_TYPE
108};
109
110enum ipu6_fw_isys_stream_source {
111 IPU6_FW_ISYS_STREAM_SRC_PORT_0 = 0,
112 IPU6_FW_ISYS_STREAM_SRC_PORT_1,
113 IPU6_FW_ISYS_STREAM_SRC_PORT_2,
114 IPU6_FW_ISYS_STREAM_SRC_PORT_3,
115 IPU6_FW_ISYS_STREAM_SRC_PORT_4,
116 IPU6_FW_ISYS_STREAM_SRC_PORT_5,
117 IPU6_FW_ISYS_STREAM_SRC_PORT_6,
118 IPU6_FW_ISYS_STREAM_SRC_PORT_7,
119 IPU6_FW_ISYS_STREAM_SRC_PORT_8,
120 IPU6_FW_ISYS_STREAM_SRC_PORT_9,
121 IPU6_FW_ISYS_STREAM_SRC_PORT_10,
122 IPU6_FW_ISYS_STREAM_SRC_PORT_11,
123 IPU6_FW_ISYS_STREAM_SRC_PORT_12,
124 IPU6_FW_ISYS_STREAM_SRC_PORT_13,
125 IPU6_FW_ISYS_STREAM_SRC_PORT_14,
126 IPU6_FW_ISYS_STREAM_SRC_PORT_15,
127 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_0,
128 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_1,
129 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_2,
130 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_3,
131 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_4,
132 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_5,
133 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_6,
134 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_7,
135 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_8,
136 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_9,
137 N_IPU6_FW_ISYS_STREAM_SRC
138};
139
140#define IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0 IPU6_FW_ISYS_STREAM_SRC_PORT_0
141#define IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT1 IPU6_FW_ISYS_STREAM_SRC_PORT_1
142#define IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT2 IPU6_FW_ISYS_STREAM_SRC_PORT_2
143#define IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT3 IPU6_FW_ISYS_STREAM_SRC_PORT_3
144
145#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_PORTA IPU6_FW_ISYS_STREAM_SRC_PORT_4
146#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_PORTB IPU6_FW_ISYS_STREAM_SRC_PORT_5
147#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_CPHY_PORT0 \
148 IPU6_FW_ISYS_STREAM_SRC_PORT_6
149#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_CPHY_PORT1 \
150 IPU6_FW_ISYS_STREAM_SRC_PORT_7
151#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_CPHY_PORT2 \
152 IPU6_FW_ISYS_STREAM_SRC_PORT_8
153#define IPU6_FW_ISYS_STREAM_SRC_CSI2_3PH_CPHY_PORT3 \
154 IPU6_FW_ISYS_STREAM_SRC_PORT_9
155
156#define IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_PORT0 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_0
157#define IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_PORT1 IPU6_FW_ISYS_STREAM_SRC_MIPIGEN_1
158
159/*
160 * enum ipu6_fw_isys_mipi_vc: MIPI csi2 spec
161 * supports up to 4 virtual per physical channel
162 */
163enum ipu6_fw_isys_mipi_vc {
164 IPU6_FW_ISYS_MIPI_VC_0 = 0,
165 IPU6_FW_ISYS_MIPI_VC_1,
166 IPU6_FW_ISYS_MIPI_VC_2,
167 IPU6_FW_ISYS_MIPI_VC_3,
168 N_IPU6_FW_ISYS_MIPI_VC
169};
170
171enum ipu6_fw_isys_frame_format_type {
172 IPU6_FW_ISYS_FRAME_FORMAT_NV11 = 0, /* 12 bit YUV 411, Y, UV plane */
173 IPU6_FW_ISYS_FRAME_FORMAT_NV12, /* 12 bit YUV 420, Y, UV plane */
174 IPU6_FW_ISYS_FRAME_FORMAT_NV12_16, /* 16 bit YUV 420, Y, UV plane */
175 /* 12 bit YUV 420, Intel proprietary tiled format */
176 IPU6_FW_ISYS_FRAME_FORMAT_NV12_TILEY,
177
178 IPU6_FW_ISYS_FRAME_FORMAT_NV16, /* 16 bit YUV 422, Y, UV plane */
179 IPU6_FW_ISYS_FRAME_FORMAT_NV21, /* 12 bit YUV 420, Y, VU plane */
180 IPU6_FW_ISYS_FRAME_FORMAT_NV61, /* 16 bit YUV 422, Y, VU plane */
181 IPU6_FW_ISYS_FRAME_FORMAT_YV12, /* 12 bit YUV 420, Y, V, U plane */
182 IPU6_FW_ISYS_FRAME_FORMAT_YV16, /* 16 bit YUV 422, Y, V, U plane */
183 IPU6_FW_ISYS_FRAME_FORMAT_YUV420, /* 12 bit YUV 420, Y, U, V plane */
184 IPU6_FW_ISYS_FRAME_FORMAT_YUV420_10, /* yuv420, 10 bits per subpixel */
185 IPU6_FW_ISYS_FRAME_FORMAT_YUV420_12, /* yuv420, 12 bits per subpixel */
186 IPU6_FW_ISYS_FRAME_FORMAT_YUV420_14, /* yuv420, 14 bits per subpixel */
187 IPU6_FW_ISYS_FRAME_FORMAT_YUV420_16, /* yuv420, 16 bits per subpixel */
188 IPU6_FW_ISYS_FRAME_FORMAT_YUV422, /* 16 bit YUV 422, Y, U, V plane */
189 IPU6_FW_ISYS_FRAME_FORMAT_YUV422_16, /* yuv422, 16 bits per subpixel */
190 IPU6_FW_ISYS_FRAME_FORMAT_UYVY, /* 16 bit YUV 422, UYVY interleaved */
191 IPU6_FW_ISYS_FRAME_FORMAT_YUYV, /* 16 bit YUV 422, YUYV interleaved */
192 IPU6_FW_ISYS_FRAME_FORMAT_YUV444, /* 24 bit YUV 444, Y, U, V plane */
193 /* Internal format, 2 y lines followed by a uvinterleaved line */
194 IPU6_FW_ISYS_FRAME_FORMAT_YUV_LINE,
195 IPU6_FW_ISYS_FRAME_FORMAT_RAW8, /* RAW8, 1 plane */
196 IPU6_FW_ISYS_FRAME_FORMAT_RAW10, /* RAW10, 1 plane */
197 IPU6_FW_ISYS_FRAME_FORMAT_RAW12, /* RAW12, 1 plane */
198 IPU6_FW_ISYS_FRAME_FORMAT_RAW14, /* RAW14, 1 plane */
199 IPU6_FW_ISYS_FRAME_FORMAT_RAW16, /* RAW16, 1 plane */
200 /**
201 * 16 bit RGB, 1 plane. Each 3 sub pixels are packed into one 16 bit
202 * value, 5 bits for R, 6 bits for G and 5 bits for B.
203 */
204 IPU6_FW_ISYS_FRAME_FORMAT_RGB565,
205 IPU6_FW_ISYS_FRAME_FORMAT_PLANAR_RGB888, /* 24 bit RGB, 3 planes */
206 IPU6_FW_ISYS_FRAME_FORMAT_RGBA888, /* 32 bit RGBA, 1 plane, A=Alpha */
207 IPU6_FW_ISYS_FRAME_FORMAT_QPLANE6, /* Internal, for advanced ISP */
208 IPU6_FW_ISYS_FRAME_FORMAT_BINARY_8, /* byte stream, used for jpeg. */
209 N_IPU6_FW_ISYS_FRAME_FORMAT
210};
211
212enum ipu6_fw_isys_pin_type {
213 /* captured as MIPI packets */
214 IPU6_FW_ISYS_PIN_TYPE_MIPI = 0,
215 /* captured through the SoC path */
216 IPU6_FW_ISYS_PIN_TYPE_RAW_SOC = 3,
217};
218
219/*
220 * enum ipu6_fw_isys_mipi_store_mode. Describes if long MIPI packets reach
221 * MIPI SRAM with the long packet header or
222 * if not, then only option is to capture it with pin type MIPI.
223 */
224enum ipu6_fw_isys_mipi_store_mode {
225 IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL = 0,
226 IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER,
227 N_IPU6_FW_ISYS_MIPI_STORE_MODE
228};
229
230enum ipu6_fw_isys_capture_mode {
231 IPU6_FW_ISYS_CAPTURE_MODE_REGULAR = 0,
232 IPU6_FW_ISYS_CAPTURE_MODE_BURST,
233 N_IPU6_FW_ISYS_CAPTURE_MODE,
234};
235
236enum ipu6_fw_isys_sensor_mode {
237 IPU6_FW_ISYS_SENSOR_MODE_NORMAL = 0,
238 IPU6_FW_ISYS_SENSOR_MODE_TOBII,
239 N_IPU6_FW_ISYS_SENSOR_MODE,
240};
241
242enum ipu6_fw_isys_error {
243 IPU6_FW_ISYS_ERROR_NONE = 0,
244 IPU6_FW_ISYS_ERROR_FW_INTERNAL_CONSISTENCY,
245 IPU6_FW_ISYS_ERROR_HW_CONSISTENCY,
246 IPU6_FW_ISYS_ERROR_DRIVER_INVALID_COMMAND_SEQUENCE,
247 IPU6_FW_ISYS_ERROR_DRIVER_INVALID_DEVICE_CONFIGURATION,
248 IPU6_FW_ISYS_ERROR_DRIVER_INVALID_STREAM_CONFIGURATION,
249 IPU6_FW_ISYS_ERROR_DRIVER_INVALID_FRAME_CONFIGURATION,
250 IPU6_FW_ISYS_ERROR_INSUFFICIENT_RESOURCES,
251 IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO,
252 IPU6_FW_ISYS_ERROR_HW_REPORTED_SIG2CIO,
253 IPU6_FW_ISYS_ERROR_SENSOR_FW_SYNC,
254 IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION,
255 IPU6_FW_ISYS_ERROR_RESPONSE_QUEUE_FULL,
256 N_IPU6_FW_ISYS_ERROR
257};
258
259enum ipu6_fw_proxy_error {
260 IPU6_FW_PROXY_ERROR_NONE = 0,
261 IPU6_FW_PROXY_ERROR_INVALID_WRITE_REGION,
262 IPU6_FW_PROXY_ERROR_INVALID_WRITE_OFFSET,
263 N_IPU6_FW_PROXY_ERROR
264};
265
266/* firmware ABI structure below are aligned in firmware, no need pack */
267struct ipu6_fw_isys_buffer_partition_abi {
268 u32 num_gda_pages[IPU6_STREAM_ID_MAX];
269};
270
271struct ipu6_fw_isys_fw_config {
272 struct ipu6_fw_isys_buffer_partition_abi buffer_partition;
273 u32 num_send_queues[N_IPU6_FW_ISYS_QUEUE_TYPE];
274 u32 num_recv_queues[N_IPU6_FW_ISYS_QUEUE_TYPE];
275};
276
277/*
278 * struct ipu6_fw_isys_resolution_abi: Generic resolution structure.
279 */
280struct ipu6_fw_isys_resolution_abi {
281 u32 width;
282 u32 height;
283};
284
285/**
286 * struct ipu6_fw_isys_output_pin_payload_abi - ISYS output pin buffer
287 * @out_buf_id: Points to output pin buffer - buffer identifier
288 * @addr: Points to output pin buffer - CSS Virtual Address
289 * @compress: Request frame compression (1), or not (0)
290 */
291struct ipu6_fw_isys_output_pin_payload_abi {
292 u64 out_buf_id;
293 u32 addr;
294 u32 compress;
295};
296
297/**
298 * struct ipu6_fw_isys_output_pin_info_abi - ISYS output pin info
299 * @output_res: output pin resolution
300 * @stride: output stride in Bytes (not valid for statistics)
301 * @watermark_in_lines: pin watermark level in lines
302 * @payload_buf_size: minimum size in Bytes of all buffers that will be
303 * supplied for capture on this pin
304 * @ts_offsets: ts_offsets
305 * @s2m_pixel_soc_pixel_remapping: pixel soc remapping (see the definition of
306 * S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING)
307 * @csi_be_soc_pixel_remapping: see s2m_pixel_soc_pixel_remapping
308 * @send_irq: assert if pin event should trigger irq
309 * @input_pin_id: related input pin id
310 * @pt: pin type -real format "enum ipu6_fw_isys_pin_type"
311 * @ft: frame format type -real format "enum ipu6_fw_isys_frame_format_type"
312 * @reserved: a reserved field
313 * @reserve_compression: reserve compression resources for pin
314 * @snoopable: snoopable
315 * @error_handling_enable: enable error handling
316 * @sensor_type: sensor_type
317 */
318struct ipu6_fw_isys_output_pin_info_abi {
319 struct ipu6_fw_isys_resolution_abi output_res;
320 u32 stride;
321 u32 watermark_in_lines;
322 u32 payload_buf_size;
323 u32 ts_offsets[IPU6_PIN_PLANES_MAX];
324 u32 s2m_pixel_soc_pixel_remapping;
325 u32 csi_be_soc_pixel_remapping;
326 u8 send_irq;
327 u8 input_pin_id;
328 u8 pt;
329 u8 ft;
330 u8 reserved;
331 u8 reserve_compression;
332 u8 snoopable;
333 u8 error_handling_enable;
334 u32 sensor_type;
335};
336
337/**
338 * struct ipu6_fw_isys_input_pin_info_abi - ISYS input pin info
339 * @input_res: input resolution
340 * @dt: mipi data type ((enum ipu6_fw_isys_mipi_data_type)
341 * @mipi_store_mode: defines if legacy long packet header will be stored or
342 * discarded if discarded, output pin type for this
343 * input pin can only be MIPI
344 * (enum ipu6_fw_isys_mipi_store_mode)
345 * @bits_per_pix: native bits per pixel
346 * @mapped_dt: actual data type from sensor
347 * @mipi_decompression: defines which compression will be in mipi backend
348 * @crop_first_and_last_lines: Control whether to crop the first and last line
349 * of the input image. Crop done by HW device.
350 * @capture_mode: mode of capture, regular or burst, default value is regular
351 * @reserved: a reserved field
352 */
353struct ipu6_fw_isys_input_pin_info_abi {
354 struct ipu6_fw_isys_resolution_abi input_res;
355 u8 dt;
356 u8 mipi_store_mode;
357 u8 bits_per_pix;
358 u8 mapped_dt;
359 u8 mipi_decompression;
360 u8 crop_first_and_last_lines;
361 u8 capture_mode;
362 u8 reserved;
363};
364
365/**
366 * struct ipu6_fw_isys_cropping_abi - ISYS cropping coordinates
367 * @top_offset: Top offset
368 * @left_offset: Left offset
369 * @bottom_offset: Bottom offset
370 * @right_offset: Right offset
371 */
372struct ipu6_fw_isys_cropping_abi {
373 s32 top_offset;
374 s32 left_offset;
375 s32 bottom_offset;
376 s32 right_offset;
377};
378
379/**
380 * struct ipu6_fw_isys_stream_cfg_data_abi - ISYS stream configuration data
381 * ISYS stream configuration data structure
382 * @crop: for extended use and is not used in FW currently
383 * @input_pins: input pin descriptors
384 * @output_pins: output pin descriptors
385 * @compfmt: de-compression setting for User Defined Data
386 * @nof_input_pins: number of input pins
387 * @nof_output_pins: number of output pins
388 * @send_irq_sof_discarded: send irq on discarded frame sof response
389 * - if '1' it will override the send_resp_sof_discarded
390 * and send the response
391 * - if '0' the send_resp_sof_discarded will determine
392 * whether to send the response
393 * @send_irq_eof_discarded: send irq on discarded frame eof response
394 * - if '1' it will override the send_resp_eof_discarded
395 * and send the response
396 * - if '0' the send_resp_eof_discarded will determine
397 * whether to send the response
398 * @send_resp_sof_discarded: send response for discarded frame sof detected,
399 * used only when send_irq_sof_discarded is '0'
400 * @send_resp_eof_discarded: send response for discarded frame eof detected,
401 * used only when send_irq_eof_discarded is '0'
402 * @src: Stream source index e.g. MIPI_generator_0, CSI2-rx_1
403 * @vc: MIPI Virtual Channel (up to 4 virtual per physical channel)
404 * @isl_use: indicates whether stream requires ISL and how
405 * @sensor_type: type of connected sensor, tobii or others, default is 0
406 * @reserved: a reserved field
407 * @reserved2: a reserved field
408 */
409struct ipu6_fw_isys_stream_cfg_data_abi {
410 struct ipu6_fw_isys_cropping_abi crop;
411 struct ipu6_fw_isys_input_pin_info_abi input_pins[IPU6_MAX_IPINS];
412 struct ipu6_fw_isys_output_pin_info_abi output_pins[IPU6_MAX_OPINS];
413 u32 compfmt;
414 u8 nof_input_pins;
415 u8 nof_output_pins;
416 u8 send_irq_sof_discarded;
417 u8 send_irq_eof_discarded;
418 u8 send_resp_sof_discarded;
419 u8 send_resp_eof_discarded;
420 u8 src;
421 u8 vc;
422 u8 isl_use;
423 u8 sensor_type;
424 u8 reserved;
425 u8 reserved2;
426};
427
428/**
429 * struct ipu6_fw_isys_frame_buff_set_abi - ISYS frame buffer set (request)
430 * @output_pins: output pin addresses
431 * @send_irq_sof: send irq on frame sof response
432 * - if '1' it will override the send_resp_sof and
433 * send the response
434 * - if '0' the send_resp_sof will determine whether to
435 * send the response
436 * @send_irq_eof: send irq on frame eof response
437 * - if '1' it will override the send_resp_eof and
438 * send the response
439 * - if '0' the send_resp_eof will determine whether to
440 * send the response
441 * @send_irq_capture_ack: send irq on capture ack
442 * @send_irq_capture_done: send irq on capture done
443 * @send_resp_sof: send response for frame sof detected,
444 * used only when send_irq_sof is '0'
445 * @send_resp_eof: send response for frame eof detected,
446 * used only when send_irq_eof is '0'
447 * @send_resp_capture_ack: send response for capture ack event
448 * @send_resp_capture_done: send response for capture done event
449 * @reserved: a reserved field
450 */
451struct ipu6_fw_isys_frame_buff_set_abi {
452 struct ipu6_fw_isys_output_pin_payload_abi output_pins[IPU6_MAX_OPINS];
453 u8 send_irq_sof;
454 u8 send_irq_eof;
455 u8 send_irq_capture_ack;
456 u8 send_irq_capture_done;
457 u8 send_resp_sof;
458 u8 send_resp_eof;
459 u8 send_resp_capture_ack;
460 u8 send_resp_capture_done;
461 u8 reserved[8];
462};
463
464/**
465 * struct ipu6_fw_isys_error_info_abi - ISYS error information
466 * @error: error code if something went wrong
467 * @error_details: depending on error code, it may contain additional error info
468 */
469struct ipu6_fw_isys_error_info_abi {
470 u32 error;
471 u32 error_details;
472};
473
474/**
475 * struct ipu6_fw_isys_resp_info_abi - ISYS firmware response
476 * @buf_id: buffer ID
477 * @pin: this var is only valid for pin event related responses,
478 * contains pin addresses
479 * @error_info: error information from the FW
480 * @timestamp: Time information for event if available
481 * @stream_handle: stream id the response corresponds to
482 * @type: response type (enum ipu6_fw_isys_resp_type)
483 * @pin_id: pin id that the pin payload corresponds to
484 * @reserved: a reserved field
485 * @reserved2: a reserved field
486 */
487struct ipu6_fw_isys_resp_info_abi {
488 u64 buf_id;
489 struct ipu6_fw_isys_output_pin_payload_abi pin;
490 struct ipu6_fw_isys_error_info_abi error_info;
491 u32 timestamp[2];
492 u8 stream_handle;
493 u8 type;
494 u8 pin_id;
495 u8 reserved;
496 u32 reserved2;
497};
498
499/**
500 * struct ipu6_fw_isys_proxy_error_info_abi - ISYS proxy error
501 * @error: error code if something went wrong
502 * @error_details: depending on error code, it may contain additional error info
503 */
504struct ipu6_fw_isys_proxy_error_info_abi {
505 u32 error;
506 u32 error_details;
507};
508
509struct ipu6_fw_isys_proxy_resp_info_abi {
510 u32 request_id;
511 struct ipu6_fw_isys_proxy_error_info_abi error_info;
512};
513
514/**
515 * struct ipu6_fw_proxy_write_queue_token - ISYS proxy write queue token
516 * @request_id: update id for the specific proxy write request
517 * @region_index: Region id for the proxy write request
518 * @offset: Offset of the write request according to the base address
519 * of the region
520 * @value: Value that is requested to be written with the proxy write request
521 */
522struct ipu6_fw_proxy_write_queue_token {
523 u32 request_id;
524 u32 region_index;
525 u32 offset;
526 u32 value;
527};
528
529/**
530 * struct ipu6_fw_resp_queue_token - ISYS response queue token
531 * @resp_info: response info
532 */
533struct ipu6_fw_resp_queue_token {
534 struct ipu6_fw_isys_resp_info_abi resp_info;
535};
536
537/**
538 * struct ipu6_fw_send_queue_token - ISYS send queue token
539 * @buf_handle: buffer handle
540 * @payload: payload
541 * @send_type: send_type
542 * @stream_id: stream_id
543 */
544struct ipu6_fw_send_queue_token {
545 u64 buf_handle;
546 u32 payload;
547 u16 send_type;
548 u16 stream_id;
549};
550
551/**
552 * struct ipu6_fw_proxy_resp_queue_token - ISYS proxy response queue token
553 * @proxy_resp_info: proxy response info
554 */
555struct ipu6_fw_proxy_resp_queue_token {
556 struct ipu6_fw_isys_proxy_resp_info_abi proxy_resp_info;
557};
558
559/**
560 * struct ipu6_fw_proxy_send_queue_token - SYS proxy send queue token
561 * @request_id: request_id
562 * @region_index: region_index
563 * @offset: offset
564 * @value: value
565 */
566struct ipu6_fw_proxy_send_queue_token {
567 u32 request_id;
568 u32 region_index;
569 u32 offset;
570 u32 value;
571};
572
573void
574ipu6_fw_isys_dump_stream_cfg(struct device *dev,
575 struct ipu6_fw_isys_stream_cfg_data_abi *cfg);
576void
577ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
578 struct ipu6_fw_isys_frame_buff_set_abi *buf,
579 unsigned int outputs);
580int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams);
581int ipu6_fw_isys_close(struct ipu6_isys *isys);
582int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
583 const unsigned int stream_handle, u16 send_type);
584int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
585 const unsigned int stream_handle,
586 void *cpu_mapped_buf, dma_addr_t dma_mapped_buf,
587 size_t size, u16 send_type);
588int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
589 unsigned int req_id,
590 unsigned int index,
591 unsigned int offset, u32 value);
592void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
593struct ipu6_fw_isys_resp_info_abi *
594ipu6_fw_isys_get_resp(void *context, unsigned int queue);
595void ipu6_fw_isys_put_resp(void *context, unsigned int queue);
596#endif
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c+663−0
@@ -0,0 +1,663 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/atomic.h>
7#include <linux/bitfield.h>
8#include <linux/bits.h>
9#include <linux/delay.h>
10#include <linux/device.h>
11#include <linux/err.h>
12#include <linux/io.h>
13#include <linux/minmax.h>
14#include <linux/sprintf.h>
15
16#include <media/media-entity.h>
17#include <media/v4l2-ctrls.h>
18#include <media/v4l2-device.h>
19#include <media/v4l2-event.h>
20#include <media/v4l2-subdev.h>
21
22#include "ipu6-bus.h"
23#include "ipu6-isys.h"
24#include "ipu6-isys-csi2.h"
25#include "ipu6-isys-subdev.h"
26#include "ipu6-platform-isys-csi2-reg.h"
27
28static const u32 csi2_supported_codes[] = {
29 MEDIA_BUS_FMT_RGB565_1X16,
30 MEDIA_BUS_FMT_RGB888_1X24,
31 MEDIA_BUS_FMT_UYVY8_1X16,
32 MEDIA_BUS_FMT_YUYV8_1X16,
33 MEDIA_BUS_FMT_SBGGR10_1X10,
34 MEDIA_BUS_FMT_SGBRG10_1X10,
35 MEDIA_BUS_FMT_SGRBG10_1X10,
36 MEDIA_BUS_FMT_SRGGB10_1X10,
37 MEDIA_BUS_FMT_SBGGR12_1X12,
38 MEDIA_BUS_FMT_SGBRG12_1X12,
39 MEDIA_BUS_FMT_SGRBG12_1X12,
40 MEDIA_BUS_FMT_SRGGB12_1X12,
41 MEDIA_BUS_FMT_SBGGR8_1X8,
42 MEDIA_BUS_FMT_SGBRG8_1X8,
43 MEDIA_BUS_FMT_SGRBG8_1X8,
44 MEDIA_BUS_FMT_SRGGB8_1X8,
45 MEDIA_BUS_FMT_META_8,
46 MEDIA_BUS_FMT_META_10,
47 MEDIA_BUS_FMT_META_12,
48 MEDIA_BUS_FMT_META_16,
49 MEDIA_BUS_FMT_META_24,
50 0
51};
52
53/*
54 * Strings corresponding to CSI-2 receiver errors are here.
55 * Corresponding macros are defined in the header file.
56 */
57static const struct ipu6_csi2_error dphy_rx_errors[] = {
58 { "Single packet header error corrected", true },
59 { "Multiple packet header errors detected", true },
60 { "Payload checksum (CRC) error", true },
61 { "Transfer FIFO overflow", false },
62 { "Reserved short packet data type detected", true },
63 { "Reserved long packet data type detected", true },
64 { "Incomplete long packet detected", false },
65 { "Frame sync error", false },
66 { "Line sync error", false },
67 { "DPHY recoverable synchronization error", true },
68 { "DPHY fatal error", false },
69 { "DPHY elastic FIFO overflow", false },
70 { "Inter-frame short packet discarded", true },
71 { "Inter-frame long packet discarded", true },
72 { "MIPI pktgen overflow", false },
73 { "MIPI pktgen data loss", false },
74 { "FIFO overflow", false },
75 { "Lane deskew", false },
76 { "SOT sync error", false },
77 { "HSIDLE detected", false }
78};
79
80s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2)
81{
82 struct media_pad *src_pad;
83 struct v4l2_subdev *ext_sd;
84 struct device *dev;
85
86 if (!csi2)
87 return -EINVAL;
88
89 dev = &csi2->isys->adev->auxdev.dev;
90 src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
91 if (IS_ERR(src_pad)) {
92 dev_err(dev, "can't get source pad of %s (%ld)\n",
93 csi2->asd.sd.name, PTR_ERR(src_pad));
94 return PTR_ERR(src_pad);
95 }
96
97 ext_sd = media_entity_to_v4l2_subdev(src_pad->entity);
98 if (WARN(!ext_sd, "Failed to get subdev for %s\n", csi2->asd.sd.name))
99 return -ENODEV;
100
101 return v4l2_get_link_freq(ext_sd->ctrl_handler, 0, 0);
102}
103
104static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
105 struct v4l2_event_subscription *sub)
106{
107 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
108 struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
109 struct device *dev = &csi2->isys->adev->auxdev.dev;
110
111 dev_dbg(dev, "csi2 subscribe event(type %u id %u)\n",
112 sub->type, sub->id);
113
114 switch (sub->type) {
115 case V4L2_EVENT_FRAME_SYNC:
116 return v4l2_event_subscribe(fh, sub, 10, NULL);
117 case V4L2_EVENT_CTRL:
118 return v4l2_ctrl_subscribe_event(fh, sub);
119 default:
120 return -EINVAL;
121 }
122}
123
124static const struct v4l2_subdev_core_ops csi2_sd_core_ops = {
125 .subscribe_event = csi2_subscribe_event,
126 .unsubscribe_event = v4l2_event_subdev_unsubscribe,
127};
128
129/*
130 * The input system CSI2+ receiver has several
131 * parameters affecting the receiver timings. These depend
132 * on the MIPI bus frequency F in Hz (sensor transmitter rate)
133 * as follows:
134 * register value = (A/1e9 + B * UI) / COUNT_ACC
135 * where
136 * UI = 1 / (2 * F) in seconds
137 * COUNT_ACC = counter accuracy in seconds
138 * COUNT_ACC = 0.125 ns = 1 / 8 ns, ACCINV = 8.
139 *
140 * A and B are coefficients from the table below,
141 * depending whether the register minimum or maximum value is
142 * calculated.
143 * Minimum Maximum
144 * Clock lane A B A B
145 * reg_rx_csi_dly_cnt_termen_clane 0 0 38 0
146 * reg_rx_csi_dly_cnt_settle_clane 95 -8 300 -16
147 * Data lanes
148 * reg_rx_csi_dly_cnt_termen_dlane0 0 0 35 4
149 * reg_rx_csi_dly_cnt_settle_dlane0 85 -2 145 -6
150 * reg_rx_csi_dly_cnt_termen_dlane1 0 0 35 4
151 * reg_rx_csi_dly_cnt_settle_dlane1 85 -2 145 -6
152 * reg_rx_csi_dly_cnt_termen_dlane2 0 0 35 4
153 * reg_rx_csi_dly_cnt_settle_dlane2 85 -2 145 -6
154 * reg_rx_csi_dly_cnt_termen_dlane3 0 0 35 4
155 * reg_rx_csi_dly_cnt_settle_dlane3 85 -2 145 -6
156 *
157 * We use the minimum values of both A and B.
158 */
159
160#define DIV_SHIFT 8
161#define CSI2_ACCINV 8
162
163static u32 calc_timing(s32 a, s32 b, s64 link_freq, s32 accinv)
164{
165 return accinv * a + (accinv * b * (500000000 >> DIV_SHIFT)
166 / (s32)(link_freq >> DIV_SHIFT));
167}
168
169static int
170ipu6_isys_csi2_calc_timing(struct ipu6_isys_csi2 *csi2,
171 struct ipu6_isys_csi2_timing *timing, s32 accinv)
172{
173 struct device *dev = &csi2->isys->adev->auxdev.dev;
174 s64 link_freq;
175
176 link_freq = ipu6_isys_csi2_get_link_freq(csi2);
177 if (link_freq < 0)
178 return link_freq;
179
180 timing->ctermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A,
181 CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B,
182 link_freq, accinv);
183 timing->csettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A,
184 CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_B,
185 link_freq, accinv);
186 timing->dtermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A,
187 CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_B,
188 link_freq, accinv);
189 timing->dsettle = calc_timing(CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A,
190 CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_B,
191 link_freq, accinv);
192
193 dev_dbg(dev, "ctermen %u csettle %u dtermen %u dsettle %u\n",
194 timing->ctermen, timing->csettle,
195 timing->dtermen, timing->dsettle);
196
197 return 0;
198}
199
200void ipu6_isys_register_errors(struct ipu6_isys_csi2 *csi2)
201{
202 u32 irq = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
203 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
204 struct ipu6_isys *isys = csi2->isys;
205 u32 mask;
206
207 mask = isys->pdata->ipdata->csi2.irq_mask;
208 writel(irq & mask, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
209 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
210 csi2->receiver_errors |= irq & mask;
211}
212
213void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
214{
215 struct device *dev = &csi2->isys->adev->auxdev.dev;
216 const struct ipu6_csi2_error *errors;
217 u32 status;
218 u32 i;
219
220 /* register errors once more in case of interrupts are disabled */
221 ipu6_isys_register_errors(csi2);
222 status = csi2->receiver_errors;
223 csi2->receiver_errors = 0;
224 errors = dphy_rx_errors;
225
226 for (i = 0; i < CSI_RX_NUM_ERRORS_IN_IRQ; i++) {
227 if (status & BIT(i))
228 dev_err_ratelimited(dev, "csi2-%i error: %s\n",
229 csi2->port, errors[i].error_string);
230 }
231}
232
233static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
234 const struct ipu6_isys_csi2_timing *timing,
235 unsigned int nlanes, int enable)
236{
237 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
238 struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
239 struct ipu6_isys *isys = csi2->isys;
240 struct device *dev = &isys->adev->auxdev.dev;
241 struct ipu6_isys_csi2_config cfg;
242 unsigned int nports;
243 int ret = 0;
244 u32 mask = 0;
245 u32 i;
246
247 dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
248 csi2->port, nlanes);
249
250 cfg.port = csi2->port;
251 cfg.nlanes = nlanes;
252
253 mask = isys->pdata->ipdata->csi2.irq_mask;
254 nports = isys->pdata->ipdata->csi2.nports;
255
256 if (!enable) {
257 writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
258 writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
259
260 writel(0,
261 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
262 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
263 writel(mask,
264 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
265 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
266 writel(0,
267 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
268 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
269 writel(0xffffffff,
270 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
271 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
272
273 isys->phy_set_power(isys, &cfg, timing, false);
274
275 writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
276 (isys->pdata->ipdata->csi2.fw_access_port_ofs,
277 csi2->port));
278 writel(0, isys->pdata->base +
279 CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
280
281 return ret;
282 }
283
284 /* reset port reset */
285 writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
286 usleep_range(100, 200);
287 writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
288
289 /* enable port clock */
290 for (i = 0; i < nports; i++) {
291 writel(1, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(i));
292 writel(1, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
293 (isys->pdata->ipdata->csi2.fw_access_port_ofs, i));
294 }
295
296 /* enable all error related irq */
297 writel(mask,
298 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
299 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
300 writel(mask,
301 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
302 CSI_PORT_REG_BASE_IRQ_MASK_OFFSET);
303 writel(mask,
304 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
305 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
306 writel(mask,
307 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
308 CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET);
309 writel(mask,
310 csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
311 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
312
313 /*
314 * Using event from firmware instead of irq to handle CSI2 sync event
315 * which can reduce system wakeups. If CSI2 sync irq enabled, we need
316 * disable the firmware CSI2 sync event to avoid duplicate handling.
317 */
318 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
319 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
320 writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
321 CSI_PORT_REG_BASE_IRQ_MASK_OFFSET);
322 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
323 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
324 writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
325 CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET);
326 writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
327 CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
328
329 /* configure to enable FE and PPI2CSI */
330 writel(0, csi2->base + CSI_REG_CSI_FE_MODE);
331 writel(CSI_SENSOR_INPUT, csi2->base + CSI_REG_CSI_FE_MUX_CTRL);
332 writel(CSI_CNTR_SENSOR_LINE_ID | CSI_CNTR_SENSOR_FRAME_ID,
333 csi2->base + CSI_REG_CSI_FE_SYNC_CNTR_SEL);
334 writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK, nlanes - 1),
335 csi2->base + CSI_REG_PPI2CSI_CONFIG_PPI_INTF);
336
337 writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
338 writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
339
340 ret = isys->phy_set_power(isys, &cfg, timing, true);
341 if (ret)
342 dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port,
343 ret);
344
345 return ret;
346}
347
348static int set_stream(struct v4l2_subdev *sd, int enable)
349{
350 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
351 struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
352 struct device *dev = &csi2->isys->adev->auxdev.dev;
353 struct ipu6_isys_csi2_timing timing = { };
354 unsigned int nlanes;
355 int ret;
356
357 dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off");
358
359 if (!enable) {
360 csi2->stream_count--;
361 if (csi2->stream_count)
362 return 0;
363
364 ipu6_isys_csi2_set_stream(sd, &timing, 0, enable);
365 return 0;
366 }
367
368 if (csi2->stream_count) {
369 csi2->stream_count++;
370 return 0;
371 }
372
373 nlanes = csi2->nlanes;
374
375 ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
376 if (ret)
377 return ret;
378
379 ret = ipu6_isys_csi2_set_stream(sd, &timing, nlanes, enable);
380 if (ret)
381 return ret;
382
383 csi2->stream_count++;
384
385 return 0;
386}
387
388static int ipu6_isys_csi2_set_sel(struct v4l2_subdev *sd,
389 struct v4l2_subdev_state *state,
390 struct v4l2_subdev_selection *sel)
391{
392 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
393 struct device *dev = &asd->isys->adev->auxdev.dev;
394 struct v4l2_mbus_framefmt *sink_ffmt;
395 struct v4l2_mbus_framefmt *src_ffmt;
396 struct v4l2_rect *crop;
397
398 if (sel->pad == CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
399 return -EINVAL;
400
401 sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
402 sel->pad,
403 sel->stream);
404 if (!sink_ffmt)
405 return -EINVAL;
406
407 src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream);
408 if (!src_ffmt)
409 return -EINVAL;
410
411 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
412 if (!crop)
413 return -EINVAL;
414
415 /* Only vertical cropping is supported */
416 sel->r.left = 0;
417 sel->r.width = sink_ffmt->width;
418 /* Non-bayer formats can't be single line cropped */
419 if (!ipu6_isys_is_bayer_format(sink_ffmt->code))
420 sel->r.top &= ~1;
421 sel->r.height = clamp(sel->r.height & ~1, IPU6_ISYS_MIN_HEIGHT,
422 sink_ffmt->height - sel->r.top);
423 *crop = sel->r;
424
425 /* update source pad format */
426 src_ffmt->width = sel->r.width;
427 src_ffmt->height = sel->r.height;
428 if (ipu6_isys_is_bayer_format(sink_ffmt->code))
429 src_ffmt->code = ipu6_isys_convert_bayer_order(sink_ffmt->code,
430 sel->r.left,
431 sel->r.top);
432 dev_dbg(dev, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n",
433 sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height,
434 src_ffmt->code);
435
436 return 0;
437}
438
439static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
440 struct v4l2_subdev_state *state,
441 struct v4l2_subdev_selection *sel)
442{
443 struct v4l2_mbus_framefmt *sink_ffmt;
444 struct v4l2_rect *crop;
445 int ret = 0;
446
447 if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK)
448 return -EINVAL;
449
450 sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state,
451 sel->pad,
452 sel->stream);
453 if (!sink_ffmt)
454 return -EINVAL;
455
456 crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream);
457 if (!crop)
458 return -EINVAL;
459
460 switch (sel->target) {
461 case V4L2_SEL_TGT_CROP_DEFAULT:
462 case V4L2_SEL_TGT_CROP_BOUNDS:
463 sel->r.left = 0;
464 sel->r.top = 0;
465 sel->r.width = sink_ffmt->width;
466 sel->r.height = sink_ffmt->height;
467 break;
468 case V4L2_SEL_TGT_CROP:
469 sel->r = *crop;
470 break;
471 default:
472 ret = -EINVAL;
473 }
474
475 return ret;
476}
477
478static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
479 .s_stream = set_stream,
480};
481
482static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
483 .get_fmt = v4l2_subdev_get_fmt,
484 .set_fmt = ipu6_isys_subdev_set_fmt,
485 .get_selection = ipu6_isys_csi2_get_sel,
486 .set_selection = ipu6_isys_csi2_set_sel,
487 .enum_mbus_code = ipu6_isys_subdev_enum_mbus_code,
488 .set_routing = ipu6_isys_subdev_set_routing,
489};
490
491static const struct v4l2_subdev_ops csi2_sd_ops = {
492 .core = &csi2_sd_core_ops,
493 .video = &csi2_sd_video_ops,
494 .pad = &csi2_sd_pad_ops,
495};
496
497static const struct media_entity_operations csi2_entity_ops = {
498 .link_validate = v4l2_subdev_link_validate,
499 .has_pad_interdep = v4l2_subdev_has_pad_interdep,
500};
501
502void ipu6_isys_csi2_cleanup(struct ipu6_isys_csi2 *csi2)
503{
504 if (!csi2->isys)
505 return;
506
507 v4l2_device_unregister_subdev(&csi2->asd.sd);
508 v4l2_subdev_cleanup(&csi2->asd.sd);
509 ipu6_isys_subdev_cleanup(&csi2->asd);
510 csi2->isys = NULL;
511}
512
513int ipu6_isys_csi2_init(struct ipu6_isys_csi2 *csi2,
514 struct ipu6_isys *isys,
515 void __iomem *base, unsigned int index)
516{
517 struct device *dev = &isys->adev->auxdev.dev;
518 int ret;
519
520 csi2->isys = isys;
521 csi2->base = base;
522 csi2->port = index;
523
524 csi2->asd.sd.entity.ops = &csi2_entity_ops;
525 csi2->asd.isys = isys;
526 ret = ipu6_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0,
527 NR_OF_CSI2_SINK_PADS, NR_OF_CSI2_SRC_PADS);
528 if (ret)
529 goto fail;
530
531 csi2->asd.source = IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0 + index;
532 csi2->asd.supported_codes = csi2_supported_codes;
533 snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name),
534 IPU6_ISYS_ENTITY_PREFIX " CSI2 %u", index);
535 v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd);
536 ret = v4l2_subdev_init_finalize(&csi2->asd.sd);
537 if (ret) {
538 dev_err(dev, "failed to init v4l2 subdev\n");
539 goto fail;
540 }
541
542 ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd);
543 if (ret) {
544 dev_err(dev, "failed to register v4l2 subdev\n");
545 goto fail;
546 }
547
548 return 0;
549
550fail:
551 ipu6_isys_csi2_cleanup(csi2);
552
553 return ret;
554}
555
556void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream *stream)
557{
558 struct video_device *vdev = stream->asd->sd.devnode;
559 struct device *dev = &stream->isys->adev->auxdev.dev;
560 struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
561 struct v4l2_event ev = {
562 .type = V4L2_EVENT_FRAME_SYNC,
563 };
564
565 ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence);
566 v4l2_event_queue(vdev, &ev);
567
568 dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n",
569 csi2->port, ev.u.frame_sync.frame_sequence, stream->vc);
570}
571
572void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream)
573{
574 struct device *dev = &stream->isys->adev->auxdev.dev;
575 struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
576 u32 frame_sequence = atomic_read(&stream->sequence);
577
578 dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n",
579 csi2->port, frame_sequence);
580}
581
582int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
583 struct ipu6_isys_csi2 *csi2,
584 struct media_entity *source_entity,
585 struct v4l2_mbus_frame_desc_entry *entry)
586{
587 struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
588 struct device *dev = &csi2->isys->adev->auxdev.dev;
589 struct v4l2_mbus_frame_desc desc;
590 struct v4l2_subdev *source;
591 struct media_pad *pad;
592 unsigned int i;
593 int ret;
594
595 source = media_entity_to_v4l2_subdev(source_entity);
596 if (!source)
597 return -EPIPE;
598
599 pad = media_pad_remote_pad_first(&csi2->asd.pad[CSI2_PAD_SINK]);
600 if (!pad)
601 return -EPIPE;
602
603 ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc);
604 if (ret)
605 return ret;
606
607 if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
608 dev_err(dev, "Unsupported frame descriptor type\n");
609 return -EINVAL;
610 }
611
612 for (i = 0; i < desc.num_entries; i++) {
613 if (source_stream == desc.entry[i].stream) {
614 desc_entry = &desc.entry[i];
615 break;
616 }
617 }
618
619 if (!desc_entry) {
620 dev_err(dev, "Failed to find stream %u from remote subdev\n",
621 source_stream);
622 return -EINVAL;
623 }
624
625 if (desc_entry->bus.csi2.vc >= NR_OF_CSI2_VC) {
626 dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc);
627 return -EINVAL;
628 }
629
630 *entry = *desc_entry;
631
632 return 0;
633}
634
635void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status)
636{
637 struct ipu6_isys_stream *stream = av->stream;
638 struct v4l2_subdev *sd = &stream->asd->sd;
639 struct v4l2_subdev_state *state;
640 struct media_pad *r_pad;
641 unsigned int i;
642 u32 r_stream;
643
644 r_pad = media_pad_remote_pad_first(&av->pad);
645 r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
646
647 state = v4l2_subdev_lock_and_get_active_state(sd);
648
649 for (i = 0; i < state->stream_configs.num_configs; i++) {
650 struct v4l2_subdev_stream_config *cfg =
651 &state->stream_configs.configs[i];
652
653 if (cfg->pad == r_pad->index && r_stream == cfg->stream) {
654 dev_dbg(&av->isys->adev->auxdev.dev,
655 "%s: pad:%u, stream:%u, status:%u\n",
656 sd->entity.name, r_pad->index, r_stream,
657 status);
658 cfg->enabled = status;
659 }
660 }
661
662 v4l2_subdev_unlock_state(state);
663}
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h+82−0
@@ -0,0 +1,82 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_ISYS_CSI2_H
5#define IPU6_ISYS_CSI2_H
6
7#include <linux/container_of.h>
8
9#include "ipu6-isys-subdev.h"
10#include "ipu6-isys-video.h"
11
12struct media_entity;
13struct v4l2_mbus_frame_desc_entry;
14
15struct ipu6_isys_video;
16struct ipu6_isys;
17struct ipu6_isys_csi2_pdata;
18struct ipu6_isys_stream;
19
20#define NR_OF_CSI2_VC 16
21#define INVALID_VC_ID -1
22#define NR_OF_CSI2_SINK_PADS 1
23#define CSI2_PAD_SINK 0
24#define NR_OF_CSI2_SRC_PADS 8
25#define CSI2_PAD_SRC 1
26#define NR_OF_CSI2_PADS (NR_OF_CSI2_SINK_PADS + NR_OF_CSI2_SRC_PADS)
27
28#define CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A 0
29#define CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B 0
30#define CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_A 95
31#define CSI2_CSI_RX_DLY_CNT_SETTLE_CLANE_B -8
32
33#define CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_A 0
34#define CSI2_CSI_RX_DLY_CNT_TERMEN_DLANE_B 0
35#define CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_A 85
36#define CSI2_CSI_RX_DLY_CNT_SETTLE_DLANE_B -2
37
38struct ipu6_isys_csi2 {
39 struct ipu6_isys_subdev asd;
40 struct ipu6_isys_csi2_pdata *pdata;
41 struct ipu6_isys *isys;
42 struct ipu6_isys_video av[NR_OF_CSI2_SRC_PADS];
43
44 void __iomem *base;
45 u32 receiver_errors;
46 unsigned int nlanes;
47 unsigned int port;
48 unsigned int stream_count;
49};
50
51struct ipu6_isys_csi2_timing {
52 u32 ctermen;
53 u32 csettle;
54 u32 dtermen;
55 u32 dsettle;
56};
57
58struct ipu6_csi2_error {
59 const char *error_string;
60 bool is_info_only;
61};
62
63#define ipu6_isys_subdev_to_csi2(__sd) \
64 container_of(__sd, struct ipu6_isys_csi2, asd)
65
66#define to_ipu6_isys_csi2(__asd) container_of(__asd, struct ipu6_isys_csi2, asd)
67
68s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2);
69int ipu6_isys_csi2_init(struct ipu6_isys_csi2 *csi2, struct ipu6_isys *isys,
70 void __iomem *base, unsigned int index);
71void ipu6_isys_csi2_cleanup(struct ipu6_isys_csi2 *csi2);
72void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream *stream);
73void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream);
74void ipu6_isys_register_errors(struct ipu6_isys_csi2 *csi2);
75void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2);
76int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
77 struct ipu6_isys_csi2 *csi2,
78 struct media_entity *source_entity,
79 struct v4l2_mbus_frame_desc_entry *entry);
80void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status);
81
82#endif /* IPU6_ISYS_CSI2_H */
drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c+536−0
@@ -0,0 +1,536 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/delay.h>
9#include <linux/device.h>
10#include <linux/iopoll.h>
11#include <linux/math64.h>
12
13#include "ipu6-bus.h"
14#include "ipu6-isys.h"
15#include "ipu6-platform-isys-csi2-reg.h"
16
17#define IPU6_DWC_DPHY_BASE(i) (0x238038 + 0x34 * (i))
18#define IPU6_DWC_DPHY_RSTZ 0x00
19#define IPU6_DWC_DPHY_SHUTDOWNZ 0x04
20#define IPU6_DWC_DPHY_HSFREQRANGE 0x08
21#define IPU6_DWC_DPHY_CFGCLKFREQRANGE 0x0c
22#define IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE 0x10
23#define IPU6_DWC_DPHY_TEST_IFC_REQ 0x14
24#define IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION 0x18
25#define IPU6_DWC_DPHY_DFT_CTRL0 0x28
26#define IPU6_DWC_DPHY_DFT_CTRL1 0x2c
27#define IPU6_DWC_DPHY_DFT_CTRL2 0x30
28
29/*
30 * test IFC request definition:
31 * - req: 0 for read, 1 for write
32 * - 12 bits address
33 * - 8bits data (will ignore for read)
34 * --24----16------4-----0
35 * --|-data-|-addr-|-req-|
36 */
37#define IFC_REQ(req, addr, data) (FIELD_PREP(GENMASK(23, 16), data) | \
38 FIELD_PREP(GENMASK(15, 4), addr) | \
39 FIELD_PREP(GENMASK(1, 0), req))
40
41#define TEST_IFC_REQ_READ 0
42#define TEST_IFC_REQ_WRITE 1
43#define TEST_IFC_REQ_RESET 2
44
45#define TEST_IFC_ACCESS_MODE_FSM 0
46#define TEST_IFC_ACCESS_MODE_IFC_CTL 1
47
48enum phy_fsm_state {
49 PHY_FSM_STATE_POWERON = 0,
50 PHY_FSM_STATE_BGPON = 1,
51 PHY_FSM_STATE_CAL_TYPE = 2,
52 PHY_FSM_STATE_BURNIN_CAL = 3,
53 PHY_FSM_STATE_TERMCAL = 4,
54 PHY_FSM_STATE_OFFSETCAL = 5,
55 PHY_FSM_STATE_OFFSET_LANE = 6,
56 PHY_FSM_STATE_IDLE = 7,
57 PHY_FSM_STATE_ULP = 8,
58 PHY_FSM_STATE_DDLTUNNING = 9,
59 PHY_FSM_STATE_SKEW_BACKWARD = 10,
60 PHY_FSM_STATE_INVALID,
61};
62
63static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
64 u32 data)
65{
66 struct device *dev = &isys->adev->auxdev.dev;
67 void __iomem *isys_base = isys->pdata->base;
68 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
69
70 dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base,
71 data);
72 writel(data, base + addr);
73}
74
75static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr)
76{
77 struct device *dev = &isys->adev->auxdev.dev;
78 void __iomem *isys_base = isys->pdata->base;
79 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
80 u32 data;
81
82 data = readl(base + addr);
83 dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base,
84 data);
85
86 return data;
87}
88
89static void dwc_dphy_write_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
90 u32 data, u8 shift, u8 width)
91{
92 u32 temp;
93 u32 mask;
94
95 mask = (1 << width) - 1;
96 temp = dwc_dphy_read(isys, phy_id, addr);
97 temp &= ~(mask << shift);
98 temp |= (data & mask) << shift;
99 dwc_dphy_write(isys, phy_id, addr, temp);
100}
101
102static u32 __maybe_unused dwc_dphy_read_mask(struct ipu6_isys *isys, u32 phy_id,
103 u32 addr, u8 shift, u8 width)
104{
105 u32 val;
106
107 val = dwc_dphy_read(isys, phy_id, addr) >> shift;
108 return val & ((1 << width) - 1);
109}
110
111#define DWC_DPHY_TIMEOUT (5 * USEC_PER_SEC)
112static int dwc_dphy_ifc_read(struct ipu6_isys *isys, u32 phy_id, u32 addr,
113 u32 *val)
114{
115 struct device *dev = &isys->adev->auxdev.dev;
116 void __iomem *isys_base = isys->pdata->base;
117 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
118 void __iomem *reg;
119 u32 completion;
120 int ret;
121
122 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
123 IFC_REQ(TEST_IFC_REQ_READ, addr, 0));
124 reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
125 ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
126 10, DWC_DPHY_TIMEOUT);
127 if (ret) {
128 dev_err(dev, "DWC ifc request read timeout\n");
129 return ret;
130 }
131
132 *val = completion >> 8 & 0xff;
133 *val = FIELD_GET(GENMASK(15, 8), completion);
134 dev_dbg(dev, "DWC ifc read 0x%x = 0x%x", addr, *val);
135
136 return 0;
137}
138
139static int dwc_dphy_ifc_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
140 u32 data)
141{
142 struct device *dev = &isys->adev->auxdev.dev;
143 void __iomem *isys_base = isys->pdata->base;
144 void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
145 void __iomem *reg;
146 u32 completion;
147 int ret;
148
149 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
150 IFC_REQ(TEST_IFC_REQ_WRITE, addr, data));
151 completion = readl(base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION);
152 reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
153 ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
154 10, DWC_DPHY_TIMEOUT);
155 if (ret)
156 dev_err(dev, "DWC ifc request write timeout\n");
157
158 return ret;
159}
160
161static void dwc_dphy_ifc_write_mask(struct ipu6_isys *isys, u32 phy_id,
162 u32 addr, u32 data, u8 shift, u8 width)
163{
164 u32 temp, mask;
165 int ret;
166
167 ret = dwc_dphy_ifc_read(isys, phy_id, addr, &temp);
168 if (ret)
169 return;
170
171 mask = (1 << width) - 1;
172 temp &= ~(mask << shift);
173 temp |= (data & mask) << shift;
174 dwc_dphy_ifc_write(isys, phy_id, addr, temp);
175}
176
177static u32 dwc_dphy_ifc_read_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
178 u8 shift, u8 width)
179{
180 int ret;
181 u32 val;
182
183 ret = dwc_dphy_ifc_read(isys, phy_id, addr, &val);
184 if (ret)
185 return 0;
186
187 return ((val >> shift) & ((1 << width) - 1));
188}
189
190static int dwc_dphy_pwr_up(struct ipu6_isys *isys, u32 phy_id)
191{
192 struct device *dev = &isys->adev->auxdev.dev;
193 u32 fsm_state;
194 int ret;
195
196 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 1);
197 usleep_range(10, 20);
198 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 1);
199
200 ret = read_poll_timeout(dwc_dphy_ifc_read_mask, fsm_state,
201 (fsm_state == PHY_FSM_STATE_IDLE ||
202 fsm_state == PHY_FSM_STATE_ULP),
203 100, DWC_DPHY_TIMEOUT, false, isys,
204 phy_id, 0x1e, 0, 4);
205
206 if (ret)
207 dev_err(dev, "Dphy %d power up failed, state 0x%x", phy_id,
208 fsm_state);
209
210 return ret;
211}
212
213struct dwc_dphy_freq_range {
214 u8 hsfreq;
215 u16 min;
216 u16 max;
217 u16 default_mbps;
218 u16 osc_freq_target;
219};
220
221#define DPHY_FREQ_RANGE_NUM (63)
222#define DPHY_FREQ_RANGE_INVALID_INDEX (0xff)
223static const struct dwc_dphy_freq_range freqranges[DPHY_FREQ_RANGE_NUM] = {
224 {0x00, 80, 97, 80, 335},
225 {0x10, 80, 107, 90, 335},
226 {0x20, 84, 118, 100, 335},
227 {0x30, 93, 128, 110, 335},
228 {0x01, 103, 139, 120, 335},
229 {0x11, 112, 149, 130, 335},
230 {0x21, 122, 160, 140, 335},
231 {0x31, 131, 170, 150, 335},
232 {0x02, 141, 181, 160, 335},
233 {0x12, 150, 191, 170, 335},
234 {0x22, 160, 202, 180, 335},
235 {0x32, 169, 212, 190, 335},
236 {0x03, 183, 228, 205, 335},
237 {0x13, 198, 244, 220, 335},
238 {0x23, 212, 259, 235, 335},
239 {0x33, 226, 275, 250, 335},
240 {0x04, 250, 301, 275, 335},
241 {0x14, 274, 328, 300, 335},
242 {0x25, 297, 354, 325, 335},
243 {0x35, 321, 380, 350, 335},
244 {0x05, 369, 433, 400, 335},
245 {0x16, 416, 485, 450, 335},
246 {0x26, 464, 538, 500, 335},
247 {0x37, 511, 590, 550, 335},
248 {0x07, 559, 643, 600, 335},
249 {0x18, 606, 695, 650, 335},
250 {0x28, 654, 748, 700, 335},
251 {0x39, 701, 800, 750, 335},
252 {0x09, 749, 853, 800, 335},
253 {0x19, 796, 905, 850, 335},
254 {0x29, 844, 958, 900, 335},
255 {0x3a, 891, 1010, 950, 335},
256 {0x0a, 939, 1063, 1000, 335},
257 {0x1a, 986, 1115, 1050, 335},
258 {0x2a, 1034, 1168, 1100, 335},
259 {0x3b, 1081, 1220, 1150, 335},
260 {0x0b, 1129, 1273, 1200, 335},
261 {0x1b, 1176, 1325, 1250, 335},
262 {0x2b, 1224, 1378, 1300, 335},
263 {0x3c, 1271, 1430, 1350, 335},
264 {0x0c, 1319, 1483, 1400, 335},
265 {0x1c, 1366, 1535, 1450, 335},
266 {0x2c, 1414, 1588, 1500, 335},
267 {0x3d, 1461, 1640, 1550, 208},
268 {0x0d, 1509, 1693, 1600, 214},
269 {0x1d, 1556, 1745, 1650, 221},
270 {0x2e, 1604, 1798, 1700, 228},
271 {0x3e, 1651, 1850, 1750, 234},
272 {0x0e, 1699, 1903, 1800, 241},
273 {0x1e, 1746, 1955, 1850, 248},
274 {0x2f, 1794, 2008, 1900, 255},
275 {0x3f, 1841, 2060, 1950, 261},
276 {0x0f, 1889, 2113, 2000, 268},
277 {0x40, 1936, 2165, 2050, 275},
278 {0x41, 1984, 2218, 2100, 281},
279 {0x42, 2031, 2270, 2150, 288},
280 {0x43, 2079, 2323, 2200, 294},
281 {0x44, 2126, 2375, 2250, 302},
282 {0x45, 2174, 2428, 2300, 308},
283 {0x46, 2221, 2480, 2350, 315},
284 {0x47, 2269, 2500, 2400, 321},
285 {0x48, 2316, 2500, 2450, 328},
286 {0x49, 2364, 2500, 2500, 335}
287};
288
289static u16 get_hsfreq_by_mbps(u32 mbps)
290{
291 unsigned int i = DPHY_FREQ_RANGE_NUM;
292
293 while (i--) {
294 if (freqranges[i].default_mbps == mbps ||
295 (mbps >= freqranges[i].min && mbps <= freqranges[i].max))
296 return i;
297 }
298
299 return DPHY_FREQ_RANGE_INVALID_INDEX;
300}
301
302static int ipu6_isys_dwc_phy_config(struct ipu6_isys *isys,
303 u32 phy_id, u32 mbps)
304{
305 struct ipu6_bus_device *adev = isys->adev;
306 struct device *dev = &adev->auxdev.dev;
307 struct ipu6_device *isp = adev->isp;
308 u32 cfg_clk_freqrange;
309 u32 osc_freq_target;
310 u32 index;
311
312 dev_dbg(dev, "config Dphy %u with %u mbps", phy_id, mbps);
313
314 index = get_hsfreq_by_mbps(mbps);
315 if (index == DPHY_FREQ_RANGE_INVALID_INDEX) {
316 dev_err(dev, "link freq not found for mbps %u", mbps);
317 return -EINVAL;
318 }
319
320 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_HSFREQRANGE,
321 freqranges[index].hsfreq, 0, 7);
322
323 /* Force termination Calibration */
324 if (isys->phy_termcal_val) {
325 dwc_dphy_ifc_write_mask(isys, phy_id, 0x20a, 0x1, 0, 1);
326 dwc_dphy_ifc_write_mask(isys, phy_id, 0x209, 0x3, 0, 2);
327 dwc_dphy_ifc_write_mask(isys, phy_id, 0x209,
328 isys->phy_termcal_val, 4, 4);
329 }
330
331 /*
332 * Enable override to configure the DDL target oscillation
333 * frequency on bit 0 of register 0xe4
334 */
335 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe4, 0x1, 0, 1);
336 /*
337 * configure registers 0xe2, 0xe3 with the
338 * appropriate DDL target oscillation frequency
339 * 0x1cc(460)
340 */
341 osc_freq_target = freqranges[index].osc_freq_target;
342 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe2,
343 osc_freq_target & 0xff, 0, 8);
344 dwc_dphy_ifc_write_mask(isys, phy_id, 0xe3,
345 (osc_freq_target >> 8) & 0xf, 0, 4);
346
347 if (mbps < 1500) {
348 /* deskew_polarity_rw, for < 1.5Gbps */
349 dwc_dphy_ifc_write_mask(isys, phy_id, 0x8, 0x1, 5, 1);
350 }
351
352 /*
353 * Set cfgclkfreqrange[5:0] = round[(Fcfg_clk(MHz)-17)*4]
354 * (38.4 - 17) * 4 = ~85 (0x55)
355 */
356 cfg_clk_freqrange = (isp->buttress.ref_clk - 170) * 4 / 10;
357 dev_dbg(dev, "ref_clk = %u clk_freqrange = %u",
358 isp->buttress.ref_clk, cfg_clk_freqrange);
359 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_CFGCLKFREQRANGE,
360 cfg_clk_freqrange, 0, 8);
361
362 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 4, 1);
363 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 8, 1);
364
365 return 0;
366}
367
368static void ipu6_isys_dwc_phy_aggr_setup(struct ipu6_isys *isys, u32 master,
369 u32 slave, u32 mbps)
370{
371 /* Config mastermacro */
372 dwc_dphy_ifc_write_mask(isys, master, 0x133, 0x1, 0, 1);
373 dwc_dphy_ifc_write_mask(isys, slave, 0x133, 0x0, 0, 1);
374
375 /* Config master PHY clk lane to drive long channel clk */
376 dwc_dphy_ifc_write_mask(isys, master, 0x307, 0x1, 2, 1);
377 dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x0, 2, 1);
378
379 /* Config both PHYs data lanes to get clk from long channel */
380 dwc_dphy_ifc_write_mask(isys, master, 0x508, 0x1, 5, 1);
381 dwc_dphy_ifc_write_mask(isys, slave, 0x508, 0x1, 5, 1);
382 dwc_dphy_ifc_write_mask(isys, master, 0x708, 0x1, 5, 1);
383 dwc_dphy_ifc_write_mask(isys, slave, 0x708, 0x1, 5, 1);
384
385 /* Config slave PHY clk lane to bypass long channel clk to DDR clk */
386 dwc_dphy_ifc_write_mask(isys, master, 0x308, 0x0, 3, 1);
387 dwc_dphy_ifc_write_mask(isys, slave, 0x308, 0x1, 3, 1);
388
389 /* Override slave PHY clk lane enable (DPHYRXCLK_CLL_demux module) */
390 dwc_dphy_ifc_write_mask(isys, slave, 0xe0, 0x3, 0, 2);
391
392 /* Override slave PHY DDR clk lane enable (DPHYHSRX_div124 module) */
393 dwc_dphy_ifc_write_mask(isys, slave, 0xe1, 0x1, 1, 1);
394 dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x1, 3, 1);
395
396 /* Turn off slave PHY LP-RX clk lane */
397 dwc_dphy_ifc_write_mask(isys, slave, 0x304, 0x1, 7, 1);
398 dwc_dphy_ifc_write_mask(isys, slave, 0x305, 0xa, 0, 5);
399}
400
401#define PHY_E 4
402static int ipu6_isys_dwc_phy_powerup_ack(struct ipu6_isys *isys, u32 phy_id)
403{
404 struct device *dev = &isys->adev->auxdev.dev;
405 u32 rescal_done;
406 int ret;
407
408 ret = dwc_dphy_pwr_up(isys, phy_id);
409 if (ret != 0) {
410 dev_err(dev, "Dphy %u power up failed(%d)", phy_id, ret);
411 return ret;
412 }
413
414 /* reset forcerxmode */
415 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 4, 1);
416 dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 8, 1);
417
418 dev_dbg(dev, "Dphy %u is ready!", phy_id);
419
420 if (phy_id != PHY_E || isys->phy_termcal_val)
421 return 0;
422
423 usleep_range(100, 200);
424 rescal_done = dwc_dphy_ifc_read_mask(isys, phy_id, 0x221, 7, 1);
425 if (rescal_done) {
426 isys->phy_termcal_val = dwc_dphy_ifc_read_mask(isys, phy_id,
427 0x220, 2, 4);
428 dev_dbg(dev, "termcal done with value = %u",
429 isys->phy_termcal_val);
430 }
431
432 return 0;
433}
434
435static void ipu6_isys_dwc_phy_reset(struct ipu6_isys *isys, u32 phy_id)
436{
437 dev_dbg(&isys->adev->auxdev.dev, "Reset phy %u", phy_id);
438
439 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 0);
440 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 0);
441 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE,
442 TEST_IFC_ACCESS_MODE_FSM);
443 dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
444 TEST_IFC_REQ_RESET);
445}
446
447int ipu6_isys_dwc_phy_set_power(struct ipu6_isys *isys,
448 struct ipu6_isys_csi2_config *cfg,
449 const struct ipu6_isys_csi2_timing *timing,
450 bool on)
451{
452 struct device *dev = &isys->adev->auxdev.dev;
453 void __iomem *isys_base = isys->pdata->base;
454 u32 phy_id, primary, secondary;
455 u32 nlanes, port, mbps;
456 s64 link_freq;
457 int ret;
458
459 port = cfg->port;
460
461 if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
462 dev_warn(dev, "invalid port ID %d\n", port);
463 return -EINVAL;
464 }
465
466 nlanes = cfg->nlanes;
467 /* only port 0, 2 and 4 support 4 lanes */
468 if (nlanes == 4 && port % 2) {
469 dev_err(dev, "invalid csi-port %u with %u lanes\n", port,
470 nlanes);
471 return -EINVAL;
472 }
473
474 link_freq = ipu6_isys_csi2_get_link_freq(&isys->csi2[port]);
475 if (link_freq < 0) {
476 dev_err(dev, "get link freq failed(%lld).\n", link_freq);
477 return link_freq;
478 }
479
480 mbps = div_u64(link_freq, 500000);
481
482 phy_id = port;
483 primary = port & ~1;
484 secondary = primary + 1;
485 if (on) {
486 if (nlanes == 4) {
487 dev_dbg(dev, "config phy %u and %u in aggr mode\n",
488 primary, secondary);
489
490 ipu6_isys_dwc_phy_reset(isys, primary);
491 ipu6_isys_dwc_phy_reset(isys, secondary);
492 ipu6_isys_dwc_phy_aggr_setup(isys, primary,
493 secondary, mbps);
494
495 ret = ipu6_isys_dwc_phy_config(isys, primary, mbps);
496 if (ret)
497 return ret;
498 ret = ipu6_isys_dwc_phy_config(isys, secondary, mbps);
499 if (ret)
500 return ret;
501
502 ret = ipu6_isys_dwc_phy_powerup_ack(isys, primary);
503 if (ret)
504 return ret;
505
506 ret = ipu6_isys_dwc_phy_powerup_ack(isys, secondary);
507 return ret;
508 }
509
510 dev_dbg(dev, "config phy %u with %u lanes in non-aggr mode\n",
511 phy_id, nlanes);
512
513 ipu6_isys_dwc_phy_reset(isys, phy_id);
514 ret = ipu6_isys_dwc_phy_config(isys, phy_id, mbps);
515 if (ret)
516 return ret;
517
518 ret = ipu6_isys_dwc_phy_powerup_ack(isys, phy_id);
519 return ret;
520 }
521
522 if (nlanes == 4) {
523 dev_dbg(dev, "Power down phy %u and phy %u for port %u\n",
524 primary, secondary, port);
525 ipu6_isys_dwc_phy_reset(isys, secondary);
526 ipu6_isys_dwc_phy_reset(isys, primary);
527
528 return 0;
529 }
530
531 dev_dbg(dev, "Powerdown phy %u with %u lanes\n", phy_id, nlanes);
532
533 ipu6_isys_dwc_phy_reset(isys, phy_id);
534
535 return 0;
536}
drivers/media/pci/intel/ipu6/ipu6-isys-jsl-phy.c+242−0
@@ -0,0 +1,242 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/device.h>
9#include <linux/io.h>
10
11#include "ipu6-bus.h"
12#include "ipu6-isys.h"
13#include "ipu6-isys-csi2.h"
14#include "ipu6-platform-isys-csi2-reg.h"
15
16/* only use BB0, BB2, BB4, and BB6 on PHY0 */
17#define IPU6SE_ISYS_PHY_BB_NUM 4
18#define IPU6SE_ISYS_PHY_0_BASE 0x10000
19
20#define PHY_CPHY_DLL_OVRD(x) (0x100 + 0x100 * (x))
21#define PHY_CPHY_RX_CONTROL1(x) (0x110 + 0x100 * (x))
22#define PHY_DPHY_CFG(x) (0x148 + 0x100 * (x))
23#define PHY_BB_AFE_CONFIG(x) (0x174 + 0x100 * (x))
24
25/*
26 * use port_cfg to configure that which data lanes used
27 * +---------+ +------+ +-----+
28 * | port0 x4<-----| | | |
29 * | | | port | | |
30 * | port1 x2<-----| | | |
31 * | | | <-| PHY |
32 * | port2 x4<-----| | | |
33 * | | |config| | |
34 * | port3 x2<-----| | | |
35 * +---------+ +------+ +-----+
36 */
37static const unsigned int csi2_port_cfg[][3] = {
38 {0, 0, 0x1f}, /* no link */
39 {4, 0, 0x10}, /* x4 + x4 config */
40 {2, 0, 0x12}, /* x2 + x2 config */
41 {1, 0, 0x13}, /* x1 + x1 config */
42 {2, 1, 0x15}, /* x2x1 + x2x1 config */
43 {1, 1, 0x16}, /* x1x1 + x1x1 config */
44 {2, 2, 0x18}, /* x2x2 + x2x2 config */
45 {1, 2, 0x19} /* x1x2 + x1x2 config */
46};
47
48/* port, nlanes, bbindex, portcfg */
49static const unsigned int phy_port_cfg[][4] = {
50 /* sip0 */
51 {0, 1, 0, 0x15},
52 {0, 2, 0, 0x15},
53 {0, 4, 0, 0x15},
54 {0, 4, 2, 0x22},
55 /* sip1 */
56 {2, 1, 4, 0x15},
57 {2, 2, 4, 0x15},
58 {2, 4, 4, 0x15},
59 {2, 4, 6, 0x22}
60};
61
62static void ipu6_isys_csi2_phy_config_by_port(struct ipu6_isys *isys,
63 unsigned int port,
64 unsigned int nlanes)
65{
66 struct device *dev = &isys->adev->auxdev.dev;
67 void __iomem *base = isys->adev->isp->base;
68 unsigned int bbnum;
69 u32 val, reg, i;
70
71 dev_dbg(dev, "port %u with %u lanes", port, nlanes);
72
73 /* only support <1.5Gbps */
74 for (i = 0; i < IPU6SE_ISYS_PHY_BB_NUM; i++) {
75 /* cphy_dll_ovrd.crcdc_fsm_dlane0 = 13 */
76 reg = IPU6SE_ISYS_PHY_0_BASE + PHY_CPHY_DLL_OVRD(i);
77 val = readl(base + reg);
78 val |= FIELD_PREP(GENMASK(6, 1), 13);
79 writel(val, base + reg);
80
81 /* cphy_rx_control1.en_crc1 = 1 */
82 reg = IPU6SE_ISYS_PHY_0_BASE + PHY_CPHY_RX_CONTROL1(i);
83 val = readl(base + reg);
84 val |= BIT(31);
85 writel(val, base + reg);
86
87 /* dphy_cfg.reserved = 1, .lden_from_dll_ovrd_0 = 1 */
88 reg = IPU6SE_ISYS_PHY_0_BASE + PHY_DPHY_CFG(i);
89 val = readl(base + reg);
90 val |= BIT(25) | BIT(26);
91 writel(val, base + reg);
92
93 /* cphy_dll_ovrd.lden_crcdc_fsm_dlane0 = 1 */
94 reg = IPU6SE_ISYS_PHY_0_BASE + PHY_CPHY_DLL_OVRD(i);
95 val = readl(base + reg);
96 val |= BIT(0);
97 writel(val, base + reg);
98 }
99
100 /* Front end config, use minimal channel loss */
101 for (i = 0; i < ARRAY_SIZE(phy_port_cfg); i++) {
102 if (phy_port_cfg[i][0] == port &&
103 phy_port_cfg[i][1] == nlanes) {
104 bbnum = phy_port_cfg[i][2] / 2;
105 reg = IPU6SE_ISYS_PHY_0_BASE + PHY_BB_AFE_CONFIG(bbnum);
106 val = readl(base + reg);
107 val |= phy_port_cfg[i][3];
108 writel(val, base + reg);
109 }
110 }
111}
112
113static void ipu6_isys_csi2_rx_control(struct ipu6_isys *isys)
114{
115 void __iomem *base = isys->adev->isp->base;
116 u32 val, reg;
117
118 reg = CSI2_HUB_GPREG_SIP0_CSI_RX_A_CONTROL;
119 val = readl(base + reg);
120 val |= BIT(0);
121 writel(val, base + CSI2_HUB_GPREG_SIP0_CSI_RX_A_CONTROL);
122
123 reg = CSI2_HUB_GPREG_SIP0_CSI_RX_B_CONTROL;
124 val = readl(base + reg);
125 val |= BIT(0);
126 writel(val, base + CSI2_HUB_GPREG_SIP0_CSI_RX_B_CONTROL);
127
128 reg = CSI2_HUB_GPREG_SIP1_CSI_RX_A_CONTROL;
129 val = readl(base + reg);
130 val |= BIT(0);
131 writel(val, base + CSI2_HUB_GPREG_SIP1_CSI_RX_A_CONTROL);
132
133 reg = CSI2_HUB_GPREG_SIP1_CSI_RX_B_CONTROL;
134 val = readl(base + reg);
135 val |= BIT(0);
136 writel(val, base + CSI2_HUB_GPREG_SIP1_CSI_RX_B_CONTROL);
137}
138
139static int ipu6_isys_csi2_set_port_cfg(struct ipu6_isys *isys,
140 unsigned int port, unsigned int nlanes)
141{
142 struct device *dev = &isys->adev->auxdev.dev;
143 unsigned int sip = port / 2;
144 unsigned int index;
145
146 switch (nlanes) {
147 case 1:
148 index = 5;
149 break;
150 case 2:
151 index = 6;
152 break;
153 case 4:
154 index = 1;
155 break;
156 default:
157 dev_err(dev, "lanes nr %u is unsupported\n", nlanes);
158 return -EINVAL;
159 }
160
161 dev_dbg(dev, "port config for port %u with %u lanes\n", port, nlanes);
162
163 writel(csi2_port_cfg[index][2],
164 isys->pdata->base + CSI2_HUB_GPREG_SIP_FB_PORT_CFG(sip));
165
166 return 0;
167}
168
169static void
170ipu6_isys_csi2_set_timing(struct ipu6_isys *isys,
171 const struct ipu6_isys_csi2_timing *timing,
172 unsigned int port, unsigned int nlanes)
173{
174 struct device *dev = &isys->adev->auxdev.dev;
175 void __iomem *reg;
176 u32 port_base;
177 u32 i;
178
179 port_base = (port % 2) ? CSI2_SIP_TOP_CSI_RX_PORT_BASE_1(port) :
180 CSI2_SIP_TOP_CSI_RX_PORT_BASE_0(port);
181
182 dev_dbg(dev, "set timing for port %u with %u lanes\n", port, nlanes);
183
184 reg = isys->pdata->base + port_base;
185 reg += CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_CLANE;
186
187 writel(timing->ctermen, reg);
188
189 reg = isys->pdata->base + port_base;
190 reg += CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_CLANE;
191 writel(timing->csettle, reg);
192
193 for (i = 0; i < nlanes; i++) {
194 reg = isys->pdata->base + port_base;
195 reg += CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_DLANE(i);
196 writel(timing->dtermen, reg);
197
198 reg = isys->pdata->base + port_base;
199 reg += CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_DLANE(i);
200 writel(timing->dsettle, reg);
201 }
202}
203
204#define DPHY_TIMER_INCR 0x28
205int ipu6_isys_jsl_phy_set_power(struct ipu6_isys *isys,
206 struct ipu6_isys_csi2_config *cfg,
207 const struct ipu6_isys_csi2_timing *timing,
208 bool on)
209{
210 struct device *dev = &isys->adev->auxdev.dev;
211 void __iomem *isys_base = isys->pdata->base;
212 int ret = 0;
213 u32 nlanes;
214 u32 port;
215
216 if (!on)
217 return 0;
218
219 port = cfg->port;
220 nlanes = cfg->nlanes;
221
222 if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
223 dev_warn(dev, "invalid port ID %d\n", port);
224 return -EINVAL;
225 }
226
227 ipu6_isys_csi2_phy_config_by_port(isys, port, nlanes);
228
229 writel(DPHY_TIMER_INCR,
230 isys->pdata->base + CSI2_HUB_GPREG_DPHY_TIMER_INCR);
231
232 /* set port cfg and rx timing */
233 ipu6_isys_csi2_set_timing(isys, timing, port, nlanes);
234
235 ret = ipu6_isys_csi2_set_port_cfg(isys, port, nlanes);
236 if (ret)
237 return ret;
238
239 ipu6_isys_csi2_rx_control(isys);
240
241 return 0;
242}
drivers/media/pci/intel/ipu6/ipu6-isys-mcd-phy.c+720−0
@@ -0,0 +1,720 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bits.h>
7#include <linux/container_of.h>
8#include <linux/device.h>
9#include <linux/iopoll.h>
10#include <linux/list.h>
11#include <linux/refcount.h>
12#include <linux/time64.h>
13
14#include <media/v4l2-async.h>
15
16#include "ipu6.h"
17#include "ipu6-bus.h"
18#include "ipu6-isys.h"
19#include "ipu6-isys-csi2.h"
20#include "ipu6-platform-isys-csi2-reg.h"
21
22#define CSI_REG_HUB_GPREG_PHY_CTL(id) (CSI_REG_BASE + 0x18008 + (id) * 0x8)
23#define CSI_REG_HUB_GPREG_PHY_CTL_RESET BIT(4)
24#define CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN BIT(0)
25#define CSI_REG_HUB_GPREG_PHY_STATUS(id) (CSI_REG_BASE + 0x1800c + (id) * 0x8)
26#define CSI_REG_HUB_GPREG_PHY_POWER_ACK BIT(0)
27#define CSI_REG_HUB_GPREG_PHY_READY BIT(4)
28
29#define MCD_PHY_POWER_STATUS_TIMEOUT (200 * USEC_PER_MSEC)
30
31/*
32 * bridge to phy in buttress reg map, each phy has 16 kbytes
33 * only 2 phys for TGL U and Y
34 */
35#define IPU6_ISYS_MCD_PHY_BASE(i) (0x10000 + (i) * 0x4000)
36
37/*
38 * There are 2 MCD DPHY instances on TGL and 1 MCD DPHY instance on ADL.
39 * Each MCD PHY has 12-lanes which has 8 data lanes and 4 clock lanes.
40 * CSI port 1, 3 (5, 7) can support max 2 data lanes.
41 * CSI port 0, 2 (4, 6) can support max 4 data lanes.
42 * PHY configurations are PPI based instead of port.
43 * Left:
44 * +---------+---------+---------+---------+--------+---------+----------+
45 * | | | | | | | |
46 * | PPI | PPI5 | PPI4 | PPI3 | PPI2 | PPI1 | PPI0 |
47 * +---------+---------+---------+---------+--------+---------+----------+
48 * | | | | | | | |
49 * | x4 | unused | D3 | D2 | C0 | D0 | D1 |
50 * |---------+---------+---------+---------+--------+---------+----------+
51 * | | | | | | | |
52 * | x2x2 | C1 | D0 | D1 | C0 | D0 | D1 |
53 * ----------+---------+---------+---------+--------+---------+----------+
54 * | | | | | | | |
55 * | x2x1 | C1 | D0 | unused | C0 | D0 | D1 |
56 * +---------+---------+---------+---------+--------+---------+----------+
57 * | | | | | | | |
58 * | x1x1 | C1 | D0 | unused | C0 | D0 | unused |
59 * +---------+---------+---------+---------+--------+---------+----------+
60 * | | | | | | | |
61 * | x1x2 | C1 | D0 | D1 | C0 | D0 | unused |
62 * +---------+---------+---------+---------+--------+---------+----------+
63 *
64 * Right:
65 * +---------+---------+---------+---------+--------+---------+----------+
66 * | | | | | | | |
67 * | PPI | PPI6 | PPI7 | PPI8 | PPI9 | PPI10 | PPI11 |
68 * +---------+---------+---------+---------+--------+---------+----------+
69 * | | | | | | | |
70 * | x4 | D1 | D0 | C2 | D2 | D3 | unused |
71 * |---------+---------+---------+---------+--------+---------+----------+
72 * | | | | | | | |
73 * | x2x2 | D1 | D0 | C2 | D1 | D0 | C3 |
74 * ----------+---------+---------+---------+--------+---------+----------+
75 * | | | | | | | |
76 * | x2x1 | D1 | D0 | C2 | unused | D0 | C3 |
77 * +---------+---------+---------+---------+--------+---------+----------+
78 * | | | | | | | |
79 * | x1x1 | unused | D0 | C2 | unused | D0 | C3 |
80 * +---------+---------+---------+---------+--------+---------+----------+
81 * | | | | | | | |
82 * | x1x2 | unused | D0 | C2 | D1 | D0 | C3 |
83 * +---------+---------+---------+---------+--------+---------+----------+
84 *
85 * ppi mapping per phy :
86 *
87 * x4 + x4:
88 * Left : port0 - PPI range {0, 1, 2, 3, 4}
89 * Right: port2 - PPI range {6, 7, 8, 9, 10}
90 *
91 * x4 + x2x2:
92 * Left: port0 - PPI range {0, 1, 2, 3, 4}
93 * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11}
94 *
95 * x2x2 + x4:
96 * Left: port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5}
97 * Right: port2 - PPI range {6, 7, 8, 9, 10}
98 *
99 * x2x2 + x2x2:
100 * Left : port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5}
101 * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11}
102 */
103
104struct phy_reg {
105 u32 reg;
106 u32 val;
107};
108
109static const struct phy_reg common_init_regs[] = {
110 /* for TGL-U, use 0x80000000 */
111 {0x00000040, 0x80000000},
112 {0x00000044, 0x00a80880},
113 {0x00000044, 0x00b80880},
114 {0x00000010, 0x0000078c},
115 {0x00000344, 0x2f4401e2},
116 {0x00000544, 0x924401e2},
117 {0x00000744, 0x594401e2},
118 {0x00000944, 0x624401e2},
119 {0x00000b44, 0xfc4401e2},
120 {0x00000d44, 0xc54401e2},
121 {0x00000f44, 0x034401e2},
122 {0x00001144, 0x8f4401e2},
123 {0x00001344, 0x754401e2},
124 {0x00001544, 0xe94401e2},
125 {0x00001744, 0xcb4401e2},
126 {0x00001944, 0xfa4401e2}
127};
128
129static const struct phy_reg x1_port0_config_regs[] = {
130 {0x00000694, 0xc80060fa},
131 {0x00000680, 0x3d4f78ea},
132 {0x00000690, 0x10a0140b},
133 {0x000006a8, 0xdf04010a},
134 {0x00000700, 0x57050060},
135 {0x00000710, 0x0030001c},
136 {0x00000738, 0x5f004444},
137 {0x0000073c, 0x78464204},
138 {0x00000748, 0x7821f940},
139 {0x0000074c, 0xb2000433},
140 {0x00000494, 0xfe6030fa},
141 {0x00000480, 0x29ef5ed0},
142 {0x00000490, 0x10a0540b},
143 {0x000004a8, 0x7a01010a},
144 {0x00000500, 0xef053460},
145 {0x00000510, 0xe030101c},
146 {0x00000538, 0xdf808444},
147 {0x0000053c, 0xc8422204},
148 {0x00000540, 0x0180088c},
149 {0x00000574, 0x00000000},
150 {0x00000000, 0x00000000}
151};
152
153static const struct phy_reg x1_port1_config_regs[] = {
154 {0x00000c94, 0xc80060fa},
155 {0x00000c80, 0xcf47abea},
156 {0x00000c90, 0x10a0840b},
157 {0x00000ca8, 0xdf04010a},
158 {0x00000d00, 0x57050060},
159 {0x00000d10, 0x0030001c},
160 {0x00000d38, 0x5f004444},
161 {0x00000d3c, 0x78464204},
162 {0x00000d48, 0x7821f940},
163 {0x00000d4c, 0xb2000433},
164 {0x00000a94, 0xc91030fa},
165 {0x00000a80, 0x5a166ed0},
166 {0x00000a90, 0x10a0540b},
167 {0x00000aa8, 0x5d060100},
168 {0x00000b00, 0xef053460},
169 {0x00000b10, 0xa030101c},
170 {0x00000b38, 0xdf808444},
171 {0x00000b3c, 0xc8422204},
172 {0x00000b40, 0x0180088c},
173 {0x00000b74, 0x00000000},
174 {0x00000000, 0x00000000}
175};
176
177static const struct phy_reg x1_port2_config_regs[] = {
178 {0x00001294, 0x28f000fa},
179 {0x00001280, 0x08130cea},
180 {0x00001290, 0x10a0140b},
181 {0x000012a8, 0xd704010a},
182 {0x00001300, 0x8d050060},
183 {0x00001310, 0x0030001c},
184 {0x00001338, 0xdf008444},
185 {0x0000133c, 0x78422204},
186 {0x00001348, 0x7821f940},
187 {0x0000134c, 0x5a000433},
188 {0x00001094, 0x2d20b0fa},
189 {0x00001080, 0xade75dd0},
190 {0x00001090, 0x10a0540b},
191 {0x000010a8, 0xb101010a},
192 {0x00001100, 0x33053460},
193 {0x00001110, 0x0030101c},
194 {0x00001138, 0xdf808444},
195 {0x0000113c, 0xc8422204},
196 {0x00001140, 0x8180088c},
197 {0x00001174, 0x00000000},
198 {0x00000000, 0x00000000}
199};
200
201static const struct phy_reg x1_port3_config_regs[] = {
202 {0x00001894, 0xc80060fa},
203 {0x00001880, 0x0f90fd6a},
204 {0x00001890, 0x10a0840b},
205 {0x000018a8, 0xdf04010a},
206 {0x00001900, 0x57050060},
207 {0x00001910, 0x0030001c},
208 {0x00001938, 0x5f004444},
209 {0x0000193c, 0x78464204},
210 {0x00001948, 0x7821f940},
211 {0x0000194c, 0xb2000433},
212 {0x00001694, 0x3050d0fa},
213 {0x00001680, 0x0ef6d050},
214 {0x00001690, 0x10a0540b},
215 {0x000016a8, 0xe301010a},
216 {0x00001700, 0x69053460},
217 {0x00001710, 0xa030101c},
218 {0x00001738, 0xdf808444},
219 {0x0000173c, 0xc8422204},
220 {0x00001740, 0x0180088c},
221 {0x00001774, 0x00000000},
222 {0x00000000, 0x00000000}
223};
224
225static const struct phy_reg x2_port0_config_regs[] = {
226 {0x00000694, 0xc80060fa},
227 {0x00000680, 0x3d4f78ea},
228 {0x00000690, 0x10a0140b},
229 {0x000006a8, 0xdf04010a},
230 {0x00000700, 0x57050060},
231 {0x00000710, 0x0030001c},
232 {0x00000738, 0x5f004444},
233 {0x0000073c, 0x78464204},
234 {0x00000748, 0x7821f940},
235 {0x0000074c, 0xb2000433},
236 {0x00000494, 0xc80060fa},
237 {0x00000480, 0x29ef5ed8},
238 {0x00000490, 0x10a0540b},
239 {0x000004a8, 0x7a01010a},
240 {0x00000500, 0xef053460},
241 {0x00000510, 0xe030101c},
242 {0x00000538, 0xdf808444},
243 {0x0000053c, 0xc8422204},
244 {0x00000540, 0x0180088c},
245 {0x00000574, 0x00000000},
246 {0x00000294, 0xc80060fa},
247 {0x00000280, 0xcb45b950},
248 {0x00000290, 0x10a0540b},
249 {0x000002a8, 0x8c01010a},
250 {0x00000300, 0xef053460},
251 {0x00000310, 0x8030101c},
252 {0x00000338, 0x41808444},
253 {0x0000033c, 0x32422204},
254 {0x00000340, 0x0180088c},
255 {0x00000374, 0x00000000},
256 {0x00000000, 0x00000000}
257};
258
259static const struct phy_reg x2_port1_config_regs[] = {
260 {0x00000c94, 0xc80060fa},
261 {0x00000c80, 0xcf47abea},
262 {0x00000c90, 0x10a0840b},
263 {0x00000ca8, 0xdf04010a},
264 {0x00000d00, 0x57050060},
265 {0x00000d10, 0x0030001c},
266 {0x00000d38, 0x5f004444},
267 {0x00000d3c, 0x78464204},
268 {0x00000d48, 0x7821f940},
269 {0x00000d4c, 0xb2000433},
270 {0x00000a94, 0xc80060fa},
271 {0x00000a80, 0x5a166ed8},
272 {0x00000a90, 0x10a0540b},
273 {0x00000aa8, 0x7a01010a},
274 {0x00000b00, 0xef053460},
275 {0x00000b10, 0xa030101c},
276 {0x00000b38, 0xdf808444},
277 {0x00000b3c, 0xc8422204},
278 {0x00000b40, 0x0180088c},
279 {0x00000b74, 0x00000000},
280 {0x00000894, 0xc80060fa},
281 {0x00000880, 0x4d4f21d0},
282 {0x00000890, 0x10a0540b},
283 {0x000008a8, 0x5601010a},
284 {0x00000900, 0xef053460},
285 {0x00000910, 0x8030101c},
286 {0x00000938, 0xdf808444},
287 {0x0000093c, 0xc8422204},
288 {0x00000940, 0x0180088c},
289 {0x00000974, 0x00000000},
290 {0x00000000, 0x00000000}
291};
292
293static const struct phy_reg x2_port2_config_regs[] = {
294 {0x00001294, 0xc80060fa},
295 {0x00001280, 0x08130cea},
296 {0x00001290, 0x10a0140b},
297 {0x000012a8, 0xd704010a},
298 {0x00001300, 0x8d050060},
299 {0x00001310, 0x0030001c},
300 {0x00001338, 0xdf008444},
301 {0x0000133c, 0x78422204},
302 {0x00001348, 0x7821f940},
303 {0x0000134c, 0x5a000433},
304 {0x00001094, 0xc80060fa},
305 {0x00001080, 0xade75dd8},
306 {0x00001090, 0x10a0540b},
307 {0x000010a8, 0xb101010a},
308 {0x00001100, 0x33053460},
309 {0x00001110, 0x0030101c},
310 {0x00001138, 0xdf808444},
311 {0x0000113c, 0xc8422204},
312 {0x00001140, 0x8180088c},
313 {0x00001174, 0x00000000},
314 {0x00000e94, 0xc80060fa},
315 {0x00000e80, 0x0fbf16d0},
316 {0x00000e90, 0x10a0540b},
317 {0x00000ea8, 0x7a01010a},
318 {0x00000f00, 0xf5053460},
319 {0x00000f10, 0xc030101c},
320 {0x00000f38, 0xdf808444},
321 {0x00000f3c, 0xc8422204},
322 {0x00000f40, 0x8180088c},
323 {0x00000000, 0x00000000}
324};
325
326static const struct phy_reg x2_port3_config_regs[] = {
327 {0x00001894, 0xc80060fa},
328 {0x00001880, 0x0f90fd6a},
329 {0x00001890, 0x10a0840b},
330 {0x000018a8, 0xdf04010a},
331 {0x00001900, 0x57050060},
332 {0x00001910, 0x0030001c},
333 {0x00001938, 0x5f004444},
334 {0x0000193c, 0x78464204},
335 {0x00001948, 0x7821f940},
336 {0x0000194c, 0xb2000433},
337 {0x00001694, 0xc80060fa},
338 {0x00001680, 0x0ef6d058},
339 {0x00001690, 0x10a0540b},
340 {0x000016a8, 0x7a01010a},
341 {0x00001700, 0x69053460},
342 {0x00001710, 0xa030101c},
343 {0x00001738, 0xdf808444},
344 {0x0000173c, 0xc8422204},
345 {0x00001740, 0x0180088c},
346 {0x00001774, 0x00000000},
347 {0x00001494, 0xc80060fa},
348 {0x00001480, 0xf9d34bd0},
349 {0x00001490, 0x10a0540b},
350 {0x000014a8, 0x7a01010a},
351 {0x00001500, 0x1b053460},
352 {0x00001510, 0x0030101c},
353 {0x00001538, 0xdf808444},
354 {0x0000153c, 0xc8422204},
355 {0x00001540, 0x8180088c},
356 {0x00001574, 0x00000000},
357 {0x00000000, 0x00000000}
358};
359
360static const struct phy_reg x4_port0_config_regs[] = {
361 {0x00000694, 0xc80060fa},
362 {0x00000680, 0x3d4f78fa},
363 {0x00000690, 0x10a0140b},
364 {0x000006a8, 0xdf04010a},
365 {0x00000700, 0x57050060},
366 {0x00000710, 0x0030001c},
367 {0x00000738, 0x5f004444},
368 {0x0000073c, 0x78464204},
369 {0x00000748, 0x7821f940},
370 {0x0000074c, 0xb2000433},
371 {0x00000494, 0xfe6030fa},
372 {0x00000480, 0x29ef5ed8},
373 {0x00000490, 0x10a0540b},
374 {0x000004a8, 0x7a01010a},
375 {0x00000500, 0xef053460},
376 {0x00000510, 0xe030101c},
377 {0x00000538, 0xdf808444},
378 {0x0000053c, 0xc8422204},
379 {0x00000540, 0x0180088c},
380 {0x00000574, 0x00000004},
381 {0x00000294, 0x23e030fa},
382 {0x00000280, 0xcb45b950},
383 {0x00000290, 0x10a0540b},
384 {0x000002a8, 0x8c01010a},
385 {0x00000300, 0xef053460},
386 {0x00000310, 0x8030101c},
387 {0x00000338, 0x41808444},
388 {0x0000033c, 0x32422204},
389 {0x00000340, 0x0180088c},
390 {0x00000374, 0x00000004},
391 {0x00000894, 0x5620b0fa},
392 {0x00000880, 0x4d4f21dc},
393 {0x00000890, 0x10a0540b},
394 {0x000008a8, 0x5601010a},
395 {0x00000900, 0xef053460},
396 {0x00000910, 0x8030101c},
397 {0x00000938, 0xdf808444},
398 {0x0000093c, 0xc8422204},
399 {0x00000940, 0x0180088c},
400 {0x00000974, 0x00000004},
401 {0x00000a94, 0xc91030fa},
402 {0x00000a80, 0x5a166ecc},
403 {0x00000a90, 0x10a0540b},
404 {0x00000aa8, 0x5d01010a},
405 {0x00000b00, 0xef053460},
406 {0x00000b10, 0xa030101c},
407 {0x00000b38, 0xdf808444},
408 {0x00000b3c, 0xc8422204},
409 {0x00000b40, 0x0180088c},
410 {0x00000b74, 0x00000004},
411 {0x00000000, 0x00000000}
412};
413
414static const struct phy_reg x4_port1_config_regs[] = {
415 {0x00000000, 0x00000000}
416};
417
418static const struct phy_reg x4_port2_config_regs[] = {
419 {0x00001294, 0x28f000fa},
420 {0x00001280, 0x08130cfa},
421 {0x00001290, 0x10c0140b},
422 {0x000012a8, 0xd704010a},
423 {0x00001300, 0x8d050060},
424 {0x00001310, 0x0030001c},
425 {0x00001338, 0xdf008444},
426 {0x0000133c, 0x78422204},
427 {0x00001348, 0x7821f940},
428 {0x0000134c, 0x5a000433},
429 {0x00001094, 0x2d20b0fa},
430 {0x00001080, 0xade75dd8},
431 {0x00001090, 0x10a0540b},
432 {0x000010a8, 0xb101010a},
433 {0x00001100, 0x33053460},
434 {0x00001110, 0x0030101c},
435 {0x00001138, 0xdf808444},
436 {0x0000113c, 0xc8422204},
437 {0x00001140, 0x8180088c},
438 {0x00001174, 0x00000004},
439 {0x00000e94, 0xd308d0fa},
440 {0x00000e80, 0x0fbf16d0},
441 {0x00000e90, 0x10a0540b},
442 {0x00000ea8, 0x2c01010a},
443 {0x00000f00, 0xf5053460},
444 {0x00000f10, 0xc030101c},
445 {0x00000f38, 0xdf808444},
446 {0x00000f3c, 0xc8422204},
447 {0x00000f40, 0x8180088c},
448 {0x00000f74, 0x00000004},
449 {0x00001494, 0x136850fa},
450 {0x00001480, 0xf9d34bdc},
451 {0x00001490, 0x10a0540b},
452 {0x000014a8, 0x5a01010a},
453 {0x00001500, 0x1b053460},
454 {0x00001510, 0x0030101c},
455 {0x00001538, 0xdf808444},
456 {0x0000153c, 0xc8422204},
457 {0x00001540, 0x8180088c},
458 {0x00001574, 0x00000004},
459 {0x00001694, 0x3050d0fa},
460 {0x00001680, 0x0ef6d04c},
461 {0x00001690, 0x10a0540b},
462 {0x000016a8, 0xe301010a},
463 {0x00001700, 0x69053460},
464 {0x00001710, 0xa030101c},
465 {0x00001738, 0xdf808444},
466 {0x0000173c, 0xc8422204},
467 {0x00001740, 0x0180088c},
468 {0x00001774, 0x00000004},
469 {0x00000000, 0x00000000}
470};
471
472static const struct phy_reg x4_port3_config_regs[] = {
473 {0x00000000, 0x00000000}
474};
475
476static const struct phy_reg *x1_config_regs[4] = {
477 x1_port0_config_regs,
478 x1_port1_config_regs,
479 x1_port2_config_regs,
480 x1_port3_config_regs
481};
482
483static const struct phy_reg *x2_config_regs[4] = {
484 x2_port0_config_regs,
485 x2_port1_config_regs,
486 x2_port2_config_regs,
487 x2_port3_config_regs
488};
489
490static const struct phy_reg *x4_config_regs[4] = {
491 x4_port0_config_regs,
492 x4_port1_config_regs,
493 x4_port2_config_regs,
494 x4_port3_config_regs
495};
496
497static const struct phy_reg **config_regs[3] = {
498 x1_config_regs,
499 x2_config_regs,
500 x4_config_regs
501};
502
503static int ipu6_isys_mcd_phy_powerup_ack(struct ipu6_isys *isys, u8 id)
504{
505 struct device *dev = &isys->adev->auxdev.dev;
506 void __iomem *isys_base = isys->pdata->base;
507 u32 val;
508 int ret;
509
510 val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
511 val |= CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN;
512 writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
513
514 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
515 val, val & CSI_REG_HUB_GPREG_PHY_POWER_ACK,
516 200, MCD_PHY_POWER_STATUS_TIMEOUT);
517 if (ret)
518 dev_err(dev, "PHY%d powerup ack timeout", id);
519
520 return ret;
521}
522
523static int ipu6_isys_mcd_phy_powerdown_ack(struct ipu6_isys *isys, u8 id)
524{
525 struct device *dev = &isys->adev->auxdev.dev;
526 void __iomem *isys_base = isys->pdata->base;
527 u32 val;
528 int ret;
529
530 writel(0, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
531 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
532 val, !(val & CSI_REG_HUB_GPREG_PHY_POWER_ACK),
533 200, MCD_PHY_POWER_STATUS_TIMEOUT);
534 if (ret)
535 dev_err(dev, "PHY%d powerdown ack timeout", id);
536
537 return ret;
538}
539
540static void ipu6_isys_mcd_phy_reset(struct ipu6_isys *isys, u8 id, bool assert)
541{
542 void __iomem *isys_base = isys->pdata->base;
543 u32 val;
544
545 val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
546 if (assert)
547 val |= CSI_REG_HUB_GPREG_PHY_CTL_RESET;
548 else
549 val &= ~(CSI_REG_HUB_GPREG_PHY_CTL_RESET);
550
551 writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));
552}
553
554static int ipu6_isys_mcd_phy_ready(struct ipu6_isys *isys, u8 id)
555{
556 struct device *dev = &isys->adev->auxdev.dev;
557 void __iomem *isys_base = isys->pdata->base;
558 u32 val;
559 int ret;
560
561 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id),
562 val, val & CSI_REG_HUB_GPREG_PHY_READY,
563 200, MCD_PHY_POWER_STATUS_TIMEOUT);
564 if (ret)
565 dev_err(dev, "PHY%d ready ack timeout", id);
566
567 return ret;
568}
569
570static void ipu6_isys_mcd_phy_common_init(struct ipu6_isys *isys)
571{
572 struct ipu6_bus_device *adev = isys->adev;
573 struct ipu6_device *isp = adev->isp;
574 void __iomem *isp_base = isp->base;
575 struct sensor_async_sd *s_asd;
576 struct v4l2_async_connection *asc;
577 void __iomem *phy_base;
578 unsigned int i;
579 u8 phy_id;
580
581 list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) {
582 s_asd = container_of(asc, struct sensor_async_sd, asc);
583 phy_id = s_asd->csi2.port / 4;
584 phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id);
585
586 for (i = 0; i < ARRAY_SIZE(common_init_regs); i++)
587 writel(common_init_regs[i].val,
588 phy_base + common_init_regs[i].reg);
589 }
590}
591
592static int ipu6_isys_driver_port_to_phy_port(struct ipu6_isys_csi2_config *cfg)
593{
594 int phy_port;
595 int ret;
596
597 if (!(cfg->nlanes == 4 || cfg->nlanes == 2 || cfg->nlanes == 1))
598 return -EINVAL;
599
600 /* B,F -> C0 A,E -> C1 C,G -> C2 D,H -> C4 */
601 /* normalize driver port number */
602 phy_port = cfg->port % 4;
603
604 /* swap port number only for A and B */
605 if (phy_port == 0)
606 phy_port = 1;
607 else if (phy_port == 1)
608 phy_port = 0;
609
610 ret = phy_port;
611
612 /* check validity per lane configuration */
613 if (cfg->nlanes == 4 && !(phy_port == 0 || phy_port == 2))
614 ret = -EINVAL;
615 else if ((cfg->nlanes == 2 || cfg->nlanes == 1) &&
616 !(phy_port >= 0 && phy_port <= 3))
617 ret = -EINVAL;
618
619 return ret;
620}
621
622static int ipu6_isys_mcd_phy_config(struct ipu6_isys *isys)
623{
624 struct device *dev = &isys->adev->auxdev.dev;
625 struct ipu6_bus_device *adev = isys->adev;
626 const struct phy_reg **phy_config_regs;
627 struct ipu6_device *isp = adev->isp;
628 void __iomem *isp_base = isp->base;
629 struct sensor_async_sd *s_asd;
630 struct ipu6_isys_csi2_config cfg;
631 struct v4l2_async_connection *asc;
632 int phy_port, phy_id;
633 unsigned int i;
634 void __iomem *phy_base;
635
636 list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) {
637 s_asd = container_of(asc, struct sensor_async_sd, asc);
638 cfg.port = s_asd->csi2.port;
639 cfg.nlanes = s_asd->csi2.nlanes;
640 phy_port = ipu6_isys_driver_port_to_phy_port(&cfg);
641 if (phy_port < 0) {
642 dev_err(dev, "invalid port %d for lane %d", cfg.port,
643 cfg.nlanes);
644 return -ENXIO;
645 }
646
647 phy_id = cfg.port / 4;
648 phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id);
649 dev_dbg(dev, "port%d PHY%u lanes %u\n", cfg.port, phy_id,
650 cfg.nlanes);
651
652 phy_config_regs = config_regs[cfg.nlanes / 2];
653 cfg.port = phy_port;
654 for (i = 0; phy_config_regs[cfg.port][i].reg; i++)
655 writel(phy_config_regs[cfg.port][i].val,
656 phy_base + phy_config_regs[cfg.port][i].reg);
657 }
658
659 return 0;
660}
661
662#define CSI_MCD_PHY_NUM 2
663static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM];
664
665int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys,
666 struct ipu6_isys_csi2_config *cfg,
667 const struct ipu6_isys_csi2_timing *timing,
668 bool on)
669{
670 struct device *dev = &isys->adev->auxdev.dev;
671 void __iomem *isys_base = isys->pdata->base;
672 u8 port, phy_id;
673 refcount_t *ref;
674 int ret;
675
676 port = cfg->port;
677 phy_id = port / 4;
678
679 ref = &phy_power_ref_count[phy_id];
680
681 dev_dbg(dev, "for phy %d port %d, lanes: %d\n", phy_id, port,
682 cfg->nlanes);
683
684 if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
685 dev_warn(dev, "invalid port ID %d\n", port);
686 return -EINVAL;
687 }
688
689 if (on) {
690 if (refcount_read(ref)) {
691 dev_dbg(dev, "for phy %d is already UP", phy_id);
692 refcount_inc(ref);
693 return 0;
694 }
695
696 ret = ipu6_isys_mcd_phy_powerup_ack(isys, phy_id);
697 if (ret)
698 return ret;
699
700 ipu6_isys_mcd_phy_reset(isys, phy_id, 0);
701 ipu6_isys_mcd_phy_common_init(isys);
702
703 ret = ipu6_isys_mcd_phy_config(isys);
704 if (ret)
705 return ret;
706
707 ipu6_isys_mcd_phy_reset(isys, phy_id, 1);
708 ret = ipu6_isys_mcd_phy_ready(isys, phy_id);
709 if (ret)
710 return ret;
711
712 refcount_set(ref, 1);
713 return 0;
714 }
715
716 if (!refcount_dec_and_test(ref))
717 return 0;
718
719 return ipu6_isys_mcd_phy_powerdown_ack(isys, phy_id);
720}
drivers/media/pci/intel/ipu6/ipu6-isys-queue.c+810−0
@@ -0,0 +1,810 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5#include <linux/atomic.h>
6#include <linux/bug.h>
7#include <linux/device.h>
8#include <linux/list.h>
9#include <linux/lockdep.h>
10#include <linux/mutex.h>
11#include <linux/spinlock.h>
12#include <linux/types.h>
13
14#include <media/media-entity.h>
15#include <media/v4l2-subdev.h>
16#include <media/videobuf2-dma-contig.h>
17#include <media/videobuf2-v4l2.h>
18
19#include "ipu6-bus.h"
20#include "ipu6-fw-isys.h"
21#include "ipu6-isys.h"
22#include "ipu6-isys-video.h"
23
24static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
25 unsigned int *num_planes, unsigned int sizes[],
26 struct device *alloc_devs[])
27{
28 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
29 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
30 struct device *dev = &av->isys->adev->auxdev.dev;
31 u32 size = ipu6_isys_get_data_size(av);
32
33 /* num_planes == 0: we're being called through VIDIOC_REQBUFS */
34 if (!*num_planes) {
35 sizes[0] = size;
36 } else if (sizes[0] < size) {
37 dev_dbg(dev, "%s: queue setup: size %u < %u\n",
38 av->vdev.name, sizes[0], size);
39 return -EINVAL;
40 }
41
42 *num_planes = 1;
43
44 return 0;
45}
46
47static int ipu6_isys_buf_prepare(struct vb2_buffer *vb)
48{
49 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
50 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
51 struct device *dev = &av->isys->adev->auxdev.dev;
52 u32 bytesperline = ipu6_isys_get_bytes_per_line(av);
53 u32 height = ipu6_isys_get_frame_height(av);
54 u32 size = ipu6_isys_get_data_size(av);
55
56 dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n",
57 av->vdev.name, size, vb2_plane_size(vb, 0));
58
59 if (size > vb2_plane_size(vb, 0))
60 return -EINVAL;
61
62 vb2_set_plane_payload(vb, 0, bytesperline * height);
63
64 return 0;
65}
66
67/*
68 * Queue a buffer list back to incoming or active queues. The buffers
69 * are removed from the buffer list.
70 */
71void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
72 unsigned long op_flags,
73 enum vb2_buffer_state state)
74{
75 struct ipu6_isys_buffer *ib, *ib_safe;
76 unsigned long flags;
77 bool first = true;
78
79 if (!bl)
80 return;
81
82 WARN_ON_ONCE(!bl->nbufs);
83 WARN_ON_ONCE(op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE &&
84 op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING);
85
86 list_for_each_entry_safe(ib, ib_safe, &bl->head, head) {
87 struct ipu6_isys_video *av;
88 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
89 struct ipu6_isys_queue *aq =
90 vb2_queue_to_isys_queue(vb->vb2_queue);
91 struct device *dev;
92
93 av = ipu6_isys_queue_to_video(aq);
94 dev = &av->isys->adev->auxdev.dev;
95 spin_lock_irqsave(&aq->lock, flags);
96 list_del(&ib->head);
97 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE)
98 list_add(&ib->head, &aq->active);
99 else if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING)
100 list_add_tail(&ib->head, &aq->incoming);
101 spin_unlock_irqrestore(&aq->lock, flags);
102
103 if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)
104 vb2_buffer_done(vb, state);
105
106 if (first) {
107 dev_dbg(dev,
108 "queue buf list %p flags %lx, s %d, %d bufs\n",
109 bl, op_flags, state, bl->nbufs);
110 first = false;
111 }
112
113 bl->nbufs--;
114 }
115
116 WARN_ON(bl->nbufs);
117}
118
119/*
120 * flush_firmware_streamon_fail() - Flush in cases where requests may
121 * have been queued to firmware and the *firmware streamon fails for a
122 * reason or another.
123 */
124static void flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)
125{
126 struct device *dev = &stream->isys->adev->auxdev.dev;
127 struct ipu6_isys_queue *aq;
128 unsigned long flags;
129
130 lockdep_assert_held(&stream->mutex);
131
132 list_for_each_entry(aq, &stream->queues, node) {
133 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
134 struct ipu6_isys_buffer *ib, *ib_safe;
135
136 spin_lock_irqsave(&aq->lock, flags);
137 list_for_each_entry_safe(ib, ib_safe, &aq->active, head) {
138 struct vb2_buffer *vb =
139 ipu6_isys_buffer_to_vb2_buffer(ib);
140
141 list_del(&ib->head);
142 if (av->streaming) {
143 dev_dbg(dev,
144 "%s: queue buffer %u back to incoming\n",
145 av->vdev.name, vb->index);
146 /* Queue already streaming, return to driver. */
147 list_add(&ib->head, &aq->incoming);
148 continue;
149 }
150 /* Queue not yet streaming, return to user. */
151 dev_dbg(dev, "%s: return %u back to videobuf2\n",
152 av->vdev.name, vb->index);
153 vb2_buffer_done(ipu6_isys_buffer_to_vb2_buffer(ib),
154 VB2_BUF_STATE_QUEUED);
155 }
156 spin_unlock_irqrestore(&aq->lock, flags);
157 }
158}
159
160/*
161 * Attempt obtaining a buffer list from the incoming queues, a list of buffers
162 * that contains one entry from each video buffer queue. If a buffer can't be
163 * obtained from every queue, the buffers are returned back to the queue.
164 */
165static int buffer_list_get(struct ipu6_isys_stream *stream,
166 struct ipu6_isys_buffer_list *bl)
167{
168 struct device *dev = &stream->isys->adev->auxdev.dev;
169 struct ipu6_isys_queue *aq;
170 unsigned long flags;
171 unsigned long buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;
172
173 bl->nbufs = 0;
174 INIT_LIST_HEAD(&bl->head);
175
176 list_for_each_entry(aq, &stream->queues, node) {
177 struct ipu6_isys_buffer *ib;
178
179 spin_lock_irqsave(&aq->lock, flags);
180 if (list_empty(&aq->incoming)) {
181 spin_unlock_irqrestore(&aq->lock, flags);
182 if (!list_empty(&bl->head))
183 ipu6_isys_buffer_list_queue(bl, buf_flag, 0);
184 return -ENODATA;
185 }
186
187 ib = list_last_entry(&aq->incoming,
188 struct ipu6_isys_buffer, head);
189
190 dev_dbg(dev, "buffer: %s: buffer %u\n",
191 ipu6_isys_queue_to_video(aq)->vdev.name,
192 ipu6_isys_buffer_to_vb2_buffer(ib)->index);
193 list_del(&ib->head);
194 list_add(&ib->head, &bl->head);
195 spin_unlock_irqrestore(&aq->lock, flags);
196
197 bl->nbufs++;
198 }
199
200 dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs);
201
202 return 0;
203}
204
205static void
206ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
207 struct ipu6_fw_isys_frame_buff_set_abi *set)
208{
209 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
210
211 set->output_pins[aq->fw_output].addr =
212 vb2_dma_contig_plane_dma_addr(vb, 0);
213 set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
214}
215
216/*
217 * Convert a buffer list to a isys fw ABI framebuffer set. The
218 * buffer list is not modified.
219 */
220#define IPU6_ISYS_FRAME_NUM_THRESHOLD (30)
221void
222ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
223 struct ipu6_isys_stream *stream,
224 struct ipu6_isys_buffer_list *bl)
225{
226 struct ipu6_isys_buffer *ib;
227
228 WARN_ON(!bl->nbufs);
229
230 set->send_irq_sof = 1;
231 set->send_resp_sof = 1;
232 set->send_irq_eof = 0;
233 set->send_resp_eof = 0;
234
235 if (stream->streaming)
236 set->send_irq_capture_ack = 0;
237 else
238 set->send_irq_capture_ack = 1;
239 set->send_irq_capture_done = 0;
240
241 set->send_resp_capture_ack = 1;
242 set->send_resp_capture_done = 1;
243 if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {
244 set->send_resp_capture_ack = 0;
245 set->send_resp_capture_done = 0;
246 }
247
248 list_for_each_entry(ib, &bl->head, head) {
249 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
250
251 ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
252 }
253}
254
255/* Start streaming for real. The buffer list must be available. */
256static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
257 struct ipu6_isys_buffer_list *bl, bool error)
258{
259 struct ipu6_isys_stream *stream = av->stream;
260 struct device *dev = &stream->isys->adev->auxdev.dev;
261 struct ipu6_isys_buffer_list __bl;
262 int ret;
263
264 mutex_lock(&stream->isys->stream_mutex);
265 ret = ipu6_isys_video_set_streaming(av, 1, bl);
266 mutex_unlock(&stream->isys->stream_mutex);
267 if (ret)
268 goto out_requeue;
269
270 stream->streaming = 1;
271
272 bl = &__bl;
273
274 do {
275 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
276 struct isys_fw_msgs *msg;
277 u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;
278
279 ret = buffer_list_get(stream, bl);
280 if (ret < 0)
281 break;
282
283 msg = ipu6_get_fw_msg_buf(stream);
284 if (!msg)
285 return -ENOMEM;
286
287 buf = &msg->fw_msg.frame;
288 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
289 ipu6_fw_isys_dump_frame_buff_set(dev, buf,
290 stream->nr_output_pins);
291 ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
292 0);
293 ret = ipu6_fw_isys_complex_cmd(stream->isys,
294 stream->stream_handle, buf,
295 msg->dma_addr, sizeof(*buf),
296 send_type);
297 } while (!WARN_ON(ret));
298
299 return 0;
300
301out_requeue:
302 if (bl && bl->nbufs)
303 ipu6_isys_buffer_list_queue(bl,
304 (IPU6_ISYS_BUFFER_LIST_FL_INCOMING |
305 error) ?
306 IPU6_ISYS_BUFFER_LIST_FL_SET_STATE :
307 0, error ? VB2_BUF_STATE_ERROR :
308 VB2_BUF_STATE_QUEUED);
309 flush_firmware_streamon_fail(stream);
310
311 return ret;
312}
313
314static void buf_queue(struct vb2_buffer *vb)
315{
316 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
317 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
318 struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
319 struct ipu6_isys_video_buffer *ivb =
320 vb2_buffer_to_ipu6_isys_video_buffer(vvb);
321 struct ipu6_isys_buffer *ib = &ivb->ib;
322 struct device *dev = &av->isys->adev->auxdev.dev;
323 struct media_pipeline *media_pipe =
324 media_entity_pipeline(&av->vdev.entity);
325 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
326 struct ipu6_isys_stream *stream = av->stream;
327 struct ipu6_isys_buffer_list bl;
328 struct isys_fw_msgs *msg;
329 unsigned long flags;
330 dma_addr_t dma;
331 int ret;
332
333 dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);
334
335 dma = vb2_dma_contig_plane_dma_addr(vb, 0);
336 dev_dbg(dev, "iova: iova %pad\n", &dma);
337
338 spin_lock_irqsave(&aq->lock, flags);
339 list_add(&ib->head, &aq->incoming);
340 spin_unlock_irqrestore(&aq->lock, flags);
341
342 if (!media_pipe || !vb->vb2_queue->start_streaming_called) {
343 dev_dbg(dev, "media pipeline is not ready for %s\n",
344 av->vdev.name);
345 return;
346 }
347
348 mutex_lock(&stream->mutex);
349
350 if (stream->nr_streaming != stream->nr_queues) {
351 dev_dbg(dev, "not streaming yet, adding to incoming\n");
352 goto out;
353 }
354
355 /*
356 * We just put one buffer to the incoming list of this queue
357 * (above). Let's see whether all queues in the pipeline would
358 * have a buffer.
359 */
360 ret = buffer_list_get(stream, &bl);
361 if (ret < 0) {
362 dev_dbg(dev, "No buffers available\n");
363 goto out;
364 }
365
366 msg = ipu6_get_fw_msg_buf(stream);
367 if (!msg) {
368 ret = -ENOMEM;
369 goto out;
370 }
371
372 buf = &msg->fw_msg.frame;
373 ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
374 ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
375
376 if (!stream->streaming) {
377 ret = ipu6_isys_stream_start(av, &bl, true);
378 if (ret)
379 dev_err(dev, "stream start failed.\n");
380 goto out;
381 }
382
383 /*
384 * We must queue the buffers in the buffer list to the
385 * appropriate video buffer queues BEFORE passing them to the
386 * firmware since we could get a buffer event back before we
387 * have queued them ourselves to the active queue.
388 */
389 ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
390
391 ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
392 buf, msg->dma_addr, sizeof(*buf),
393 IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
394 if (ret < 0)
395 dev_err(dev, "send stream capture failed\n");
396
397out:
398 mutex_unlock(&stream->mutex);
399}
400
401static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
402{
403 struct v4l2_mbus_framefmt format;
404 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
405 struct device *dev = &av->isys->adev->auxdev.dev;
406 struct media_pad *remote_pad =
407 media_pad_remote_pad_first(av->vdev.entity.pads);
408 struct v4l2_subdev *sd;
409 u32 r_stream, code;
410 int ret;
411
412 if (!remote_pad)
413 return -ENOTCONN;
414
415 sd = media_entity_to_v4l2_subdev(remote_pad->entity);
416 r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, remote_pad->index);
417
418 ret = ipu6_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,
419 &format);
420
421 if (ret) {
422 dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",
423 sd->entity.name, remote_pad->index, r_stream);
424 return ret;
425 }
426
427 if (format.width != ipu6_isys_get_frame_width(av) ||
428 format.height != ipu6_isys_get_frame_height(av)) {
429 dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n",
430 ipu6_isys_get_frame_width(av),
431 ipu6_isys_get_frame_height(av), format.width,
432 format.height);
433 return -EINVAL;
434 }
435
436 code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
437 if (format.code != code) {
438 dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n",
439 code, format.code);
440 return -EINVAL;
441 }
442
443 return 0;
444}
445
446static void return_buffers(struct ipu6_isys_queue *aq,
447 enum vb2_buffer_state state)
448{
449 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
450 struct ipu6_isys_buffer *ib;
451 bool need_reset = false;
452 unsigned long flags;
453
454 spin_lock_irqsave(&aq->lock, flags);
455 while (!list_empty(&aq->incoming)) {
456 struct vb2_buffer *vb;
457
458 ib = list_first_entry(&aq->incoming, struct ipu6_isys_buffer,
459 head);
460 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
461 list_del(&ib->head);
462 spin_unlock_irqrestore(&aq->lock, flags);
463
464 vb2_buffer_done(vb, state);
465
466 spin_lock_irqsave(&aq->lock, flags);
467 }
468
469 /*
470 * Something went wrong (FW crash / HW hang / not all buffers
471 * returned from isys) if there are still buffers queued in active
472 * queue. We have to clean up places a bit.
473 */
474 while (!list_empty(&aq->active)) {
475 struct vb2_buffer *vb;
476
477 ib = list_first_entry(&aq->active, struct ipu6_isys_buffer,
478 head);
479 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
480
481 list_del(&ib->head);
482 spin_unlock_irqrestore(&aq->lock, flags);
483
484 vb2_buffer_done(vb, state);
485
486 spin_lock_irqsave(&aq->lock, flags);
487 need_reset = true;
488 }
489
490 spin_unlock_irqrestore(&aq->lock, flags);
491
492 if (need_reset) {
493 mutex_lock(&av->isys->mutex);
494 av->isys->need_reset = true;
495 mutex_unlock(&av->isys->mutex);
496 }
497}
498
499static void ipu6_isys_stream_cleanup(struct ipu6_isys_video *av)
500{
501 video_device_pipeline_stop(&av->vdev);
502 ipu6_isys_put_stream(av->stream);
503 av->stream = NULL;
504}
505
506static int start_streaming(struct vb2_queue *q, unsigned int count)
507{
508 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
509 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
510 struct device *dev = &av->isys->adev->auxdev.dev;
511 const struct ipu6_isys_pixelformat *pfmt =
512 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
513 struct ipu6_isys_buffer_list __bl, *bl = NULL;
514 struct ipu6_isys_stream *stream;
515 struct media_entity *source_entity = NULL;
516 int nr_queues, ret;
517
518 dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
519 av->vdev.name, ipu6_isys_get_frame_width(av),
520 ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);
521
522 ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);
523 if (ret < 0) {
524 dev_dbg(dev, "failed to setup video\n");
525 goto out_return_buffers;
526 }
527
528 ret = ipu6_isys_link_fmt_validate(aq);
529 if (ret) {
530 dev_dbg(dev,
531 "%s: link format validation failed (%d)\n",
532 av->vdev.name, ret);
533 goto out_pipeline_stop;
534 }
535
536 ret = ipu6_isys_fw_open(av->isys);
537 if (ret)
538 goto out_pipeline_stop;
539
540 stream = av->stream;
541 mutex_lock(&stream->mutex);
542 if (!stream->nr_streaming) {
543 ret = ipu6_isys_video_prepare_stream(av, source_entity,
544 nr_queues);
545 if (ret)
546 goto out_fw_close;
547 }
548
549 stream->nr_streaming++;
550 dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,
551 stream->nr_queues);
552
553 list_add(&aq->node, &stream->queues);
554 ipu6_isys_set_csi2_streams_status(av, true);
555 ipu6_isys_configure_stream_watermark(av, true);
556 ipu6_isys_update_stream_watermark(av, true);
557
558 if (stream->nr_streaming != stream->nr_queues)
559 goto out;
560
561 bl = &__bl;
562 ret = buffer_list_get(stream, bl);
563 if (ret < 0) {
564 dev_warn(dev, "no buffer available, DRIVER BUG?\n");
565 goto out;
566 }
567
568 ret = ipu6_isys_stream_start(av, bl, false);
569 if (ret)
570 goto out_stream_start;
571
572out:
573 mutex_unlock(&stream->mutex);
574
575 return 0;
576
577out_stream_start:
578 ipu6_isys_update_stream_watermark(av, false);
579 list_del(&aq->node);
580 stream->nr_streaming--;
581
582out_fw_close:
583 mutex_unlock(&stream->mutex);
584 ipu6_isys_fw_close(av->isys);
585
586out_pipeline_stop:
587 ipu6_isys_stream_cleanup(av);
588
589out_return_buffers:
590 return_buffers(aq, VB2_BUF_STATE_QUEUED);
591
592 return ret;
593}
594
595static void stop_streaming(struct vb2_queue *q)
596{
597 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
598 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
599 struct ipu6_isys_stream *stream = av->stream;
600
601 ipu6_isys_set_csi2_streams_status(av, false);
602
603 mutex_lock(&stream->mutex);
604
605 ipu6_isys_update_stream_watermark(av, false);
606
607 mutex_lock(&av->isys->stream_mutex);
608 if (stream->nr_streaming == stream->nr_queues && stream->streaming)
609 ipu6_isys_video_set_streaming(av, 0, NULL);
610 mutex_unlock(&av->isys->stream_mutex);
611
612 stream->nr_streaming--;
613 list_del(&aq->node);
614 stream->streaming = 0;
615 mutex_unlock(&stream->mutex);
616
617 ipu6_isys_stream_cleanup(av);
618
619 return_buffers(aq, VB2_BUF_STATE_ERROR);
620
621 ipu6_isys_fw_close(av->isys);
622}
623
624static unsigned int
625get_sof_sequence_by_timestamp(struct ipu6_isys_stream *stream,
626 struct ipu6_fw_isys_resp_info_abi *info)
627{
628 u64 time = (u64)info->timestamp[1] << 32 | info->timestamp[0];
629 struct ipu6_isys *isys = stream->isys;
630 struct device *dev = &isys->adev->auxdev.dev;
631 unsigned int i;
632
633 /*
634 * The timestamp is invalid as no TSC in some FPGA platform,
635 * so get the sequence from pipeline directly in this case.
636 */
637 if (time == 0)
638 return atomic_read(&stream->sequence) - 1;
639
640 for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)
641 if (time == stream->seq[i].timestamp) {
642 dev_dbg(dev, "sof: using seq nr %u for ts %llu\n",
643 stream->seq[i].sequence, time);
644 return stream->seq[i].sequence;
645 }
646
647 for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)
648 dev_dbg(dev, "sof: sequence %u, timestamp value %llu\n",
649 stream->seq[i].sequence, stream->seq[i].timestamp);
650
651 return 0;
652}
653
654static u64 get_sof_ns_delta(struct ipu6_isys_video *av,
655 struct ipu6_fw_isys_resp_info_abi *info)
656{
657 struct ipu6_bus_device *adev = av->isys->adev;
658 struct ipu6_device *isp = adev->isp;
659 u64 delta, tsc_now;
660
661 ipu6_buttress_tsc_read(isp, &tsc_now);
662 if (!tsc_now)
663 return 0;
664
665 delta = tsc_now - ((u64)info->timestamp[1] << 32 | info->timestamp[0]);
666
667 return ipu6_buttress_tsc_ticks_to_ns(delta, isp);
668}
669
670void ipu6_isys_buf_calc_sequence_time(struct ipu6_isys_buffer *ib,
671 struct ipu6_fw_isys_resp_info_abi *info)
672{
673 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
674 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
675 struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
676 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
677 struct device *dev = &av->isys->adev->auxdev.dev;
678 struct ipu6_isys_stream *stream = av->stream;
679 u64 ns;
680 u32 sequence;
681
682 ns = ktime_get_ns() - get_sof_ns_delta(av, info);
683 sequence = get_sof_sequence_by_timestamp(stream, info);
684
685 vbuf->vb2_buf.timestamp = ns;
686 vbuf->sequence = sequence;
687
688 dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n",
689 av->vdev.name, ktime_get_ns(), sequence);
690 dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index,
691 vbuf->vb2_buf.timestamp);
692}
693
694void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)
695{
696 struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
697
698 if (atomic_read(&ib->str2mmio_flag)) {
699 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
700 /*
701 * Operation on buffer is ended with error and will be reported
702 * to the userspace when it is de-queued
703 */
704 atomic_set(&ib->str2mmio_flag, 0);
705 } else {
706 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
707 }
708}
709
710void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
711 struct ipu6_fw_isys_resp_info_abi *info)
712{
713 struct ipu6_isys_queue *aq = stream->output_pins[info->pin_id].aq;
714 struct ipu6_isys *isys = stream->isys;
715 struct device *dev = &isys->adev->auxdev.dev;
716 struct ipu6_isys_buffer *ib;
717 struct vb2_buffer *vb;
718 unsigned long flags;
719 bool first = true;
720 struct vb2_v4l2_buffer *buf;
721
722 spin_lock_irqsave(&aq->lock, flags);
723 if (list_empty(&aq->active)) {
724 spin_unlock_irqrestore(&aq->lock, flags);
725 dev_err(dev, "active queue empty\n");
726 return;
727 }
728
729 list_for_each_entry_reverse(ib, &aq->active, head) {
730 dma_addr_t addr;
731
732 vb = ipu6_isys_buffer_to_vb2_buffer(ib);
733 addr = vb2_dma_contig_plane_dma_addr(vb, 0);
734
735 if (info->pin.addr != addr) {
736 if (first)
737 dev_err(dev, "Unexpected buffer address %pad\n",
738 &addr);
739 first = false;
740 continue;
741 }
742
743 if (info->error_info.error ==
744 IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO) {
745 /*
746 * Check for error message:
747 * 'IPU6_FW_ISYS_ERROR_HW_REPORTED_STR2MMIO'
748 */
749 atomic_set(&ib->str2mmio_flag, 1);
750 }
751 dev_dbg(dev, "buffer: found buffer %pad\n", &addr);
752
753 buf = to_vb2_v4l2_buffer(vb);
754 buf->field = V4L2_FIELD_NONE;
755
756 list_del(&ib->head);
757 spin_unlock_irqrestore(&aq->lock, flags);
758
759 ipu6_isys_buf_calc_sequence_time(ib, info);
760
761 ipu6_isys_queue_buf_done(ib);
762
763 return;
764 }
765
766 dev_err(dev, "Failed to find a matching video buffer");
767
768 spin_unlock_irqrestore(&aq->lock, flags);
769}
770
771static const struct vb2_ops ipu6_isys_queue_ops = {
772 .queue_setup = queue_setup,
773 .wait_prepare = vb2_ops_wait_prepare,
774 .wait_finish = vb2_ops_wait_finish,
775 .buf_prepare = ipu6_isys_buf_prepare,
776 .start_streaming = start_streaming,
777 .stop_streaming = stop_streaming,
778 .buf_queue = buf_queue,
779};
780
781int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)
782{
783 struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys;
784 struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
785 int ret;
786
787 /* no support for userptr */
788 if (!aq->vbq.io_modes)
789 aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;
790
791 aq->vbq.drv_priv = aq;
792 aq->vbq.ops = &ipu6_isys_queue_ops;
793 aq->vbq.lock = &av->mutex;
794 aq->vbq.mem_ops = &vb2_dma_contig_memops;
795 aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
796 aq->vbq.min_queued_buffers = 1;
797 aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
798
799 ret = vb2_queue_init(&aq->vbq);
800 if (ret)
801 return ret;
802
803 aq->dev = &isys->adev->auxdev.dev;
804 aq->vbq.dev = &isys->adev->auxdev.dev;
805 spin_lock_init(&aq->lock);
806 INIT_LIST_HEAD(&aq->active);
807 INIT_LIST_HEAD(&aq->incoming);
808
809 return 0;
810}
drivers/media/pci/intel/ipu6/ipu6-isys-queue.h+78−0
@@ -0,0 +1,78 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_ISYS_QUEUE_H
5#define IPU6_ISYS_QUEUE_H
6
7#include <linux/container_of.h>
8#include <linux/atomic.h>
9#include <linux/device.h>
10#include <linux/list.h>
11#include <linux/spinlock_types.h>
12
13#include <media/videobuf2-v4l2.h>
14
15#include "ipu6-fw-isys.h"
16#include "ipu6-isys-video.h"
17
18struct ipu6_isys_stream;
19
20struct ipu6_isys_queue {
21 struct vb2_queue vbq;
22 struct list_head node;
23 struct device *dev;
24 /*
25 * @lock: serialise access to queued and pre_streamon_queued
26 */
27 spinlock_t lock;
28 struct list_head active;
29 struct list_head incoming;
30 unsigned int fw_output;
31};
32
33struct ipu6_isys_buffer {
34 struct list_head head;
35 atomic_t str2mmio_flag;
36};
37
38struct ipu6_isys_video_buffer {
39 struct vb2_v4l2_buffer vb_v4l2;
40 struct ipu6_isys_buffer ib;
41};
42
43#define IPU6_ISYS_BUFFER_LIST_FL_INCOMING BIT(0)
44#define IPU6_ISYS_BUFFER_LIST_FL_ACTIVE BIT(1)
45#define IPU6_ISYS_BUFFER_LIST_FL_SET_STATE BIT(2)
46
47struct ipu6_isys_buffer_list {
48 struct list_head head;
49 unsigned int nbufs;
50};
51
52#define vb2_queue_to_isys_queue(__vb2) \
53 container_of(__vb2, struct ipu6_isys_queue, vbq)
54
55#define ipu6_isys_to_isys_video_buffer(__ib) \
56 container_of(__ib, struct ipu6_isys_video_buffer, ib)
57
58#define vb2_buffer_to_ipu6_isys_video_buffer(__vvb) \
59 container_of(__vvb, struct ipu6_isys_video_buffer, vb_v4l2)
60
61#define ipu6_isys_buffer_to_vb2_buffer(__ib) \
62 (&ipu6_isys_to_isys_video_buffer(__ib)->vb_v4l2.vb2_buf)
63
64void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
65 unsigned long op_flags,
66 enum vb2_buffer_state state);
67void
68ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
69 struct ipu6_isys_stream *stream,
70 struct ipu6_isys_buffer_list *bl);
71void
72ipu6_isys_buf_calc_sequence_time(struct ipu6_isys_buffer *ib,
73 struct ipu6_fw_isys_resp_info_abi *info);
74void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib);
75void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
76 struct ipu6_fw_isys_resp_info_abi *info);
77int ipu6_isys_queue_init(struct ipu6_isys_queue *aq);
78#endif /* IPU6_ISYS_QUEUE_H */
drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c+403−0
@@ -0,0 +1,403 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bug.h>
7#include <linux/device.h>
8#include <linux/minmax.h>
9
10#include <media/media-entity.h>
11#include <media/mipi-csi2.h>
12#include <media/v4l2-ctrls.h>
13#include <media/v4l2-subdev.h>
14
15#include "ipu6-bus.h"
16#include "ipu6-isys.h"
17#include "ipu6-isys-subdev.h"
18
19unsigned int ipu6_isys_mbus_code_to_bpp(u32 code)
20{
21 switch (code) {
22 case MEDIA_BUS_FMT_RGB888_1X24:
23 case MEDIA_BUS_FMT_META_24:
24 return 24;
25 case MEDIA_BUS_FMT_RGB565_1X16:
26 case MEDIA_BUS_FMT_UYVY8_1X16:
27 case MEDIA_BUS_FMT_YUYV8_1X16:
28 case MEDIA_BUS_FMT_META_16:
29 return 16;
30 case MEDIA_BUS_FMT_SBGGR12_1X12:
31 case MEDIA_BUS_FMT_SGBRG12_1X12:
32 case MEDIA_BUS_FMT_SGRBG12_1X12:
33 case MEDIA_BUS_FMT_SRGGB12_1X12:
34 case MEDIA_BUS_FMT_META_12:
35 return 12;
36 case MEDIA_BUS_FMT_SBGGR10_1X10:
37 case MEDIA_BUS_FMT_SGBRG10_1X10:
38 case MEDIA_BUS_FMT_SGRBG10_1X10:
39 case MEDIA_BUS_FMT_SRGGB10_1X10:
40 case MEDIA_BUS_FMT_META_10:
41 return 10;
42 case MEDIA_BUS_FMT_SBGGR8_1X8:
43 case MEDIA_BUS_FMT_SGBRG8_1X8:
44 case MEDIA_BUS_FMT_SGRBG8_1X8:
45 case MEDIA_BUS_FMT_SRGGB8_1X8:
46 case MEDIA_BUS_FMT_META_8:
47 return 8;
48 default:
49 WARN_ON(1);
50 return 8;
51 }
52}
53
54unsigned int ipu6_isys_mbus_code_to_mipi(u32 code)
55{
56 switch (code) {
57 case MEDIA_BUS_FMT_RGB565_1X16:
58 return MIPI_CSI2_DT_RGB565;
59 case MEDIA_BUS_FMT_RGB888_1X24:
60 return MIPI_CSI2_DT_RGB888;
61 case MEDIA_BUS_FMT_UYVY8_1X16:
62 case MEDIA_BUS_FMT_YUYV8_1X16:
63 return MIPI_CSI2_DT_YUV422_8B;
64 case MEDIA_BUS_FMT_SBGGR16_1X16:
65 case MEDIA_BUS_FMT_SGBRG16_1X16:
66 case MEDIA_BUS_FMT_SGRBG16_1X16:
67 case MEDIA_BUS_FMT_SRGGB16_1X16:
68 return MIPI_CSI2_DT_RAW16;
69 case MEDIA_BUS_FMT_SBGGR12_1X12:
70 case MEDIA_BUS_FMT_SGBRG12_1X12:
71 case MEDIA_BUS_FMT_SGRBG12_1X12:
72 case MEDIA_BUS_FMT_SRGGB12_1X12:
73 return MIPI_CSI2_DT_RAW12;
74 case MEDIA_BUS_FMT_SBGGR10_1X10:
75 case MEDIA_BUS_FMT_SGBRG10_1X10:
76 case MEDIA_BUS_FMT_SGRBG10_1X10:
77 case MEDIA_BUS_FMT_SRGGB10_1X10:
78 return MIPI_CSI2_DT_RAW10;
79 case MEDIA_BUS_FMT_SBGGR8_1X8:
80 case MEDIA_BUS_FMT_SGBRG8_1X8:
81 case MEDIA_BUS_FMT_SGRBG8_1X8:
82 case MEDIA_BUS_FMT_SRGGB8_1X8:
83 return MIPI_CSI2_DT_RAW8;
84 default:
85 /* return unavailable MIPI data type - 0x3f */
86 WARN_ON(1);
87 return 0x3f;
88 }
89}
90
91bool ipu6_isys_is_bayer_format(u32 code)
92{
93 switch (ipu6_isys_mbus_code_to_mipi(code)) {
94 case MIPI_CSI2_DT_RAW8:
95 case MIPI_CSI2_DT_RAW10:
96 case MIPI_CSI2_DT_RAW12:
97 case MIPI_CSI2_DT_RAW14:
98 case MIPI_CSI2_DT_RAW16:
99 case MIPI_CSI2_DT_RAW20:
100 case MIPI_CSI2_DT_RAW24:
101 case MIPI_CSI2_DT_RAW28:
102 return true;
103 default:
104 return false;
105 }
106}
107
108u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y)
109{
110 static const u32 code_map[] = {
111 MEDIA_BUS_FMT_SRGGB8_1X8,
112 MEDIA_BUS_FMT_SGRBG8_1X8,
113 MEDIA_BUS_FMT_SGBRG8_1X8,
114 MEDIA_BUS_FMT_SBGGR8_1X8,
115 MEDIA_BUS_FMT_SRGGB10_1X10,
116 MEDIA_BUS_FMT_SGRBG10_1X10,
117 MEDIA_BUS_FMT_SGBRG10_1X10,
118 MEDIA_BUS_FMT_SBGGR10_1X10,
119 MEDIA_BUS_FMT_SRGGB12_1X12,
120 MEDIA_BUS_FMT_SGRBG12_1X12,
121 MEDIA_BUS_FMT_SGBRG12_1X12,
122 MEDIA_BUS_FMT_SBGGR12_1X12,
123 MEDIA_BUS_FMT_SRGGB16_1X16,
124 MEDIA_BUS_FMT_SGRBG16_1X16,
125 MEDIA_BUS_FMT_SGBRG16_1X16,
126 MEDIA_BUS_FMT_SBGGR16_1X16,
127 };
128 u32 i;
129
130 for (i = 0; i < ARRAY_SIZE(code_map); i++)
131 if (code_map[i] == code)
132 break;
133
134 if (WARN_ON(i == ARRAY_SIZE(code_map)))
135 return code;
136
137 return code_map[i ^ (((y & 1) << 1) | (x & 1))];
138}
139
140int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
141 struct v4l2_subdev_state *state,
142 struct v4l2_subdev_format *format)
143{
144 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
145 struct v4l2_mbus_framefmt *fmt;
146 struct v4l2_rect *crop;
147 u32 code = asd->supported_codes[0];
148 u32 other_pad, other_stream;
149 unsigned int i;
150 int ret;
151
152 /* No transcoding, source and sink formats must match. */
153 if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) &&
154 sd->entity.num_pads > 1)
155 return v4l2_subdev_get_fmt(sd, state, format);
156
157 format->format.width = clamp(format->format.width, IPU6_ISYS_MIN_WIDTH,
158 IPU6_ISYS_MAX_WIDTH);
159 format->format.height = clamp(format->format.height,
160 IPU6_ISYS_MIN_HEIGHT,
161 IPU6_ISYS_MAX_HEIGHT);
162
163 for (i = 0; asd->supported_codes[i]; i++) {
164 if (asd->supported_codes[i] == format->format.code) {
165 code = asd->supported_codes[i];
166 break;
167 }
168 }
169 format->format.code = code;
170 format->format.field = V4L2_FIELD_NONE;
171
172 /* Store the format and propagate it to the source pad. */
173 fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
174 if (!fmt)
175 return -EINVAL;
176
177 *fmt = format->format;
178
179 if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK))
180 return 0;
181
182 /* propagate format to following source pad */
183 fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
184 format->stream);
185 if (!fmt)
186 return -EINVAL;
187
188 *fmt = format->format;
189
190 ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
191 format->pad,
192 format->stream,
193 &other_pad,
194 &other_stream);
195 if (ret)
196 return -EINVAL;
197
198 crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream);
199 /* reset crop */
200 crop->left = 0;
201 crop->top = 0;
202 crop->width = fmt->width;
203 crop->height = fmt->height;
204
205 return 0;
206}
207
208int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
209 struct v4l2_subdev_state *state,
210 struct v4l2_subdev_mbus_code_enum *code)
211{
212 struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
213 const u32 *supported_codes = asd->supported_codes;
214 u32 index;
215
216 for (index = 0; supported_codes[index]; index++) {
217 if (index == code->index) {
218 code->code = supported_codes[index];
219 return 0;
220 }
221 }
222
223 return -EINVAL;
224}
225
226static int subdev_set_routing(struct v4l2_subdev *sd,
227 struct v4l2_subdev_state *state,
228 struct v4l2_subdev_krouting *routing)
229{
230 static const struct v4l2_mbus_framefmt format = {
231 .width = 4096,
232 .height = 3072,
233 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
234 .field = V4L2_FIELD_NONE,
235 };
236 int ret;
237
238 ret = v4l2_subdev_routing_validate(sd, routing,
239 V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
240 if (ret)
241 return ret;
242
243 return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
244}
245
246int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
247 struct v4l2_mbus_framefmt *format)
248{
249 struct v4l2_mbus_framefmt *fmt;
250 struct v4l2_subdev_state *state;
251
252 if (!sd || !format)
253 return -EINVAL;
254
255 state = v4l2_subdev_lock_and_get_active_state(sd);
256 fmt = v4l2_subdev_state_get_format(state, pad, stream);
257 if (fmt)
258 *format = *fmt;
259 v4l2_subdev_unlock_state(state);
260
261 return fmt ? 0 : -EINVAL;
262}
263
264int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
265 struct v4l2_rect *crop)
266{
267 struct v4l2_subdev_state *state;
268 struct v4l2_rect *rect;
269
270 if (!sd || !crop)
271 return -EINVAL;
272
273 state = v4l2_subdev_lock_and_get_active_state(sd);
274 rect = v4l2_subdev_state_get_crop(state, pad, stream);
275 if (rect)
276 *crop = *rect;
277 v4l2_subdev_unlock_state(state);
278
279 return rect ? 0 : -EINVAL;
280}
281
282u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
283{
284 struct v4l2_subdev_state *state;
285 struct v4l2_subdev_route *routes;
286 unsigned int i;
287 u32 source_stream = 0;
288
289 state = v4l2_subdev_lock_and_get_active_state(sd);
290 if (!state)
291 return 0;
292
293 routes = state->routing.routes;
294 for (i = 0; i < state->routing.num_routes; i++) {
295 if (routes[i].source_pad == pad) {
296 source_stream = routes[i].source_stream;
297 break;
298 }
299 }
300
301 v4l2_subdev_unlock_state(state);
302
303 return source_stream;
304}
305
306static int ipu6_isys_subdev_init_state(struct v4l2_subdev *sd,
307 struct v4l2_subdev_state *state)
308{
309 struct v4l2_subdev_route route = {
310 .sink_pad = 0,
311 .sink_stream = 0,
312 .source_pad = 1,
313 .source_stream = 0,
314 .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
315 };
316 struct v4l2_subdev_krouting routing = {
317 .num_routes = 1,
318 .routes = &route,
319 };
320
321 return subdev_set_routing(sd, state, &routing);
322}
323
324int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
325 struct v4l2_subdev_state *state,
326 enum v4l2_subdev_format_whence which,
327 struct v4l2_subdev_krouting *routing)
328{
329 return subdev_set_routing(sd, state, routing);
330}
331
332static const struct v4l2_subdev_internal_ops ipu6_isys_subdev_internal_ops = {
333 .init_state = ipu6_isys_subdev_init_state,
334};
335
336int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
337 const struct v4l2_subdev_ops *ops,
338 unsigned int nr_ctrls,
339 unsigned int num_sink_pads,
340 unsigned int num_source_pads)
341{
342 unsigned int num_pads = num_sink_pads + num_source_pads;
343 unsigned int i;
344 int ret;
345
346 v4l2_subdev_init(&asd->sd, ops);
347
348 asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
349 V4L2_SUBDEV_FL_HAS_EVENTS |
350 V4L2_SUBDEV_FL_STREAMS;
351 asd->sd.owner = THIS_MODULE;
352 asd->sd.dev = &asd->isys->adev->auxdev.dev;
353 asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
354 asd->sd.internal_ops = &ipu6_isys_subdev_internal_ops;
355
356 asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads,
357 sizeof(*asd->pad), GFP_KERNEL);
358 if (!asd->pad)
359 return -ENOMEM;
360
361 for (i = 0; i < num_sink_pads; i++)
362 asd->pad[i].flags = MEDIA_PAD_FL_SINK |
363 MEDIA_PAD_FL_MUST_CONNECT;
364
365 for (i = num_sink_pads; i < num_pads; i++)
366 asd->pad[i].flags = MEDIA_PAD_FL_SOURCE;
367
368 ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad);
369 if (ret)
370 return ret;
371
372 if (asd->ctrl_init) {
373 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls);
374 if (ret)
375 goto out_media_entity_cleanup;
376
377 asd->ctrl_init(&asd->sd);
378 if (asd->ctrl_handler.error) {
379 ret = asd->ctrl_handler.error;
380 goto out_v4l2_ctrl_handler_free;
381 }
382
383 asd->sd.ctrl_handler = &asd->ctrl_handler;
384 }
385
386 asd->source = -1;
387
388 return 0;
389
390out_v4l2_ctrl_handler_free:
391 v4l2_ctrl_handler_free(&asd->ctrl_handler);
392
393out_media_entity_cleanup:
394 media_entity_cleanup(&asd->sd.entity);
395
396 return ret;
397}
398
399void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd)
400{
401 media_entity_cleanup(&asd->sd.entity);
402 v4l2_ctrl_handler_free(&asd->ctrl_handler);
403}
drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h+59−0
@@ -0,0 +1,59 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_ISYS_SUBDEV_H
5#define IPU6_ISYS_SUBDEV_H
6
7#include <linux/container_of.h>
8
9#include <media/media-entity.h>
10#include <media/v4l2-ctrls.h>
11#include <media/v4l2-subdev.h>
12
13struct ipu6_isys;
14
15struct ipu6_isys_subdev {
16 struct v4l2_subdev sd;
17 struct ipu6_isys *isys;
18 u32 const *supported_codes;
19 struct media_pad *pad;
20 struct v4l2_ctrl_handler ctrl_handler;
21 void (*ctrl_init)(struct v4l2_subdev *sd);
22 int source; /* SSI stream source; -1 if unset */
23};
24
25#define to_ipu6_isys_subdev(__sd) \
26 container_of(__sd, struct ipu6_isys_subdev, sd)
27
28unsigned int ipu6_isys_mbus_code_to_bpp(u32 code);
29unsigned int ipu6_isys_mbus_code_to_mipi(u32 code);
30bool ipu6_isys_is_bayer_format(u32 code);
31u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y);
32
33int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
34 struct v4l2_subdev_state *state,
35 struct v4l2_subdev_format *fmt);
36int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
37 struct v4l2_subdev_state *state,
38 struct v4l2_subdev_mbus_code_enum
39 *code);
40int ipu6_isys_subdev_link_validate(struct v4l2_subdev *sd,
41 struct media_link *link,
42 struct v4l2_subdev_format *source_fmt,
43 struct v4l2_subdev_format *sink_fmt);
44u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad);
45int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
46 struct v4l2_mbus_framefmt *format);
47int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
48 struct v4l2_rect *crop);
49int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
50 struct v4l2_subdev_state *state,
51 enum v4l2_subdev_format_whence which,
52 struct v4l2_subdev_krouting *routing);
53int ipu6_isys_subdev_init(struct ipu6_isys_subdev *asd,
54 const struct v4l2_subdev_ops *ops,
55 unsigned int nr_ctrls,
56 unsigned int num_sink_pads,
57 unsigned int num_source_pads);
58void ipu6_isys_subdev_cleanup(struct ipu6_isys_subdev *asd);
59#endif /* IPU6_ISYS_SUBDEV_H */
drivers/media/pci/intel/ipu6/ipu6-isys-video.c+1420−0
@@ -0,0 +1,1420 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/align.h>
7#include <linux/bits.h>
8#include <linux/bug.h>
9#include <linux/completion.h>
10#include <linux/container_of.h>
11#include <linux/device.h>
12#include <linux/list.h>
13#include <linux/math64.h>
14#include <linux/minmax.h>
15#include <linux/module.h>
16#include <linux/mutex.h>
17#include <linux/pm_runtime.h>
18#include <linux/spinlock.h>
19#include <linux/string.h>
20
21#include <media/media-entity.h>
22#include <media/v4l2-ctrls.h>
23#include <media/v4l2-dev.h>
24#include <media/v4l2-fh.h>
25#include <media/v4l2-ioctl.h>
26#include <media/v4l2-subdev.h>
27#include <media/videobuf2-v4l2.h>
28
29#include "ipu6.h"
30#include "ipu6-bus.h"
31#include "ipu6-cpd.h"
32#include "ipu6-fw-isys.h"
33#include "ipu6-isys.h"
34#include "ipu6-isys-csi2.h"
35#include "ipu6-isys-queue.h"
36#include "ipu6-isys-video.h"
37#include "ipu6-platform-regs.h"
38
39const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = {
40 { V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
41 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
42 { V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
43 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
44 { V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
45 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
46 { V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
47 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
48 { V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
49 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
50 { V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
51 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
52 { V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
53 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
54 { V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
55 IPU6_FW_ISYS_FRAME_FORMAT_RAW16 },
56 { V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8,
57 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
58 { V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8,
59 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
60 { V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8,
61 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
62 { V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8,
63 IPU6_FW_ISYS_FRAME_FORMAT_RAW8 },
64 { V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12,
65 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
66 { V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12,
67 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
68 { V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12,
69 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
70 { V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12,
71 IPU6_FW_ISYS_FRAME_FORMAT_RAW12 },
72 { V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10,
73 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
74 { V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10,
75 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
76 { V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10,
77 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
78 { V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10,
79 IPU6_FW_ISYS_FRAME_FORMAT_RAW10 },
80 { V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16,
81 IPU6_FW_ISYS_FRAME_FORMAT_UYVY},
82 { V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16,
83 IPU6_FW_ISYS_FRAME_FORMAT_YUYV},
84 { V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16,
85 IPU6_FW_ISYS_FRAME_FORMAT_RGB565 },
86 { V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24,
87 IPU6_FW_ISYS_FRAME_FORMAT_RGBA888 },
88 { V4L2_META_FMT_GENERIC_8, 8, 8, MEDIA_BUS_FMT_META_8,
89 IPU6_FW_ISYS_FRAME_FORMAT_RAW8, true },
90 { V4L2_META_FMT_GENERIC_CSI2_10, 10, 10, MEDIA_BUS_FMT_META_10,
91 IPU6_FW_ISYS_FRAME_FORMAT_RAW10, true },
92 { V4L2_META_FMT_GENERIC_CSI2_12, 12, 12, MEDIA_BUS_FMT_META_12,
93 IPU6_FW_ISYS_FRAME_FORMAT_RAW12, true },
94 { V4L2_META_FMT_GENERIC_CSI2_16, 16, 16, MEDIA_BUS_FMT_META_16,
95 IPU6_FW_ISYS_FRAME_FORMAT_RAW16, true },
96};
97
98static int video_open(struct file *file)
99{
100 struct ipu6_isys_video *av = video_drvdata(file);
101 struct ipu6_isys *isys = av->isys;
102 struct ipu6_bus_device *adev = isys->adev;
103
104 mutex_lock(&isys->mutex);
105 if (isys->need_reset) {
106 mutex_unlock(&isys->mutex);
107 dev_warn(&adev->auxdev.dev, "isys power cycle required\n");
108 return -EIO;
109 }
110 mutex_unlock(&isys->mutex);
111
112 return v4l2_fh_open(file);
113}
114
115const struct ipu6_isys_pixelformat *
116ipu6_isys_get_isys_format(u32 pixelformat, u32 type)
117{
118 const struct ipu6_isys_pixelformat *default_pfmt = NULL;
119 unsigned int i;
120
121 for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
122 const struct ipu6_isys_pixelformat *pfmt = &ipu6_isys_pfmts[i];
123
124 if (type && ((!pfmt->is_meta &&
125 type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
126 (pfmt->is_meta &&
127 type != V4L2_BUF_TYPE_META_CAPTURE)))
128 continue;
129
130 if (!default_pfmt)
131 default_pfmt = pfmt;
132
133 if (pfmt->pixelformat != pixelformat)
134 continue;
135
136 return pfmt;
137 }
138
139 return default_pfmt;
140}
141
142static int ipu6_isys_vidioc_querycap(struct file *file, void *fh,
143 struct v4l2_capability *cap)
144{
145 struct ipu6_isys_video *av = video_drvdata(file);
146
147 strscpy(cap->driver, IPU6_ISYS_NAME, sizeof(cap->driver));
148 strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card));
149
150 return 0;
151}
152
153static int ipu6_isys_vidioc_enum_fmt(struct file *file, void *fh,
154 struct v4l2_fmtdesc *f)
155{
156 unsigned int i, num_found;
157
158 for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
159 if ((ipu6_isys_pfmts[i].is_meta &&
160 f->type != V4L2_BUF_TYPE_META_CAPTURE) ||
161 (!ipu6_isys_pfmts[i].is_meta &&
162 f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
163 continue;
164
165 if (f->mbus_code && f->mbus_code != ipu6_isys_pfmts[i].code)
166 continue;
167
168 if (num_found < f->index) {
169 num_found++;
170 continue;
171 }
172
173 f->flags = 0;
174 f->pixelformat = ipu6_isys_pfmts[i].pixelformat;
175
176 return 0;
177 }
178
179 return -EINVAL;
180}
181
182static int ipu6_isys_vidioc_enum_framesizes(struct file *file, void *fh,
183 struct v4l2_frmsizeenum *fsize)
184{
185 unsigned int i;
186
187 if (fsize->index > 0)
188 return -EINVAL;
189
190 for (i = 0; i < ARRAY_SIZE(ipu6_isys_pfmts); i++) {
191 if (fsize->pixel_format != ipu6_isys_pfmts[i].pixelformat)
192 continue;
193
194 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
195 fsize->stepwise.min_width = IPU6_ISYS_MIN_WIDTH;
196 fsize->stepwise.max_width = IPU6_ISYS_MAX_WIDTH;
197 fsize->stepwise.min_height = IPU6_ISYS_MIN_HEIGHT;
198 fsize->stepwise.max_height = IPU6_ISYS_MAX_HEIGHT;
199 fsize->stepwise.step_width = 2;
200 fsize->stepwise.step_height = 2;
201
202 return 0;
203 }
204
205 return -EINVAL;
206}
207
208static int ipu6_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh,
209 struct v4l2_format *f)
210{
211 struct ipu6_isys_video *av = video_drvdata(file);
212
213 f->fmt.pix = av->pix_fmt;
214
215 return 0;
216}
217
218static int ipu6_isys_vidioc_g_fmt_meta_cap(struct file *file, void *fh,
219 struct v4l2_format *f)
220{
221 struct ipu6_isys_video *av = video_drvdata(file);
222
223 f->fmt.meta = av->meta_fmt;
224
225 return 0;
226}
227
228static void ipu6_isys_try_fmt_cap(struct ipu6_isys_video *av, u32 type,
229 u32 *format, u32 *width, u32 *height,
230 u32 *bytesperline, u32 *sizeimage)
231{
232 const struct ipu6_isys_pixelformat *pfmt =
233 ipu6_isys_get_isys_format(*format, type);
234
235 *format = pfmt->pixelformat;
236 *width = clamp(*width, IPU6_ISYS_MIN_WIDTH, IPU6_ISYS_MAX_WIDTH);
237 *height = clamp(*height, IPU6_ISYS_MIN_HEIGHT, IPU6_ISYS_MAX_HEIGHT);
238
239 if (pfmt->bpp != pfmt->bpp_packed)
240 *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE);
241 else
242 *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE);
243
244 *bytesperline = ALIGN(*bytesperline, av->isys->line_align);
245
246 /*
247 * (height + 1) * bytesperline due to a hardware issue: the DMA unit
248 * is a power of two, and a line should be transferred as few units
249 * as possible. The result is that up to line length more data than
250 * the image size may be transferred to memory after the image.
251 * Another limitation is the GDA allocation unit size. For low
252 * resolution it gives a bigger number. Use larger one to avoid
253 * memory corruption.
254 */
255 *sizeimage = *bytesperline * *height +
256 max(*bytesperline,
257 av->isys->pdata->ipdata->isys_dma_overshoot);
258}
259
260static void __ipu6_isys_vidioc_try_fmt_vid_cap(struct ipu6_isys_video *av,
261 struct v4l2_format *f)
262{
263 ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat,
264 &f->fmt.pix.width, &f->fmt.pix.height,
265 &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage);
266
267 f->fmt.pix.field = V4L2_FIELD_NONE;
268 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW;
269 f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
270 f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
271 f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
272}
273
274static int ipu6_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh,
275 struct v4l2_format *f)
276{
277 struct ipu6_isys_video *av = video_drvdata(file);
278
279 if (vb2_is_busy(&av->aq.vbq))
280 return -EBUSY;
281
282 __ipu6_isys_vidioc_try_fmt_vid_cap(av, f);
283
284 return 0;
285}
286
287static int __ipu6_isys_vidioc_try_fmt_meta_cap(struct ipu6_isys_video *av,
288 struct v4l2_format *f)
289{
290 ipu6_isys_try_fmt_cap(av, f->type, &f->fmt.meta.dataformat,
291 &f->fmt.meta.width, &f->fmt.meta.height,
292 &f->fmt.meta.bytesperline,
293 &f->fmt.meta.buffersize);
294
295 return 0;
296}
297
298static int ipu6_isys_vidioc_try_fmt_meta_cap(struct file *file, void *fh,
299 struct v4l2_format *f)
300{
301 struct ipu6_isys_video *av = video_drvdata(file);
302
303 __ipu6_isys_vidioc_try_fmt_meta_cap(av, f);
304
305 return 0;
306}
307
308static int ipu6_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh,
309 struct v4l2_format *f)
310{
311 struct ipu6_isys_video *av = video_drvdata(file);
312
313 ipu6_isys_vidioc_try_fmt_vid_cap(file, fh, f);
314 av->pix_fmt = f->fmt.pix;
315
316 return 0;
317}
318
319static int ipu6_isys_vidioc_s_fmt_meta_cap(struct file *file, void *fh,
320 struct v4l2_format *f)
321{
322 struct ipu6_isys_video *av = video_drvdata(file);
323
324 if (vb2_is_busy(&av->aq.vbq))
325 return -EBUSY;
326
327 ipu6_isys_vidioc_try_fmt_meta_cap(file, fh, f);
328 av->meta_fmt = f->fmt.meta;
329
330 return 0;
331}
332
333static int ipu6_isys_vidioc_reqbufs(struct file *file, void *priv,
334 struct v4l2_requestbuffers *p)
335{
336 struct ipu6_isys_video *av = video_drvdata(file);
337 int ret;
338
339 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type);
340 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type);
341
342 ret = vb2_queue_change_type(&av->aq.vbq, p->type);
343 if (ret)
344 return ret;
345
346 return vb2_ioctl_reqbufs(file, priv, p);
347}
348
349static int ipu6_isys_vidioc_create_bufs(struct file *file, void *priv,
350 struct v4l2_create_buffers *p)
351{
352 struct ipu6_isys_video *av = video_drvdata(file);
353 int ret;
354
355 av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type);
356 av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type);
357
358 ret = vb2_queue_change_type(&av->aq.vbq, p->format.type);
359 if (ret)
360 return ret;
361
362 return vb2_ioctl_create_bufs(file, priv, p);
363}
364
365static int link_validate(struct media_link *link)
366{
367 struct ipu6_isys_video *av =
368 container_of(link->sink, struct ipu6_isys_video, pad);
369 struct device *dev = &av->isys->adev->auxdev.dev;
370 struct v4l2_subdev_state *s_state;
371 struct v4l2_subdev *s_sd;
372 struct v4l2_mbus_framefmt *s_fmt;
373 struct media_pad *s_pad;
374 u32 s_stream, code;
375 int ret = -EPIPE;
376
377 if (!link->source->entity)
378 return ret;
379
380 s_sd = media_entity_to_v4l2_subdev(link->source->entity);
381 s_state = v4l2_subdev_get_unlocked_active_state(s_sd);
382 if (!s_state)
383 return ret;
384
385 dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n",
386 link->source->entity->name, link->source->index,
387 link->sink->entity->name);
388
389 s_pad = media_pad_remote_pad_first(&av->pad);
390 s_stream = ipu6_isys_get_src_stream_by_src_pad(s_sd, s_pad->index);
391
392 v4l2_subdev_lock_state(s_state);
393
394 s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream);
395 if (!s_fmt) {
396 dev_err(dev, "failed to get source pad format\n");
397 goto unlock;
398 }
399
400 code = ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0)->code;
401
402 if (s_fmt->width != ipu6_isys_get_frame_width(av) ||
403 s_fmt->height != ipu6_isys_get_frame_height(av) ||
404 s_fmt->code != code) {
405 dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n",
406 s_fmt->width, s_fmt->height, s_fmt->code,
407 ipu6_isys_get_frame_width(av),
408 ipu6_isys_get_frame_height(av), code);
409 goto unlock;
410 }
411
412 v4l2_subdev_unlock_state(s_state);
413
414 return 0;
415unlock:
416 v4l2_subdev_unlock_state(s_state);
417
418 return ret;
419}
420
421static void get_stream_opened(struct ipu6_isys_video *av)
422{
423 unsigned long flags;
424
425 spin_lock_irqsave(&av->isys->streams_lock, flags);
426 av->isys->stream_opened++;
427 spin_unlock_irqrestore(&av->isys->streams_lock, flags);
428}
429
430static void put_stream_opened(struct ipu6_isys_video *av)
431{
432 unsigned long flags;
433
434 spin_lock_irqsave(&av->isys->streams_lock, flags);
435 av->isys->stream_opened--;
436 spin_unlock_irqrestore(&av->isys->streams_lock, flags);
437}
438
439static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
440 struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
441{
442 struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
443 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
444 struct ipu6_fw_isys_input_pin_info_abi *input_pin;
445 struct ipu6_fw_isys_output_pin_info_abi *output_pin;
446 struct ipu6_isys_stream *stream = av->stream;
447 struct ipu6_isys_queue *aq = &av->aq;
448 struct v4l2_mbus_framefmt fmt;
449 const struct ipu6_isys_pixelformat *pfmt =
450 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
451 struct v4l2_rect v4l2_crop;
452 struct ipu6_isys *isys = av->isys;
453 struct device *dev = &isys->adev->auxdev.dev;
454 int input_pins = cfg->nof_input_pins++;
455 int output_pins;
456 u32 src_stream;
457 int ret;
458
459 src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
460 ret = ipu6_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
461 &fmt);
462 if (ret < 0) {
463 dev_err(dev, "can't get stream format (%d)\n", ret);
464 return ret;
465 }
466
467 ret = ipu6_isys_get_stream_pad_crop(sd, src_pad->index, src_stream,
468 &v4l2_crop);
469 if (ret < 0) {
470 dev_err(dev, "can't get stream crop (%d)\n", ret);
471 return ret;
472 }
473
474 input_pin = &cfg->input_pins[input_pins];
475 input_pin->input_res.width = fmt.width;
476 input_pin->input_res.height = fmt.height;
477 input_pin->dt = av->dt;
478 input_pin->bits_per_pix = pfmt->bpp_packed;
479 input_pin->mapped_dt = 0x40; /* invalid mipi data type */
480 input_pin->mipi_decompression = 0;
481 input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
482 input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
483 IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
484 IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
485 input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
486
487 output_pins = cfg->nof_output_pins++;
488 aq->fw_output = output_pins;
489 stream->output_pins[output_pins].pin_ready = ipu6_isys_queue_buf_ready;
490 stream->output_pins[output_pins].aq = aq;
491
492 output_pin = &cfg->output_pins[output_pins];
493 output_pin->input_pin_id = input_pins;
494 output_pin->output_res.width = ipu6_isys_get_frame_width(av);
495 output_pin->output_res.height = ipu6_isys_get_frame_height(av);
496
497 output_pin->stride = ipu6_isys_get_bytes_per_line(av);
498 if (pfmt->bpp != pfmt->bpp_packed)
499 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
500 else
501 output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
502 output_pin->ft = pfmt->css_pixelformat;
503 output_pin->send_irq = 1;
504 memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
505 output_pin->s2m_pixel_soc_pixel_remapping =
506 S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
507 output_pin->csi_be_soc_pixel_remapping =
508 CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
509
510 output_pin->snoopable = true;
511 output_pin->error_handling_enable = false;
512 output_pin->sensor_type = isys->sensor_type++;
513 if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
514 isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
515
516 return 0;
517}
518
519static int start_stream_firmware(struct ipu6_isys_video *av,
520 struct ipu6_isys_buffer_list *bl)
521{
522 struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
523 struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
524 struct ipu6_isys_stream *stream = av->stream;
525 struct device *dev = &av->isys->adev->auxdev.dev;
526 struct isys_fw_msgs *msg = NULL;
527 struct ipu6_isys_queue *aq;
528 int ret, retout, tout;
529 u16 send_type;
530
531 msg = ipu6_get_fw_msg_buf(stream);
532 if (!msg)
533 return -ENOMEM;
534
535 stream_cfg = &msg->fw_msg.stream;
536 stream_cfg->src = stream->stream_source;
537 stream_cfg->vc = stream->vc;
538 stream_cfg->isl_use = 0;
539 stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
540
541 list_for_each_entry(aq, &stream->queues, node) {
542 struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
543
544 ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
545 if (ret < 0) {
546 ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
547 return ret;
548 }
549 }
550
551 ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg);
552
553 stream->nr_output_pins = stream_cfg->nof_output_pins;
554
555 reinit_completion(&stream->stream_open_completion);
556
557 ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
558 stream_cfg, msg->dma_addr,
559 sizeof(*stream_cfg),
560 IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
561 if (ret < 0) {
562 dev_err(dev, "can't open stream (%d)\n", ret);
563 ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
564 return ret;
565 }
566
567 get_stream_opened(av);
568
569 tout = wait_for_completion_timeout(&stream->stream_open_completion,
570 IPU6_FW_CALL_TIMEOUT_JIFFIES);
571
572 ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
573
574 if (!tout) {
575 dev_err(dev, "stream open time out\n");
576 ret = -ETIMEDOUT;
577 goto out_put_stream_opened;
578 }
579 if (stream->error) {
580 dev_err(dev, "stream open error: %d\n", stream->error);
581 ret = -EIO;
582 goto out_put_stream_opened;
583 }
584 dev_dbg(dev, "start stream: open complete\n");
585
586 if (bl) {
587 msg = ipu6_get_fw_msg_buf(stream);
588 if (!msg) {
589 ret = -ENOMEM;
590 goto out_put_stream_opened;
591 }
592 buf = &msg->fw_msg.frame;
593 ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
594 ipu6_isys_buffer_list_queue(bl,
595 IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
596 }
597
598 reinit_completion(&stream->stream_start_completion);
599
600 if (bl) {
601 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
602 ipu6_fw_isys_dump_frame_buff_set(dev, buf,
603 stream_cfg->nof_output_pins);
604 ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
605 buf, msg->dma_addr,
606 sizeof(*buf), send_type);
607 } else {
608 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
609 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
610 send_type);
611 }
612
613 if (ret < 0) {
614 dev_err(dev, "can't start streaming (%d)\n", ret);
615 goto out_stream_close;
616 }
617
618 tout = wait_for_completion_timeout(&stream->stream_start_completion,
619 IPU6_FW_CALL_TIMEOUT_JIFFIES);
620 if (!tout) {
621 dev_err(dev, "stream start time out\n");
622 ret = -ETIMEDOUT;
623 goto out_stream_close;
624 }
625 if (stream->error) {
626 dev_err(dev, "stream start error: %d\n", stream->error);
627 ret = -EIO;
628 goto out_stream_close;
629 }
630 dev_dbg(dev, "start stream: complete\n");
631
632 return 0;
633
634out_stream_close:
635 reinit_completion(&stream->stream_close_completion);
636
637 retout = ipu6_fw_isys_simple_cmd(av->isys,
638 stream->stream_handle,
639 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
640 if (retout < 0) {
641 dev_dbg(dev, "can't close stream (%d)\n", retout);
642 goto out_put_stream_opened;
643 }
644
645 tout = wait_for_completion_timeout(&stream->stream_close_completion,
646 IPU6_FW_CALL_TIMEOUT_JIFFIES);
647 if (!tout)
648 dev_err(dev, "stream close time out\n");
649 else if (stream->error)
650 dev_err(dev, "stream close error: %d\n", stream->error);
651 else
652 dev_dbg(dev, "stream close complete\n");
653
654out_put_stream_opened:
655 put_stream_opened(av);
656
657 return ret;
658}
659
660static void stop_streaming_firmware(struct ipu6_isys_video *av)
661{
662 struct device *dev = &av->isys->adev->auxdev.dev;
663 struct ipu6_isys_stream *stream = av->stream;
664 int ret, tout;
665
666 reinit_completion(&stream->stream_stop_completion);
667
668 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
669 IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
670
671 if (ret < 0) {
672 dev_err(dev, "can't stop stream (%d)\n", ret);
673 return;
674 }
675
676 tout = wait_for_completion_timeout(&stream->stream_stop_completion,
677 IPU6_FW_CALL_TIMEOUT_JIFFIES);
678 if (!tout)
679 dev_warn(dev, "stream stop time out\n");
680 else if (stream->error)
681 dev_warn(dev, "stream stop error: %d\n", stream->error);
682 else
683 dev_dbg(dev, "stop stream: complete\n");
684}
685
686static void close_streaming_firmware(struct ipu6_isys_video *av)
687{
688 struct ipu6_isys_stream *stream = av->stream;
689 struct device *dev = &av->isys->adev->auxdev.dev;
690 int ret, tout;
691
692 reinit_completion(&stream->stream_close_completion);
693
694 ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
695 IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
696 if (ret < 0) {
697 dev_err(dev, "can't close stream (%d)\n", ret);
698 return;
699 }
700
701 tout = wait_for_completion_timeout(&stream->stream_close_completion,
702 IPU6_FW_CALL_TIMEOUT_JIFFIES);
703 if (!tout)
704 dev_warn(dev, "stream close time out\n");
705 else if (stream->error)
706 dev_warn(dev, "stream close error: %d\n", stream->error);
707 else
708 dev_dbg(dev, "close stream: complete\n");
709
710 put_stream_opened(av);
711}
712
713int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
714 struct media_entity *source_entity,
715 int nr_queues)
716{
717 struct ipu6_isys_stream *stream = av->stream;
718 struct ipu6_isys_csi2 *csi2;
719
720 if (WARN_ON(stream->nr_streaming))
721 return -EINVAL;
722
723 stream->nr_queues = nr_queues;
724 atomic_set(&stream->sequence, 0);
725
726 stream->seq_index = 0;
727 memset(stream->seq, 0, sizeof(stream->seq));
728
729 if (WARN_ON(!list_empty(&stream->queues)))
730 return -EINVAL;
731
732 stream->stream_source = stream->asd->source;
733 csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
734 csi2->receiver_errors = 0;
735 stream->source_entity = source_entity;
736
737 dev_dbg(&av->isys->adev->auxdev.dev,
738 "prepare stream: external entity %s\n",
739 stream->source_entity->name);
740
741 return 0;
742}
743
744void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
745 bool state)
746{
747 struct ipu6_isys *isys = av->isys;
748 struct ipu6_isys_csi2 *csi2 = NULL;
749 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
750 struct device *dev = &isys->adev->auxdev.dev;
751 struct v4l2_mbus_framefmt format;
752 struct v4l2_subdev *esd;
753 struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
754 unsigned int bpp, lanes;
755 s64 link_freq = 0;
756 u64 pixel_rate = 0;
757 int ret;
758
759 if (!state)
760 return;
761
762 esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
763
764 av->watermark.width = ipu6_isys_get_frame_width(av);
765 av->watermark.height = ipu6_isys_get_frame_height(av);
766 av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
767 av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
768
769 ret = v4l2_g_ctrl(esd->ctrl_handler, &hb);
770 if (!ret && hb.value >= 0)
771 av->watermark.hblank = hb.value;
772 else
773 av->watermark.hblank = 0;
774
775 csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
776 link_freq = ipu6_isys_csi2_get_link_freq(csi2);
777 if (link_freq > 0) {
778 lanes = csi2->nlanes;
779 ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0,
780 av->source_stream, &format);
781 if (!ret) {
782 bpp = ipu6_isys_mbus_code_to_bpp(format.code);
783 pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
784 }
785 }
786
787 av->watermark.pixel_rate = pixel_rate;
788
789 if (!pixel_rate) {
790 mutex_lock(&iwake_watermark->mutex);
791 iwake_watermark->force_iwake_disable = true;
792 mutex_unlock(&iwake_watermark->mutex);
793 dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
794 av->stream->source_entity->name);
795 }
796}
797
798static void calculate_stream_datarate(struct ipu6_isys_video *av)
799{
800 struct video_stream_watermark *watermark = &av->watermark;
801 const struct ipu6_isys_pixelformat *pfmt =
802 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
803 u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
804 u64 line_time_ns, stream_data_rate;
805 u16 shift, size;
806
807 shift = watermark->sram_gran_shift;
808 size = watermark->sram_gran_size;
809
810 pixels_per_line = watermark->width + watermark->hblank;
811 line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC,
812 watermark->pixel_rate);
813 bytes_per_line = watermark->width * pfmt->bpp / 8;
814 pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
815 pb_bytes_per_line = pages_per_line << shift;
816 stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
817
818 watermark->stream_data_rate = stream_data_rate;
819}
820
821void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
822{
823 struct isys_iwake_watermark *iwake_watermark =
824 &av->isys->iwake_watermark;
825
826 if (!av->watermark.pixel_rate)
827 return;
828
829 if (state) {
830 calculate_stream_datarate(av);
831 mutex_lock(&iwake_watermark->mutex);
832 list_add(&av->watermark.stream_node,
833 &iwake_watermark->video_list);
834 mutex_unlock(&iwake_watermark->mutex);
835 } else {
836 av->watermark.stream_data_rate = 0;
837 mutex_lock(&iwake_watermark->mutex);
838 list_del(&av->watermark.stream_node);
839 mutex_unlock(&iwake_watermark->mutex);
840 }
841
842 update_watermark_setting(av->isys);
843}
844
845void ipu6_isys_put_stream(struct ipu6_isys_stream *stream)
846{
847 struct device *dev;
848 unsigned int i;
849 unsigned long flags;
850
851 if (!stream) {
852 pr_err("ipu6-isys: no available stream\n");
853 return;
854 }
855
856 dev = &stream->isys->adev->auxdev.dev;
857
858 spin_lock_irqsave(&stream->isys->streams_lock, flags);
859 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
860 if (&stream->isys->streams[i] == stream) {
861 if (stream->isys->streams_ref_count[i] > 0)
862 stream->isys->streams_ref_count[i]--;
863 else
864 dev_warn(dev, "invalid stream %d\n", i);
865
866 break;
867 }
868 }
869 spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
870}
871
872static struct ipu6_isys_stream *
873ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd)
874{
875 struct ipu6_isys_stream *stream = NULL;
876 struct ipu6_isys *isys = av->isys;
877 unsigned long flags;
878 unsigned int i;
879 u8 vc = av->vc;
880
881 if (!isys)
882 return NULL;
883
884 spin_lock_irqsave(&isys->streams_lock, flags);
885 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
886 if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
887 isys->streams[i].asd == asd) {
888 isys->streams_ref_count[i]++;
889 stream = &isys->streams[i];
890 break;
891 }
892 }
893
894 if (!stream) {
895 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
896 if (!isys->streams_ref_count[i]) {
897 isys->streams_ref_count[i]++;
898 stream = &isys->streams[i];
899 stream->vc = vc;
900 stream->asd = asd;
901 break;
902 }
903 }
904 }
905 spin_unlock_irqrestore(&isys->streams_lock, flags);
906
907 return stream;
908}
909
910struct ipu6_isys_stream *
911ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle)
912{
913 unsigned long flags;
914 struct ipu6_isys_stream *stream = NULL;
915
916 if (!isys)
917 return NULL;
918
919 if (stream_handle >= IPU6_ISYS_MAX_STREAMS) {
920 dev_err(&isys->adev->auxdev.dev,
921 "stream_handle %d is invalid\n", stream_handle);
922 return NULL;
923 }
924
925 spin_lock_irqsave(&isys->streams_lock, flags);
926 if (isys->streams_ref_count[stream_handle] > 0) {
927 isys->streams_ref_count[stream_handle]++;
928 stream = &isys->streams[stream_handle];
929 }
930 spin_unlock_irqrestore(&isys->streams_lock, flags);
931
932 return stream;
933}
934
935struct ipu6_isys_stream *
936ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc)
937{
938 struct ipu6_isys_stream *stream = NULL;
939 unsigned long flags;
940 unsigned int i;
941
942 if (!isys)
943 return NULL;
944
945 if (source < 0) {
946 dev_err(&stream->isys->adev->auxdev.dev,
947 "query stream with invalid port number\n");
948 return NULL;
949 }
950
951 spin_lock_irqsave(&isys->streams_lock, flags);
952 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
953 if (!isys->streams_ref_count[i])
954 continue;
955
956 if (isys->streams[i].stream_source == source &&
957 isys->streams[i].vc == vc) {
958 stream = &isys->streams[i];
959 isys->streams_ref_count[i]++;
960 break;
961 }
962 }
963 spin_unlock_irqrestore(&isys->streams_lock, flags);
964
965 return stream;
966}
967
968static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av)
969{
970 struct media_pipeline *pipeline =
971 media_entity_pipeline(&__av->vdev.entity);
972 unsigned int i;
973 u64 stream_mask = 0;
974
975 for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) {
976 struct ipu6_isys_video *av = &__av->csi2->av[i];
977
978 if (pipeline == media_entity_pipeline(&av->vdev.entity))
979 stream_mask |= BIT_ULL(av->source_stream);
980 }
981
982 return stream_mask;
983}
984
985int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
986 struct ipu6_isys_buffer_list *bl)
987{
988 struct v4l2_subdev_krouting *routing;
989 struct ipu6_isys_stream *stream = av->stream;
990 struct v4l2_subdev_state *subdev_state;
991 struct device *dev = &av->isys->adev->auxdev.dev;
992 struct v4l2_subdev *sd;
993 struct v4l2_subdev *ssd;
994 struct media_pad *r_pad;
995 struct media_pad *s_pad;
996 u32 sink_pad, sink_stream;
997 u64 r_stream;
998 u64 stream_mask = 0;
999 int ret = 0;
1000
1001 dev_dbg(dev, "set stream: %d\n", state);
1002
1003 if (WARN(!stream->source_entity, "No source entity for stream\n"))
1004 return -ENODEV;
1005
1006 ssd = media_entity_to_v4l2_subdev(stream->source_entity);
1007 sd = &stream->asd->sd;
1008 r_pad = media_pad_remote_pad_first(&av->pad);
1009 r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
1010
1011 subdev_state = v4l2_subdev_lock_and_get_active_state(sd);
1012 routing = &subdev_state->routing;
1013 ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,
1014 r_stream, &sink_pad,
1015 &sink_stream);
1016 v4l2_subdev_unlock_state(subdev_state);
1017 if (ret)
1018 return ret;
1019
1020 s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]);
1021
1022 stream_mask = get_stream_mask_by_pipeline(av);
1023 if (!state) {
1024 stop_streaming_firmware(av);
1025
1026 /* stop external sub-device now. */
1027 dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask,
1028 ssd->name);
1029 ret = v4l2_subdev_disable_streams(ssd, s_pad->index,
1030 stream_mask);
1031 if (ret) {
1032 dev_err(dev, "disable streams of %s failed with %d\n",
1033 ssd->name, ret);
1034 return ret;
1035 }
1036
1037 /* stop sub-device which connects with video */
1038 dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name,
1039 r_pad->index);
1040 ret = v4l2_subdev_call(sd, video, s_stream, state);
1041 if (ret) {
1042 dev_err(dev, "stream off %s failed with %d\n", sd->name,
1043 ret);
1044 return ret;
1045 }
1046 close_streaming_firmware(av);
1047 } else {
1048 ret = start_stream_firmware(av, bl);
1049 if (ret) {
1050 dev_err(dev, "start stream of firmware failed\n");
1051 return ret;
1052 }
1053
1054 /* start sub-device which connects with video */
1055 dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
1056 ret = v4l2_subdev_call(sd, video, s_stream, state);
1057 if (ret) {
1058 dev_err(dev, "stream on %s failed with %d\n", sd->name,
1059 ret);
1060 goto out_media_entity_stop_streaming_firmware;
1061 }
1062
1063 /* start external sub-device now. */
1064 dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask,
1065 ssd->name);
1066 ret = v4l2_subdev_enable_streams(ssd, s_pad->index,
1067 stream_mask);
1068 if (ret) {
1069 dev_err(dev,
1070 "enable streams 0x%llx of %s failed with %d\n",
1071 stream_mask, stream->source_entity->name, ret);
1072 goto out_media_entity_stop_streaming;
1073 }
1074 }
1075
1076 av->streaming = state;
1077
1078 return 0;
1079
1080out_media_entity_stop_streaming:
1081 v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream));
1082
1083out_media_entity_stop_streaming_firmware:
1084 stop_streaming_firmware(av);
1085
1086 return ret;
1087}
1088
1089static const struct v4l2_ioctl_ops ipu6_v4l2_ioctl_ops = {
1090 .vidioc_querycap = ipu6_isys_vidioc_querycap,
1091 .vidioc_enum_fmt_vid_cap = ipu6_isys_vidioc_enum_fmt,
1092 .vidioc_enum_fmt_meta_cap = ipu6_isys_vidioc_enum_fmt,
1093 .vidioc_enum_framesizes = ipu6_isys_vidioc_enum_framesizes,
1094 .vidioc_g_fmt_vid_cap = ipu6_isys_vidioc_g_fmt_vid_cap,
1095 .vidioc_s_fmt_vid_cap = ipu6_isys_vidioc_s_fmt_vid_cap,
1096 .vidioc_try_fmt_vid_cap = ipu6_isys_vidioc_try_fmt_vid_cap,
1097 .vidioc_g_fmt_meta_cap = ipu6_isys_vidioc_g_fmt_meta_cap,
1098 .vidioc_s_fmt_meta_cap = ipu6_isys_vidioc_s_fmt_meta_cap,
1099 .vidioc_try_fmt_meta_cap = ipu6_isys_vidioc_try_fmt_meta_cap,
1100 .vidioc_reqbufs = ipu6_isys_vidioc_reqbufs,
1101 .vidioc_create_bufs = ipu6_isys_vidioc_create_bufs,
1102 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1103 .vidioc_querybuf = vb2_ioctl_querybuf,
1104 .vidioc_qbuf = vb2_ioctl_qbuf,
1105 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1106 .vidioc_streamon = vb2_ioctl_streamon,
1107 .vidioc_streamoff = vb2_ioctl_streamoff,
1108 .vidioc_expbuf = vb2_ioctl_expbuf,
1109};
1110
1111static const struct media_entity_operations entity_ops = {
1112 .link_validate = link_validate,
1113};
1114
1115static const struct v4l2_file_operations isys_fops = {
1116 .owner = THIS_MODULE,
1117 .poll = vb2_fop_poll,
1118 .unlocked_ioctl = video_ioctl2,
1119 .mmap = vb2_fop_mmap,
1120 .open = video_open,
1121 .release = vb2_fop_release,
1122};
1123
1124int ipu6_isys_fw_open(struct ipu6_isys *isys)
1125{
1126 struct ipu6_bus_device *adev = isys->adev;
1127 const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
1128 int ret;
1129
1130 ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
1131 if (ret < 0)
1132 return ret;
1133
1134 mutex_lock(&isys->mutex);
1135
1136 if (isys->ref_count++)
1137 goto unlock;
1138
1139 ipu6_configure_spc(adev->isp, &ipdata->hw_variant,
1140 IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,
1141 adev->pkg_dir, adev->pkg_dir_dma_addr);
1142
1143 /*
1144 * Buffers could have been left to wrong queue at last closure.
1145 * Move them now back to empty buffer queue.
1146 */
1147 ipu6_cleanup_fw_msg_bufs(isys);
1148
1149 if (isys->fwcom) {
1150 /*
1151 * Something went wrong in previous shutdown. As we are now
1152 * restarting isys we can safely delete old context.
1153 */
1154 dev_warn(&adev->auxdev.dev, "clearing old context\n");
1155 ipu6_fw_isys_cleanup(isys);
1156 }
1157
1158 ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
1159 if (ret < 0)
1160 goto out;
1161
1162unlock:
1163 mutex_unlock(&isys->mutex);
1164
1165 return 0;
1166
1167out:
1168 isys->ref_count--;
1169 mutex_unlock(&isys->mutex);
1170 pm_runtime_put(&adev->auxdev.dev);
1171
1172 return ret;
1173}
1174
1175void ipu6_isys_fw_close(struct ipu6_isys *isys)
1176{
1177 mutex_lock(&isys->mutex);
1178
1179 isys->ref_count--;
1180 if (!isys->ref_count) {
1181 ipu6_fw_isys_close(isys);
1182 if (isys->fwcom) {
1183 isys->need_reset = true;
1184 dev_warn(&isys->adev->auxdev.dev,
1185 "failed to close fw isys\n");
1186 }
1187 }
1188
1189 mutex_unlock(&isys->mutex);
1190
1191 if (isys->need_reset)
1192 pm_runtime_put_sync(&isys->adev->auxdev.dev);
1193 else
1194 pm_runtime_put(&isys->adev->auxdev.dev);
1195}
1196
1197int ipu6_isys_setup_video(struct ipu6_isys_video *av,
1198 struct media_entity **source_entity, int *nr_queues)
1199{
1200 const struct ipu6_isys_pixelformat *pfmt =
1201 ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
1202 struct device *dev = &av->isys->adev->auxdev.dev;
1203 struct v4l2_mbus_frame_desc_entry entry;
1204 struct v4l2_subdev_route *route = NULL;
1205 struct v4l2_subdev_route *r;
1206 struct v4l2_subdev_state *state;
1207 struct ipu6_isys_subdev *asd;
1208 struct v4l2_subdev *remote_sd;
1209 struct media_pipeline *pipeline;
1210 struct media_pad *source_pad, *remote_pad;
1211 int ret = -EINVAL;
1212
1213 *nr_queues = 0;
1214
1215 remote_pad = media_pad_remote_pad_unique(&av->pad);
1216 if (IS_ERR(remote_pad)) {
1217 dev_dbg(dev, "failed to get remote pad\n");
1218 return PTR_ERR(remote_pad);
1219 }
1220
1221 remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
1222 asd = to_ipu6_isys_subdev(remote_sd);
1223 source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
1224 if (!source_pad) {
1225 dev_dbg(dev, "No external source entity\n");
1226 return -ENODEV;
1227 }
1228
1229 *source_entity = source_pad->entity;
1230
1231 /* Find the root */
1232 state = v4l2_subdev_lock_and_get_active_state(remote_sd);
1233 for_each_active_route(&state->routing, r) {
1234 (*nr_queues)++;
1235
1236 if (r->source_pad == remote_pad->index)
1237 route = r;
1238 }
1239
1240 if (!route) {
1241 v4l2_subdev_unlock_state(state);
1242 dev_dbg(dev, "Failed to find route\n");
1243 return -ENODEV;
1244 }
1245 av->source_stream = route->sink_stream;
1246 v4l2_subdev_unlock_state(state);
1247
1248 ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
1249 to_ipu6_isys_csi2(asd),
1250 *source_entity, &entry);
1251 if (ret == -ENOIOCTLCMD) {
1252 av->vc = 0;
1253 av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
1254 } else if (!ret) {
1255 dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
1256 entry.stream, entry.length, entry.bus.csi2.vc,
1257 entry.bus.csi2.dt);
1258
1259 av->vc = entry.bus.csi2.vc;
1260 av->dt = entry.bus.csi2.dt;
1261 } else {
1262 dev_err(dev, "failed to get remote frame desc\n");
1263 return ret;
1264 }
1265
1266 pipeline = media_entity_pipeline(&av->vdev.entity);
1267 if (!pipeline)
1268 ret = video_device_pipeline_alloc_start(&av->vdev);
1269 else
1270 ret = video_device_pipeline_start(&av->vdev, pipeline);
1271 if (ret < 0) {
1272 dev_dbg(dev, "media pipeline start failed\n");
1273 return ret;
1274 }
1275
1276 av->stream = ipu6_isys_get_stream(av, asd);
1277 if (!av->stream) {
1278 video_device_pipeline_stop(&av->vdev);
1279 dev_err(dev, "no available stream for firmware\n");
1280 return -EINVAL;
1281 }
1282
1283 return 0;
1284}
1285
1286/*
1287 * Do everything that's needed to initialise things related to video
1288 * buffer queue, video node, and the related media entity. The caller
1289 * is expected to assign isys field and set the name of the video
1290 * device.
1291 */
1292int ipu6_isys_video_init(struct ipu6_isys_video *av)
1293{
1294 struct v4l2_format format = {
1295 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1296 .fmt.pix = {
1297 .width = 1920,
1298 .height = 1080,
1299 },
1300 };
1301 struct v4l2_format format_meta = {
1302 .type = V4L2_BUF_TYPE_META_CAPTURE,
1303 .fmt.meta = {
1304 .width = 1920,
1305 .height = 4,
1306 },
1307 };
1308 int ret;
1309
1310 mutex_init(&av->mutex);
1311 av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC |
1312 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
1313 av->vdev.vfl_dir = VFL_DIR_RX;
1314
1315 ret = ipu6_isys_queue_init(&av->aq);
1316 if (ret)
1317 goto out_free_watermark;
1318
1319 av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
1320 ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
1321 if (ret)
1322 goto out_vb2_queue_release;
1323
1324 av->vdev.entity.ops = &entity_ops;
1325 av->vdev.release = video_device_release_empty;
1326 av->vdev.fops = &isys_fops;
1327 av->vdev.v4l2_dev = &av->isys->v4l2_dev;
1328 if (!av->vdev.ioctl_ops)
1329 av->vdev.ioctl_ops = &ipu6_v4l2_ioctl_ops;
1330 av->vdev.queue = &av->aq.vbq;
1331 av->vdev.lock = &av->mutex;
1332
1333 __ipu6_isys_vidioc_try_fmt_vid_cap(av, &format);
1334 av->pix_fmt = format.fmt.pix;
1335 __ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta);
1336 av->meta_fmt = format_meta.fmt.meta;
1337
1338 set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags);
1339 video_set_drvdata(&av->vdev, av);
1340
1341 ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1);
1342 if (ret)
1343 goto out_media_entity_cleanup;
1344
1345 return ret;
1346
1347out_media_entity_cleanup:
1348 vb2_video_unregister_device(&av->vdev);
1349 media_entity_cleanup(&av->vdev.entity);
1350
1351out_vb2_queue_release:
1352 vb2_queue_release(&av->aq.vbq);
1353
1354out_free_watermark:
1355 mutex_destroy(&av->mutex);
1356
1357 return ret;
1358}
1359
1360void ipu6_isys_video_cleanup(struct ipu6_isys_video *av)
1361{
1362 vb2_video_unregister_device(&av->vdev);
1363 media_entity_cleanup(&av->vdev.entity);
1364 mutex_destroy(&av->mutex);
1365}
1366
1367u32 ipu6_isys_get_format(struct ipu6_isys_video *av)
1368{
1369 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1370 return av->pix_fmt.pixelformat;
1371
1372 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1373 return av->meta_fmt.dataformat;
1374
1375 return 0;
1376}
1377
1378u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av)
1379{
1380 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1381 return av->pix_fmt.sizeimage;
1382
1383 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1384 return av->meta_fmt.buffersize;
1385
1386 return 0;
1387}
1388
1389u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av)
1390{
1391 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1392 return av->pix_fmt.bytesperline;
1393
1394 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1395 return av->meta_fmt.bytesperline;
1396
1397 return 0;
1398}
1399
1400u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av)
1401{
1402 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1403 return av->pix_fmt.width;
1404
1405 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1406 return av->meta_fmt.width;
1407
1408 return 0;
1409}
1410
1411u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av)
1412{
1413 if (av->aq.vbq.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1414 return av->pix_fmt.height;
1415
1416 if (av->aq.vbq.type == V4L2_BUF_TYPE_META_CAPTURE)
1417 return av->meta_fmt.height;
1418
1419 return 0;
1420}
drivers/media/pci/intel/ipu6/ipu6-isys-video.h+141−0
@@ -0,0 +1,141 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_ISYS_VIDEO_H
5#define IPU6_ISYS_VIDEO_H
6
7#include <linux/atomic.h>
8#include <linux/completion.h>
9#include <linux/container_of.h>
10#include <linux/list.h>
11#include <linux/mutex.h>
12
13#include <media/media-entity.h>
14#include <media/v4l2-dev.h>
15
16#include "ipu6-isys-queue.h"
17
18#define IPU6_ISYS_OUTPUT_PINS 11
19#define IPU6_ISYS_MAX_PARALLEL_SOF 2
20
21struct file;
22struct ipu6_isys;
23struct ipu6_isys_csi2;
24struct ipu6_isys_subdev;
25
26struct ipu6_isys_pixelformat {
27 u32 pixelformat;
28 u32 bpp;
29 u32 bpp_packed;
30 u32 code;
31 u32 css_pixelformat;
32 bool is_meta;
33};
34
35struct sequence_info {
36 unsigned int sequence;
37 u64 timestamp;
38};
39
40struct output_pin_data {
41 void (*pin_ready)(struct ipu6_isys_stream *stream,
42 struct ipu6_fw_isys_resp_info_abi *info);
43 struct ipu6_isys_queue *aq;
44};
45
46/*
47 * Align with firmware stream. Each stream represents a CSI virtual channel.
48 * May map to multiple video devices
49 */
50struct ipu6_isys_stream {
51 struct mutex mutex;
52 struct media_entity *source_entity;
53 atomic_t sequence;
54 unsigned int seq_index;
55 struct sequence_info seq[IPU6_ISYS_MAX_PARALLEL_SOF];
56 int stream_source;
57 int stream_handle;
58 unsigned int nr_output_pins;
59 struct ipu6_isys_subdev *asd;
60
61 int nr_queues; /* Number of capture queues */
62 int nr_streaming;
63 int streaming; /* Has streaming been really started? */
64 struct list_head queues;
65 struct completion stream_open_completion;
66 struct completion stream_close_completion;
67 struct completion stream_start_completion;
68 struct completion stream_stop_completion;
69 struct ipu6_isys *isys;
70
71 struct output_pin_data output_pins[IPU6_ISYS_OUTPUT_PINS];
72 int error;
73 u8 vc;
74};
75
76struct video_stream_watermark {
77 u32 width;
78 u32 height;
79 u32 hblank;
80 u32 frame_rate;
81 u64 pixel_rate;
82 u64 stream_data_rate;
83 u16 sram_gran_shift;
84 u16 sram_gran_size;
85 struct list_head stream_node;
86};
87
88struct ipu6_isys_video {
89 struct ipu6_isys_queue aq;
90 /* Serialise access to other fields in the struct. */
91 struct mutex mutex;
92 struct media_pad pad;
93 struct video_device vdev;
94 struct v4l2_pix_format pix_fmt;
95 struct v4l2_meta_format meta_fmt;
96 struct ipu6_isys *isys;
97 struct ipu6_isys_csi2 *csi2;
98 struct ipu6_isys_stream *stream;
99 unsigned int streaming;
100 struct video_stream_watermark watermark;
101 u32 source_stream;
102 u8 vc;
103 u8 dt;
104};
105
106#define ipu6_isys_queue_to_video(__aq) \
107 container_of(__aq, struct ipu6_isys_video, aq)
108
109extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts[];
110extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts_packed[];
111
112const struct ipu6_isys_pixelformat *
113ipu6_isys_get_isys_format(u32 pixelformat, u32 code);
114int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
115 struct media_entity *source_entity,
116 int nr_queues);
117int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
118 struct ipu6_isys_buffer_list *bl);
119int ipu6_isys_fw_open(struct ipu6_isys *isys);
120void ipu6_isys_fw_close(struct ipu6_isys *isys);
121int ipu6_isys_setup_video(struct ipu6_isys_video *av,
122 struct media_entity **source_entity, int *nr_queues);
123int ipu6_isys_video_init(struct ipu6_isys_video *av);
124void ipu6_isys_video_cleanup(struct ipu6_isys_video *av);
125void ipu6_isys_put_stream(struct ipu6_isys_stream *stream);
126struct ipu6_isys_stream *
127ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle);
128struct ipu6_isys_stream *
129ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc);
130
131void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
132 bool state);
133void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state);
134
135u32 ipu6_isys_get_format(struct ipu6_isys_video *av);
136u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av);
137u32 ipu6_isys_get_bytes_per_line(struct ipu6_isys_video *av);
138u32 ipu6_isys_get_frame_width(struct ipu6_isys_video *av);
139u32 ipu6_isys_get_frame_height(struct ipu6_isys_video *av);
140
141#endif /* IPU6_ISYS_VIDEO_H */
drivers/media/pci/intel/ipu6/ipu6-isys.c+1367−0
@@ -0,0 +1,1367 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/auxiliary_bus.h>
7#include <linux/bitfield.h>
8#include <linux/bits.h>
9#include <linux/completion.h>
10#include <linux/container_of.h>
11#include <linux/delay.h>
12#include <linux/device.h>
13#include <linux/dma-mapping.h>
14#include <linux/err.h>
15#include <linux/firmware.h>
16#include <linux/io.h>
17#include <linux/irqreturn.h>
18#include <linux/list.h>
19#include <linux/module.h>
20#include <linux/mutex.h>
21#include <linux/pci.h>
22#include <linux/pm_runtime.h>
23#include <linux/pm_qos.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/string.h>
27
28#include <media/ipu-bridge.h>
29#include <media/media-device.h>
30#include <media/media-entity.h>
31#include <media/v4l2-async.h>
32#include <media/v4l2-device.h>
33#include <media/v4l2-fwnode.h>
34
35#include "ipu6-bus.h"
36#include "ipu6-cpd.h"
37#include "ipu6-isys.h"
38#include "ipu6-isys-csi2.h"
39#include "ipu6-mmu.h"
40#include "ipu6-platform-buttress-regs.h"
41#include "ipu6-platform-isys-csi2-reg.h"
42#include "ipu6-platform-regs.h"
43
44#define IPU6_BUTTRESS_FABIC_CONTROL 0x68
45#define GDA_ENABLE_IWAKE_INDEX 2
46#define GDA_IWAKE_THRESHOLD_INDEX 1
47#define GDA_IRQ_CRITICAL_THRESHOLD_INDEX 0
48#define GDA_MEMOPEN_THRESHOLD_INDEX 3
49#define DEFAULT_DID_RATIO 90
50#define DEFAULT_IWAKE_THRESHOLD 0x42
51#define DEFAULT_MEM_OPEN_TIME 10
52#define ONE_THOUSAND_MICROSECOND 1000
53/* One page is 2KB, 8 x 16 x 16 = 2048B = 2KB */
54#define ISF_DMA_TOP_GDA_PROFERTY_PAGE_SIZE 0x800
55
56/* LTR & DID value are 10 bit at most */
57#define LTR_DID_VAL_MAX 1023
58#define LTR_DEFAULT_VALUE 0x70503c19
59#define FILL_TIME_DEFAULT_VALUE 0xfff0783c
60#define LTR_DID_PKGC_2R 20
61#define LTR_SCALE_DEFAULT 5
62#define LTR_SCALE_1024NS 2
63#define DID_SCALE_1US 2
64#define DID_SCALE_32US 3
65#define REG_PKGC_PMON_CFG 0xb00
66
67#define VAL_PKGC_PMON_CFG_RESET 0x38
68#define VAL_PKGC_PMON_CFG_START 0x7
69
70#define IS_PIXEL_BUFFER_PAGES 0x80
71/*
72 * when iwake mode is disabled, the critical threshold is statically set
73 * to 75% of the IS pixel buffer, criticalThreshold = (128 * 3) / 4
74 */
75#define CRITICAL_THRESHOLD_IWAKE_DISABLE (IS_PIXEL_BUFFER_PAGES * 3 / 4)
76
77union fabric_ctrl {
78 struct {
79 u16 ltr_val : 10;
80 u16 ltr_scale : 3;
81 u16 reserved : 3;
82 u16 did_val : 10;
83 u16 did_scale : 3;
84 u16 reserved2 : 1;
85 u16 keep_power_in_D0 : 1;
86 u16 keep_power_override : 1;
87 } bits;
88 u32 value;
89};
90
91enum ltr_did_type {
92 LTR_IWAKE_ON,
93 LTR_IWAKE_OFF,
94 LTR_ISYS_ON,
95 LTR_ISYS_OFF,
96 LTR_ENHANNCE_IWAKE,
97 LTR_TYPE_MAX
98};
99
100#define ISYS_PM_QOS_VALUE 300
101
102static int isys_isr_one(struct ipu6_bus_device *adev);
103
104static int
105isys_complete_ext_device_registration(struct ipu6_isys *isys,
106 struct v4l2_subdev *sd,
107 struct ipu6_isys_csi2_config *csi2)
108{
109 struct device *dev = &isys->adev->auxdev.dev;
110 unsigned int i;
111 int ret;
112
113 for (i = 0; i < sd->entity.num_pads; i++) {
114 if (sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
115 break;
116 }
117
118 if (i == sd->entity.num_pads) {
119 dev_warn(dev, "no src pad in external entity\n");
120 ret = -ENOENT;
121 goto unregister_subdev;
122 }
123
124 ret = media_create_pad_link(&sd->entity, i,
125 &isys->csi2[csi2->port].asd.sd.entity,
126 0, MEDIA_LNK_FL_ENABLED |
127 MEDIA_LNK_FL_IMMUTABLE);
128 if (ret) {
129 dev_warn(dev, "can't create link\n");
130 goto unregister_subdev;
131 }
132
133 isys->csi2[csi2->port].nlanes = csi2->nlanes;
134
135 return 0;
136
137unregister_subdev:
138 v4l2_device_unregister_subdev(sd);
139
140 return ret;
141}
142
143static void isys_stream_init(struct ipu6_isys *isys)
144{
145 u32 i;
146
147 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
148 mutex_init(&isys->streams[i].mutex);
149 init_completion(&isys->streams[i].stream_open_completion);
150 init_completion(&isys->streams[i].stream_close_completion);
151 init_completion(&isys->streams[i].stream_start_completion);
152 init_completion(&isys->streams[i].stream_stop_completion);
153 INIT_LIST_HEAD(&isys->streams[i].queues);
154 isys->streams[i].isys = isys;
155 isys->streams[i].stream_handle = i;
156 isys->streams[i].vc = INVALID_VC_ID;
157 }
158}
159
160static void isys_csi2_unregister_subdevices(struct ipu6_isys *isys)
161{
162 const struct ipu6_isys_internal_csi2_pdata *csi2 =
163 &isys->pdata->ipdata->csi2;
164 unsigned int i;
165
166 for (i = 0; i < csi2->nports; i++)
167 ipu6_isys_csi2_cleanup(&isys->csi2[i]);
168}
169
170static int isys_csi2_register_subdevices(struct ipu6_isys *isys)
171{
172 const struct ipu6_isys_internal_csi2_pdata *csi2_pdata =
173 &isys->pdata->ipdata->csi2;
174 unsigned int i;
175 int ret;
176
177 for (i = 0; i < csi2_pdata->nports; i++) {
178 ret = ipu6_isys_csi2_init(&isys->csi2[i], isys,
179 isys->pdata->base +
180 CSI_REG_PORT_BASE(i), i);
181 if (ret)
182 goto fail;
183
184 isys->isr_csi2_bits |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
185 }
186
187 return 0;
188
189fail:
190 while (i--)
191 ipu6_isys_csi2_cleanup(&isys->csi2[i]);
192
193 return ret;
194}
195
196static int isys_csi2_create_media_links(struct ipu6_isys *isys)
197{
198 const struct ipu6_isys_internal_csi2_pdata *csi2_pdata =
199 &isys->pdata->ipdata->csi2;
200 struct device *dev = &isys->adev->auxdev.dev;
201 unsigned int i, j;
202 int ret;
203
204 for (i = 0; i < csi2_pdata->nports; i++) {
205 struct media_entity *sd = &isys->csi2[i].asd.sd.entity;
206
207 for (j = 0; j < NR_OF_CSI2_SRC_PADS; j++) {
208 struct ipu6_isys_video *av = &isys->csi2[i].av[j];
209
210 ret = media_create_pad_link(sd, CSI2_PAD_SRC + j,
211 &av->vdev.entity, 0, 0);
212 if (ret) {
213 dev_err(dev, "CSI2 can't create link\n");
214 return ret;
215 }
216
217 av->csi2 = &isys->csi2[i];
218 }
219 }
220
221 return 0;
222}
223
224static void isys_unregister_video_devices(struct ipu6_isys *isys)
225{
226 const struct ipu6_isys_internal_csi2_pdata *csi2_pdata =
227 &isys->pdata->ipdata->csi2;
228 unsigned int i, j;
229
230 for (i = 0; i < csi2_pdata->nports; i++)
231 for (j = 0; j < NR_OF_CSI2_SRC_PADS; j++)
232 ipu6_isys_video_cleanup(&isys->csi2[i].av[j]);
233}
234
235static int isys_register_video_devices(struct ipu6_isys *isys)
236{
237 const struct ipu6_isys_internal_csi2_pdata *csi2_pdata =
238 &isys->pdata->ipdata->csi2;
239 unsigned int i, j;
240 int ret;
241
242 for (i = 0; i < csi2_pdata->nports; i++) {
243 for (j = 0; j < NR_OF_CSI2_SRC_PADS; j++) {
244 struct ipu6_isys_video *av = &isys->csi2[i].av[j];
245
246 snprintf(av->vdev.name, sizeof(av->vdev.name),
247 IPU6_ISYS_ENTITY_PREFIX " ISYS Capture %u",
248 i * NR_OF_CSI2_SRC_PADS + j);
249 av->isys = isys;
250 av->aq.vbq.buf_struct_size =
251 sizeof(struct ipu6_isys_video_buffer);
252
253 ret = ipu6_isys_video_init(av);
254 if (ret)
255 goto fail;
256 }
257 }
258
259 return 0;
260
261fail:
262 while (i--) {
263 while (j--)
264 ipu6_isys_video_cleanup(&isys->csi2[i].av[j]);
265 j = NR_OF_CSI2_SRC_PADS;
266 }
267
268 return ret;
269}
270
271void isys_setup_hw(struct ipu6_isys *isys)
272{
273 void __iomem *base = isys->pdata->base;
274 const u8 *thd = isys->pdata->ipdata->hw_variant.cdc_fifo_threshold;
275 u32 irqs = 0;
276 unsigned int i, nports;
277
278 nports = isys->pdata->ipdata->csi2.nports;
279
280 /* Enable irqs for all MIPI ports */
281 for (i = 0; i < nports; i++)
282 irqs |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
283
284 writel(irqs, base + isys->pdata->ipdata->csi2.ctrl0_irq_edge);
285 writel(irqs, base + isys->pdata->ipdata->csi2.ctrl0_irq_lnp);
286 writel(irqs, base + isys->pdata->ipdata->csi2.ctrl0_irq_mask);
287 writel(irqs, base + isys->pdata->ipdata->csi2.ctrl0_irq_enable);
288 writel(GENMASK(19, 0),
289 base + isys->pdata->ipdata->csi2.ctrl0_irq_clear);
290
291 irqs = ISYS_UNISPART_IRQS;
292 writel(irqs, base + IPU6_REG_ISYS_UNISPART_IRQ_EDGE);
293 writel(irqs, base + IPU6_REG_ISYS_UNISPART_IRQ_LEVEL_NOT_PULSE);
294 writel(GENMASK(28, 0), base + IPU6_REG_ISYS_UNISPART_IRQ_CLEAR);
295 writel(irqs, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
296 writel(irqs, base + IPU6_REG_ISYS_UNISPART_IRQ_ENABLE);
297
298 writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
299 writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_MUX_REG);
300
301 /* Write CDC FIFO threshold values for isys */
302 for (i = 0; i < isys->pdata->ipdata->hw_variant.cdc_fifos; i++)
303 writel(thd[i], base + IPU6_REG_ISYS_CDC_THRESHOLD(i));
304}
305
306static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
307{
308 struct ipu6_isys_stream *stream;
309 unsigned int i;
310 u32 status;
311 int source;
312
313 ipu6_isys_register_errors(csi2);
314
315 status = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
316 CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
317
318 writel(status, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
319 CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
320
321 source = csi2->asd.source;
322 for (i = 0; i < NR_OF_CSI2_VC; i++) {
323 if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
324 stream = ipu6_isys_query_stream_by_source(csi2->isys,
325 source, i);
326 if (stream) {
327 ipu6_isys_csi2_sof_event_by_stream(stream);
328 ipu6_isys_put_stream(stream);
329 }
330 }
331
332 if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
333 stream = ipu6_isys_query_stream_by_source(csi2->isys,
334 source, i);
335 if (stream) {
336 ipu6_isys_csi2_eof_event_by_stream(stream);
337 ipu6_isys_put_stream(stream);
338 }
339 }
340 }
341}
342
343irqreturn_t isys_isr(struct ipu6_bus_device *adev)
344{
345 struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
346 void __iomem *base = isys->pdata->base;
347 u32 status_sw, status_csi;
348 u32 ctrl0_status, ctrl0_clear;
349
350 spin_lock(&isys->power_lock);
351 if (!isys->power) {
352 spin_unlock(&isys->power_lock);
353 return IRQ_NONE;
354 }
355
356 ctrl0_status = isys->pdata->ipdata->csi2.ctrl0_irq_status;
357 ctrl0_clear = isys->pdata->ipdata->csi2.ctrl0_irq_clear;
358
359 status_csi = readl(isys->pdata->base + ctrl0_status);
360 status_sw = readl(isys->pdata->base +
361 IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
362
363 writel(ISYS_UNISPART_IRQS & ~IPU6_ISYS_UNISPART_IRQ_SW,
364 base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
365
366 do {
367 writel(status_csi, isys->pdata->base + ctrl0_clear);
368
369 writel(status_sw, isys->pdata->base +
370 IPU6_REG_ISYS_UNISPART_IRQ_CLEAR);
371
372 if (isys->isr_csi2_bits & status_csi) {
373 unsigned int i;
374
375 for (i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
376 /* irq from not enabled port */
377 if (!isys->csi2[i].base)
378 continue;
379 if (status_csi & IPU6_ISYS_UNISPART_IRQ_CSI2(i))
380 ipu6_isys_csi2_isr(&isys->csi2[i]);
381 }
382 }
383
384 writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
385
386 if (!isys_isr_one(adev))
387 status_sw = IPU6_ISYS_UNISPART_IRQ_SW;
388 else
389 status_sw = 0;
390
391 status_csi = readl(isys->pdata->base + ctrl0_status);
392 status_sw |= readl(isys->pdata->base +
393 IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
394 } while ((status_csi & isys->isr_csi2_bits) ||
395 (status_sw & IPU6_ISYS_UNISPART_IRQ_SW));
396
397 writel(ISYS_UNISPART_IRQS, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
398
399 spin_unlock(&isys->power_lock);
400
401 return IRQ_HANDLED;
402}
403
404static void get_lut_ltrdid(struct ipu6_isys *isys, struct ltr_did *pltr_did)
405{
406 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
407 struct ltr_did ltrdid_default;
408
409 ltrdid_default.lut_ltr.value = LTR_DEFAULT_VALUE;
410 ltrdid_default.lut_fill_time.value = FILL_TIME_DEFAULT_VALUE;
411
412 if (iwake_watermark->ltrdid.lut_ltr.value)
413 *pltr_did = iwake_watermark->ltrdid;
414 else
415 *pltr_did = ltrdid_default;
416}
417
418static int set_iwake_register(struct ipu6_isys *isys, u32 index, u32 value)
419{
420 struct device *dev = &isys->adev->auxdev.dev;
421 u32 req_id = index;
422 u32 offset = 0;
423 int ret;
424
425 ret = ipu6_fw_isys_send_proxy_token(isys, req_id, index, offset, value);
426 if (ret)
427 dev_err(dev, "write %d failed %d", index, ret);
428
429 return ret;
430}
431
432/*
433 * When input system is powered up and before enabling any new sensor capture,
434 * or after disabling any sensor capture the following values need to be set:
435 * LTR_value = LTR(usec) from calculation;
436 * LTR_scale = 2;
437 * DID_value = DID(usec) from calculation;
438 * DID_scale = 2;
439 *
440 * When input system is powered down, the LTR and DID values
441 * must be returned to the default values:
442 * LTR_value = 1023;
443 * LTR_scale = 5;
444 * DID_value = 1023;
445 * DID_scale = 2;
446 */
447static void set_iwake_ltrdid(struct ipu6_isys *isys, u16 ltr, u16 did,
448 enum ltr_did_type use)
449{
450 struct device *dev = &isys->adev->auxdev.dev;
451 u16 ltr_val, ltr_scale = LTR_SCALE_1024NS;
452 u16 did_val, did_scale = DID_SCALE_1US;
453 struct ipu6_device *isp = isys->adev->isp;
454 union fabric_ctrl fc;
455
456 switch (use) {
457 case LTR_IWAKE_ON:
458 ltr_val = min_t(u16, ltr, (u16)LTR_DID_VAL_MAX);
459 did_val = min_t(u16, did, (u16)LTR_DID_VAL_MAX);
460 ltr_scale = (ltr == LTR_DID_VAL_MAX &&
461 did == LTR_DID_VAL_MAX) ?
462 LTR_SCALE_DEFAULT : LTR_SCALE_1024NS;
463 break;
464 case LTR_ISYS_ON:
465 case LTR_IWAKE_OFF:
466 ltr_val = LTR_DID_PKGC_2R;
467 did_val = LTR_DID_PKGC_2R;
468 break;
469 case LTR_ISYS_OFF:
470 ltr_val = LTR_DID_VAL_MAX;
471 did_val = LTR_DID_VAL_MAX;
472 ltr_scale = LTR_SCALE_DEFAULT;
473 break;
474 case LTR_ENHANNCE_IWAKE:
475 if (ltr == LTR_DID_VAL_MAX && did == LTR_DID_VAL_MAX) {
476 ltr_val = LTR_DID_VAL_MAX;
477 did_val = LTR_DID_VAL_MAX;
478 ltr_scale = LTR_SCALE_DEFAULT;
479 } else if (did < ONE_THOUSAND_MICROSECOND) {
480 ltr_val = ltr;
481 did_val = did;
482 } else {
483 ltr_val = ltr;
484 /* div 90% value by 32 to account for scale change */
485 did_val = did / 32;
486 did_scale = DID_SCALE_32US;
487 }
488 break;
489 default:
490 ltr_val = LTR_DID_VAL_MAX;
491 did_val = LTR_DID_VAL_MAX;
492 ltr_scale = LTR_SCALE_DEFAULT;
493 break;
494 }
495
496 fc.value = readl(isp->base + IPU6_BUTTRESS_FABIC_CONTROL);
497 fc.bits.ltr_val = ltr_val;
498 fc.bits.ltr_scale = ltr_scale;
499 fc.bits.did_val = did_val;
500 fc.bits.did_scale = did_scale;
501
502 dev_dbg(dev, "ltr: value %u scale %u, did: value %u scale %u\n",
503 ltr_val, ltr_scale, did_val, did_scale);
504 writel(fc.value, isp->base + IPU6_BUTTRESS_FABIC_CONTROL);
505}
506
507/*
508 * Driver may clear register GDA_ENABLE_IWAKE before FW configures the
509 * stream for debug purpose. Otherwise driver should not access this register.
510 */
511static void enable_iwake(struct ipu6_isys *isys, bool enable)
512{
513 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
514 int ret;
515
516 mutex_lock(&iwake_watermark->mutex);
517
518 if (iwake_watermark->iwake_enabled == enable) {
519 mutex_unlock(&iwake_watermark->mutex);
520 return;
521 }
522
523 ret = set_iwake_register(isys, GDA_ENABLE_IWAKE_INDEX, enable);
524 if (!ret)
525 iwake_watermark->iwake_enabled = enable;
526
527 mutex_unlock(&iwake_watermark->mutex);
528}
529
530void update_watermark_setting(struct ipu6_isys *isys)
531{
532 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
533 u32 iwake_threshold, iwake_critical_threshold, page_num;
534 struct device *dev = &isys->adev->auxdev.dev;
535 u32 calc_fill_time_us = 0, ltr = 0, did = 0;
536 struct video_stream_watermark *p_watermark;
537 enum ltr_did_type ltr_did_type;
538 struct list_head *stream_node;
539 u64 isys_pb_datarate_mbs = 0;
540 u32 mem_open_threshold = 0;
541 struct ltr_did ltrdid;
542 u64 threshold_bytes;
543 u32 max_sram_size;
544 u32 shift;
545
546 shift = isys->pdata->ipdata->sram_gran_shift;
547 max_sram_size = isys->pdata->ipdata->max_sram_size;
548
549 mutex_lock(&iwake_watermark->mutex);
550 if (iwake_watermark->force_iwake_disable) {
551 set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
552 set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
553 CRITICAL_THRESHOLD_IWAKE_DISABLE);
554 goto unlock_exit;
555 }
556
557 if (list_empty(&iwake_watermark->video_list)) {
558 isys_pb_datarate_mbs = 0;
559 } else {
560 list_for_each(stream_node, &iwake_watermark->video_list) {
561 p_watermark = list_entry(stream_node,
562 struct video_stream_watermark,
563 stream_node);
564 isys_pb_datarate_mbs += p_watermark->stream_data_rate;
565 }
566 }
567 mutex_unlock(&iwake_watermark->mutex);
568
569 if (!isys_pb_datarate_mbs) {
570 enable_iwake(isys, false);
571 set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
572 mutex_lock(&iwake_watermark->mutex);
573 set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
574 CRITICAL_THRESHOLD_IWAKE_DISABLE);
575 goto unlock_exit;
576 }
577
578 enable_iwake(isys, true);
579 calc_fill_time_us = max_sram_size / isys_pb_datarate_mbs;
580
581 if (isys->pdata->ipdata->enhanced_iwake) {
582 ltr = isys->pdata->ipdata->ltr;
583 did = calc_fill_time_us * DEFAULT_DID_RATIO / 100;
584 ltr_did_type = LTR_ENHANNCE_IWAKE;
585 } else {
586 get_lut_ltrdid(isys, &ltrdid);
587
588 if (calc_fill_time_us <= ltrdid.lut_fill_time.bits.th0)
589 ltr = 0;
590 else if (calc_fill_time_us <= ltrdid.lut_fill_time.bits.th1)
591 ltr = ltrdid.lut_ltr.bits.val0;
592 else if (calc_fill_time_us <= ltrdid.lut_fill_time.bits.th2)
593 ltr = ltrdid.lut_ltr.bits.val1;
594 else if (calc_fill_time_us <= ltrdid.lut_fill_time.bits.th3)
595 ltr = ltrdid.lut_ltr.bits.val2;
596 else
597 ltr = ltrdid.lut_ltr.bits.val3;
598
599 did = calc_fill_time_us - ltr;
600 ltr_did_type = LTR_IWAKE_ON;
601 }
602
603 set_iwake_ltrdid(isys, ltr, did, ltr_did_type);
604
605 /* calculate iwake threshold with 2KB granularity pages */
606 threshold_bytes = did * isys_pb_datarate_mbs;
607 iwake_threshold = max_t(u32, 1, threshold_bytes >> shift);
608 iwake_threshold = min_t(u32, iwake_threshold, max_sram_size);
609
610 mutex_lock(&iwake_watermark->mutex);
611 if (isys->pdata->ipdata->enhanced_iwake) {
612 set_iwake_register(isys, GDA_IWAKE_THRESHOLD_INDEX,
613 DEFAULT_IWAKE_THRESHOLD);
614 /* calculate number of pages that will be filled in 10 usec */
615 page_num = (DEFAULT_MEM_OPEN_TIME * isys_pb_datarate_mbs) /
616 ISF_DMA_TOP_GDA_PROFERTY_PAGE_SIZE;
617 page_num += ((DEFAULT_MEM_OPEN_TIME * isys_pb_datarate_mbs) %
618 ISF_DMA_TOP_GDA_PROFERTY_PAGE_SIZE) ? 1 : 0;
619 mem_open_threshold = isys->pdata->ipdata->memopen_threshold;
620 mem_open_threshold = max_t(u32, mem_open_threshold, page_num);
621 dev_dbg(dev, "mem_open_threshold: %u\n", mem_open_threshold);
622 set_iwake_register(isys, GDA_MEMOPEN_THRESHOLD_INDEX,
623 mem_open_threshold);
624 } else {
625 set_iwake_register(isys, GDA_IWAKE_THRESHOLD_INDEX,
626 iwake_threshold);
627 }
628
629 iwake_critical_threshold = iwake_threshold +
630 (IS_PIXEL_BUFFER_PAGES - iwake_threshold) / 2;
631
632 dev_dbg(dev, "threshold: %u critical: %u\n", iwake_threshold,
633 iwake_critical_threshold);
634
635 set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
636 iwake_critical_threshold);
637
638 writel(VAL_PKGC_PMON_CFG_RESET,
639 isys->adev->isp->base + REG_PKGC_PMON_CFG);
640 writel(VAL_PKGC_PMON_CFG_START,
641 isys->adev->isp->base + REG_PKGC_PMON_CFG);
642unlock_exit:
643 mutex_unlock(&iwake_watermark->mutex);
644}
645
646static void isys_iwake_watermark_init(struct ipu6_isys *isys)
647{
648 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
649
650 INIT_LIST_HEAD(&iwake_watermark->video_list);
651 mutex_init(&iwake_watermark->mutex);
652
653 iwake_watermark->ltrdid.lut_ltr.value = 0;
654 iwake_watermark->isys = isys;
655 iwake_watermark->iwake_enabled = false;
656 iwake_watermark->force_iwake_disable = false;
657}
658
659static void isys_iwake_watermark_cleanup(struct ipu6_isys *isys)
660{
661 struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
662
663 mutex_lock(&iwake_watermark->mutex);
664 list_del(&iwake_watermark->video_list);
665 mutex_unlock(&iwake_watermark->mutex);
666
667 mutex_destroy(&iwake_watermark->mutex);
668}
669
670/* The .bound() notifier callback when a match is found */
671static int isys_notifier_bound(struct v4l2_async_notifier *notifier,
672 struct v4l2_subdev *sd,
673 struct v4l2_async_connection *asc)
674{
675 struct ipu6_isys *isys =
676 container_of(notifier, struct ipu6_isys, notifier);
677 struct sensor_async_sd *s_asd =
678 container_of(asc, struct sensor_async_sd, asc);
679 int ret;
680
681 ret = ipu_bridge_instantiate_vcm(sd->dev);
682 if (ret) {
683 dev_err(&isys->adev->auxdev.dev, "instantiate vcm failed\n");
684 return ret;
685 }
686
687 dev_dbg(&isys->adev->auxdev.dev, "bind %s nlanes is %d port is %d\n",
688 sd->name, s_asd->csi2.nlanes, s_asd->csi2.port);
689 ret = isys_complete_ext_device_registration(isys, sd, &s_asd->csi2);
690 if (ret)
691 return ret;
692
693 return v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
694}
695
696static int isys_notifier_complete(struct v4l2_async_notifier *notifier)
697{
698 struct ipu6_isys *isys =
699 container_of(notifier, struct ipu6_isys, notifier);
700
701 return v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
702}
703
704static const struct v4l2_async_notifier_operations isys_async_ops = {
705 .bound = isys_notifier_bound,
706 .complete = isys_notifier_complete,
707};
708
709#define ISYS_MAX_PORTS 8
710static int isys_notifier_init(struct ipu6_isys *isys)
711{
712 struct ipu6_device *isp = isys->adev->isp;
713 struct device *dev = &isp->pdev->dev;
714 unsigned int i;
715 int ret;
716
717 v4l2_async_nf_init(&isys->notifier, &isys->v4l2_dev);
718
719 for (i = 0; i < ISYS_MAX_PORTS; i++) {
720 struct v4l2_fwnode_endpoint vep = {
721 .bus_type = V4L2_MBUS_CSI2_DPHY
722 };
723 struct sensor_async_sd *s_asd;
724 struct fwnode_handle *ep;
725
726 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), i, 0,
727 FWNODE_GRAPH_ENDPOINT_NEXT);
728 if (!ep)
729 continue;
730
731 ret = v4l2_fwnode_endpoint_parse(ep, &vep);
732 if (ret) {
733 dev_err(dev, "fwnode endpoint parse failed: %d\n", ret);
734 goto err_parse;
735 }
736
737 s_asd = v4l2_async_nf_add_fwnode_remote(&isys->notifier, ep,
738 struct sensor_async_sd);
739 if (IS_ERR(s_asd)) {
740 ret = PTR_ERR(s_asd);
741 dev_err(dev, "add remove fwnode failed: %d\n", ret);
742 goto err_parse;
743 }
744
745 s_asd->csi2.port = vep.base.port;
746 s_asd->csi2.nlanes = vep.bus.mipi_csi2.num_data_lanes;
747
748 dev_dbg(dev, "remote endpoint port %d with %d lanes added\n",
749 s_asd->csi2.port, s_asd->csi2.nlanes);
750
751 fwnode_handle_put(ep);
752
753 continue;
754
755err_parse:
756 fwnode_handle_put(ep);
757 return ret;
758 }
759
760 isys->notifier.ops = &isys_async_ops;
761 ret = v4l2_async_nf_register(&isys->notifier);
762 if (ret) {
763 dev_err(dev, "failed to register async notifier : %d\n", ret);
764 v4l2_async_nf_cleanup(&isys->notifier);
765 }
766
767 return ret;
768}
769
770static void isys_notifier_cleanup(struct ipu6_isys *isys)
771{
772 v4l2_async_nf_unregister(&isys->notifier);
773 v4l2_async_nf_cleanup(&isys->notifier);
774}
775
776static int isys_register_devices(struct ipu6_isys *isys)
777{
778 struct device *dev = &isys->adev->auxdev.dev;
779 struct pci_dev *pdev = isys->adev->isp->pdev;
780 int ret;
781
782 isys->media_dev.dev = dev;
783 media_device_pci_init(&isys->media_dev,
784 pdev, IPU6_MEDIA_DEV_MODEL_NAME);
785
786 strscpy(isys->v4l2_dev.name, isys->media_dev.model,
787 sizeof(isys->v4l2_dev.name));
788
789 ret = media_device_register(&isys->media_dev);
790 if (ret < 0)
791 goto out_media_device_unregister;
792
793 isys->v4l2_dev.mdev = &isys->media_dev;
794 isys->v4l2_dev.ctrl_handler = NULL;
795
796 ret = v4l2_device_register(&pdev->dev, &isys->v4l2_dev);
797 if (ret < 0)
798 goto out_media_device_unregister;
799
800 ret = isys_register_video_devices(isys);
801 if (ret)
802 goto out_v4l2_device_unregister;
803
804 ret = isys_csi2_register_subdevices(isys);
805 if (ret)
806 goto out_isys_unregister_video_device;
807
808 ret = isys_csi2_create_media_links(isys);
809 if (ret)
810 goto out_isys_unregister_subdevices;
811
812 ret = isys_notifier_init(isys);
813 if (ret)
814 goto out_isys_unregister_subdevices;
815
816 return 0;
817
818out_isys_unregister_subdevices:
819 isys_csi2_unregister_subdevices(isys);
820
821out_isys_unregister_video_device:
822 isys_unregister_video_devices(isys);
823
824out_v4l2_device_unregister:
825 v4l2_device_unregister(&isys->v4l2_dev);
826
827out_media_device_unregister:
828 media_device_unregister(&isys->media_dev);
829 media_device_cleanup(&isys->media_dev);
830
831 dev_err(dev, "failed to register isys devices\n");
832
833 return ret;
834}
835
836static void isys_unregister_devices(struct ipu6_isys *isys)
837{
838 isys_unregister_video_devices(isys);
839 isys_csi2_unregister_subdevices(isys);
840 v4l2_device_unregister(&isys->v4l2_dev);
841 media_device_unregister(&isys->media_dev);
842 media_device_cleanup(&isys->media_dev);
843}
844
845static int isys_runtime_pm_resume(struct device *dev)
846{
847 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
848 struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
849 struct ipu6_device *isp = adev->isp;
850 unsigned long flags;
851 int ret;
852
853 if (!isys)
854 return 0;
855
856 ret = ipu6_mmu_hw_init(adev->mmu);
857 if (ret)
858 return ret;
859
860 cpu_latency_qos_update_request(&isys->pm_qos, ISYS_PM_QOS_VALUE);
861
862 ret = ipu6_buttress_start_tsc_sync(isp);
863 if (ret)
864 return ret;
865
866 spin_lock_irqsave(&isys->power_lock, flags);
867 isys->power = 1;
868 spin_unlock_irqrestore(&isys->power_lock, flags);
869
870 isys_setup_hw(isys);
871
872 set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
873
874 return 0;
875}
876
877static int isys_runtime_pm_suspend(struct device *dev)
878{
879 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
880 struct ipu6_isys *isys;
881 unsigned long flags;
882
883 isys = dev_get_drvdata(dev);
884 if (!isys)
885 return 0;
886
887 spin_lock_irqsave(&isys->power_lock, flags);
888 isys->power = 0;
889 spin_unlock_irqrestore(&isys->power_lock, flags);
890
891 mutex_lock(&isys->mutex);
892 isys->need_reset = false;
893 mutex_unlock(&isys->mutex);
894
895 isys->phy_termcal_val = 0;
896 cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
897
898 set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
899
900 ipu6_mmu_hw_cleanup(adev->mmu);
901
902 return 0;
903}
904
905static int isys_suspend(struct device *dev)
906{
907 struct ipu6_isys *isys = dev_get_drvdata(dev);
908
909 /* If stream is open, refuse to suspend */
910 if (isys->stream_opened)
911 return -EBUSY;
912
913 return 0;
914}
915
916static int isys_resume(struct device *dev)
917{
918 return 0;
919}
920
921static const struct dev_pm_ops isys_pm_ops = {
922 .runtime_suspend = isys_runtime_pm_suspend,
923 .runtime_resume = isys_runtime_pm_resume,
924 .suspend = isys_suspend,
925 .resume = isys_resume,
926};
927
928static void isys_remove(struct auxiliary_device *auxdev)
929{
930 struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
931 struct ipu6_isys *isys = dev_get_drvdata(&auxdev->dev);
932 struct ipu6_device *isp = adev->isp;
933 struct isys_fw_msgs *fwmsg, *safe;
934 unsigned int i;
935
936 list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head)
937 dma_free_attrs(&auxdev->dev, sizeof(struct isys_fw_msgs),
938 fwmsg, fwmsg->dma_addr, 0);
939
940 list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head)
941 dma_free_attrs(&auxdev->dev, sizeof(struct isys_fw_msgs),
942 fwmsg, fwmsg->dma_addr, 0);
943
944 isys_unregister_devices(isys);
945 isys_notifier_cleanup(isys);
946
947 cpu_latency_qos_remove_request(&isys->pm_qos);
948
949 if (!isp->secure_mode) {
950 ipu6_cpd_free_pkg_dir(adev);
951 ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
952 release_firmware(adev->fw);
953 }
954
955 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
956 mutex_destroy(&isys->streams[i].mutex);
957
958 isys_iwake_watermark_cleanup(isys);
959 mutex_destroy(&isys->stream_mutex);
960 mutex_destroy(&isys->mutex);
961}
962
963static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount)
964{
965 struct device *dev = &isys->adev->auxdev.dev;
966 struct isys_fw_msgs *addr;
967 dma_addr_t dma_addr;
968 unsigned long flags;
969 unsigned int i;
970
971 for (i = 0; i < amount; i++) {
972 addr = dma_alloc_attrs(dev, sizeof(struct isys_fw_msgs),
973 &dma_addr, GFP_KERNEL, 0);
974 if (!addr)
975 break;
976 addr->dma_addr = dma_addr;
977
978 spin_lock_irqsave(&isys->listlock, flags);
979 list_add(&addr->head, &isys->framebuflist);
980 spin_unlock_irqrestore(&isys->listlock, flags);
981 }
982
983 if (i == amount)
984 return 0;
985
986 spin_lock_irqsave(&isys->listlock, flags);
987 while (!list_empty(&isys->framebuflist)) {
988 addr = list_first_entry(&isys->framebuflist,
989 struct isys_fw_msgs, head);
990 list_del(&addr->head);
991 spin_unlock_irqrestore(&isys->listlock, flags);
992 dma_free_attrs(dev, sizeof(struct isys_fw_msgs), addr,
993 addr->dma_addr, 0);
994 spin_lock_irqsave(&isys->listlock, flags);
995 }
996 spin_unlock_irqrestore(&isys->listlock, flags);
997
998 return -ENOMEM;
999}
1000
1001struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream)
1002{
1003 struct ipu6_isys *isys = stream->isys;
1004 struct device *dev = &isys->adev->auxdev.dev;
1005 struct isys_fw_msgs *msg;
1006 unsigned long flags;
1007 int ret;
1008
1009 spin_lock_irqsave(&isys->listlock, flags);
1010 if (list_empty(&isys->framebuflist)) {
1011 spin_unlock_irqrestore(&isys->listlock, flags);
1012 dev_dbg(dev, "Frame list empty\n");
1013
1014 ret = alloc_fw_msg_bufs(isys, 5);
1015 if (ret < 0)
1016 return NULL;
1017
1018 spin_lock_irqsave(&isys->listlock, flags);
1019 if (list_empty(&isys->framebuflist)) {
1020 spin_unlock_irqrestore(&isys->listlock, flags);
1021 dev_err(dev, "Frame list empty\n");
1022 return NULL;
1023 }
1024 }
1025 msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head);
1026 list_move(&msg->head, &isys->framebuflist_fw);
1027 spin_unlock_irqrestore(&isys->listlock, flags);
1028 memset(&msg->fw_msg, 0, sizeof(msg->fw_msg));
1029
1030 return msg;
1031}
1032
1033void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys)
1034{
1035 struct isys_fw_msgs *fwmsg, *fwmsg0;
1036 unsigned long flags;
1037
1038 spin_lock_irqsave(&isys->listlock, flags);
1039 list_for_each_entry_safe(fwmsg, fwmsg0, &isys->framebuflist_fw, head)
1040 list_move(&fwmsg->head, &isys->framebuflist);
1041 spin_unlock_irqrestore(&isys->listlock, flags);
1042}
1043
1044void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data)
1045{
1046 struct isys_fw_msgs *msg;
1047 unsigned long flags;
1048 u64 *ptr = (u64 *)data;
1049
1050 if (!ptr)
1051 return;
1052
1053 spin_lock_irqsave(&isys->listlock, flags);
1054 msg = container_of(ptr, struct isys_fw_msgs, fw_msg.dummy);
1055 list_move(&msg->head, &isys->framebuflist);
1056 spin_unlock_irqrestore(&isys->listlock, flags);
1057}
1058
1059static int isys_probe(struct auxiliary_device *auxdev,
1060 const struct auxiliary_device_id *auxdev_id)
1061{
1062 const struct ipu6_isys_internal_csi2_pdata *csi2_pdata;
1063 struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
1064 struct ipu6_device *isp = adev->isp;
1065 const struct firmware *fw;
1066 struct ipu6_isys *isys;
1067 unsigned int i;
1068 int ret;
1069
1070 if (!isp->bus_ready_to_probe)
1071 return -EPROBE_DEFER;
1072
1073 isys = devm_kzalloc(&auxdev->dev, sizeof(*isys), GFP_KERNEL);
1074 if (!isys)
1075 return -ENOMEM;
1076
1077 adev->auxdrv_data =
1078 (const struct ipu6_auxdrv_data *)auxdev_id->driver_data;
1079 adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver);
1080 isys->adev = adev;
1081 isys->pdata = adev->pdata;
1082 csi2_pdata = &isys->pdata->ipdata->csi2;
1083
1084 isys->csi2 = devm_kcalloc(&auxdev->dev, csi2_pdata->nports,
1085 sizeof(*isys->csi2), GFP_KERNEL);
1086 if (!isys->csi2)
1087 return -ENOMEM;
1088
1089 ret = ipu6_mmu_hw_init(adev->mmu);
1090 if (ret)
1091 return ret;
1092
1093 /* initial sensor type */
1094 isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
1095
1096 spin_lock_init(&isys->streams_lock);
1097 spin_lock_init(&isys->power_lock);
1098 isys->power = 0;
1099 isys->phy_termcal_val = 0;
1100
1101 mutex_init(&isys->mutex);
1102 mutex_init(&isys->stream_mutex);
1103
1104 spin_lock_init(&isys->listlock);
1105 INIT_LIST_HEAD(&isys->framebuflist);
1106 INIT_LIST_HEAD(&isys->framebuflist_fw);
1107
1108 isys->line_align = IPU6_ISYS_2600_MEM_LINE_ALIGN;
1109 isys->icache_prefetch = 0;
1110
1111 dev_set_drvdata(&auxdev->dev, isys);
1112
1113 isys_stream_init(isys);
1114
1115 if (!isp->secure_mode) {
1116 fw = isp->cpd_fw;
1117 ret = ipu6_buttress_map_fw_image(adev, fw, &adev->fw_sgt);
1118 if (ret)
1119 goto release_firmware;
1120
1121 ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
1122 if (ret)
1123 goto remove_shared_buffer;
1124 }
1125
1126 cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
1127
1128 ret = alloc_fw_msg_bufs(isys, 20);
1129 if (ret < 0)
1130 goto out_remove_pkg_dir_shared_buffer;
1131
1132 isys_iwake_watermark_init(isys);
1133
1134 if (is_ipu6se(adev->isp->hw_ver))
1135 isys->phy_set_power = ipu6_isys_jsl_phy_set_power;
1136 else if (is_ipu6ep_mtl(adev->isp->hw_ver))
1137 isys->phy_set_power = ipu6_isys_dwc_phy_set_power;
1138 else
1139 isys->phy_set_power = ipu6_isys_mcd_phy_set_power;
1140
1141 ret = isys_register_devices(isys);
1142 if (ret)
1143 goto out_remove_pkg_dir_shared_buffer;
1144
1145 ipu6_mmu_hw_cleanup(adev->mmu);
1146
1147 return 0;
1148
1149out_remove_pkg_dir_shared_buffer:
1150 if (!isp->secure_mode)
1151 ipu6_cpd_free_pkg_dir(adev);
1152remove_shared_buffer:
1153 if (!isp->secure_mode)
1154 ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
1155release_firmware:
1156 if (!isp->secure_mode)
1157 release_firmware(adev->fw);
1158
1159 for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
1160 mutex_destroy(&isys->streams[i].mutex);
1161
1162 mutex_destroy(&isys->mutex);
1163 mutex_destroy(&isys->stream_mutex);
1164
1165 ipu6_mmu_hw_cleanup(adev->mmu);
1166
1167 return ret;
1168}
1169
1170struct fwmsg {
1171 int type;
1172 char *msg;
1173 bool valid_ts;
1174};
1175
1176static const struct fwmsg fw_msg[] = {
1177 {IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE", 0},
1178 {IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK", 0},
1179 {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK, "STREAM_START_ACK", 0},
1180 {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
1181 "STREAM_START_AND_CAPTURE_ACK", 0},
1182 {IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK, "STREAM_STOP_ACK", 0},
1183 {IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK", 0},
1184 {IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY", 1},
1185 {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK", 0},
1186 {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
1187 "STREAM_START_AND_CAPTURE_DONE", 1},
1188 {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE", 1},
1189 {IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF", 1},
1190 {IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF", 1},
1191 {IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY, "STATS_READY", 1},
1192 {-1, "UNKNOWN MESSAGE", 0}
1193};
1194
1195static u32 resp_type_to_index(int type)
1196{
1197 unsigned int i;
1198
1199 for (i = 0; i < ARRAY_SIZE(fw_msg); i++)
1200 if (fw_msg[i].type == type)
1201 return i;
1202
1203 return ARRAY_SIZE(fw_msg) - 1;
1204}
1205
1206static int isys_isr_one(struct ipu6_bus_device *adev)
1207{
1208 struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
1209 struct ipu6_fw_isys_resp_info_abi *resp;
1210 struct ipu6_isys_stream *stream;
1211 struct ipu6_isys_csi2 *csi2 = NULL;
1212 u32 index;
1213 u64 ts;
1214
1215 if (!isys->fwcom)
1216 return 1;
1217
1218 resp = ipu6_fw_isys_get_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
1219 if (!resp)
1220 return 1;
1221
1222 ts = (u64)resp->timestamp[1] << 32 | resp->timestamp[0];
1223
1224 index = resp_type_to_index(resp->type);
1225 dev_dbg(&adev->auxdev.dev,
1226 "FW resp %02d %s, stream %u, ts 0x%16.16llx, pin %d\n",
1227 resp->type, fw_msg[index].msg, resp->stream_handle,
1228 fw_msg[index].valid_ts ? ts : 0, resp->pin_id);
1229
1230 if (resp->error_info.error == IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION)
1231 /* Suspension is kind of special case: not enough buffers */
1232 dev_dbg(&adev->auxdev.dev,
1233 "FW error resp SUSPENSION, details %d\n",
1234 resp->error_info.error_details);
1235 else if (resp->error_info.error)
1236 dev_dbg(&adev->auxdev.dev,
1237 "FW error resp error %d, details %d\n",
1238 resp->error_info.error, resp->error_info.error_details);
1239
1240 if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
1241 dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
1242 resp->stream_handle);
1243 goto leave;
1244 }
1245
1246 stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_handle);
1247 if (!stream) {
1248 dev_err(&adev->auxdev.dev, "stream of stream_handle %u is unused\n",
1249 resp->stream_handle);
1250 goto leave;
1251 }
1252 stream->error = resp->error_info.error;
1253
1254 csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
1255
1256 switch (resp->type) {
1257 case IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE:
1258 complete(&stream->stream_open_completion);
1259 break;
1260 case IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK:
1261 complete(&stream->stream_close_completion);
1262 break;
1263 case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK:
1264 complete(&stream->stream_start_completion);
1265 break;
1266 case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
1267 complete(&stream->stream_start_completion);
1268 break;
1269 case IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK:
1270 complete(&stream->stream_stop_completion);
1271 break;
1272 case IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK:
1273 complete(&stream->stream_stop_completion);
1274 break;
1275 case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
1276 /*
1277 * firmware only release the capture msg until software
1278 * get pin_data_ready event
1279 */
1280 ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
1281 if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
1282 stream->output_pins[resp->pin_id].pin_ready)
1283 stream->output_pins[resp->pin_id].pin_ready(stream,
1284 resp);
1285 else
1286 dev_warn(&adev->auxdev.dev,
1287 "%d:No data pin ready handler for pin id %d\n",
1288 resp->stream_handle, resp->pin_id);
1289 if (csi2)
1290 ipu6_isys_csi2_error(csi2);
1291
1292 break;
1293 case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK:
1294 break;
1295 case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
1296 case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE:
1297 break;
1298 case IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF:
1299
1300 ipu6_isys_csi2_sof_event_by_stream(stream);
1301 stream->seq[stream->seq_index].sequence =
1302 atomic_read(&stream->sequence) - 1;
1303 stream->seq[stream->seq_index].timestamp = ts;
1304 dev_dbg(&adev->auxdev.dev,
1305 "sof: handle %d: (index %u), timestamp 0x%16.16llx\n",
1306 resp->stream_handle,
1307 stream->seq[stream->seq_index].sequence, ts);
1308 stream->seq_index = (stream->seq_index + 1)
1309 % IPU6_ISYS_MAX_PARALLEL_SOF;
1310 break;
1311 case IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF:
1312 ipu6_isys_csi2_eof_event_by_stream(stream);
1313 dev_dbg(&adev->auxdev.dev,
1314 "eof: handle %d: (index %u), timestamp 0x%16.16llx\n",
1315 resp->stream_handle,
1316 stream->seq[stream->seq_index].sequence, ts);
1317 break;
1318 case IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY:
1319 break;
1320 default:
1321 dev_err(&adev->auxdev.dev, "%d:unknown response type %u\n",
1322 resp->stream_handle, resp->type);
1323 break;
1324 }
1325
1326 ipu6_isys_put_stream(stream);
1327leave:
1328 ipu6_fw_isys_put_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
1329 return 0;
1330}
1331
1332static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
1333 .isr = isys_isr,
1334 .isr_threaded = NULL,
1335 .wake_isr_thread = false,
1336};
1337
1338static const struct auxiliary_device_id ipu6_isys_id_table[] = {
1339 {
1340 .name = "intel_ipu6.isys",
1341 .driver_data = (kernel_ulong_t)&ipu6_isys_auxdrv_data,
1342 },
1343 { }
1344};
1345MODULE_DEVICE_TABLE(auxiliary, ipu6_isys_id_table);
1346
1347static struct auxiliary_driver isys_driver = {
1348 .name = IPU6_ISYS_NAME,
1349 .probe = isys_probe,
1350 .remove = isys_remove,
1351 .id_table = ipu6_isys_id_table,
1352 .driver = {
1353 .pm = &isys_pm_ops,
1354 },
1355};
1356
1357module_auxiliary_driver(isys_driver);
1358
1359MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1360MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
1361MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
1362MODULE_AUTHOR("Yunliang Ding <yunliang.ding@intel.com>");
1363MODULE_AUTHOR("Hongju Wang <hongju.wang@intel.com>");
1364MODULE_LICENSE("GPL");
1365MODULE_DESCRIPTION("Intel IPU6 input system driver");
1366MODULE_IMPORT_NS(INTEL_IPU6);
1367MODULE_IMPORT_NS(INTEL_IPU_BRIDGE);
drivers/media/pci/intel/ipu6/ipu6-isys.h+206−0
@@ -0,0 +1,206 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_ISYS_H
5#define IPU6_ISYS_H
6
7#include <linux/irqreturn.h>
8#include <linux/list.h>
9#include <linux/mutex.h>
10#include <linux/pm_qos.h>
11#include <linux/spinlock_types.h>
12#include <linux/types.h>
13
14#include <media/media-device.h>
15#include <media/v4l2-async.h>
16#include <media/v4l2-device.h>
17
18#include "ipu6.h"
19#include "ipu6-fw-isys.h"
20#include "ipu6-isys-csi2.h"
21#include "ipu6-isys-video.h"
22
23struct ipu6_bus_device;
24
25#define IPU6_ISYS_ENTITY_PREFIX "Intel IPU6"
26/* FW support max 16 streams */
27#define IPU6_ISYS_MAX_STREAMS 16
28#define ISYS_UNISPART_IRQS (IPU6_ISYS_UNISPART_IRQ_SW | \
29 IPU6_ISYS_UNISPART_IRQ_CSI0 | \
30 IPU6_ISYS_UNISPART_IRQ_CSI1)
31
32#define IPU6_ISYS_2600_MEM_LINE_ALIGN 64
33
34/*
35 * Current message queue configuration. These must be big enough
36 * so that they never gets full. Queues are located in system memory
37 */
38#define IPU6_ISYS_SIZE_RECV_QUEUE 40
39#define IPU6_ISYS_SIZE_SEND_QUEUE 40
40#define IPU6_ISYS_SIZE_PROXY_RECV_QUEUE 5
41#define IPU6_ISYS_SIZE_PROXY_SEND_QUEUE 5
42#define IPU6_ISYS_NUM_RECV_QUEUE 1
43
44#define IPU6_ISYS_MIN_WIDTH 2U
45#define IPU6_ISYS_MIN_HEIGHT 2U
46#define IPU6_ISYS_MAX_WIDTH 4672U
47#define IPU6_ISYS_MAX_HEIGHT 3416U
48
49/* the threshold granularity is 2KB on IPU6 */
50#define IPU6_SRAM_GRANULARITY_SHIFT 11
51#define IPU6_SRAM_GRANULARITY_SIZE 2048
52/* the threshold granularity is 1KB on IPU6SE */
53#define IPU6SE_SRAM_GRANULARITY_SHIFT 10
54#define IPU6SE_SRAM_GRANULARITY_SIZE 1024
55/* IS pixel buffer is 256KB, MaxSRAMSize is 200KB on IPU6 */
56#define IPU6_MAX_SRAM_SIZE (200 << 10)
57/* IS pixel buffer is 128KB, MaxSRAMSize is 96KB on IPU6SE */
58#define IPU6SE_MAX_SRAM_SIZE (96 << 10)
59
60#define IPU6EP_LTR_VALUE 200
61#define IPU6EP_MIN_MEMOPEN_TH 0x4
62#define IPU6EP_MTL_LTR_VALUE 1023
63#define IPU6EP_MTL_MIN_MEMOPEN_TH 0xc
64
65struct ltr_did {
66 union {
67 u32 value;
68 struct {
69 u8 val0;
70 u8 val1;
71 u8 val2;
72 u8 val3;
73 } bits;
74 } lut_ltr;
75 union {
76 u32 value;
77 struct {
78 u8 th0;
79 u8 th1;
80 u8 th2;
81 u8 th3;
82 } bits;
83 } lut_fill_time;
84};
85
86struct isys_iwake_watermark {
87 bool iwake_enabled;
88 bool force_iwake_disable;
89 u32 iwake_threshold;
90 u64 isys_pixelbuffer_datarate;
91 struct ltr_did ltrdid;
92 struct mutex mutex; /* protect whole struct */
93 struct ipu6_isys *isys;
94 struct list_head video_list;
95};
96
97struct ipu6_isys_csi2_config {
98 u32 nlanes;
99 u32 port;
100};
101
102struct sensor_async_sd {
103 struct v4l2_async_connection asc;
104 struct ipu6_isys_csi2_config csi2;
105};
106
107/*
108 * struct ipu6_isys
109 *
110 * @media_dev: Media device
111 * @v4l2_dev: V4L2 device
112 * @adev: ISYS bus device
113 * @power: Is ISYS powered on or not?
114 * @isr_bits: Which bits does the ISR handle?
115 * @power_lock: Serialise access to power (power state in general)
116 * @csi2_rx_ctrl_cached: cached shared value between all CSI2 receivers
117 * @streams_lock: serialise access to streams
118 * @streams: streams per firmware stream ID
119 * @fwcom: fw communication layer private pointer
120 * or optional external library private pointer
121 * @line_align: line alignment in memory
122 * @phy_termcal_val: the termination calibration value, only used for DWC PHY
123 * @need_reset: Isys requires d0i0->i3 transition
124 * @ref_count: total number of callers fw open
125 * @mutex: serialise access isys video open/release related operations
126 * @stream_mutex: serialise stream start and stop, queueing requests
127 * @pdata: platform data pointer
128 * @csi2: CSI-2 receivers
129 */
130struct ipu6_isys {
131 struct media_device media_dev;
132 struct v4l2_device v4l2_dev;
133 struct ipu6_bus_device *adev;
134
135 int power;
136 spinlock_t power_lock;
137 u32 isr_csi2_bits;
138 u32 csi2_rx_ctrl_cached;
139 spinlock_t streams_lock;
140 struct ipu6_isys_stream streams[IPU6_ISYS_MAX_STREAMS];
141 int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
142 void *fwcom;
143 unsigned int line_align;
144 u32 phy_termcal_val;
145 bool need_reset;
146 bool icache_prefetch;
147 bool csi2_cse_ipc_not_supported;
148 unsigned int ref_count;
149 unsigned int stream_opened;
150 unsigned int sensor_type;
151
152 struct mutex mutex;
153 struct mutex stream_mutex;
154
155 struct ipu6_isys_pdata *pdata;
156
157 int (*phy_set_power)(struct ipu6_isys *isys,
158 struct ipu6_isys_csi2_config *cfg,
159 const struct ipu6_isys_csi2_timing *timing,
160 bool on);
161
162 struct ipu6_isys_csi2 *csi2;
163
164 struct pm_qos_request pm_qos;
165 spinlock_t listlock; /* Protect framebuflist */
166 struct list_head framebuflist;
167 struct list_head framebuflist_fw;
168 struct v4l2_async_notifier notifier;
169 struct isys_iwake_watermark iwake_watermark;
170};
171
172struct isys_fw_msgs {
173 union {
174 u64 dummy;
175 struct ipu6_fw_isys_frame_buff_set_abi frame;
176 struct ipu6_fw_isys_stream_cfg_data_abi stream;
177 } fw_msg;
178 struct list_head head;
179 dma_addr_t dma_addr;
180};
181
182struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
183void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data);
184void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
185
186extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops;
187
188void isys_setup_hw(struct ipu6_isys *isys);
189irqreturn_t isys_isr(struct ipu6_bus_device *adev);
190void update_watermark_setting(struct ipu6_isys *isys);
191
192int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys,
193 struct ipu6_isys_csi2_config *cfg,
194 const struct ipu6_isys_csi2_timing *timing,
195 bool on);
196
197int ipu6_isys_dwc_phy_set_power(struct ipu6_isys *isys,
198 struct ipu6_isys_csi2_config *cfg,
199 const struct ipu6_isys_csi2_timing *timing,
200 bool on);
201
202int ipu6_isys_jsl_phy_set_power(struct ipu6_isys *isys,
203 struct ipu6_isys_csi2_config *cfg,
204 const struct ipu6_isys_csi2_timing *timing,
205 bool on);
206#endif /* IPU6_ISYS_H */
drivers/media/pci/intel/ipu6/ipu6-mmu.c+846−0
@@ -0,0 +1,846 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5#include <asm/barrier.h>
6
7#include <linux/align.h>
8#include <linux/atomic.h>
9#include <linux/bitops.h>
10#include <linux/bits.h>
11#include <linux/bug.h>
12#include <linux/cacheflush.h>
13#include <linux/dma-mapping.h>
14#include <linux/err.h>
15#include <linux/gfp.h>
16#include <linux/io.h>
17#include <linux/iova.h>
18#include <linux/math.h>
19#include <linux/minmax.h>
20#include <linux/mm.h>
21#include <linux/pfn.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/types.h>
25#include <linux/vmalloc.h>
26
27#include "ipu6.h"
28#include "ipu6-dma.h"
29#include "ipu6-mmu.h"
30#include "ipu6-platform-regs.h"
31
32#define ISP_PAGE_SHIFT 12
33#define ISP_PAGE_SIZE BIT(ISP_PAGE_SHIFT)
34#define ISP_PAGE_MASK (~(ISP_PAGE_SIZE - 1))
35
36#define ISP_L1PT_SHIFT 22
37#define ISP_L1PT_MASK (~((1U << ISP_L1PT_SHIFT) - 1))
38
39#define ISP_L2PT_SHIFT 12
40#define ISP_L2PT_MASK (~(ISP_L1PT_MASK | (~(ISP_PAGE_MASK))))
41
42#define ISP_L1PT_PTES 1024
43#define ISP_L2PT_PTES 1024
44
45#define ISP_PADDR_SHIFT 12
46
47#define REG_TLB_INVALIDATE 0x0000
48
49#define REG_L1_PHYS 0x0004 /* 27-bit pfn */
50#define REG_INFO 0x0008
51
52#define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT)
53
54static void tlb_invalidate(struct ipu6_mmu *mmu)
55{
56 unsigned long flags;
57 unsigned int i;
58
59 spin_lock_irqsave(&mmu->ready_lock, flags);
60 if (!mmu->ready) {
61 spin_unlock_irqrestore(&mmu->ready_lock, flags);
62 return;
63 }
64
65 for (i = 0; i < mmu->nr_mmus; i++) {
66 /*
67 * To avoid the HW bug induced dead lock in some of the IPU6
68 * MMUs on successive invalidate calls, we need to first do a
69 * read to the page table base before writing the invalidate
70 * register. MMUs which need to implement this WA, will have
71 * the insert_read_before_invalidate flags set as true.
72 * Disregard the return value of the read.
73 */
74 if (mmu->mmu_hw[i].insert_read_before_invalidate)
75 readl(mmu->mmu_hw[i].base + REG_L1_PHYS);
76
77 writel(0xffffffff, mmu->mmu_hw[i].base +
78 REG_TLB_INVALIDATE);
79 /*
80 * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
81 * When the actual MMIO write reaches the IPU6 TLB Invalidate
82 * register, wmb() will force the TLB invalidate out if the CPU
83 * attempts to update the IOMMU page table (or sooner).
84 */
85 wmb();
86 }
87 spin_unlock_irqrestore(&mmu->ready_lock, flags);
88}
89
90#ifdef DEBUG
91static void page_table_dump(struct ipu6_mmu_info *mmu_info)
92{
93 u32 l1_idx;
94
95 dev_dbg(mmu_info->dev, "begin IOMMU page table dump\n");
96
97 for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) {
98 u32 l2_idx;
99 u32 iova = (phys_addr_t)l1_idx << ISP_L1PT_SHIFT;
100
101 if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval)
102 continue;
103 dev_dbg(mmu_info->dev,
104 "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pa\n",
105 l1_idx, iova, iova + ISP_PAGE_SIZE,
106 TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx]));
107
108 for (l2_idx = 0; l2_idx < ISP_L2PT_PTES; l2_idx++) {
109 u32 *l2_pt = mmu_info->l2_pts[l1_idx];
110 u32 iova2 = iova + (l2_idx << ISP_L2PT_SHIFT);
111
112 if (l2_pt[l2_idx] == mmu_info->dummy_page_pteval)
113 continue;
114
115 dev_dbg(mmu_info->dev,
116 "\tl2 entry %u; iova 0x%8.8x, phys %pa\n",
117 l2_idx, iova2,
118 TBL_PHYS_ADDR(l2_pt[l2_idx]));
119 }
120 }
121
122 dev_dbg(mmu_info->dev, "end IOMMU page table dump\n");
123}
124#endif /* DEBUG */
125
126static dma_addr_t map_single(struct ipu6_mmu_info *mmu_info, void *ptr)
127{
128 dma_addr_t dma;
129
130 dma = dma_map_single(mmu_info->dev, ptr, PAGE_SIZE, DMA_BIDIRECTIONAL);
131 if (dma_mapping_error(mmu_info->dev, dma))
132 return 0;
133
134 return dma;
135}
136
137static int get_dummy_page(struct ipu6_mmu_info *mmu_info)
138{
139 void *pt = (void *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32);
140 dma_addr_t dma;
141
142 if (!pt)
143 return -ENOMEM;
144
145 dev_dbg(mmu_info->dev, "dummy_page: get_zeroed_page() == %p\n", pt);
146
147 dma = map_single(mmu_info, pt);
148 if (!dma) {
149 dev_err(mmu_info->dev, "Failed to map dummy page\n");
150 goto err_free_page;
151 }
152
153 mmu_info->dummy_page = pt;
154 mmu_info->dummy_page_pteval = dma >> ISP_PAGE_SHIFT;
155
156 return 0;
157
158err_free_page:
159 free_page((unsigned long)pt);
160 return -ENOMEM;
161}
162
163static void free_dummy_page(struct ipu6_mmu_info *mmu_info)
164{
165 dma_unmap_single(mmu_info->dev,
166 TBL_PHYS_ADDR(mmu_info->dummy_page_pteval),
167 PAGE_SIZE, DMA_BIDIRECTIONAL);
168 free_page((unsigned long)mmu_info->dummy_page);
169}
170
171static int alloc_dummy_l2_pt(struct ipu6_mmu_info *mmu_info)
172{
173 u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32);
174 dma_addr_t dma;
175 unsigned int i;
176
177 if (!pt)
178 return -ENOMEM;
179
180 dev_dbg(mmu_info->dev, "dummy_l2: get_zeroed_page() = %p\n", pt);
181
182 dma = map_single(mmu_info, pt);
183 if (!dma) {
184 dev_err(mmu_info->dev, "Failed to map l2pt page\n");
185 goto err_free_page;
186 }
187
188 for (i = 0; i < ISP_L2PT_PTES; i++)
189 pt[i] = mmu_info->dummy_page_pteval;
190
191 mmu_info->dummy_l2_pt = pt;
192 mmu_info->dummy_l2_pteval = dma >> ISP_PAGE_SHIFT;
193
194 return 0;
195
196err_free_page:
197 free_page((unsigned long)pt);
198 return -ENOMEM;
199}
200
201static void free_dummy_l2_pt(struct ipu6_mmu_info *mmu_info)
202{
203 dma_unmap_single(mmu_info->dev,
204 TBL_PHYS_ADDR(mmu_info->dummy_l2_pteval),
205 PAGE_SIZE, DMA_BIDIRECTIONAL);
206 free_page((unsigned long)mmu_info->dummy_l2_pt);
207}
208
209static u32 *alloc_l1_pt(struct ipu6_mmu_info *mmu_info)
210{
211 u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32);
212 dma_addr_t dma;
213 unsigned int i;
214
215 if (!pt)
216 return NULL;
217
218 dev_dbg(mmu_info->dev, "alloc_l1: get_zeroed_page() = %p\n", pt);
219
220 for (i = 0; i < ISP_L1PT_PTES; i++)
221 pt[i] = mmu_info->dummy_l2_pteval;
222
223 dma = map_single(mmu_info, pt);
224 if (!dma) {
225 dev_err(mmu_info->dev, "Failed to map l1pt page\n");
226 goto err_free_page;
227 }
228
229 mmu_info->l1_pt_dma = dma >> ISP_PADDR_SHIFT;
230 dev_dbg(mmu_info->dev, "l1 pt %p mapped at %llx\n", pt, dma);
231
232 return pt;
233
234err_free_page:
235 free_page((unsigned long)pt);
236 return NULL;
237}
238
239static u32 *alloc_l2_pt(struct ipu6_mmu_info *mmu_info)
240{
241 u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32);
242 unsigned int i;
243
244 if (!pt)
245 return NULL;
246
247 dev_dbg(mmu_info->dev, "alloc_l2: get_zeroed_page() = %p\n", pt);
248
249 for (i = 0; i < ISP_L1PT_PTES; i++)
250 pt[i] = mmu_info->dummy_page_pteval;
251
252 return pt;
253}
254
255static int l2_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
256 phys_addr_t paddr, size_t size)
257{
258 u32 l1_idx = iova >> ISP_L1PT_SHIFT;
259 u32 iova_start = iova;
260 u32 *l2_pt, *l2_virt;
261 unsigned int l2_idx;
262 unsigned long flags;
263 dma_addr_t dma;
264 u32 l1_entry;
265
266 dev_dbg(mmu_info->dev,
267 "mapping l2 page table for l1 index %u (iova %8.8x)\n",
268 l1_idx, (u32)iova);
269
270 spin_lock_irqsave(&mmu_info->lock, flags);
271 l1_entry = mmu_info->l1_pt[l1_idx];
272 if (l1_entry == mmu_info->dummy_l2_pteval) {
273 l2_virt = mmu_info->l2_pts[l1_idx];
274 if (likely(!l2_virt)) {
275 l2_virt = alloc_l2_pt(mmu_info);
276 if (!l2_virt) {
277 spin_unlock_irqrestore(&mmu_info->lock, flags);
278 return -ENOMEM;
279 }
280 }
281
282 dma = map_single(mmu_info, l2_virt);
283 if (!dma) {
284 dev_err(mmu_info->dev, "Failed to map l2pt page\n");
285 free_page((unsigned long)l2_virt);
286 spin_unlock_irqrestore(&mmu_info->lock, flags);
287 return -EINVAL;
288 }
289
290 l1_entry = dma >> ISP_PADDR_SHIFT;
291
292 dev_dbg(mmu_info->dev, "page for l1_idx %u %p allocated\n",
293 l1_idx, l2_virt);
294 mmu_info->l1_pt[l1_idx] = l1_entry;
295 mmu_info->l2_pts[l1_idx] = l2_virt;
296 clflush_cache_range((void *)&mmu_info->l1_pt[l1_idx],
297 sizeof(mmu_info->l1_pt[l1_idx]));
298 }
299
300 l2_pt = mmu_info->l2_pts[l1_idx];
301
302 dev_dbg(mmu_info->dev, "l2_pt at %p with dma 0x%x\n", l2_pt, l1_entry);
303
304 paddr = ALIGN(paddr, ISP_PAGE_SIZE);
305
306 l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
307
308 dev_dbg(mmu_info->dev, "l2_idx %u, phys 0x%8.8x\n", l2_idx,
309 l2_pt[l2_idx]);
310 if (l2_pt[l2_idx] != mmu_info->dummy_page_pteval) {
311 spin_unlock_irqrestore(&mmu_info->lock, flags);
312 return -EINVAL;
313 }
314
315 l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT;
316
317 clflush_cache_range((void *)&l2_pt[l2_idx], sizeof(l2_pt[l2_idx]));
318 spin_unlock_irqrestore(&mmu_info->lock, flags);
319
320 dev_dbg(mmu_info->dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx,
321 l2_pt[l2_idx]);
322
323 return 0;
324}
325
326static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
327 phys_addr_t paddr, size_t size)
328{
329 u32 iova_start = round_down(iova, ISP_PAGE_SIZE);
330 u32 iova_end = ALIGN(iova + size, ISP_PAGE_SIZE);
331
332 dev_dbg(mmu_info->dev,
333 "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr 0x%10.10llx\n",
334 iova_start, iova_end, size, paddr);
335
336 return l2_map(mmu_info, iova_start, paddr, size);
337}
338
339static size_t l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
340 phys_addr_t dummy, size_t size)
341{
342 u32 l1_idx = iova >> ISP_L1PT_SHIFT;
343 u32 iova_start = iova;
344 unsigned int l2_idx;
345 size_t unmapped = 0;
346 unsigned long flags;
347 u32 *l2_pt;
348
349 dev_dbg(mmu_info->dev, "unmapping l2 page table for l1 index %u (iova 0x%8.8lx)\n",
350 l1_idx, iova);
351
352 spin_lock_irqsave(&mmu_info->lock, flags);
353 if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
354 spin_unlock_irqrestore(&mmu_info->lock, flags);
355 dev_err(mmu_info->dev,
356 "unmap iova 0x%8.8lx l1 idx %u which was not mapped\n",
357 iova, l1_idx);
358 return 0;
359 }
360
361 for (l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
362 (iova_start & ISP_L1PT_MASK) + (l2_idx << ISP_PAGE_SHIFT)
363 < iova_start + size && l2_idx < ISP_L2PT_PTES; l2_idx++) {
364 l2_pt = mmu_info->l2_pts[l1_idx];
365 dev_dbg(mmu_info->dev,
366 "unmap l2 index %u with pteval 0x%10.10llx\n",
367 l2_idx, TBL_PHYS_ADDR(l2_pt[l2_idx]));
368 l2_pt[l2_idx] = mmu_info->dummy_page_pteval;
369
370 clflush_cache_range((void *)&l2_pt[l2_idx],
371 sizeof(l2_pt[l2_idx]));
372 unmapped++;
373 }
374 spin_unlock_irqrestore(&mmu_info->lock, flags);
375
376 return unmapped << ISP_PAGE_SHIFT;
377}
378
379static size_t __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info,
380 unsigned long iova, size_t size)
381{
382 return l2_unmap(mmu_info, iova, 0, size);
383}
384
385static int allocate_trash_buffer(struct ipu6_mmu *mmu)
386{
387 unsigned int n_pages = PHYS_PFN(PAGE_ALIGN(IPU6_MMUV2_TRASH_RANGE));
388 struct iova *iova;
389 unsigned int i;
390 dma_addr_t dma;
391 unsigned long iova_addr;
392 int ret;
393
394 /* Allocate 8MB in iova range */
395 iova = alloc_iova(&mmu->dmap->iovad, n_pages,
396 PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0);
397 if (!iova) {
398 dev_err(mmu->dev, "cannot allocate iova range for trash\n");
399 return -ENOMEM;
400 }
401
402 dma = dma_map_page(mmu->dmap->mmu_info->dev, mmu->trash_page, 0,
403 PAGE_SIZE, DMA_BIDIRECTIONAL);
404 if (dma_mapping_error(mmu->dmap->mmu_info->dev, dma)) {
405 dev_err(mmu->dmap->mmu_info->dev, "Failed to map trash page\n");
406 ret = -ENOMEM;
407 goto out_free_iova;
408 }
409
410 mmu->pci_trash_page = dma;
411
412 /*
413 * Map the 8MB iova address range to the same physical trash page
414 * mmu->trash_page which is already reserved at the probe
415 */
416 iova_addr = iova->pfn_lo;
417 for (i = 0; i < n_pages; i++) {
418 ret = ipu6_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr),
419 mmu->pci_trash_page, PAGE_SIZE);
420 if (ret) {
421 dev_err(mmu->dev,
422 "mapping trash buffer range failed\n");
423 goto out_unmap;
424 }
425
426 iova_addr++;
427 }
428
429 mmu->iova_trash_page = PFN_PHYS(iova->pfn_lo);
430 dev_dbg(mmu->dev, "iova trash buffer for MMUID: %d is %u\n",
431 mmu->mmid, (unsigned int)mmu->iova_trash_page);
432 return 0;
433
434out_unmap:
435 ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
436 PFN_PHYS(iova_size(iova)));
437 dma_unmap_page(mmu->dmap->mmu_info->dev, mmu->pci_trash_page,
438 PAGE_SIZE, DMA_BIDIRECTIONAL);
439out_free_iova:
440 __free_iova(&mmu->dmap->iovad, iova);
441 return ret;
442}
443
444int ipu6_mmu_hw_init(struct ipu6_mmu *mmu)
445{
446 struct ipu6_mmu_info *mmu_info;
447 unsigned long flags;
448 unsigned int i;
449
450 mmu_info = mmu->dmap->mmu_info;
451
452 /* Initialise the each MMU HW block */
453 for (i = 0; i < mmu->nr_mmus; i++) {
454 struct ipu6_mmu_hw *mmu_hw = &mmu->mmu_hw[i];
455 unsigned int j;
456 u16 block_addr;
457
458 /* Write page table address per MMU */
459 writel((phys_addr_t)mmu_info->l1_pt_dma,
460 mmu->mmu_hw[i].base + REG_L1_PHYS);
461
462 /* Set info bits per MMU */
463 writel(mmu->mmu_hw[i].info_bits,
464 mmu->mmu_hw[i].base + REG_INFO);
465
466 /* Configure MMU TLB stream configuration for L1 */
467 for (j = 0, block_addr = 0; j < mmu_hw->nr_l1streams;
468 block_addr += mmu->mmu_hw[i].l1_block_sz[j], j++) {
469 if (block_addr > IPU6_MAX_LI_BLOCK_ADDR) {
470 dev_err(mmu->dev, "invalid L1 configuration\n");
471 return -EINVAL;
472 }
473
474 /* Write block start address for each streams */
475 writel(block_addr, mmu_hw->base +
476 mmu_hw->l1_stream_id_reg_offset + 4 * j);
477 }
478
479 /* Configure MMU TLB stream configuration for L2 */
480 for (j = 0, block_addr = 0; j < mmu_hw->nr_l2streams;
481 block_addr += mmu->mmu_hw[i].l2_block_sz[j], j++) {
482 if (block_addr > IPU6_MAX_L2_BLOCK_ADDR) {
483 dev_err(mmu->dev, "invalid L2 configuration\n");
484 return -EINVAL;
485 }
486
487 writel(block_addr, mmu_hw->base +
488 mmu_hw->l2_stream_id_reg_offset + 4 * j);
489 }
490 }
491
492 if (!mmu->trash_page) {
493 int ret;
494
495 mmu->trash_page = alloc_page(GFP_KERNEL);
496 if (!mmu->trash_page) {
497 dev_err(mmu->dev, "insufficient memory for trash buffer\n");
498 return -ENOMEM;
499 }
500
501 ret = allocate_trash_buffer(mmu);
502 if (ret) {
503 __free_page(mmu->trash_page);
504 mmu->trash_page = NULL;
505 dev_err(mmu->dev, "trash buffer allocation failed\n");
506 return ret;
507 }
508 }
509
510 spin_lock_irqsave(&mmu->ready_lock, flags);
511 mmu->ready = true;
512 spin_unlock_irqrestore(&mmu->ready_lock, flags);
513
514 return 0;
515}
516EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_init, INTEL_IPU6);
517
518static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp)
519{
520 struct ipu6_mmu_info *mmu_info;
521 int ret;
522
523 mmu_info = kzalloc(sizeof(*mmu_info), GFP_KERNEL);
524 if (!mmu_info)
525 return NULL;
526
527 mmu_info->aperture_start = 0;
528 mmu_info->aperture_end = DMA_BIT_MASK(isp->secure_mode ?
529 IPU6_MMU_ADDR_BITS :
530 IPU6_MMU_ADDR_BITS_NON_SECURE);
531 mmu_info->pgsize_bitmap = SZ_4K;
532 mmu_info->dev = &isp->pdev->dev;
533
534 ret = get_dummy_page(mmu_info);
535 if (ret)
536 goto err_free_info;
537
538 ret = alloc_dummy_l2_pt(mmu_info);
539 if (ret)
540 goto err_free_dummy_page;
541
542 mmu_info->l2_pts = vzalloc(ISP_L2PT_PTES * sizeof(*mmu_info->l2_pts));
543 if (!mmu_info->l2_pts)
544 goto err_free_dummy_l2_pt;
545
546 /*
547 * We always map the L1 page table (a single page as well as
548 * the L2 page tables).
549 */
550 mmu_info->l1_pt = alloc_l1_pt(mmu_info);
551 if (!mmu_info->l1_pt)
552 goto err_free_l2_pts;
553
554 spin_lock_init(&mmu_info->lock);
555
556 dev_dbg(mmu_info->dev, "domain initialised\n");
557
558 return mmu_info;
559
560err_free_l2_pts:
561 vfree(mmu_info->l2_pts);
562err_free_dummy_l2_pt:
563 free_dummy_l2_pt(mmu_info);
564err_free_dummy_page:
565 free_dummy_page(mmu_info);
566err_free_info:
567 kfree(mmu_info);
568
569 return NULL;
570}
571
572void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu)
573{
574 unsigned long flags;
575
576 spin_lock_irqsave(&mmu->ready_lock, flags);
577 mmu->ready = false;
578 spin_unlock_irqrestore(&mmu->ready_lock, flags);
579}
580EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_cleanup, INTEL_IPU6);
581
582static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp)
583{
584 struct ipu6_dma_mapping *dmap;
585
586 dmap = kzalloc(sizeof(*dmap), GFP_KERNEL);
587 if (!dmap)
588 return NULL;
589
590 dmap->mmu_info = ipu6_mmu_alloc(isp);
591 if (!dmap->mmu_info) {
592 kfree(dmap);
593 return NULL;
594 }
595
596 init_iova_domain(&dmap->iovad, SZ_4K, 1);
597 dmap->mmu_info->dmap = dmap;
598
599 dev_dbg(&isp->pdev->dev, "alloc mapping\n");
600
601 iova_cache_get();
602
603 return dmap;
604}
605
606phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
607 dma_addr_t iova)
608{
609 phys_addr_t phy_addr;
610 unsigned long flags;
611 u32 *l2_pt;
612
613 spin_lock_irqsave(&mmu_info->lock, flags);
614 l2_pt = mmu_info->l2_pts[iova >> ISP_L1PT_SHIFT];
615 phy_addr = (phys_addr_t)l2_pt[(iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT];
616 phy_addr <<= ISP_PAGE_SHIFT;
617 spin_unlock_irqrestore(&mmu_info->lock, flags);
618
619 return phy_addr;
620}
621
622static size_t ipu6_mmu_pgsize(unsigned long pgsize_bitmap,
623 unsigned long addr_merge, size_t size)
624{
625 unsigned int pgsize_idx;
626 size_t pgsize;
627
628 /* Max page size that still fits into 'size' */
629 pgsize_idx = __fls(size);
630
631 if (likely(addr_merge)) {
632 /* Max page size allowed by address */
633 unsigned int align_pgsize_idx = __ffs(addr_merge);
634
635 pgsize_idx = min(pgsize_idx, align_pgsize_idx);
636 }
637
638 pgsize = (1UL << (pgsize_idx + 1)) - 1;
639 pgsize &= pgsize_bitmap;
640
641 WARN_ON(!pgsize);
642
643 /* pick the biggest page */
644 pgsize_idx = __fls(pgsize);
645 pgsize = 1UL << pgsize_idx;
646
647 return pgsize;
648}
649
650size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
651 size_t size)
652{
653 size_t unmapped_page, unmapped = 0;
654 unsigned int min_pagesz;
655
656 /* find out the minimum page size supported */
657 min_pagesz = 1 << __ffs(mmu_info->pgsize_bitmap);
658
659 /*
660 * The virtual address and the size of the mapping must be
661 * aligned (at least) to the size of the smallest page supported
662 * by the hardware
663 */
664 if (!IS_ALIGNED(iova | size, min_pagesz)) {
665 dev_err(NULL, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
666 iova, size, min_pagesz);
667 return -EINVAL;
668 }
669
670 /*
671 * Keep iterating until we either unmap 'size' bytes (or more)
672 * or we hit an area that isn't mapped.
673 */
674 while (unmapped < size) {
675 size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap,
676 iova, size - unmapped);
677
678 unmapped_page = __ipu6_mmu_unmap(mmu_info, iova, pgsize);
679 if (!unmapped_page)
680 break;
681
682 dev_dbg(mmu_info->dev, "unmapped: iova 0x%lx size 0x%zx\n",
683 iova, unmapped_page);
684
685 iova += unmapped_page;
686 unmapped += unmapped_page;
687 }
688
689 return unmapped;
690}
691
692int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
693 phys_addr_t paddr, size_t size)
694{
695 unsigned long orig_iova = iova;
696 unsigned int min_pagesz;
697 size_t orig_size = size;
698 int ret = 0;
699
700 if (mmu_info->pgsize_bitmap == 0UL)
701 return -ENODEV;
702
703 /* find out the minimum page size supported */
704 min_pagesz = 1 << __ffs(mmu_info->pgsize_bitmap);
705
706 /*
707 * both the virtual address and the physical one, as well as
708 * the size of the mapping, must be aligned (at least) to the
709 * size of the smallest page supported by the hardware
710 */
711 if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
712 dev_err(mmu_info->dev,
713 "unaligned: iova %lx pa %pa size %zx min_pagesz %x\n",
714 iova, &paddr, size, min_pagesz);
715 return -EINVAL;
716 }
717
718 dev_dbg(mmu_info->dev, "map: iova 0x%lx pa %pa size 0x%zx\n",
719 iova, &paddr, size);
720
721 while (size) {
722 size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap,
723 iova | paddr, size);
724
725 dev_dbg(mmu_info->dev,
726 "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
727 iova, &paddr, pgsize);
728
729 ret = __ipu6_mmu_map(mmu_info, iova, paddr, pgsize);
730 if (ret)
731 break;
732
733 iova += pgsize;
734 paddr += pgsize;
735 size -= pgsize;
736 }
737
738 /* unroll mapping in case something went wrong */
739 if (ret)
740 ipu6_mmu_unmap(mmu_info, orig_iova, orig_size - size);
741
742 return ret;
743}
744
745static void ipu6_mmu_destroy(struct ipu6_mmu *mmu)
746{
747 struct ipu6_dma_mapping *dmap = mmu->dmap;
748 struct ipu6_mmu_info *mmu_info = dmap->mmu_info;
749 struct iova *iova;
750 u32 l1_idx;
751
752 if (mmu->iova_trash_page) {
753 iova = find_iova(&dmap->iovad, PHYS_PFN(mmu->iova_trash_page));
754 if (iova) {
755 /* unmap and free the trash buffer iova */
756 ipu6_mmu_unmap(mmu_info, PFN_PHYS(iova->pfn_lo),
757 PFN_PHYS(iova_size(iova)));
758 __free_iova(&dmap->iovad, iova);
759 } else {
760 dev_err(mmu->dev, "trash buffer iova not found.\n");
761 }
762
763 mmu->iova_trash_page = 0;
764 dma_unmap_page(mmu_info->dev, mmu->pci_trash_page,
765 PAGE_SIZE, DMA_BIDIRECTIONAL);
766 mmu->pci_trash_page = 0;
767 __free_page(mmu->trash_page);
768 }
769
770 for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) {
771 if (mmu_info->l1_pt[l1_idx] != mmu_info->dummy_l2_pteval) {
772 dma_unmap_single(mmu_info->dev,
773 TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx]),
774 PAGE_SIZE, DMA_BIDIRECTIONAL);
775 free_page((unsigned long)mmu_info->l2_pts[l1_idx]);
776 }
777 }
778
779 vfree(mmu_info->l2_pts);
780 free_dummy_page(mmu_info);
781 dma_unmap_single(mmu_info->dev, TBL_PHYS_ADDR(mmu_info->l1_pt_dma),
782 PAGE_SIZE, DMA_BIDIRECTIONAL);
783 free_page((unsigned long)mmu_info->dummy_l2_pt);
784 free_page((unsigned long)mmu_info->l1_pt);
785 kfree(mmu_info);
786}
787
788struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
789 void __iomem *base, int mmid,
790 const struct ipu6_hw_variants *hw)
791{
792 struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
793 struct ipu6_mmu_pdata *pdata;
794 struct ipu6_mmu *mmu;
795 unsigned int i;
796
797 if (hw->nr_mmus > IPU6_MMU_MAX_DEVICES)
798 return ERR_PTR(-EINVAL);
799
800 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
801 if (!pdata)
802 return ERR_PTR(-ENOMEM);
803
804 for (i = 0; i < hw->nr_mmus; i++) {
805 struct ipu6_mmu_hw *pdata_mmu = &pdata->mmu_hw[i];
806 const struct ipu6_mmu_hw *src_mmu = &hw->mmu_hw[i];
807
808 if (src_mmu->nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
809 src_mmu->nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
810 return ERR_PTR(-EINVAL);
811
812 *pdata_mmu = *src_mmu;
813 pdata_mmu->base = base + src_mmu->offset;
814 }
815
816 mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
817 if (!mmu)
818 return ERR_PTR(-ENOMEM);
819
820 mmu->mmid = mmid;
821 mmu->mmu_hw = pdata->mmu_hw;
822 mmu->nr_mmus = hw->nr_mmus;
823 mmu->tlb_invalidate = tlb_invalidate;
824 mmu->ready = false;
825 INIT_LIST_HEAD(&mmu->vma_list);
826 spin_lock_init(&mmu->ready_lock);
827
828 mmu->dmap = alloc_dma_mapping(isp);
829 if (!mmu->dmap) {
830 dev_err(dev, "can't alloc dma mapping\n");
831 return ERR_PTR(-ENOMEM);
832 }
833
834 return mmu;
835}
836
837void ipu6_mmu_cleanup(struct ipu6_mmu *mmu)
838{
839 struct ipu6_dma_mapping *dmap = mmu->dmap;
840
841 ipu6_mmu_destroy(mmu);
842 mmu->dmap = NULL;
843 iova_cache_put();
844 put_iova_domain(&dmap->iovad);
845 kfree(dmap);
846}
drivers/media/pci/intel/ipu6/ipu6-mmu.h+73−0
@@ -0,0 +1,73 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2013--2024 Intel Corporation */
3
4#ifndef IPU6_MMU_H
5#define IPU6_MMU_H
6
7#define ISYS_MMID 1
8#define PSYS_MMID 0
9
10#include <linux/list.h>
11#include <linux/spinlock_types.h>
12#include <linux/types.h>
13
14struct device;
15struct page;
16struct ipu6_hw_variants;
17
18struct ipu6_mmu_info {
19 struct device *dev;
20
21 u32 *l1_pt;
22 u32 l1_pt_dma;
23 u32 **l2_pts;
24
25 u32 *dummy_l2_pt;
26 u32 dummy_l2_pteval;
27 void *dummy_page;
28 u32 dummy_page_pteval;
29
30 dma_addr_t aperture_start;
31 dma_addr_t aperture_end;
32 unsigned long pgsize_bitmap;
33
34 spinlock_t lock; /* Serialize access to users */
35 struct ipu6_dma_mapping *dmap;
36};
37
38struct ipu6_mmu {
39 struct list_head node;
40
41 struct ipu6_mmu_hw *mmu_hw;
42 unsigned int nr_mmus;
43 unsigned int mmid;
44
45 phys_addr_t pgtbl;
46 struct device *dev;
47
48 struct ipu6_dma_mapping *dmap;
49 struct list_head vma_list;
50
51 struct page *trash_page;
52 dma_addr_t pci_trash_page; /* IOVA from PCI DMA services (parent) */
53 dma_addr_t iova_trash_page; /* IOVA for IPU6 child nodes to use */
54
55 bool ready;
56 spinlock_t ready_lock; /* Serialize access to bool ready */
57
58 void (*tlb_invalidate)(struct ipu6_mmu *mmu);
59};
60
61struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
62 void __iomem *base, int mmid,
63 const struct ipu6_hw_variants *hw);
64void ipu6_mmu_cleanup(struct ipu6_mmu *mmu);
65int ipu6_mmu_hw_init(struct ipu6_mmu *mmu);
66void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu);
67int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
68 phys_addr_t paddr, size_t size);
69size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
70 size_t size);
71phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
72 dma_addr_t iova);
73#endif
drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h+226−0
@@ -0,0 +1,226 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2023--2024 Intel Corporation */
3
4#ifndef IPU6_PLATFORM_BUTTRESS_REGS_H
5#define IPU6_PLATFORM_BUTTRESS_REGS_H
6
7#include <linux/bits.h>
8
9/* IS_WORKPOINT_REQ */
10#define IPU6_BUTTRESS_REG_IS_FREQ_CTL 0x34
11/* PS_WORKPOINT_REQ */
12#define IPU6_BUTTRESS_REG_PS_FREQ_CTL 0x38
13
14/* should be tuned for real silicon */
15#define IPU6_IS_FREQ_CTL_DEFAULT_RATIO 0x08
16#define IPU6SE_IS_FREQ_CTL_DEFAULT_RATIO 0x0a
17#define IPU6_PS_FREQ_CTL_DEFAULT_RATIO 0x0d
18
19#define IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x10
20#define IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x0708
21
22#define IPU6_BUTTRESS_PWR_STATE_IS_PWR_SHIFT 3
23#define IPU6_BUTTRESS_PWR_STATE_IS_PWR_MASK GENMASK(4, 3)
24
25#define IPU6_BUTTRESS_PWR_STATE_PS_PWR_SHIFT 6
26#define IPU6_BUTTRESS_PWR_STATE_PS_PWR_MASK GENMASK(7, 6)
27
28#define IPU6_BUTTRESS_PWR_STATE_DN_DONE 0x0
29#define IPU6_BUTTRESS_PWR_STATE_UP_PROCESS 0x1
30#define IPU6_BUTTRESS_PWR_STATE_DN_PROCESS 0x2
31#define IPU6_BUTTRESS_PWR_STATE_UP_DONE 0x3
32
33#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_0 0x270
34#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_1 0x274
35#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_2 0x278
36#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_3 0x27c
37#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_4 0x280
38#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_5 0x284
39#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_6 0x288
40#define IPU6_BUTTRESS_REG_FPGA_SUPPORT_7 0x28c
41
42#define BUTTRESS_REG_WDT 0x8
43#define BUTTRESS_REG_BTRS_CTRL 0xc
44#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0 BIT(0)
45#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1 BIT(1)
46#define BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND GENMASK(9, 8)
47
48#define BUTTRESS_REG_FW_RESET_CTL 0x30
49#define BUTTRESS_FW_RESET_CTL_START BIT(0)
50#define BUTTRESS_FW_RESET_CTL_DONE BIT(1)
51
52#define BUTTRESS_REG_IS_FREQ_CTL 0x34
53#define BUTTRESS_REG_PS_FREQ_CTL 0x38
54
55#define BUTTRESS_FREQ_CTL_START BIT(31)
56#define BUTTRESS_FREQ_CTL_ICCMAX_LEVEL GENMASK(19, 16)
57#define BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK GENMASK(15, 8)
58#define BUTTRESS_FREQ_CTL_RATIO_MASK GENMASK(7, 0)
59
60#define BUTTRESS_REG_PWR_STATE 0x5c
61
62#define BUTTRESS_PWR_STATE_RESET 0x0
63#define BUTTRESS_PWR_STATE_PWR_ON_DONE 0x1
64#define BUTTRESS_PWR_STATE_PWR_RDY 0x3
65#define BUTTRESS_PWR_STATE_PWR_IDLE 0x4
66
67#define BUTTRESS_PWR_STATE_HH_STATUS_MASK GENMASK(12, 11)
68
69enum {
70 BUTTRESS_PWR_STATE_HH_STATE_IDLE,
71 BUTTRESS_PWR_STATE_HH_STATE_IN_PRGS,
72 BUTTRESS_PWR_STATE_HH_STATE_DONE,
73 BUTTRESS_PWR_STATE_HH_STATE_ERR,
74};
75
76#define BUTTRESS_PWR_STATE_IS_PWR_FSM_MASK GENMASK(23, 19)
77
78#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IDLE 0x0
79#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PLL_CMP 0x1
80#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK 0x2
81#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PG_ACK 0x3
82#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_ASSRT_CYCLES 0x4
83#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES1 0x5
84#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES2 0x6
85#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DEASSRT_CYCLES 0x7
86#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_FUSE_WR_CMP 0x8
87#define BUTTRESS_PWR_STATE_IS_PWR_FSM_BRK_POINT 0x9
88#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IS_RDY 0xa
89#define BUTTRESS_PWR_STATE_IS_PWR_FSM_HALT_HALTED 0xb
90#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DURATION_CNT3 0xc
91#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK_PD 0xd
92#define BUTTRESS_PWR_STATE_IS_PWR_FSM_PD_BRK_POINT 0xe
93#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PD_PG_ACK0 0xf
94
95#define BUTTRESS_PWR_STATE_PS_PWR_FSM_MASK GENMASK(28, 24)
96
97#define BUTTRESS_PWR_STATE_PS_PWR_FSM_IDLE 0x0
98#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_IP_RDY 0x1
99#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_PRE_CNT_EXH 0x2
100#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_VGI_PWRGOOD 0x3
101#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_POST_CNT_EXH 0x4
102#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WR_PLL_RATIO 0x5
103#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_CMP 0x6
104#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_CLKACK 0x7
105#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_ASSRT_CYCLES 0x8
106#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES1 0x9
107#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES2 0xa
108#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_DEASSRT_CYCLES 0xb
109#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PU_BRK_PNT 0xc
110#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_FUSE_ACCPT 0xd
111#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PS_PWR_UP 0xf
112#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_4_HALTED 0x10
113#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RESET_CNT3 0x11
114#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_CLKACK 0x12
115#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_OFF_IND 0x13
116#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PH4 0x14
117#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PLL_CMP 0x15
118#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_CLKACK 0x16
119
120#define BUTTRESS_REG_SECURITY_CTL 0x300
121#define BUTTRESS_REG_SKU 0x314
122#define BUTTRESS_REG_SECURITY_TOUCH 0x318
123#define BUTTRESS_REG_CAMERA_MASK 0x84
124
125#define BUTTRESS_SECURITY_CTL_FW_SECURE_MODE BIT(16)
126#define BUTTRESS_SECURITY_CTL_FW_SETUP_MASK GENMASK(4, 0)
127
128#define BUTTRESS_SECURITY_CTL_FW_SETUP_DONE BIT(0)
129#define BUTTRESS_SECURITY_CTL_AUTH_DONE BIT(1)
130#define BUTTRESS_SECURITY_CTL_AUTH_FAILED BIT(3)
131
132#define BUTTRESS_REG_FW_SOURCE_BASE_LO 0x78
133#define BUTTRESS_REG_FW_SOURCE_BASE_HI 0x7C
134#define BUTTRESS_REG_FW_SOURCE_SIZE 0x80
135
136#define BUTTRESS_REG_ISR_STATUS 0x90
137#define BUTTRESS_REG_ISR_ENABLED_STATUS 0x94
138#define BUTTRESS_REG_ISR_ENABLE 0x98
139#define BUTTRESS_REG_ISR_CLEAR 0x9C
140
141#define BUTTRESS_ISR_IS_IRQ BIT(0)
142#define BUTTRESS_ISR_PS_IRQ BIT(1)
143#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE BIT(2)
144#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH BIT(3)
145#define BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING BIT(4)
146#define BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING BIT(5)
147#define BUTTRESS_ISR_CSE_CSR_SET BIT(6)
148#define BUTTRESS_ISR_ISH_CSR_SET BIT(7)
149#define BUTTRESS_ISR_SPURIOUS_CMP BIT(8)
150#define BUTTRESS_ISR_WATCHDOG_EXPIRED BIT(9)
151#define BUTTRESS_ISR_PUNIT_2_IUNIT_IRQ BIT(10)
152#define BUTTRESS_ISR_SAI_VIOLATION BIT(11)
153#define BUTTRESS_ISR_HW_ASSERTION BIT(12)
154#define BUTTRESS_ISR_IS_CORRECTABLE_MEM_ERR BIT(13)
155#define BUTTRESS_ISR_IS_FATAL_MEM_ERR BIT(14)
156#define BUTTRESS_ISR_IS_NON_FATAL_MEM_ERR BIT(15)
157#define BUTTRESS_ISR_PS_CORRECTABLE_MEM_ERR BIT(16)
158#define BUTTRESS_ISR_PS_FATAL_MEM_ERR BIT(17)
159#define BUTTRESS_ISR_PS_NON_FATAL_MEM_ERR BIT(18)
160#define BUTTRESS_ISR_PS_FAST_THROTTLE BIT(19)
161#define BUTTRESS_ISR_UFI_ERROR BIT(20)
162
163#define BUTTRESS_REG_IU2CSEDB0 0x100
164
165#define BUTTRESS_IU2CSEDB0_BUSY BIT(31)
166#define BUTTRESS_IU2CSEDB0_IPC_CLIENT_ID_VAL 2
167
168#define BUTTRESS_REG_IU2CSEDATA0 0x104
169
170#define BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD 1
171#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN 2
172#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_REPLACE 3
173#define BUTTRESS_IU2CSEDATA0_IPC_UPDATE_SECURE_TOUCH 16
174
175#define BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE BIT(0)
176#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE BIT(1)
177#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_REPLACE_DONE BIT(2)
178#define BUTTRESS_CSE2IUDATA0_IPC_UPDATE_SECURE_TOUCH_DONE BIT(4)
179
180#define BUTTRESS_REG_IU2CSECSR 0x108
181
182#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1 BIT(0)
183#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2 BIT(1)
184#define BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE BIT(2)
185#define BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ BIT(3)
186#define BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID BIT(4)
187#define BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ BIT(5)
188
189#define BUTTRESS_REG_CSE2IUDB0 0x304
190#define BUTTRESS_REG_CSE2IUCSR 0x30C
191#define BUTTRESS_REG_CSE2IUDATA0 0x308
192
193/* 0x20 == NACK, 0xf == unknown command */
194#define BUTTRESS_CSE2IUDATA0_IPC_NACK 0xf20
195#define BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK GENMASK(15, 0)
196
197#define BUTTRESS_REG_ISH2IUCSR 0x50
198#define BUTTRESS_REG_ISH2IUDB0 0x54
199#define BUTTRESS_REG_ISH2IUDATA0 0x58
200
201#define BUTTRESS_REG_IU2ISHDB0 0x10C
202#define BUTTRESS_REG_IU2ISHDATA0 0x110
203#define BUTTRESS_REG_IU2ISHDATA1 0x114
204#define BUTTRESS_REG_IU2ISHCSR 0x118
205
206#define BUTTRESS_REG_FABRIC_CMD 0x88
207
208#define BUTTRESS_FABRIC_CMD_START_TSC_SYNC BIT(0)
209#define BUTTRESS_FABRIC_CMD_IS_DRAIN BIT(4)
210
211#define BUTTRESS_REG_TSW_CTL 0x120
212#define BUTTRESS_TSW_CTL_SOFT_RESET BIT(8)
213
214#define BUTTRESS_REG_TSC_LO 0x164
215#define BUTTRESS_REG_TSC_HI 0x168
216
217#define BUTTRESS_IRQS (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
218 BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
219 BUTTRESS_ISR_IS_IRQ | BUTTRESS_ISR_PS_IRQ)
220
221#define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
222 BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING | \
223 BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
224 BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH | \
225 BUTTRESS_ISR_SAI_VIOLATION)
226#endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
drivers/media/pci/intel/ipu6/ipu6-platform-isys-csi2-reg.h+172−0
@@ -0,0 +1,172 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2023--2024 Intel Corporation */
3
4#ifndef IPU6_PLATFORM_ISYS_CSI2_REG_H
5#define IPU6_PLATFORM_ISYS_CSI2_REG_H
6
7#include <linux/bits.h>
8
9#define CSI_REG_BASE 0x220000
10#define CSI_REG_PORT_BASE(id) (CSI_REG_BASE + (id) * 0x1000)
11
12/* CSI Port Genral Purpose Registers */
13#define CSI_REG_PORT_GPREG_SRST 0x0
14#define CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST 0x4
15#define CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL 0x8
16
17/*
18 * Port IRQs mapping events:
19 * IRQ0 - CSI_FE event
20 * IRQ1 - CSI_SYNC
21 * IRQ2 - S2M_SIDS0TO7
22 * IRQ3 - S2M_SIDS8TO15
23 */
24#define CSI_PORT_REG_BASE_IRQ_CSI 0x80
25#define CSI_PORT_REG_BASE_IRQ_CSI_SYNC 0xA0
26#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS0TOS7 0xC0
27#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS8TOS15 0xE0
28
29#define CSI_PORT_REG_BASE_IRQ_EDGE_OFFSET 0x0
30#define CSI_PORT_REG_BASE_IRQ_MASK_OFFSET 0x4
31#define CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET 0x8
32#define CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET 0xc
33#define CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET 0x10
34#define CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET 0x14
35
36#define IPU6SE_CSI_RX_ERROR_IRQ_MASK GENMASK(18, 0)
37#define IPU6_CSI_RX_ERROR_IRQ_MASK GENMASK(19, 0)
38
39#define CSI_RX_NUM_ERRORS_IN_IRQ 20
40#define CSI_RX_NUM_IRQ 32
41
42#define IPU_CSI_RX_IRQ_FS_VC(chn) (1 << ((chn) * 2))
43#define IPU_CSI_RX_IRQ_FE_VC(chn) (2 << ((chn) * 2))
44
45/* PPI2CSI */
46#define CSI_REG_PPI2CSI_ENABLE 0x200
47#define CSI_REG_PPI2CSI_CONFIG_PPI_INTF 0x204
48#define PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK GENMASK(4, 3)
49#define CSI_REG_PPI2CSI_CONFIG_CSI_FEATURE 0x208
50
51enum CSI_PPI2CSI_CTRL {
52 CSI_PPI2CSI_DISABLE = 0,
53 CSI_PPI2CSI_ENABLE = 1,
54};
55
56/* CSI_FE */
57#define CSI_REG_CSI_FE_ENABLE 0x280
58#define CSI_REG_CSI_FE_MODE 0x284
59#define CSI_REG_CSI_FE_MUX_CTRL 0x288
60#define CSI_REG_CSI_FE_SYNC_CNTR_SEL 0x290
61
62enum CSI_FE_ENABLE_TYPE {
63 CSI_FE_DISABLE = 0,
64 CSI_FE_ENABLE = 1,
65};
66
67enum CSI_FE_MODE_TYPE {
68 CSI_FE_DPHY_MODE = 0,
69 CSI_FE_CPHY_MODE = 1,
70};
71
72enum CSI_FE_INPUT_SELECTOR {
73 CSI_SENSOR_INPUT = 0,
74 CSI_MIPIGEN_INPUT = 1,
75};
76
77enum CSI_FE_SYNC_CNTR_SEL_TYPE {
78 CSI_CNTR_SENSOR_LINE_ID = BIT(0),
79 CSI_CNTR_INT_LINE_PKT_ID = ~CSI_CNTR_SENSOR_LINE_ID,
80 CSI_CNTR_SENSOR_FRAME_ID = BIT(1),
81 CSI_CNTR_INT_FRAME_PKT_ID = ~CSI_CNTR_SENSOR_FRAME_ID,
82};
83
84/* CSI HUB General Purpose Registers */
85#define CSI_REG_HUB_GPREG_SRST (CSI_REG_BASE + 0x18000)
86#define CSI_REG_HUB_GPREG_SLV_REG_SRST (CSI_REG_BASE + 0x18004)
87
88#define CSI_REG_HUB_DRV_ACCESS_PORT(id) (CSI_REG_BASE + 0x18018 + (id) * 4)
89#define CSI_REG_HUB_FW_ACCESS_PORT_OFS 0x17000
90#define CSI_REG_HUB_FW_ACCESS_PORT_V6OFS 0x16000
91#define CSI_REG_HUB_FW_ACCESS_PORT(ofs, id) \
92 (CSI_REG_BASE + (ofs) + (id) * 4)
93
94enum CSI_PORT_CLK_GATING_SWITCH {
95 CSI_PORT_CLK_GATING_OFF = 0,
96 CSI_PORT_CLK_GATING_ON = 1,
97};
98
99#define CSI_REG_BASE_HUB_IRQ 0x18200
100
101#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE 0x238200
102#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK 0x238204
103#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS 0x238208
104#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR 0x23820c
105#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE 0x238210
106#define IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE 0x238214
107
108#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_EDGE 0x238220
109#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_MASK 0x238224
110#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_STATUS 0x238228
111#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_CLEAR 0x23822c
112#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_ENABLE 0x238230
113#define IPU6_REG_ISYS_CSI_TOP_CTRL1_IRQ_LEVEL_NOT_PULSE 0x238234
114
115/* MTL IPU6V6 irq ctrl0 & ctrl1 */
116#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE 0x238700
117#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK 0x238704
118#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS 0x238708
119#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR 0x23870c
120#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE 0x238710
121#define IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE 0x238714
122
123#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_EDGE 0x238720
124#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_MASK 0x238724
125#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_STATUS 0x238728
126#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_CLEAR 0x23872c
127#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_ENABLE 0x238730
128#define IPU6V6_REG_ISYS_CSI_TOP_CTRL1_IRQ_LEVEL_NOT_PULSE 0x238734
129
130/*
131 * 3:0 CSI_PORT.irq_out[3:0] CSI_PORT_CTRL0 IRQ outputs (4bits)
132 * [0] CSI_PORT.IRQ_CTRL0_csi
133 * [1] CSI_PORT.IRQ_CTRL1_csi_sync
134 * [2] CSI_PORT.IRQ_CTRL2_s2m_sids0to7
135 * [3] CSI_PORT.IRQ_CTRL3_s2m_sids8to15
136 */
137#define IPU6_ISYS_UNISPART_IRQ_CSI2(port) \
138 (0x3 << ((port) * IPU6_CSI_IRQ_NUM_PER_PIPE))
139
140/*
141 * ipu6se support 2 front ends, 2 port per front end, 4 ports 0..3
142 * sip0 - 0, 1
143 * sip1 - 2, 3
144 * 0 and 2 support 4 data lanes, 1 and 3 support 2 data lanes
145 * all offset are base from isys base address
146 */
147
148#define CSI2_HUB_GPREG_SIP_SRST(sip) (0x238038 + (sip) * 4)
149#define CSI2_HUB_GPREG_SIP_FB_PORT_CFG(sip) (0x238050 + (sip) * 4)
150
151#define CSI2_HUB_GPREG_DPHY_TIMER_INCR 0x238040
152#define CSI2_HUB_GPREG_HPLL_FREQ 0x238044
153#define CSI2_HUB_GPREG_IS_CLK_RATIO 0x238048
154#define CSI2_HUB_GPREG_HPLL_FREQ_ISCLK_RATE_OVERRIDE 0x23804c
155#define CSI2_HUB_GPREG_PORT_CLKGATING_DISABLE 0x238058
156#define CSI2_HUB_GPREG_SIP0_CSI_RX_A_CONTROL 0x23805c
157#define CSI2_HUB_GPREG_SIP0_CSI_RX_B_CONTROL 0x238088
158#define CSI2_HUB_GPREG_SIP1_CSI_RX_A_CONTROL 0x2380a4
159#define CSI2_HUB_GPREG_SIP1_CSI_RX_B_CONTROL 0x2380d0
160
161#define CSI2_SIP_TOP_CSI_RX_BASE(sip) (0x23805c + (sip) * 0x48)
162#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_0(port) (0x23805c + ((port) / 2) * 0x48)
163#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_1(port) (0x238088 + ((port) / 2) * 0x48)
164
165/* offset from port base */
166#define CSI2_SIP_TOP_CSI_RX_PORT_CONTROL 0x0
167#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_CLANE 0x4
168#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_CLANE 0x8
169#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_DLANE(lane) (0xc + (lane) * 8)
170#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_DLANE(lane) (0x10 + (lane) * 8)
171
172#endif /* IPU6_ISYS_CSI2_REG_H */
drivers/media/pci/intel/ipu6/ipu6-platform-regs.h+179−0
@@ -0,0 +1,179 @@
1/* SPDX-License-Identifier: GPL-2.0-only */
2/* Copyright (C) 2018 - 2024 Intel Corporation */
3
4#ifndef IPU6_PLATFORM_REGS_H
5#define IPU6_PLATFORM_REGS_H
6
7#include <linux/bits.h>
8
9/*
10 * IPU6 uses uniform address within IPU6, therefore all subsystem registers
11 * locates in one single space starts from 0 but in different sctions with
12 * different addresses, the subsystem offsets are defined to 0 as the
13 * register definition will have the address offset to 0.
14 */
15#define IPU6_UNIFIED_OFFSET 0
16
17#define IPU6_ISYS_IOMMU0_OFFSET 0x2e0000
18#define IPU6_ISYS_IOMMU1_OFFSET 0x2e0500
19#define IPU6_ISYS_IOMMUI_OFFSET 0x2e0a00
20
21#define IPU6_PSYS_IOMMU0_OFFSET 0x1b0000
22#define IPU6_PSYS_IOMMU1_OFFSET 0x1b0700
23#define IPU6_PSYS_IOMMU1R_OFFSET 0x1b0e00
24#define IPU6_PSYS_IOMMUI_OFFSET 0x1b1500
25
26/* the offset from IOMMU base register */
27#define IPU6_MMU_L1_STREAM_ID_REG_OFFSET 0x0c
28#define IPU6_MMU_L2_STREAM_ID_REG_OFFSET 0x4c
29#define IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET 0x8c
30
31#define IPU6_MMU_INFO_OFFSET 0x8
32
33#define IPU6_ISYS_SPC_OFFSET 0x210000
34
35#define IPU6SE_PSYS_SPC_OFFSET 0x110000
36#define IPU6_PSYS_SPC_OFFSET 0x118000
37
38#define IPU6_ISYS_DMEM_OFFSET 0x200000
39#define IPU6_PSYS_DMEM_OFFSET 0x100000
40
41#define IPU6_REG_ISYS_UNISPART_IRQ_EDGE 0x27c000
42#define IPU6_REG_ISYS_UNISPART_IRQ_MASK 0x27c004
43#define IPU6_REG_ISYS_UNISPART_IRQ_STATUS 0x27c008
44#define IPU6_REG_ISYS_UNISPART_IRQ_CLEAR 0x27c00c
45#define IPU6_REG_ISYS_UNISPART_IRQ_ENABLE 0x27c010
46#define IPU6_REG_ISYS_UNISPART_IRQ_LEVEL_NOT_PULSE 0x27c014
47#define IPU6_REG_ISYS_UNISPART_SW_IRQ_REG 0x27c414
48#define IPU6_REG_ISYS_UNISPART_SW_IRQ_MUX_REG 0x27c418
49#define IPU6_ISYS_UNISPART_IRQ_CSI0 BIT(2)
50#define IPU6_ISYS_UNISPART_IRQ_CSI1 BIT(3)
51#define IPU6_ISYS_UNISPART_IRQ_SW BIT(22)
52
53#define IPU6_REG_ISYS_ISL_TOP_IRQ_EDGE 0x2b0200
54#define IPU6_REG_ISYS_ISL_TOP_IRQ_MASK 0x2b0204
55#define IPU6_REG_ISYS_ISL_TOP_IRQ_STATUS 0x2b0208
56#define IPU6_REG_ISYS_ISL_TOP_IRQ_CLEAR 0x2b020c
57#define IPU6_REG_ISYS_ISL_TOP_IRQ_ENABLE 0x2b0210
58#define IPU6_REG_ISYS_ISL_TOP_IRQ_LEVEL_NOT_PULSE 0x2b0214
59
60#define IPU6_REG_ISYS_CMPR_TOP_IRQ_EDGE 0x2d2100
61#define IPU6_REG_ISYS_CMPR_TOP_IRQ_MASK 0x2d2104
62#define IPU6_REG_ISYS_CMPR_TOP_IRQ_STATUS 0x2d2108
63#define IPU6_REG_ISYS_CMPR_TOP_IRQ_CLEAR 0x2d210c
64#define IPU6_REG_ISYS_CMPR_TOP_IRQ_ENABLE 0x2d2110
65#define IPU6_REG_ISYS_CMPR_TOP_IRQ_LEVEL_NOT_PULSE 0x2d2114
66
67/* CDC Burst collector thresholds for isys - 3 FIFOs i = 0..2 */
68#define IPU6_REG_ISYS_CDC_THRESHOLD(i) (0x27c400 + ((i) * 4))
69
70#define IPU6_CSI_IRQ_NUM_PER_PIPE 4
71#define IPU6SE_ISYS_CSI_PORT_NUM 4
72#define IPU6_ISYS_CSI_PORT_NUM 8
73
74#define IPU6_ISYS_CSI_PORT_IRQ(irq_num) BIT(irq_num)
75
76/* PKG DIR OFFSET in IMR in secure mode */
77#define IPU6_PKG_DIR_IMR_OFFSET 0x40
78
79#define IPU6_ISYS_REG_SPC_STATUS_CTRL 0x0
80
81#define IPU6_ISYS_SPC_STATUS_START BIT(1)
82#define IPU6_ISYS_SPC_STATUS_RUN BIT(3)
83#define IPU6_ISYS_SPC_STATUS_READY BIT(5)
84#define IPU6_ISYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12)
85#define IPU6_ISYS_SPC_STATUS_ICACHE_PREFETCH BIT(13)
86
87#define IPU6_PSYS_REG_SPC_STATUS_CTRL 0x0
88#define IPU6_PSYS_REG_SPC_START_PC 0x4
89#define IPU6_PSYS_REG_SPC_ICACHE_BASE 0x10
90#define IPU6_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER 0x14
91
92#define IPU6_PSYS_SPC_STATUS_START BIT(1)
93#define IPU6_PSYS_SPC_STATUS_RUN BIT(3)
94#define IPU6_PSYS_SPC_STATUS_READY BIT(5)
95#define IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12)
96#define IPU6_PSYS_SPC_STATUS_ICACHE_PREFETCH BIT(13)
97
98#define IPU6_PSYS_REG_SPP0_STATUS_CTRL 0x20000
99
100#define IPU6_INFO_ENABLE_SNOOP BIT(0)
101#define IPU6_INFO_DEC_FORCE_FLUSH BIT(1)
102#define IPU6_INFO_DEC_PASS_THROUGH BIT(2)
103#define IPU6_INFO_ZLW BIT(3)
104#define IPU6_INFO_REQUEST_DESTINATION_IOSF BIT(9)
105#define IPU6_INFO_IMR_BASE BIT(10)
106#define IPU6_INFO_IMR_DESTINED BIT(11)
107
108#define IPU6_INFO_REQUEST_DESTINATION_PRIMARY IPU6_INFO_REQUEST_DESTINATION_IOSF
109
110/*
111 * s2m_pixel_soc_pixel_remapping is dedicated for the enabling of the
112 * pixel s2m remp ability.Remap here means that s2m rearange the order
113 * of the pixels in each 4 pixels group.
114 * For examle, mirroring remping means that if input's 4 first pixels
115 * are 1 2 3 4 then in output we should see 4 3 2 1 in this 4 first pixels.
116 * 0xE4 is from s2m MAS document. It means no remapping.
117 */
118#define S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xe4
119/*
120 * csi_be_soc_pixel_remapping is for the enabling of the pixel remapping.
121 * This remapping is exactly like the stream2mmio remapping.
122 */
123#define CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xe4
124
125#define IPU6_REG_DMA_TOP_AB_GROUP1_BASE_ADDR 0x1ae000
126#define IPU6_REG_DMA_TOP_AB_GROUP2_BASE_ADDR 0x1af000
127#define IPU6_REG_DMA_TOP_AB_RING_MIN_OFFSET(n) (0x4 + (n) * 0xc)
128#define IPU6_REG_DMA_TOP_AB_RING_MAX_OFFSET(n) (0x8 + (n) * 0xc)
129#define IPU6_REG_DMA_TOP_AB_RING_ACCESS_OFFSET(n) (0xc + (n) * 0xc)
130
131enum ipu6_device_ab_group1_target_id {
132 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R0_SPC_DMEM,
133 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R1_SPC_DMEM,
134 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R2_SPC_DMEM,
135 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R3_SPC_STATUS_REG,
136 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R4_SPC_MASTER_BASE_ADDR,
137 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R5_SPC_PC_STALL,
138 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R6_SPC_EQ,
139 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R7_SPC_RESERVED,
140 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R8_SPC_RESERVED,
141 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R9_SPP0,
142 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R10_SPP1,
143 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R11_CENTRAL_R1,
144 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R12_IRQ,
145 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R13_CENTRAL_R2,
146 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R14_DMA,
147 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R15_DMA,
148 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R16_GP,
149 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R17_ZLW_INSERTER,
150 IPU6_DEVICE_AB_GROUP1_TARGET_ID_R18_AB,
151};
152
153enum nci_ab_access_mode {
154 NCI_AB_ACCESS_MODE_RW, /* read & write */
155 NCI_AB_ACCESS_MODE_RO, /* read only */
156 NCI_AB_ACCESS_MODE_WO, /* write only */
157 NCI_AB_ACCESS_MODE_NA, /* No access at all */
158};
159
160/* IRQ-related registers in PSYS */
161#define IPU6_REG_PSYS_GPDEV_IRQ_EDGE 0x1aa200
162#define IPU6_REG_PSYS_GPDEV_IRQ_MASK 0x1aa204
163#define IPU6_REG_PSYS_GPDEV_IRQ_STATUS 0x1aa208
164#define IPU6_REG_PSYS_GPDEV_IRQ_CLEAR 0x1aa20c
165#define IPU6_REG_PSYS_GPDEV_IRQ_ENABLE 0x1aa210
166#define IPU6_REG_PSYS_GPDEV_IRQ_LEVEL_NOT_PULSE 0x1aa214
167/* There are 8 FW interrupts, n = 0..7 */
168#define IPU6_PSYS_GPDEV_FWIRQ0 5
169#define IPU6_PSYS_GPDEV_FWIRQ1 6
170#define IPU6_PSYS_GPDEV_FWIRQ2 7
171#define IPU6_PSYS_GPDEV_FWIRQ3 8
172#define IPU6_PSYS_GPDEV_FWIRQ4 9
173#define IPU6_PSYS_GPDEV_FWIRQ5 10
174#define IPU6_PSYS_GPDEV_FWIRQ6 11
175#define IPU6_PSYS_GPDEV_FWIRQ7 12
176#define IPU6_PSYS_GPDEV_IRQ_FWIRQ(n) BIT(n)
177#define IPU6_REG_PSYS_GPDEV_FWIRQ(n) (4 * (n) + 0x1aa100)
178
179#endif /* IPU6_PLATFORM_REGS_H */
drivers/media/pci/intel/ipu6/ipu6.c+856−0
@@ -0,0 +1,856 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/dma-mapping.h>
9#include <linux/err.h>
10#include <linux/firmware.h>
11#include <linux/kernel.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/list.h>
15#include <linux/module.h>
16#include <linux/pci-ats.h>
17#include <linux/pm_runtime.h>
18#include <linux/property.h>
19#include <linux/scatterlist.h>
20#include <linux/slab.h>
21#include <linux/types.h>
22
23#include <media/ipu-bridge.h>
24#include <media/ipu6-pci-table.h>
25
26#include "ipu6.h"
27#include "ipu6-bus.h"
28#include "ipu6-buttress.h"
29#include "ipu6-cpd.h"
30#include "ipu6-isys.h"
31#include "ipu6-mmu.h"
32#include "ipu6-platform-buttress-regs.h"
33#include "ipu6-platform-isys-csi2-reg.h"
34#include "ipu6-platform-regs.h"
35
36#define IPU6_PCI_BAR 0
37
38struct ipu6_cell_program {
39 u32 magic_number;
40
41 u32 blob_offset;
42 u32 blob_size;
43
44 u32 start[3];
45
46 u32 icache_source;
47 u32 icache_target;
48 u32 icache_size;
49
50 u32 pmem_source;
51 u32 pmem_target;
52 u32 pmem_size;
53
54 u32 data_source;
55 u32 data_target;
56 u32 data_size;
57
58 u32 bss_target;
59 u32 bss_size;
60
61 u32 cell_id;
62 u32 regs_addr;
63
64 u32 cell_pmem_data_bus_address;
65 u32 cell_dmem_data_bus_address;
66 u32 cell_pmem_control_bus_address;
67 u32 cell_dmem_control_bus_address;
68
69 u32 next;
70 u32 dummy[2];
71};
72
73static struct ipu6_isys_internal_pdata isys_ipdata = {
74 .hw_variant = {
75 .offset = IPU6_UNIFIED_OFFSET,
76 .nr_mmus = 3,
77 .mmu_hw = {
78 {
79 .offset = IPU6_ISYS_IOMMU0_OFFSET,
80 .info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
81 .nr_l1streams = 16,
82 .l1_block_sz = {
83 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
84 1, 1, 1, 1, 1, 1
85 },
86 .nr_l2streams = 16,
87 .l2_block_sz = {
88 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
89 2, 2, 2, 2, 2, 2
90 },
91 .insert_read_before_invalidate = false,
92 .l1_stream_id_reg_offset =
93 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
94 .l2_stream_id_reg_offset =
95 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
96 },
97 {
98 .offset = IPU6_ISYS_IOMMU1_OFFSET,
99 .info_bits = 0,
100 .nr_l1streams = 16,
101 .l1_block_sz = {
102 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
103 2, 2, 2, 1, 1, 4
104 },
105 .nr_l2streams = 16,
106 .l2_block_sz = {
107 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
108 2, 2, 2, 2, 2, 2
109 },
110 .insert_read_before_invalidate = false,
111 .l1_stream_id_reg_offset =
112 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
113 .l2_stream_id_reg_offset =
114 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
115 },
116 {
117 .offset = IPU6_ISYS_IOMMUI_OFFSET,
118 .info_bits = 0,
119 .nr_l1streams = 0,
120 .nr_l2streams = 0,
121 .insert_read_before_invalidate = false,
122 },
123 },
124 .cdc_fifos = 3,
125 .cdc_fifo_threshold = {6, 8, 2},
126 .dmem_offset = IPU6_ISYS_DMEM_OFFSET,
127 .spc_offset = IPU6_ISYS_SPC_OFFSET,
128 },
129 .isys_dma_overshoot = IPU6_ISYS_OVERALLOC_MIN,
130};
131
132static struct ipu6_psys_internal_pdata psys_ipdata = {
133 .hw_variant = {
134 .offset = IPU6_UNIFIED_OFFSET,
135 .nr_mmus = 4,
136 .mmu_hw = {
137 {
138 .offset = IPU6_PSYS_IOMMU0_OFFSET,
139 .info_bits =
140 IPU6_INFO_REQUEST_DESTINATION_IOSF,
141 .nr_l1streams = 16,
142 .l1_block_sz = {
143 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
144 2, 2, 2, 2, 2, 2
145 },
146 .nr_l2streams = 16,
147 .l2_block_sz = {
148 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
149 2, 2, 2, 2, 2, 2
150 },
151 .insert_read_before_invalidate = false,
152 .l1_stream_id_reg_offset =
153 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
154 .l2_stream_id_reg_offset =
155 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
156 },
157 {
158 .offset = IPU6_PSYS_IOMMU1_OFFSET,
159 .info_bits = 0,
160 .nr_l1streams = 32,
161 .l1_block_sz = {
162 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
163 2, 2, 2, 2, 2, 10,
164 5, 4, 14, 6, 4, 14, 6, 4, 8,
165 4, 2, 1, 1, 1, 1, 14
166 },
167 .nr_l2streams = 32,
168 .l2_block_sz = {
169 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
170 2, 2, 2, 2, 2, 2,
171 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
172 2, 2, 2, 2, 2, 2
173 },
174 .insert_read_before_invalidate = false,
175 .l1_stream_id_reg_offset =
176 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
177 .l2_stream_id_reg_offset =
178 IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
179 },
180 {
181 .offset = IPU6_PSYS_IOMMU1R_OFFSET,
182 .info_bits = 0,
183 .nr_l1streams = 16,
184 .l1_block_sz = {
185 1, 4, 4, 4, 4, 16, 8, 4, 32,
186 16, 16, 2, 2, 2, 1, 12
187 },
188 .nr_l2streams = 16,
189 .l2_block_sz = {
190 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
191 2, 2, 2, 2, 2, 2
192 },

664 more lines aren’t shown here.

drivers/media/pci/intel/ipu6/ipu6.h+342−0

This diff is large: its 343 lines aren’t shown here.

drivers/media/pci/intel/ivsc/mei_csi.c+18−2

This diff is large: its 50 lines aren’t shown here.

drivers/media/pci/mgb4/mgb4_core.c+2−2

This diff is large: its 16 lines aren’t shown here.

drivers/media/pci/mgb4/mgb4_regs.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/pci/ngene/ngene-core.c+3−1

This diff is large: its 11 lines aren’t shown here.

drivers/media/pci/saa7134/saa7134-alsa.c+2−7

This diff is large: its 23 lines aren’t shown here.

drivers/media/pci/solo6x10/solo6x10-core.c+4−12

This diff is large: its 41 lines aren’t shown here.

drivers/media/pci/ttpci/budget-av.c+286−287

This diff is large: its 850 lines aren’t shown here.

drivers/media/pci/ttpci/budget-ci.c+247−248

This diff is large: its 674 lines aren’t shown here.

drivers/media/pci/ttpci/budget-core.c+20−18

This diff is large: its 150 lines aren’t shown here.

drivers/media/pci/ttpci/budget.c+93−80

This diff is large: its 476 lines aren’t shown here.

drivers/media/pci/ttpci/budget.h+13−8

This diff is large: its 52 lines aren’t shown here.

drivers/media/platform/Kconfig+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/Makefile+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/broadcom/Kconfig+23−0

This diff is large: its 24 lines aren’t shown here.

drivers/media/platform/broadcom/Makefile+3−0

This diff is large: its 4 lines aren’t shown here.

drivers/media/platform/broadcom/bcm2835-unicam-regs.h+246−0

This diff is large: its 247 lines aren’t shown here.

drivers/media/platform/broadcom/bcm2835-unicam.c+2739−0

This diff is large: its 2740 lines aren’t shown here.

drivers/media/platform/cadence/cdns-csi2rx.c+14−12

This diff is large: its 54 lines aren’t shown here.

drivers/media/platform/chips-media/wave5/wave5-helper.c+15−2

This diff is large: its 36 lines aren’t shown here.

drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c+12−1

This diff is large: its 27 lines aren’t shown here.

drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c+12−1

This diff is large: its 27 lines aren’t shown here.

drivers/media/platform/chips-media/wave5/wave5-vpu.c+83−42

This diff is large: its 176 lines aren’t shown here.

drivers/media/platform/chips-media/wave5/wave5-vpuapi.h+4−0

This diff is large: its 11 lines aren’t shown here.

drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c+5−5

This diff is large: its 39 lines aren’t shown here.

drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c+3−3

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c+3−3

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c+2−0

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c+11−12

This diff is large: its 59 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h+2−2

This diff is large: its 14 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c+25−17

This diff is large: its 102 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_if.c+6−6

This diff is large: its 54 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_common.h+9−6

This diff is large: its 44 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c+7−7

This diff is large: its 63 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c+3−3

This diff is large: its 21 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec_msg_queue.h+2−2

This diff is large: its 17 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c+3−1

This diff is large: its 17 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/venc/venc_h264_if.c+3−2

This diff is large: its 15 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c+4−1

This diff is large: its 19 lines aren’t shown here.

drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.h+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/nvidia/tegra-vde/h264.c+3−3

This diff is large: its 20 lines aren’t shown here.

drivers/media/platform/nxp/imx-mipi-csis.c+33−1

This diff is large: its 71 lines aren’t shown here.

drivers/media/platform/qcom/camss/Makefile+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c+105−3

This diff is large: its 141 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss-csiphy.c+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss-vfe-17x.crenamed from drivers/media/platform/qcom/camss/camss-vfe-170.c+0−0

File renamed without changes.

drivers/media/platform/qcom/camss/camss-vfe.c+20−5

This diff is large: its 53 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss-video.c+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss.c+307−0

This diff is large: its 327 lines aren’t shown here.

drivers/media/platform/qcom/camss/camss.h+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c+6−3

This diff is large: its 30 lines aren’t shown here.

drivers/media/platform/renesas/rcar-vin/rcar-vin.h+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/st/sti/c8sectpfe/Kconfig+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/st/sti/c8sectpfe/Makefile+5−2

This diff is large: its 12 lines aren’t shown here.

drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c+1−2

This diff is large: its 24 lines aren’t shown here.

drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h+5−0

This diff is large: its 13 lines aren’t shown here.

drivers/media/platform/st/sti/hva/hva-hw.c+1−2

This diff is large: its 10 lines aren’t shown here.

drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c+2−5

This diff is large: its 14 lines aren’t shown here.

drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/platform/ti/davinci/vpif_capture.c+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/ti/davinci/vpif_display.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c+2−3

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/verisilicon/hantro_h1_regs.h+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/media/platform/verisilicon/hantro_v4l2.c+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/radio/radio-shark2.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/rc/gpio-ir-recv.c+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/media/rc/imon.c+6−6

This diff is large: its 20 lines aren’t shown here.

drivers/media/rc/ir-spi.c+22−19

This diff is large: its 110 lines aren’t shown here.

drivers/media/rc/lirc_dev.c+9−9

This diff is large: its 49 lines aren’t shown here.

drivers/media/spi/cxd2880-spi.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/spi/gs1662.c+18−9

This diff is large: its 70 lines aren’t shown here.

drivers/media/test-drivers/vicodec/vicodec-core.c+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/test-drivers/vimc/vimc-capture.c+2−1

This diff is large: its 17 lines aren’t shown here.

drivers/media/test-drivers/visl/visl-video.c+1−0

This diff is large: its 8 lines aren’t shown here.

drivers/media/test-drivers/vivid/vivid-core.c+5−4

This diff is large: its 44 lines aren’t shown here.

drivers/media/test-drivers/vivid/vivid-meta-out.c+0−4

This diff is large: its 18 lines aren’t shown here.

drivers/media/test-drivers/vivid/vivid-touch-cap.c+0−4

This diff is large: its 18 lines aren’t shown here.

drivers/media/tuners/xc5000.c+17−22

This diff is large: its 82 lines aren’t shown here.

drivers/media/usb/as102/as102_usb_drv.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/usb/au0828/au0828-video.c+1−4

This diff is large: its 12 lines aren’t shown here.

drivers/media/usb/b2c2/flexcop-usb.c+10−7

This diff is large: its 52 lines aren’t shown here.

drivers/media/usb/dvb-usb-v2/af9035.c+9−1

This diff is large: its 31 lines aren’t shown here.

drivers/media/usb/dvb-usb-v2/anysee.c+2−2

This diff is large: its 17 lines aren’t shown here.

drivers/media/usb/dvb-usb/dib0700_devices.c+15−3

This diff is large: its 40 lines aren’t shown here.

drivers/media/usb/dvb-usb/dw2102.c+242−220

This diff is large: its 1080 lines aren’t shown here.

drivers/media/usb/go7007/go7007-fw.c+2−2

This diff is large: its 11 lines aren’t shown here.

drivers/media/usb/gspca/cpia1.c+2−4

This diff is large: its 13 lines aren’t shown here.

drivers/media/usb/s2255/s2255drv.c+10−10

This diff is large: its 79 lines aren’t shown here.

drivers/media/usb/siano/smsusb.c+14−6

This diff is large: its 77 lines aren’t shown here.

drivers/media/usb/stk1160/stk1160-video.c+17−13

This diff is large: its 61 lines aren’t shown here.

drivers/media/usb/uvc/uvc_ctrl.c+14−12

This diff is large: its 64 lines aren’t shown here.

drivers/media/usb/uvc/uvc_driver.c+53−1

This diff is large: its 90 lines aren’t shown here.

drivers/media/usb/uvc/uvcvideo.h+2−0

This diff is large: its 9 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-async.c+15−15

This diff is large: its 107 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-common.c+2−0

This diff is large: its 10 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-ctrls-api.c+19−14

This diff is large: its 55 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-ctrls-core.c+11−13

This diff is large: its 67 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-dev.c+6−0

This diff is large: its 29 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-device.c+7−5

This diff is large: its 41 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-i2c.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-ioctl.c+66−7

This diff is large: its 171 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-mem2mem.c+15−0

This diff is large: its 22 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-spi.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/media/v4l2-core/v4l2-subdev.c+85−28

This diff is large: its 208 lines aren’t shown here.

drivers/staging/media/atomisp/Makefile+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/Kconfig+0−15

This diff is large: its 19 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/Makefile+0−5

This diff is large: its 9 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/atomisp-gc2235.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/atomisp-lm3554.c+0−955

This diff is large: its 956 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c+2−2

This diff is large: its 18 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/atomisp-ov2722.c+1−13

This diff is large: its 63 lines aren’t shown here.

drivers/staging/media/atomisp/i2c/ov2722.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/include/linux/atomisp.h+0−81

This diff is large: its 130 lines aren’t shown here.

drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h+1−5

This diff is large: its 18 lines aren’t shown here.

drivers/staging/media/atomisp/include/linux/atomisp_platform.h+1−40

This diff is large: its 75 lines aren’t shown here.

drivers/staging/media/atomisp/include/media/lm3554.h+0−132

This diff is large: its 133 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_cmd.c+125−156

This diff is large: its 442 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_cmd.h+9−4

This diff is large: its 34 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_compat_css20.c+1−30

This diff is large: its 50 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_csi2.c+3−23

This diff is large: its 50 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_fops.c+1−48

This diff is large: its 94 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c+32−91

This diff is large: its 283 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_internal.h+3−16

This diff is large: its 77 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_ioctl.c+40−453

This diff is large: its 728 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_subdev.c+52−50

This diff is large: its 178 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_subdev.h+1−16

This diff is large: its 45 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_tpg.c+0−164

This diff is large: its 165 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_tpg.h+0−39

This diff is large: its 40 lines aren’t shown here.

drivers/staging/media/atomisp/pci/atomisp_v4l2.c+61−122

This diff is large: its 350 lines aren’t shown here.

drivers/staging/media/atomisp/pci/bits.h+2−2

This diff is large: its 12 lines aren’t shown here.

drivers/staging/media/atomisp/pci/defs.h+0−37

This diff is large: its 38 lines aren’t shown here.

drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c+0−38

This diff is large: its 59 lines aren’t shown here.

drivers/staging/media/atomisp/pci/hive_types.h+0−19

This diff is large: its 26 lines aren’t shown here.

drivers/staging/media/atomisp/pci/ia_css.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/pci/ia_css_frame_public.h+0−8

This diff is large: its 29 lines aren’t shown here.

drivers/staging/media/atomisp/pci/ia_css_stream_public.h+0−17

This diff is large: its 45 lines aren’t shown here.

drivers/staging/media/atomisp/pci/ia_css_tpg.h+0−79

This diff is large: its 80 lines aren’t shown here.

drivers/staging/media/atomisp/pci/isp2400_input_system_global.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/pci/isp2400_input_system_public.h+0−15

This diff is large: its 22 lines aren’t shown here.

drivers/staging/media/atomisp/pci/isp2401_input_system_global.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c+2−18

This diff is large: its 41 lines aren’t shown here.

drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c+0−11

This diff is large: its 18 lines aren’t shown here.

drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c+1−27

This diff is large: its 56 lines aren’t shown here.

drivers/staging/media/atomisp/pci/sh_css.c+9−129

This diff is large: its 238 lines aren’t shown here.

drivers/staging/media/atomisp/pci/sh_css_internal.h+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/atomisp/pci/sh_css_mipi.c+1−1

This diff is large: its 9 lines aren’t shown here.

drivers/staging/media/atomisp/pci/sh_css_sp.c+61−66

This diff is large: its 270 lines aren’t shown here.

drivers/staging/media/atomisp/pci/sh_css_sp.h+0−7

This diff is large: its 14 lines aren’t shown here.

drivers/staging/media/atomisp/pci/system_global.h+0−12

This diff is large: its 19 lines aren’t shown here.

drivers/staging/media/imx/Kconfig+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/ipu3/ipu3-css-fw.c+3−1

This diff is large: its 11 lines aren’t shown here.

drivers/staging/media/ipu3/ipu3-css-fw.h+2−0

This diff is large: its 9 lines aren’t shown here.

drivers/staging/media/ipu3/ipu3-css.c+0−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/ipu3/ipu3.c+7−3

This diff is large: its 25 lines aren’t shown here.

drivers/staging/media/max96712/max96712.c+1−1

This diff is large: its 8 lines aren’t shown here.

drivers/staging/media/starfive/camss/stf-camss.c+8−4

This diff is large: its 40 lines aren’t shown here.

drivers/staging/media/starfive/camss/stf-isp.c+2−8

This diff is large: its 31 lines aren’t shown here.

drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c+1−2

This diff is large: its 10 lines aren’t shown here.

drivers/staging/media/tegra-video/tegra20.c+3−7

This diff is large: its 24 lines aren’t shown here.

drivers/staging/media/tegra-video/vi.c+6−6

This diff is large: its 46 lines aren’t shown here.

include/media/cec.h+3−1

This diff is large: its 25 lines aren’t shown here.

include/media/ipu6-pci-table.h+28−0

This diff is large: its 29 lines aren’t shown here.

include/media/media-device.h+6−0

This diff is large: its 20 lines aren’t shown here.

include/media/v4l2-async.h+3−1

This diff is large: its 11 lines aren’t shown here.

include/media/v4l2-device.h+5−2

This diff is large: its 14 lines aren’t shown here.

include/media/v4l2-ioctl.h+4−0

This diff is large: its 18 lines aren’t shown here.

include/media/v4l2-mem2mem.h+2−0

This diff is large: its 9 lines aren’t shown here.

include/media/v4l2-subdev.h+56−14

This diff is large: its 118 lines aren’t shown here.

include/media/videobuf2-core.h+42−10

This diff is large: its 145 lines aren’t shown here.

include/media/videobuf2-v4l2.h+2−0

This diff is large: its 9 lines aren’t shown here.

include/uapi/linux/dvb/frontend.h+1−1

This diff is large: its 9 lines aren’t shown here.

include/uapi/linux/media-bus-format.h+9−0

This diff is large: its 14 lines aren’t shown here.

include/uapi/linux/v4l2-mediabus.h+12−6

This diff is large: its 25 lines aren’t shown here.

include/uapi/linux/v4l2-subdev.h+11−3

This diff is large: its 34 lines aren’t shown here.

include/uapi/linux/videodev2.h+44−1

This diff is large: its 105 lines aren’t shown here.