From 584d4bf1d3c2265a810e1494eb5c8ef0a72ee934 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 27 May 2020 15:12:04 +0200 Subject: [PATCH] bcm27xx: update patches from RPi foundation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit bcm2708: boot tested on RPi B+ v1.2 bcm2709: boot tested on RPi 3B v1.2 bcm2710: boot tested on RPi 3B v1.2 bcm2711: boot tested on RPi 4B v1.1 4G Signed-off-by: Álvaro Fernández Rojas --- target/linux/bcm27xx/bcm2708/config-5.4 | 8 +- target/linux/bcm27xx/bcm2709/config-5.4 | 5 + target/linux/bcm27xx/bcm2710/config-5.4 | 6 + target/linux/bcm27xx/bcm2711/config-5.4 | 6 + target/linux/bcm27xx/modules/sound.mk | 49 + target/linux/bcm27xx/modules/video.mk | 5 +- ...3d_drv-Allow-clock-retrieval-by-name.patch | 23 - ...clock-so-firmware-knows-we-are-usin.patch} | 0 ...-0352-clk-bcm2835-Disable-v3d-clock.patch} | 0 ...eq-Only-report-integer-pll-divisor-.patch} | 0 ...54-arm-dts-Correct-Pi-4B-LED-values.patch} | 0 ...k-raspberrypi-Also-support-v3d-clock.patch | 647 ---- ...a_mask-as-well-as-coherent_dma_mask.patch} | 0 ...0-0356-arm-dts-2711-Add-pcie0-alias.patch} | 0 ...2-overlay-fix-pinctrl-configuration.patch} | 0 ...-Set-up-dma-ranges-on-child-devices.patch} | 0 ...-the-old-dma-controller-for-OF-conf.patch} | 0 ...the-urb-transfer_buffer-too-early-3.patch} | 0 ...ys-Make-mcp342x-run-time-compatible.patch} | 0 ...-overlay-use-reset-gpios-instead-of.patch} | 0 ...rst-codec-is-master-in-multicodec-s.patch} | 0 ...aneous-use-of-JustBoom-DAC-and-Digi.patch} | 0 ...-dht11-Allow-multiple-instantiation.patch} | 0 ...erlays-i2c-rtc-Add-pcf85363-support.patch} | 0 ...rl-bcm2835-Remove-gpiochip-on-error.patch} | 0 ...835-Change-init-order-for-gpio-hogs.patch} | 0 ...unication-fixes-for-scaled-down-CPU.patch} | 0 ...Remove-simple-bus-from-fixed-clocks.patch} | 0 ...ove-system-timer-back-to-bcm283x.dt.patch} | 0 ...ove-pixelvalve-to-bcm2835-common.dt.patch} | 0 ...dts-bcm2838-rpi-4-b-Fix-memory-node.patch} | 0 ...pi-4-b-Backport-BT-part-from-upstre.patch} | 0 ...8-Backport-node-names-from-upstream.patch} | 0 ...ove-intc-label-to-bcm2835-common.dt.patch} | 0 ...8-Remove-always-on-from-armv7-timer.patch} | 0 ...net-bcmgenet-Add-RGMII_RXID-support.patch} | 0 ...cm2838-Backport-genet-from-upstream.patch} | 0 ...kport-BCM2711-support-from-upstream.patch} | 0 ...proc-rng200-Add-support-for-BCM2711.patch} | 0 ...bcm2838-Add-upstream-RNG-compatible.patch} | 0 ...d-Destroy-the-legacy-device-on-remo.patch} | 0 ...d-Clean-up-error-handling-use-of-ER.patch} | 0 ...d-Add-error-handling-to-the-legacy-.patch} | 0 ...d-Fix-coding-style-whitespace-issue.patch} | 0 ...char-rpimem-Add-SPDX-licence-header.patch} | 0 ...r-rpivid-Fix-access-to-freed-memory.patch} | 0 ...89-add-BME680-to-i2c-sensor-overlay.patch} | 0 ...-endpoint-max-packet-and-transfer-s.patch} | 0 ...ause-when-cancelling-split-transact.patch} | 0 ...dd-a-barrier-on-entry-into-FIQ-hand.patch} | 0 ...device-tree-overlay-for-SPI-devices.patch} | 0 ...nd-Add-the-HiFiBerry-DAC-HD-version.patch} | 0 ...ise-rpi-firmware-before-clk-bcm2835.patch} | 0 ...ettings-of-HiFiBerry-DAC-ADC-PRO-ca.patch} | 0 ...ys-Use-preferred-compatible-strings.patch} | 0 ...-amba-pl011-Add-un-throttle-support.patch} | 0 ...0-0399-Fix-i2c-pwm-pca9685a-overlay.patch} | 0 ...ure-to-HiFiBerry-DAC-ADC-PRO-sound-.patch} | 0 ...ure-to-HiFiBerry-DAC-ADC-sound-card.patch} | 0 ...ure-to-HiFiBerry-DAC-DAC-PRO-sound-.patch} | 0 ...ding-Pisound-board-hardware-revisio.patch} | 0 ...-iproc-Fix-vmmc-regulators-on-iProc.patch} | 0 ...lare-RPi-4B-SD-card-power-regulator.patch} | 0 ...-Use-BCM2711-PCIe-compatible-string.patch} | 0 ...-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch} | 0 ...11-Avoid-rare-write-when-full-error.patch} | 0 ...aspberry-Pi-FW-loader-for-VIA-VL805.patch} | 0 ...rect-the-eth_led-colour-assignments.patch} | 0 ...d_poll_once-dtparam-to-bcm283x-2711.patch} | 0 ...sd1306-spi-ssh1106-spi-ssd-1351-spi.patch} | 0 ...overlays-dwc2-Increase-RX-FIFO-size.patch} | 0 ...rlays-Fix-mcp23017-s-addr-parameter.patch} | 0 ...SH-Fix-spi-driver-compiler-warnings.patch} | 0 ...-hdmi-backlight-hwhack-gpio-overlay.patch} | 0 ...t-all-changes-to-upstream-dts-files.patch} | 0 ...n-out-downstream-BCM2711-2838-files.patch} | 0 ...-Add-minimal-Raspberry-Pi-4-support.patch} | 0 ...1-force-CMA-into-first-GB-of-memory.patch} | 0 ...-bcm2711-rpi-4-Enable-GENET-support.patch} | 0 ...s-bcm2711-fix-soc-s-node-dma-ranges.patch} | 0 ...RM-dts-Rebuild-downstream-DTS-files.patch} | 0 ...q_arm-Fix-bcm2711-compatible-string.patch} | 0 ...al-brcmstb_thermal-Correct-SoC-name.patch} | 0 ...hwrng-iproc-rng200-Correct-SoC-name.patch} | 0 ...> 950-0427-ARM-dts-Correct-SoC-name.patch} | 0 ...Remove-CMA-allocation-from-Pi-4-dts.patch} | 0 ...iq_arm-Give-vchiq-children-DT-nodes.patch} | 0 ..._arm-Add-a-matching-unregister-call.patch} | 0 ...e-audio-node-under-the-vchiq-parent.patch} | 0 ...ts-overlays-Create-custom-clocks-in.patch} | 0 ...ices-Fix-vcsm-overflow-bug-when-cou.patch} | 0 ...meout_ms-parameter-to-gpio-poweroff.patch} | 0 ...-overlay-Correct-symbol-path-fixups.patch} | 0 ...ys-sc16ic750-i2c-Fix-xtal-parameter.patch} | 0 ...oduce-of_get_next_dma_parent-helper.patch} | 0 ...-Follow-DMA-parent-for-dma-coherent.patch} | 0 ...-Factor-out-addr-size-cells-parsing.patch} | 0 ...ate-dma-ranges-for-parent-nodes-mis.patch} | 0 ...-of_dma_get_range-work-on-bus-nodes.patch} | 0 ...4_dma_phys_limit-instead-of-calling.patch} | 0 ...ables-used-to-calculate-ZONE_DMA32-.patch} | 0 ...64-use-both-ZONE_DMA-and-ZONE_DMA32.patch} | 0 ...MA-and-ZONE_DMA32-comments-in-enum-.patch} | 0 ...d-a-resource_list_first_type-helper.patch} | 0 ...-ARCH_ZONE_DMA_BITS-into-a-variable.patch} | 0 ...use-default-DMA-address-translation.patch} | 0 ...inbound-resource-parsing-to-helpers.patch} | 0 ...t-unify-the-dma_capable-definitions.patch} | 0 ...a-forward-declaration-for-phys_to_d.patch} | 0 ...e-dma_direct_map_resource-from-the-.patch} | 0 ...eat-dev-bus_dma_mask-as-a-DMA-limit.patch} | 0 ...-dts-bcm2711-Enable-PCIe-controller.patch} | 0 ...roadcom-STB-PCIe-host-controller-dr.patch} | 0 ...50-0456-PCI-brcmstb-Add-MSI-support.patch} | 0 ...uild-on-32bit-ARM-platforms-with-ol.patch} | 0 ...711-rpi.dtsi-Use-upstream-pcie-node.patch} | 0 ...-media-i2c-Add-IMX219-CMOS-sensor-b.patch} | 0 ...c-Add-driver-for-Sony-IMX219-sensor.patch} | 0 ...orrect-link-frequency-to-match-the-.patch} | 0 ...w-.dtbo-overlays-to-be-built-adjust.patch} | 0 ...return-codes-from-ov5647_write-ov56.patch} | 0 ...basic-support-for-multiple-sensor-m.patch} | 0 ...V4L2-controls-for-analogue-gain-exp.patch} | 0 ...v5647-Add-extra-10-bit-sensor-modes.patch} | 0 ...ge-defaults-to-better-match-raw-cam.patch} | 0 ...ge-crtc_state-structure-name-to-avo.patch} | 0 ...c-Add-packed-10bit-YUV-4-2-0-format.patch} | 0 ...FORMAT_P030-support-to-firmware-kms.patch} | 0 ...dd-parameter-to-configure-signal-po.patch} | 0 ...erus-amp-soundcard-and-ma120x0p-cod.patch} | 0 ...cm2711-Add-32-bit-PMU-compatibility.patch} | 0 ...dts-bcm271x-Use-a53-pmu-drop-RPI364.patch} | 0 ...r-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch} | 0 ...mdline-Fix-possible-reference-past-.patch} | 0 ...mdline-Make-various-char-pointers-c.patch} | 0 ...mdline-Stop-parsing-extras-after-bp.patch} | 0 ...mdline-Accept-extras-directly-after.patch} | 0 ...mdline-Rework-drm_mode_parse_cmdlin.patch} | 0 ...mdline-Add-freestanding-argument-to.patch} | 0 ...mdline-Set-bpp-refresh_specified-af.patch} | 0 ...mdline-Allow-specifying-stand-alone.patch} | 0 ...mdline-Add-support-for-specifying-p.patch} | 0 ...mdline-Remove-some-unnecessary-code.patch} | 0 ...mdline-Explicitly-memset-the-passed.patch} | 0 ...ait_for-macros-to-remove-use-of-msl.patch} | 0 ...8-Reduce-noise-from-rpi-poe-hat-fan.patch} | 0 ...nsirion-SPS30-to-i2c-sensor-overlay.patch} | 0 ...dd-V4L2_CTRL_TYPE_AREA-control-type.patch} | 0 ...add-V4L2_CID_UNIT_CELL_SIZE-control.patch} | 0 ...2-common-add-pixel-encoding-support.patch} | 0 ...-add-RGB565-and-RGB55-to-v4l2_forma.patch} | 0 ...-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch} | 0 ...em2mem-support-held-capture-buffers.patch} | 0 ...-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch} | 0 ...m-add-stateless_-try_-decoder_cmd-i.patch} | 0 ...4l2-mem2mem-add-new_frame-detection.patch} | 0 ...on-media-Document-V4L2_CTRL_TYPE_AR.patch} | 0 ...initions-for-HEVC-stateless-decodin.patch} | 0 ...l2-mem2mem-Fix-hold-buf-flag-checks.patch} | 0 ...ocument-the-HEVC-slice-pixel-format.patch} | 0 ...api-hevc-Add-scaling-matrix-control.patch} | 0 ...uapi-hevc-Add-segment-address-field.patch} | 0 ...Add-slice-param-dependent-slice-seg.patch} | 0 ...api-Add-hevc-ctrls-for-WPP-decoding.patch} | 0 ...-Add-a-format-for-column-YUV4-2-0-m.patch} | 0 ...m-allow-request-job-buffer-processi.patch} | 0 ...-media-Add-binding-for-the-Raspberr.patch} | 0 ...-Add-Raspberry-Pi-V4L2-H265-decoder.patch} | 0 ...erlay-to-enable-the-HEVC-V4L2-drive.patch} | 0 ...-0512-mmc-sdhci-Silence-MMC-warnings.patch | 42 + ...brcmstb-Convert-the-BRCMSTB-binding-.patch | 126 + ...brcmstb-Add-BCM2711-BSC-AUTO-I2C-bin.patch | 96 + ...Support-BCM2711-HDMI-BSC-controllers.patch | 87 + ...cmstb-Allow-to-compile-it-on-BCM2835.patch | 31 + ...k-Add-a-binding-for-the-RPi-Firmware.patch | 63 + ...-Allow-the-driver-to-be-probed-by-DT.patch | 60 + ...cm-rpi-Statically-init-clk_init_data.patch | 32 + ...rpi-Use-clk_hw_register-for-pllb_arm.patch | 56 + ...Remove-global-pllb_arm-clock-pointer.patch | 45 + ...cm-rpi-Make-sure-pllb_arm-is-removed.patch | 40 + ...emove-pllb_arm_lookup-global-pointer.patch | 51 + ...rpi-Switch-to-clk_hw_register_clkdev.patch | 45 + ...ke-sure-the-clkdev-lookup-is-removed.patch | 34 + ...eate-a-data-structure-for-the-clocks.patch | 126 + ...527-clk-bcm-rpi-Add-clock-id-to-data.patch | 86 + ...-the-clocks-data-to-the-firmware-fun.patch | 96 + ...-bcm-rpi-Rename-is_prepared-function.patch | 40 + ...0-clk-bcm-rpi-Split-pllb-clock-hooks.patch | 80 + ...-the-PLLB-registration-function-retu.patch | 144 + ...m-rpi-Add-DT-provider-for-the-clocks.patch | 67 + ...bcm-rpi-Discover-the-firmware-clocks.patch | 173 ++ ...dts-bcm2711-Add-firmware-clocks-node.patch | 39 + ...t-simple-header-out-of-drivers-reset.patch | 168 + ...0536-reset-simple-Add-reset-callback.patch | 85 + ...ndings-clock-Add-BCM2711-DVP-binding.patch | 68 + ...-0538-clk-bcm-Add-BCM2711-DVP-driver.patch | 172 ++ ...50-0539-ARM-dts-bcm2711-Add-HDMI-DVP.patch | 43 + ...play-Convert-VC4-bindings-to-schemas.patch | 706 +++++ ...lay-vc4-dpi-Add-missing-clock-names-.patch | 38 + ...lay-vc4-dsi-Add-missing-clock-proper.patch | 54 + ...lay-vc4-hdmi-Add-missing-clock-names.patch | 34 + ...ngs-display-vc4-Document-BCM2711-VC5.patch | 24 + ...-0545-drm-vc4-drv-Add-include-guards.patch | 30 + ...950-0546-drm-vc4-drv-Support-BCM2711.patch | 109 + ...drv-Add-support-for-the-BCM2711-HVS5.patch | 497 +++ ...0548-drm-vc4-plane-Improve-LBM-usage.patch | 98 + ...ve-planes-creation-to-its-own-functi.patch | 125 + ...ve-additional-planes-creation-to-dri.patch | 75 + ...lane-Register-all-the-planes-at-once.patch | 128 + ...4-plane-Create-overlays-for-any-CRTC.patch | 70 + ...553-drm-vc4-plane-Create-more-planes.patch | 32 + ...-vc4-crtc-Rename-SoC-data-structures.patch | 56 + ...rtc-Move-crtc-state-to-common-header.patch | 74 + ...l-with-different-number-of-pixel-per.patch | 86 + ...-drm-vc4-crtc-Use-a-shared-interrupt.patch | 26 + ...n-static-const-variable-into-a-defin.patch | 50 + ...e-the-cob-allocation-outside-of-bind.patch | 110 + ...c4-crtc-Rename-HVS-channel-to-output.patch | 80 + ...drm-vc4-crtc-Use-local-chan-variable.patch | 24 + ...ble-and-disable-the-PV-in-atomic_ena.patch | 55 + ...sign-output-to-channel-automatically.patch | 459 +++ ...crtc-Add-FIFO-depth-to-vc4_crtc_data.patch | 86 + ...-function-to-compute-FIFO-level-bits.patch | 44 + ...tc-Rename-HDMI-encoder-type-to-HDMI0.patch | 49 + ...-drm-vc4-crtc-Add-HDMI1-encoder-type.patch | 23 + ...ove-redundant-call-to-drm_crtc_enabl.patch | 24 + ...tc-Disable-color-management-for-HVS5.patch | 54 + ...play-vc4-pv-Add-BCM2711-pixel-valves.patch | 30 + ...drm-vc4-crtc-Add-BCM2711-pixelvalves.patch | 152 + ...m-vc4-hdmi-Use-debugfs-private-field.patch | 30 + ...rm-vc4-hdmi-Move-structure-to-header.patch | 195 ++ ...-hdmi-rework-connectors-and-encoders.patch | 348 +++ ...drm-vc4-hdmi-Rename-hdmi-to-vc4_hdmi.patch | 682 +++++ ...-vc4-hdmi-Move-accessors-to-vc4_hdmi.patch | 152 + ...vc4-hdmi-Use-local-vc4_hdmi-directly.patch | 45 + ...-container_of-macros-for-encoders-an.patch | 151 + ...m-vc4-hdmi-Pass-vc4_hdmi-to-CEC-code.patch | 107 + ...vc4-hdmi-Remove-vc4_dev-hdmi-pointer.patch | 67 + ...m-vc4-hdmi-Remove-vc4_hdmi_connector.patch | 141 + ...-Introduce-resource-init-and-variant.patch | 151 + ...lement-a-register-layout-abstraction.patch | 1310 ++++++++ ...0584-drm-vc4-hdmi-Add-reset-callback.patch | 66 + ...mi-Add-PHY-init-and-disable-function.patch | 128 + ...-Add-PHY-RNG-enable-disable-function.patch | 104 + ...rm-vc4-hdmi-Add-a-CSC-setup-callback.patch | 134 + ...-vc4-hdmi-Add-a-set_timings-callback.patch | 133 + .../950-0589-drm-vc4-hdmi-Add-HDMI-ID.patch | 46 + ...dmi-Deal-with-multiple-debugfs-files.patch | 33 + ...m-vc4-hdmi-Add-an-audio-support-flag.patch | 47 + ...mi-Move-CEC-init-to-its-own-function.patch | 165 + ...93-drm-vc4-hdmi-Add-CEC-support-flag.patch | 47 + ...i-Remove-unused-CEC_CLOCK_DIV-define.patch | 23 + ...ame-drm_encoder-pointer-in-mode_vali.patch | 26 + ...ust-HSM-clock-rate-depending-on-pixe.patch | 163 + ...Support-the-BCM2711-HDMI-controllers.patch | 1131 +++++++ ...lay-vc4-hdmi-Add-BCM2711-HDMI-contro.patch | 174 ++ ...-bcm2711-Enable-the-display-pipeline.patch | 210 ++ ...ts-rpi4-Disable-KMS-driver-by-defaul.patch | 90 + ...rlays-Add-Pi4-version-of-vc4-kms-v3d.patch | 241 ++ ...the-pitch-is-only-valid-for-linear-f.patch | 39 + ...ort-for-DRM_FORMAT_P030-to-vc4-plane.patch | 174 ++ .../950-0604-Fixup-P030-support.patch | 26 + ...k-for-assigned-HVS-channels-is-not-a.patch | 33 + ...dt-Update-v3d-to-use-firmware_clocks.patch | 23 + ...dio-infoframe-on-encoder_enable-if-p.patch | 72 + ...b-frame-marker-to-the-match-ALSA-s-d.patch | 31 + ...es-for-the-HDMI-registers-on-bcm2835.patch | 27 + ...DMI-audio-dma-values-to-bcm2711.dtsi.patch | 32 + ...se-reg-names-to-configure-HDMI-audio.patch | 35 + ...vc4-Add-audio-initialisation-for-Pi4.patch | 127 + ...950-0613-drm-vc4-Enable-audio-on-Pi4.patch | 31 + ...e-HDMI-state-machine-clock-calc-to-a.patch | 46 + ...e-comment-about-vc4-kms-v3d-locking-.patch | 28 + ...e-core-clock-up-during-a-mode-change.patch | 97 + ...-0617-drm-vc4-Fixup-for-firmware-KMS.patch | 36 + ...Fixup-plane-init-within-firmware-kms.patch | 31 + ...e-the-HDMI-audio-instances-different.patch | 26 + ...interrupt-line-is-optional-so-use-pl.patch | 49 + ...C-for-Pi4-HDMI-interfaces-to-97.5kHz.patch | 35 + ...rlays-Add-missing-rpi-poe-parameters.patch | 39 + ...-vc4_hdmi_phy-Fix-offset-calculation.patch | 30 + .../950-0624-overlays-Add-overlay_map.patch | 101 + ...rmally-rename-deprecate-old-overlays.patch | 226 ++ ...s-Add-vc4-kms-v3d-pi4-to-overlay_map.patch | 26 + ...ream-and-upstream-pi4-to-overlay_map.patch | 229 ++ ...llow-cpufreq-driver-to-also-adjust-.patch} | 6 +- ...the-AudioInjector.net-Isolated-sound.patch | 323 ++ ...verlays-Fix-dtc-warnings-in-i2c-gpio.patch | 24 + .../950-0631-kbuild-Disable-gcc-plugins.patch | 28 + ...ASoC-ma120x0p-Add-96KHz-rate-support.patch | 42 + ...ve-CMA-and-crashkernel-in-ZONE_DMA32.patch | 44 + ...tialisation-of-DMA-zones-on-non-NUMA.patch | 105 + ...-dts-bcm283x-Unify-CMA-configuration.patch | 95 + ...guous-CMA-give-precedence-to-cmdline.patch | 49 + ...M-dts-Use-upstream-CMA-configuration.patch | 36 + ...-overlays-Unify-overlay-CMA-handling.patch | 871 ++++++ ...Fix-vc4-s-firmware-bus-DMA-limitatio.patch | 28 + ...-bcm2711-Restrict-CMA-to-first-768MB.patch | 33 + ...ARM-dts-Extend-SCB-bus-address-range.patch | 23 + ...ts-bcm2711-Move-emmc2-to-its-own-bus.patch | 52 + ...ence-pixel-clock-error-on-EPROBE_DEF.patch | 29 + ...t-Silence-bind-error-on-EPROBE_DEFER.patch | 41 + ...with-clock-settings-of-HiFiBerry-DAC.patch | 42 + ...on-media-Update-sub-device-API-intro.patch | 34 + ...n-media-Document-read-only-subdevice.patch | 217 ++ ...dd-v4l2_device_register_ro_subdev_no.patch | 206 ++ ...icam-Driver-for-CCP2-CSI2-camera-int.patch | 2709 +++++++++++++++++ ...core-Add-sensor-ancillary-data-V4L2-.patch | 85 + ...EDIA_BUS_FMT_SENSOR_DATA-media-bus-f.patch | 64 + ...icam-Add-support-for-mulitple-device.patch | 1084 +++++++ ...cm2835-unicam-Add-embedded-data-node.patch | 1170 +++++++ ...icam-Use-dummy-buffer-if-none-have-b.patch | 308 ++ ...CS_HIGH-if-GPIO-descriptors-are-used.patch | 48 + ...-media-i2c-imx219-Fix-power-sequence.patch | 55 + ...-Add-support-for-RAW8-bit-bayer-form.patch | 319 ++ ...-Add-support-for-cropped-640x480-res.patch | 118 + ...-Fix-a-bug-in-imx219_enum_frame_size.patch | 34 + ...icam-Disable-event-related-ioctls-on.patch | 31 + ...icam-Add-support-for-the-FRAME_SYNC-.patch | 55 + ...ware-raspberrypi-register-clk-device.patch | 58 + ...ertise-embedded-data-node-on-media-p.patch | 335 ++ ...EMMC2-can-address-the-whole-first-GB.patch | 31 + ...ar-rpivid-Remove-legacy-name-support.patch | 53 + ...ar-rpivid-Don-t-map-more-than-wanted.patch | 51 + ...mplement-an-I2C-pinctrl-mux-for-BSC0.patch | 434 +++ ...date-CSI-overlays-to-use-i2c_csi_dsi.patch | 425 +++ ...inline-bcm283x-dt-files-for-i2c0-pin.patch | 201 ++ ...RM-dts-Create-bcm2708-rpi-b-rev1.dts.patch | 182 ++ ...50-0671-dts-bcm2711-set-size-cells-2.patch | 117 + ...711-add-High-Peripheral-mode-overlay.patch | 140 + ...v-Fix-CS-polarity-if-GPIO-descriptor.patch | 32 + ..._descriptor-fixup-moved-to-spi_setup.patch | 55 + ...-rpivid-v4l2-also-needs-size-cells-2.patch | 30 + ...icam-Re-fetch-mbus-code-from-subdev-.patch | 49 + ...isp-Add-bcm2835-isp-uapi-header-file.patch | 337 ++ ...core-Add-ISP-statistics-output-V4L2-.patch | 94 + ...trls-Add-CID-base-for-the-bcm2835-is.patch | 169 + ...iq-Fix-formatting-errors-in-mmal_par.patch | 116 + ...vices-ISP-Add-a-more-complex-ISP-pro.patch | 2255 ++++++++++++++ ...q-Load-bcm2835_isp-driver-from-vchiq.patch | 39 + ...-vc4_hvs-Mark-core-clock-as-optional.patch | 23 + ...-requires-a-fixed-hsm-clock-for-CEC-.patch | 93 + ...a-i2c-imx219-Implement-get_selection.patch | 181 ++ ...-Add-support-for-g_selection-to-refl.patch | 206 ++ ...67-Fixup-error-path-to-release-mutex.patch | 29 + ...c-ov5647-Support-V4L2_CID_PIXEL_RATE.patch | 131 + ...7-Set-V4L2_SUBDEV_FL_HAS_EVENTS-flag.patch | 143 + ...5647-Add-support-for-V4L2_CID_VBLANK.patch | 205 ++ ...-Neither-analogue-gain-nor-exposure-.patch | 58 + ...5647-Use-member-names-in-mode-tables.patch | 111 + ...-Advertise-the-correct-exposure-rang.patch | 119 + ...-Declare-that-the-driver-can-create-.patch | 27 + ...icam-Add-support-for-VIDIOC_-S-G-_SE.patch | 82 + ...icam-Do-not-stop-streaming-in-unicam.patch | 28 + ...icam-Fix-reference-counting-in-unica.patch | 38 + ...rvices-ISP-Add-enum_framesizes-ioctl.patch | 333 ++ ...te-SPI_CS_HIGH-warning-to-KERN_DEBUG.patch | 28 + ...35-dma-Add-proper-40-bit-DMA-support.patch | 801 +++++ ...dts-bcm2711-Allow-40-bit-DMA-for-SPI.patch | 40 + ...Make-the-i2c-gpio-overlay-safe-again.patch | 32 + ...vices-isp-Remove-duplicated-initiali.patch | 62 + ...vices-isp-Make-all-references-to-bcm.patch | 148 + ...-gpio-keys-Avoid-open-drain-warnings.patch | 29 + ...i_phy-Fix-typo-in-phy_get_cp_current.patch | 23 + ...-Make-use-of-intra-overlay-fragments.patch | 92 + ...i2c-tc358743-Fix-fallthrough-warning.patch | 20 + ...835-unicam-Fix-uninitialized-warning.patch | 21 + ...8_fb-Disable-FB-if-no-displays-found.patch | 34 + ...ys-sc16is752-spi1-Add-xtal-parameter.patch | 38 + ...ister-offset-when-sending-longer-CEC.patch | 42 + ...0-0713-vc4_hdmi-Fix-up-CEC-registers.patch | 43 + ...4_hdmi_regs-Add-Intr2-register-block.patch | 151 + ...Make-interrupt-mask-variant-specific.patch | 101 + .../950-0716-vc4_hdmi-Make-irq-shared.patch | 22 + ...CEC-ref-clock-based-on-its-input-clo.patch | 89 + ...cec_available-flag-as-always-support.patch | 44 + ...tc358743-Use-intra-overlay-fragments.patch | 55 + ...s-Move-fixed-clock-nodes-to-the-root.patch | 326 ++ ...-dts-Switch-to-discrete-ALSA-devices.patch | 84 + ...a-i2c-Add-IMX477-CMOS-sensor-binding.patch | 130 + ...dtoverlays-Add-IMX477-sensor-overlay.patch | 156 + ...2c-Add-driver-for-Sony-IMX477-sensor.patch | 2266 ++++++++++++++ ...-Add-support-for-adaptive-frame-cont.patch | 182 ++ ...uf-Remove-deleted-map-unmap-handlers.patch | 52 + ...udmabuf-use-cache_sgt_mapping-option.patch | 35 + ...inter-to-the-miscdevice-in-dma-buf-p.patch | 67 + ...-out-creating-destroying-scatter-tab.patch | 71 + ...t-begin_cpu_access-end_cpu_access-ho.patch | 90 + ...-0731-udmabuf-fix-dma-buf-cpu-access.patch | 60 + ...-dma-buf-Add-dma-buf-heaps-framework.patch | 525 ++++ ...-0733-dma-buf-heaps-Add-heap-helpers.patch | 394 +++ ...eaps-Add-system-heap-to-dmabuf-heaps.patch | 200 ++ ...f-heaps-Add-CMA-heap-to-dmabuf-heaps.patch | 251 ++ ...50-0736-kselftests-Add-dma-heap-test.patch | 453 +++ ...e-_IOCTL_-for-userspace-IOCTL-identi.patch | 69 + ...move-redundant-heap-identifier-from-.patch | 28 + ...urce-leak-on-ENOTTY-error-return-pat.patch | 34 + ...he-symbol-dma_heap_ioctl_cmds-static.patch | 34 + ...ts-Enable-firmware-clocks-on-all-Pis.patch | 25 + ...835-unicam-Always-service-interrupts.patch | 51 + ...6is7xx-Fix-for-hardware-flow-control.patch | 70 + ...vc4-Fix-VIC-usage-with-Broadcast-RGB.patch | 58 + ...vices-mmal-vchiq-Update-parameters-l.patch | 28 + ...vices-bcm2835-codec-Request-headers-.patch | 29 + ...vices-bcm2835-codec-Avoid-fragmentin.patch | 32 + ...vices-bcm2835-camera-Request-headers.patch | 30 + ...s-Fix-audio-parameter-of-vc4-kms-v3d.patch | 25 + ...Switch-to-snd_soc_dai_set_bclk_ratio.patch | 38 + ...icam-Retain-packing-information-on-G.patch | 48 + ...752-zswap-Defer-zswap-initialisation.patch | 115 + ...e-dma-configuration-from-the-HVS-or-.patch | 54 + ...-as-an-acceptable-node-for-dma-range.patch | 27 + ...-Return-correct-result-on-sensor-id-.patch | 25 + ...chiq_arm-Clean-up-40-bit-DMA-support.patch | 154 + ...te-for-new-VCHIQ-BCM2711-DMA-support.patch | 67 + target/linux/generic/config-5.4 | 12 + 416 files changed, 37487 insertions(+), 676 deletions(-) delete mode 100644 target/linux/bcm27xx/patches-5.4/950-0351-v3d_drv-Allow-clock-retrieval-by-name.patch rename target/linux/bcm27xx/patches-5.4/{950-0352-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch => 950-0351-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0355-clk-bcm2835-Disable-v3d-clock.patch => 950-0352-clk-bcm2835-Disable-v3d-clock.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0356-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch => 950-0353-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0357-arm-dts-Correct-Pi-4B-LED-values.patch => 950-0354-arm-dts-Correct-Pi-4B-LED-values.patch} (100%) delete mode 100644 target/linux/bcm27xx/patches-5.4/950-0354-clk-raspberrypi-Also-support-v3d-clock.patch rename target/linux/bcm27xx/patches-5.4/{950-0358-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch => 950-0355-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0359-arm-dts-2711-Add-pcie0-alias.patch => 950-0356-arm-dts-2711-Add-pcie0-alias.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0360-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch => 950-0357-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0361-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch => 950-0358-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0362-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch => 950-0359-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0363-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch => 950-0360-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0364-overlays-Make-mcp342x-run-time-compatible.patch => 950-0361-overlays-Make-mcp342x-run-time-compatible.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0365-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch => 950-0362-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0366-sound-soc-only-first-codec-is-master-in-multicodec-s.patch => 950-0363-sound-soc-only-first-codec-is-master-in-multicodec-s.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0367-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch => 950-0364-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0368-overlays-dht11-Allow-multiple-instantiation.patch => 950-0365-overlays-dht11-Allow-multiple-instantiation.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0369-overlays-i2c-rtc-Add-pcf85363-support.patch => 950-0366-overlays-i2c-rtc-Add-pcf85363-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0370-pinctrl-bcm2835-Remove-gpiochip-on-error.patch => 950-0367-pinctrl-bcm2835-Remove-gpiochip-on-error.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0371-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch => 950-0368-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0372-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch => 950-0369-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0373-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch => 950-0370-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0374-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch => 950-0371-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0375-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch => 950-0372-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0376-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch => 950-0373-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0377-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch => 950-0374-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0378-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch => 950-0375-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0379-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch => 950-0376-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0380-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch => 950-0377-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0381-net-bcmgenet-Add-RGMII_RXID-support.patch => 950-0378-net-bcmgenet-Add-RGMII_RXID-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0382-ARM-dts-bcm2838-Backport-genet-from-upstream.patch => 950-0379-ARM-dts-bcm2838-Backport-genet-from-upstream.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0383-ARM-bcm-Backport-BCM2711-support-from-upstream.patch => 950-0380-ARM-bcm-Backport-BCM2711-support-from-upstream.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0384-hwrng-iproc-rng200-Add-support-for-BCM2711.patch => 950-0381-hwrng-iproc-rng200-Add-support-for-BCM2711.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0385-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch => 950-0382-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0386-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch => 950-0383-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0387-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch => 950-0384-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0388-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch => 950-0385-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0389-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch => 950-0386-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0390-driver-char-rpimem-Add-SPDX-licence-header.patch => 950-0387-driver-char-rpimem-Add-SPDX-licence-header.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0391-driver-char-rpivid-Fix-access-to-freed-memory.patch => 950-0388-driver-char-rpivid-Fix-access-to-freed-memory.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0392-add-BME680-to-i2c-sensor-overlay.patch => 950-0389-add-BME680-to-i2c-sensor-overlay.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0393-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch => 950-0390-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0394-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch => 950-0391-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0395-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch => 950-0392-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0396-Add-universal-device-tree-overlay-for-SPI-devices.patch => 950-0393-Add-universal-device-tree-overlay-for-SPI-devices.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0397-sound-Add-the-HiFiBerry-DAC-HD-version.patch => 950-0394-sound-Add-the-HiFiBerry-DAC-HD-version.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0398-Initialise-rpi-firmware-before-clk-bcm2835.patch => 950-0395-Initialise-rpi-firmware-before-clk-bcm2835.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0399-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch => 950-0396-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0400-overlays-Use-preferred-compatible-strings.patch => 950-0397-overlays-Use-preferred-compatible-strings.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0401-tty-amba-pl011-Add-un-throttle-support.patch => 950-0398-tty-amba-pl011-Add-un-throttle-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0402-Fix-i2c-pwm-pca9685a-overlay.patch => 950-0399-Fix-i2c-pwm-pca9685a-overlay.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0403-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch => 950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0404-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch => 950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0405-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch => 950-0402-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0406-pisound-Added-reading-Pisound-board-hardware-revisio.patch => 950-0403-pisound-Added-reading-Pisound-board-hardware-revisio.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0407-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch => 950-0404-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0408-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch => 950-0405-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0409-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch => 950-0406-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0410-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch => 950-0407-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0411-tty-amba-pl011-Avoid-rare-write-when-full-error.patch => 950-0408-tty-amba-pl011-Avoid-rare-write-when-full-error.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0412-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch => 950-0409-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0413-overlays-Correct-the-eth_led-colour-assignments.patch => 950-0410-overlays-Correct-the-eth_led-colour-assignments.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0414-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch => 950-0411-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0415-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch => 950-0412-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0416-overlays-dwc2-Increase-RX-FIFO-size.patch => 950-0413-overlays-dwc2-Increase-RX-FIFO-size.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0417-overlays-Fix-mcp23017-s-addr-parameter.patch => 950-0414-overlays-Fix-mcp23017-s-addr-parameter.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0418-SQUASH-Fix-spi-driver-compiler-warnings.patch => 950-0415-SQUASH-Fix-spi-driver-compiler-warnings.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0419-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch => 950-0416-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0420-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch => 950-0417-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0421-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch => 950-0418-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0422-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch => 950-0419-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0423-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch => 950-0420-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0424-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch => 950-0421-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0425-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch => 950-0422-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0426-ARM-dts-Rebuild-downstream-DTS-files.patch => 950-0423-ARM-dts-Rebuild-downstream-DTS-files.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0427-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch => 950-0424-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0428-thermal-brcmstb_thermal-Correct-SoC-name.patch => 950-0425-thermal-brcmstb_thermal-Correct-SoC-name.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0429-hwrng-iproc-rng200-Correct-SoC-name.patch => 950-0426-hwrng-iproc-rng200-Correct-SoC-name.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0430-ARM-dts-Correct-SoC-name.patch => 950-0427-ARM-dts-Correct-SoC-name.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0431-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch => 950-0428-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0432-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch => 950-0429-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0433-staging-vchiq_arm-Add-a-matching-unregister-call.patch => 950-0430-staging-vchiq_arm-Add-a-matching-unregister-call.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0434-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch => 950-0431-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch => 950-0432-ARM-dts-overlays-Create-custom-clocks-in.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch => 950-0433-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch => 950-0434-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0438-of-overlay-Correct-symbol-path-fixups.patch => 950-0435-of-overlay-Correct-symbol-path-fixups.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch => 950-0436-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch => 950-0437-of-address-Introduce-of_get_next_dma_parent-helper.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch => 950-0438-of-address-Follow-DMA-parent-for-dma-coherent.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0442-of-Factor-out-addr-size-cells-parsing.patch => 950-0439-of-Factor-out-addr-size-cells-parsing.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch => 950-0440-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch => 950-0441-of-Make-of_dma_get_range-work-on-bus-nodes.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch => 950-0442-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch => 950-0443-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch => 950-0444-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch => 950-0445-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0449-resource-Add-a-resource_list_first_type-helper.patch => 950-0446-resource-Add-a-resource_list_first_type-helper.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch => 950-0447-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch => 950-0448-x86-PCI-sta2x11-use-default-DMA-address-translation.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch => 950-0449-PCI-of-Add-inbound-resource-parsing-to-helpers.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0453-dma-direct-unify-the-dma_capable-definitions.patch => 950-0450-dma-direct-unify-the-dma_capable-definitions.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch => 950-0451-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch => 950-0452-dma-direct-exclude-dma_direct_map_resource-from-the-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch => 950-0453-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch => 950-0454-ARM-dts-bcm2711-Enable-PCIe-controller.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch => 950-0455-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0459-PCI-brcmstb-Add-MSI-support.patch => 950-0456-PCI-brcmstb-Add-MSI-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch => 950-0457-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch => 950-0458-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch => 950-0459-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch => 950-0460-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0464-overlays-imx219-Correct-link-frequency-to-match-the-.patch => 950-0461-overlays-imx219-Correct-link-frequency-to-match-the-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0465-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch => 950-0462-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0466-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch => 950-0463-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0467-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch => 950-0464-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0468-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch => 950-0465-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0469-media-ov5647-Add-extra-10-bit-sensor-modes.patch => 950-0466-media-ov5647-Add-extra-10-bit-sensor-modes.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0470-media-ov5647-change-defaults-to-better-match-raw-cam.patch => 950-0467-media-ov5647-change-defaults-to-better-match-raw-cam.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0471-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch => 950-0468-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0472-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch => 950-0469-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0473-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch => 950-0470-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0474-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch => 950-0471-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0475-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch => 950-0472-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0476-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch => 950-0473-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0477-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch => 950-0474-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0478-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch => 950-0475-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0479-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch => 950-0476-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0480-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch => 950-0477-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0481-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch => 950-0478-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0482-drm-modes-parse_cmdline-Accept-extras-directly-after.patch => 950-0479-drm-modes-parse_cmdline-Accept-extras-directly-after.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0483-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch => 950-0480-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0484-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch => 950-0481-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0485-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch => 950-0482-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0486-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch => 950-0483-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0487-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch => 950-0484-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0488-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch => 950-0485-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0489-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch => 950-0486-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0490-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch => 950-0487-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0491-Reduce-noise-from-rpi-poe-hat-fan.patch => 950-0488-Reduce-noise-from-rpi-poe-hat-fan.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0492-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch => 950-0489-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0493-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch => 950-0490-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0494-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch => 950-0491-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0495-media-v4l2-common-add-pixel-encoding-support.patch => 950-0492-media-v4l2-common-add-pixel-encoding-support.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0496-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch => 950-0493-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0497-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch => 950-0494-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0498-media-v4l2-mem2mem-support-held-capture-buffers.patch => 950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0499-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch => 950-0496-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0500-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch => 950-0497-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0501-media-v4l2-mem2mem-add-new_frame-detection.patch => 950-0498-media-v4l2-mem2mem-add-new_frame-detection.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0502-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch => 950-0499-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0503-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch => 950-0500-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0504-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch => 950-0501-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0505-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch => 950-0502-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0506-media-uapi-hevc-Add-scaling-matrix-control.patch => 950-0503-media-uapi-hevc-Add-scaling-matrix-control.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0507-media-uapi-hevc-Add-segment-address-field.patch => 950-0504-media-uapi-hevc-Add-segment-address-field.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0508-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch => 950-0505-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0509-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch => 950-0506-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0510-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch => 950-0507-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0511-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch => 950-0508-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0512-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch => 950-0509-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0513-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch => 950-0510-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch} (100%) rename target/linux/bcm27xx/patches-5.4/{950-0514-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch => 950-0511-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch} (100%) create mode 100644 target/linux/bcm27xx/patches-5.4/950-0512-mmc-sdhci-Silence-MMC-warnings.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0513-dt-bindings-i2c-brcmstb-Convert-the-BRCMSTB-binding-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0514-dt-bindings-i2c-brcmstb-Add-BCM2711-BSC-AUTO-I2C-bin.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0515-i2c-brcmstb-Support-BCM2711-HDMI-BSC-controllers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0516-i2c-brcmstb-Allow-to-compile-it-on-BCM2835.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0517-dt-bindings-clock-Add-a-binding-for-the-RPi-Firmware.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0518-clk-bcm-rpi-Allow-the-driver-to-be-probed-by-DT.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0519-clk-bcm-rpi-Statically-init-clk_init_data.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0520-clk-bcm-rpi-Use-clk_hw_register-for-pllb_arm.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0521-clk-bcm-rpi-Remove-global-pllb_arm-clock-pointer.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0522-clk-bcm-rpi-Make-sure-pllb_arm-is-removed.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0523-clk-bcm-rpi-Remove-pllb_arm_lookup-global-pointer.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0524-clk-bcm-rpi-Switch-to-clk_hw_register_clkdev.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0525-clk-bcm-rpi-Make-sure-the-clkdev-lookup-is-removed.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0526-clk-bcm-rpi-Create-a-data-structure-for-the-clocks.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0527-clk-bcm-rpi-Add-clock-id-to-data.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0528-clk-bcm-rpi-Pass-the-clocks-data-to-the-firmware-fun.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0529-clk-bcm-rpi-Rename-is_prepared-function.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0530-clk-bcm-rpi-Split-pllb-clock-hooks.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0531-clk-bcm-rpi-Make-the-PLLB-registration-function-retu.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0532-clk-bcm-rpi-Add-DT-provider-for-the-clocks.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0534-ARM-dts-bcm2711-Add-firmware-clocks-node.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0535-reset-Move-reset-simple-header-out-of-drivers-reset.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0536-reset-simple-Add-reset-callback.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0537-dt-bindings-clock-Add-BCM2711-DVP-binding.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0538-clk-bcm-Add-BCM2711-DVP-driver.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0539-ARM-dts-bcm2711-Add-HDMI-DVP.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0540-dt-bindings-display-Convert-VC4-bindings-to-schemas.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0541-dt-bindings-display-vc4-dpi-Add-missing-clock-names-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0542-dt-bindings-display-vc4-dsi-Add-missing-clock-proper.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0543-dt-bindings-display-vc4-hdmi-Add-missing-clock-names.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0544-dt-bindings-display-vc4-Document-BCM2711-VC5.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0545-drm-vc4-drv-Add-include-guards.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0546-drm-vc4-drv-Support-BCM2711.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0547-drm-vc4-drv-Add-support-for-the-BCM2711-HVS5.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0548-drm-vc4-plane-Improve-LBM-usage.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0549-drm-vc4-plane-Move-planes-creation-to-its-own-functi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0550-drm-vc4-plane-Move-additional-planes-creation-to-dri.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0551-drm-vc4-plane-Register-all-the-planes-at-once.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0552-drm-vc4-plane-Create-overlays-for-any-CRTC.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0553-drm-vc4-plane-Create-more-planes.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0554-drm-vc4-crtc-Rename-SoC-data-structures.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Move-crtc-state-to-common-header.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0556-drm-vc4-crtc-Deal-with-different-number-of-pixel-per.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0557-drm-vc4-crtc-Use-a-shared-interrupt.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0558-drm-vc4-crtc-Turn-static-const-variable-into-a-defin.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0559-drm-vc4-crtc-Move-the-cob-allocation-outside-of-bind.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0560-drm-vc4-crtc-Rename-HVS-channel-to-output.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0561-drm-vc4-crtc-Use-local-chan-variable.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0562-drm-vc4-crtc-Enable-and-disable-the-PV-in-atomic_ena.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0563-drm-vc4-crtc-Assign-output-to-channel-automatically.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0564-drm-vc4-crtc-Add-FIFO-depth-to-vc4_crtc_data.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0565-drm-vc4-crtc-Add-function-to-compute-FIFO-level-bits.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0566-drm-vc4-crtc-Rename-HDMI-encoder-type-to-HDMI0.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0567-drm-vc4-crtc-Add-HDMI1-encoder-type.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0568-drm-vc4-crtc-Remove-redundant-call-to-drm_crtc_enabl.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0569-drm-vc4-crtc-Disable-color-management-for-HVS5.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0570-dt-bindings-display-vc4-pv-Add-BCM2711-pixel-valves.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0571-drm-vc4-crtc-Add-BCM2711-pixelvalves.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0572-drm-vc4-hdmi-Use-debugfs-private-field.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0573-drm-vc4-hdmi-Move-structure-to-header.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0574-drm-vc4-hdmi-rework-connectors-and-encoders.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0575-drm-vc4-hdmi-Rename-hdmi-to-vc4_hdmi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0576-drm-vc4-hdmi-Move-accessors-to-vc4_hdmi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0577-drm-vc4-hdmi-Use-local-vc4_hdmi-directly.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0578-drm-vc4-hdmi-Add-container_of-macros-for-encoders-an.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0579-drm-vc4-hdmi-Pass-vc4_hdmi-to-CEC-code.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0580-drm-vc4-hdmi-Remove-vc4_dev-hdmi-pointer.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0581-drm-vc4-hdmi-Remove-vc4_hdmi_connector.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0582-drm-vc4-hdmi-Introduce-resource-init-and-variant.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0583-drm-vc4-hdmi-Implement-a-register-layout-abstraction.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0584-drm-vc4-hdmi-Add-reset-callback.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0585-drm-vc4-hdmi-Add-PHY-init-and-disable-function.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0586-drm-vc4-hdmi-Add-PHY-RNG-enable-disable-function.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0587-drm-vc4-hdmi-Add-a-CSC-setup-callback.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0588-drm-vc4-hdmi-Add-a-set_timings-callback.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Add-HDMI-ID.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0590-drm-vc4-hdmi-Deal-with-multiple-debugfs-files.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0591-drm-vc4-hdmi-Add-an-audio-support-flag.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0592-drm-vc4-hdmi-Move-CEC-init-to-its-own-function.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0593-drm-vc4-hdmi-Add-CEC-support-flag.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Remove-unused-CEC_CLOCK_DIV-define.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0595-drm-vc4-hdmi-Rename-drm_encoder-pointer-in-mode_vali.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0596-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0597-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0598-dt-bindings-display-vc4-hdmi-Add-BCM2711-HDMI-contro.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0599-ARM-dts-bcm2711-Enable-the-display-pipeline.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0600-DOWNSTREAM-ARM-dts-rpi4-Disable-KMS-driver-by-defaul.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0601-dtoverlays-Add-Pi4-version-of-vc4-kms-v3d.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0602-drm-Checking-of-the-pitch-is-only-valid-for-linear-f.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0603-drm-vc4-Add-support-for-DRM_FORMAT_P030-to-vc4-plane.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0604-Fixup-P030-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0605-drm-vc4-The-check-for-assigned-HVS-channels-is-not-a.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0606-dt-Update-v3d-to-use-firmware_clocks.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0607-drm-vc4-Reset-audio-infoframe-on-encoder_enable-if-p.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0608-drm-vc4-Set-the-b-frame-marker-to-the-match-ALSA-s-d.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0609-dts-Add-reg-names-for-the-HDMI-registers-on-bcm2835.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0610-dt-Add-HDMI-audio-dma-values-to-bcm2711.dtsi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0611-drm-vc4-Use-reg-names-to-configure-HDMI-audio.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0612-drm-vc4-Add-audio-initialisation-for-Pi4.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0613-drm-vc4-Enable-audio-on-Pi4.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0614-drm-vc4-Alter-the-HDMI-state-machine-clock-calc-to-a.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0615-dtoverlays-Remove-comment-about-vc4-kms-v3d-locking-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0616-drm-vc4-Kick-the-core-clock-up-during-a-mode-change.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0617-drm-vc4-Fixup-for-firmware-KMS.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0618-drm-vc4-Fixup-plane-init-within-firmware-kms.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0619-drm-vc4-hdmi-Give-the-HDMI-audio-instances-different.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0620-i2c-brcmstb-The-interrupt-line-is-optional-so-use-pl.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0621-dt-Drop-I2C-for-Pi4-HDMI-interfaces-to-97.5kHz.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0622-overlays-Add-missing-rpi-poe-parameters.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0623-vc4_hdmi_phy-Fix-offset-calculation.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0624-overlays-Add-overlay_map.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0625-overlays-Formally-rename-deprecate-old-overlays.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0626-overlays-Add-vc4-kms-v3d-pi4-to-overlay_map.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0627-Add-upstream-and-upstream-pi4-to-overlay_map.patch rename target/linux/bcm27xx/patches-5.4/{950-0353-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch => 950-0628-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch} (81%) create mode 100644 target/linux/bcm27xx/patches-5.4/950-0629-Add-support-for-the-AudioInjector.net-Isolated-sound.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0630-overlays-Fix-dtc-warnings-in-i2c-gpio.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0631-kbuild-Disable-gcc-plugins.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0632-ASoC-ma120x0p-Add-96KHz-rate-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0633-arm64-mm-reserve-CMA-and-crashkernel-in-ZONE_DMA32.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0634-arm64-mm-Fix-initialisation-of-DMA-zones-on-non-NUMA.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0635-ARM-dts-bcm283x-Unify-CMA-configuration.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0636-dma-contiguous-CMA-give-precedence-to-cmdline.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0637-ARM-dts-Use-upstream-CMA-configuration.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0638-ARM-dts-overlays-Unify-overlay-CMA-handling.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0639-ARM-dts-bcm283x-Fix-vc4-s-firmware-bus-DMA-limitatio.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0640-ARM-dts-bcm2711-Restrict-CMA-to-first-768MB.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0641-ARM-dts-Extend-SCB-bus-address-range.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0642-dts-bcm2711-Move-emmc2-to-its-own-bus.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0643-drm-vc4-hdmi-Silence-pixel-clock-error-on-EPROBE_DEF.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0644-component-Silence-bind-error-on-EPROBE_DEFER.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0645-Fixes-a-problem-with-clock-settings-of-HiFiBerry-DAC.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0646-Documentation-media-Update-sub-device-API-intro.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0647-Documentation-media-Document-read-only-subdevice.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0648-media-v4l2-dev-Add-v4l2_device_register_ro_subdev_no.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0649-media-bcm2835-unicam-Driver-for-CCP2-CSI2-camera-int.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0650-media-uapi-v4l2-core-Add-sensor-ancillary-data-V4L2-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0651-media-uapi-Add-MEDIA_BUS_FMT_SENSOR_DATA-media-bus-f.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0652-media-bcm2835-unicam-Add-support-for-mulitple-device.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0653-media-bcm2835-unicam-Add-embedded-data-node.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0654-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0655-spi-Force-CS_HIGH-if-GPIO-descriptors-are-used.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0656-media-i2c-imx219-Fix-power-sequence.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0657-media-i2c-imx219-Add-support-for-RAW8-bit-bayer-form.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0658-media-i2c-imx219-Add-support-for-cropped-640x480-res.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0659-media-i2c-imx219-Fix-a-bug-in-imx219_enum_frame_size.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0660-media-bcm2835-unicam-Disable-event-related-ioctls-on.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0661-media-bcm2835-unicam-Add-support-for-the-FRAME_SYNC-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0662-Revert-firmware-raspberrypi-register-clk-device.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0663-media-imx219-Advertise-embedded-data-node-on-media-p.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0664-dts-bcm2711-EMMC2-can-address-the-whole-first-GB.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0665-driver-char-rpivid-Remove-legacy-name-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0666-driver-char-rpivid-Don-t-map-more-than-wanted.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0667-dt-Implement-an-I2C-pinctrl-mux-for-BSC0.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0668-dtoverlays-Update-CSI-overlays-to-use-i2c_csi_dsi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0669-dt-Update-all-mainline-bcm283x-dt-files-for-i2c0-pin.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0670-ARM-dts-Create-bcm2708-rpi-b-rev1.dts.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0671-dts-bcm2711-set-size-cells-2.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0672-dts-bcm2711-add-High-Peripheral-mode-overlay.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0673-Revert-spi-spidev-Fix-CS-polarity-if-GPIO-descriptor.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0674-spi-use_gpio_descriptor-fixup-moved-to-spi_setup.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0675-overlays-rpivid-v4l2-also-needs-size-cells-2.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0676-media-bcm2835-unicam-Re-fetch-mbus-code-from-subdev-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0677-uapi-bcm2835-isp-Add-bcm2835-isp-uapi-header-file.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0678-media-uapi-v4l2-core-Add-ISP-statistics-output-V4L2-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0679-media-uapi-v4l-ctrls-Add-CID-base-for-the-bcm2835-is.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0680-staging-mmal-vchiq-Fix-formatting-errors-in-mmal_par.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0681-staging-vc04_services-ISP-Add-a-more-complex-ISP-pro.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0682-staging-vchiq-Load-bcm2835_isp-driver-from-vchiq.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0683-vc4_hvs-Mark-core-clock-as-optional.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0684-vc4_hdmi-BCM2835-requires-a-fixed-hsm-clock-for-CEC-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0685-media-i2c-imx219-Implement-get_selection.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0686-media-i2c-ov5647-Add-support-for-g_selection-to-refl.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0687-media-i2c-ov5467-Fixup-error-path-to-release-mutex.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0688-media-i2c-ov5647-Support-V4L2_CID_PIXEL_RATE.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0689-media-i2c-ov5647-Set-V4L2_SUBDEV_FL_HAS_EVENTS-flag.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0690-media-i2c-ov5647-Add-support-for-V4L2_CID_VBLANK.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0691-media-i2c-ov5647-Neither-analogue-gain-nor-exposure-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0692-media-i2c-ov5647-Use-member-names-in-mode-tables.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0693-media-i2c-ov5647-Advertise-the-correct-exposure-rang.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0694-media-i2c-imx219-Declare-that-the-driver-can-create-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0695-media-bcm2835-unicam-Add-support-for-VIDIOC_-S-G-_SE.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0696-media-bcm2835-unicam-Do-not-stop-streaming-in-unicam.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0697-media-bcm2835-unicam-Fix-reference-counting-in-unica.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0698-staging-vc04_services-ISP-Add-enum_framesizes-ioctl.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0699-SQUASH-spi-Demote-SPI_CS_HIGH-warning-to-KERN_DEBUG.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0700-bcm2835-dma-Add-proper-40-bit-DMA-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0701-ARM-dts-bcm2711-Allow-40-bit-DMA-for-SPI.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0702-overlays-Make-the-i2c-gpio-overlay-safe-again.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0703-staging-vc04_services-isp-Remove-duplicated-initiali.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0704-staging-vc04_services-isp-Make-all-references-to-bcm.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0705-overlays-gpio-keys-Avoid-open-drain-warnings.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0706-vc4_hdmi_phy-Fix-typo-in-phy_get_cp_current.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0707-overlays-Make-use-of-intra-overlay-fragments.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0708-media-i2c-tc358743-Fix-fallthrough-warning.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0709-media-bcm2835-unicam-Fix-uninitialized-warning.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0710-video-bcm2708_fb-Disable-FB-if-no-displays-found.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0711-overlays-sc16is752-spi1-Add-xtal-parameter.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0712-vc4_hdmi-Fix-register-offset-when-sending-longer-CEC.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0713-vc4_hdmi-Fix-up-CEC-registers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0714-vc4_hdmi_regs-Add-Intr2-register-block.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0715-vc4_hdmi_regs-Make-interrupt-mask-variant-specific.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0716-vc4_hdmi-Make-irq-shared.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0717-vc4_hdmi-Adjust-CEC-ref-clock-based-on-its-input-clo.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0718-vc4_hdmi-Remove-cec_available-flag-as-always-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0719-overlays-tc358743-Use-intra-overlay-fragments.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0720-overlays-Move-fixed-clock-nodes-to-the-root.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0721-raspberrypi-dts-Switch-to-discrete-ALSA-devices.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0722-dt-bindings-media-i2c-Add-IMX477-CMOS-sensor-binding.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0723-dtoverlays-Add-IMX477-sensor-overlay.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0724-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0725-media-i2c-imx477-Add-support-for-adaptive-frame-cont.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0726-udmabuf-Remove-deleted-map-unmap-handlers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0727-udmabuf-use-cache_sgt_mapping-option.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0728-udmabuf-add-a-pointer-to-the-miscdevice-in-dma-buf-p.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0729-udmabuf-separate-out-creating-destroying-scatter-tab.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0730-udmabuf-implement-begin_cpu_access-end_cpu_access-ho.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0731-udmabuf-fix-dma-buf-cpu-access.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0732-dma-buf-Add-dma-buf-heaps-framework.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0733-dma-buf-heaps-Add-heap-helpers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0734-dma-buf-heaps-Add-system-heap-to-dmabuf-heaps.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0735-dma-buf-heaps-Add-CMA-heap-to-dmabuf-heaps.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0736-kselftests-Add-dma-heap-test.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0737-dma-buf-heaps-Use-_IOCTL_-for-userspace-IOCTL-identi.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0738-dma-buf-heaps-Remove-redundant-heap-identifier-from-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0739-dma-buf-fix-resource-leak-on-ENOTTY-error-return-pat.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0740-dma-heap-Make-the-symbol-dma_heap_ioctl_cmds-static.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0741-ARM-dts-Enable-firmware-clocks-on-all-Pis.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0742-media-bcm2835-unicam-Always-service-interrupts.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0743-sc16is7xx-Fix-for-hardware-flow-control.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0744-drm-vc4-Fix-VIC-usage-with-Broadcast-RGB.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0745-staging-vc04_services-mmal-vchiq-Update-parameters-l.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0746-staging-vc04_services-bcm2835-codec-Request-headers-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0747-staging-vc04_services-bcm2835-codec-Avoid-fragmentin.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0748-staging-vc04_services-bcm2835-camera-Request-headers.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0749-overlays-Fix-audio-parameter-of-vc4-kms-v3d.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0750-Switch-to-snd_soc_dai_set_bclk_ratio.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0751-media-bcm2835-unicam-Retain-packing-information-on-G.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0752-zswap-Defer-zswap-initialisation.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0753-drm-vc4-Adopt-the-dma-configuration-from-the-HVS-or-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0754-drm-vc4-Add-FKMS-as-an-acceptable-node-for-dma-range.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0755-media-i2c-imx477-Return-correct-result-on-sensor-id-.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0756-staging-vchiq_arm-Clean-up-40-bit-DMA-support.patch create mode 100644 target/linux/bcm27xx/patches-5.4/950-0757-ARM-dts-Update-for-new-VCHIQ-BCM2711-DMA-support.patch diff --git a/target/linux/bcm27xx/bcm2708/config-5.4 b/target/linux/bcm27xx/bcm2708/config-5.4 index 1f12a36ee72..c4802bef7dd 100644 --- a/target/linux/bcm27xx/bcm2708/config-5.4 +++ b/target/linux/bcm27xx/bcm2708/config-5.4 @@ -43,6 +43,7 @@ CONFIG_ARM_ERRATA_411920=y CONFIG_ARM_HAS_SG_CHAIN=y CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_RASPBERRYPI_CPUFREQ is not set # CONFIG_ARM_SCMI_PROTOCOL is not set CONFIG_ARM_THUMB=y CONFIG_ARM_TIMER_SP804=y @@ -79,7 +80,7 @@ CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLK_BCM2835=y -# CONFIG_CLK_RASPBERRYPI is not set +CONFIG_CLK_RASPBERRYPI=y CONFIG_CLONE_BACKWARDS=y CONFIG_CMA=y CONFIG_CMA_ALIGNMENT=8 @@ -136,6 +137,9 @@ CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMADEVICES=y CONFIG_DMA_BCM2708=y CONFIG_DMA_BCM2835=y @@ -249,6 +253,7 @@ CONFIG_HZ_FIXED=0 CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_BRCMSTB is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INPUT=y @@ -342,6 +347,7 @@ CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y # CONFIG_RPIVID_MEM is not set CONFIG_SCSI=y # CONFIG_SCSI_LOWLEVEL is not set diff --git a/target/linux/bcm27xx/bcm2709/config-5.4 b/target/linux/bcm27xx/bcm2709/config-5.4 index c1630c599d8..67019438e6f 100644 --- a/target/linux/bcm27xx/bcm2709/config-5.4 +++ b/target/linux/bcm27xx/bcm2709/config-5.4 @@ -183,6 +183,9 @@ CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" CONFIG_DIMLIB=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMADEVICES=y CONFIG_DMA_BCM2708=y CONFIG_DMA_BCM2835=y @@ -317,6 +320,7 @@ CONFIG_HZ_FIXED=0 CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_BRCMSTB is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INPUT=y @@ -441,6 +445,7 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y CONFIG_RFS_ACCEL=y # CONFIG_RPIVID_MEM is not set CONFIG_RPS=y diff --git a/target/linux/bcm27xx/bcm2710/config-5.4 b/target/linux/bcm27xx/bcm2710/config-5.4 index 4a5b491b0fc..c83149212d0 100644 --- a/target/linux/bcm27xx/bcm2710/config-5.4 +++ b/target/linux/bcm27xx/bcm2710/config-5.4 @@ -224,6 +224,9 @@ CONFIG_CRYPTO_XTS=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMADEVICES=y CONFIG_DMA_BCM2708=y CONFIG_DMA_BCM2835=y @@ -232,6 +235,7 @@ CONFIG_DMA_DIRECT_REMAP=y CONFIG_DMA_ENGINE=y CONFIG_DMA_OF=y CONFIG_DMA_REMAP=y +CONFIG_DMA_SHARED_BUFFER=y CONFIG_DMA_VIRTUAL_CHANNELS=y CONFIG_DNOTIFY=y CONFIG_DRM_RCAR_WRITEBACK=y @@ -372,6 +376,7 @@ CONFIG_HZ_250=y CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_BRCMSTB is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 @@ -513,6 +518,7 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y CONFIG_RFS_ACCEL=y CONFIG_RODATA_FULL_DEFAULT_ENABLED=y # CONFIG_RPIVID_MEM is not set diff --git a/target/linux/bcm27xx/bcm2711/config-5.4 b/target/linux/bcm27xx/bcm2711/config-5.4 index abf6e8844a1..edc04e6e627 100644 --- a/target/linux/bcm27xx/bcm2711/config-5.4 +++ b/target/linux/bcm27xx/bcm2711/config-5.4 @@ -229,6 +229,9 @@ CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_DIMLIB=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMADEVICES=y CONFIG_DMA_BCM2708=y CONFIG_DMA_BCM2835=y @@ -237,6 +240,7 @@ CONFIG_DMA_DIRECT_REMAP=y CONFIG_DMA_ENGINE=y CONFIG_DMA_OF=y CONFIG_DMA_REMAP=y +CONFIG_DMA_SHARED_BUFFER=y CONFIG_DMA_VIRTUAL_CHANNELS=y CONFIG_DNOTIFY=y CONFIG_DRM_RCAR_WRITEBACK=y @@ -378,6 +382,7 @@ CONFIG_HZ_250=y CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_BRCMSTB is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 @@ -523,6 +528,7 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y CONFIG_RFS_ACCEL=y CONFIG_RODATA_FULL_DEFAULT_ENABLED=y # CONFIG_RPIVID_MEM is not set diff --git a/target/linux/bcm27xx/modules/sound.mk b/target/linux/bcm27xx/modules/sound.mk index 8d449a51fa2..a4aeb629c34 100644 --- a/target/linux/bcm27xx/modules/sound.mk +++ b/target/linux/bcm27xx/modules/sound.mk @@ -268,6 +268,33 @@ endef $(eval $(call KernelPackage,sound-soc-allo-katana-codec)) +define KernelPackage/sound-soc-audioinjector-isolated-soundcard + TITLE:=Support for AudioInjector Isolated soundcard + KCONFIG:= \ + CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD \ + CONFIG_SND_SOC_CS4271 \ + CONFIG_SND_SOC_CS4271_I2C + FILES:= \ + $(LINUX_DIR)/sound/soc/bcm/snd-soc-audioinjector-isolated-soundcard.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8731.ko + AUTOLOAD:=$(call AutoLoad,68,snd-soc-cs4271.o \ + snd-soc-cs4271-i2c \ + snd-soc-audioinjector-isolated-soundcard) + DEPENDS:= \ + kmod-sound-soc-bcm2835-i2s \ + +kmod-i2c-bcm2835 \ + +kmod-regmap-i2c \ + +kmod-regmap-spi + $(call AddDepends/sound) +endef + +define KernelPackage/sound-soc-audioinjector-isolated-soundcard/description + This package contains support for AudioInjector Isolated soundcard +endef + +$(eval $(call KernelPackage,sound-soc-audioinjector-isolated-soundcard)) + + define KernelPackage/sound-soc-audioinjector-octo-soundcard TITLE:=Support for AudioInjector Octo soundcard KCONFIG:= \ @@ -884,6 +911,28 @@ endef $(eval $(call KernelPackage,sound-soc-rpi-dac)) +define KernelPackage/sound-soc-merus-amp + TITLE:=Support for Infineon Merus Amp + KCONFIG:= \ + CONFIG_SND_SOC_MA120X0P + FILES:= \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-ma120x0p.ko + AUTOLOAD:=$(call AutoLoad,68,snd-soc-ma120x0p) + DEPENDS:= \ + kmod-sound-soc-bcm2835-i2s \ + +kmod-sound-soc-rpi-simple-soundcard \ + +kmod-i2c-bcm2835 \ + +kmod-regmap-i2c + $(call AddDepends/sound) +endef + +define KernelPackage/sound-soc-merus-amp/description + This package contains support for Infineon Merus Amp +endef + +$(eval $(call KernelPackage,sound-soc-merus-amp)) + + define KernelPackage/sound-soc-rpi-proto TITLE:=Support for RPi-PROTO KCONFIG:= \ diff --git a/target/linux/bcm27xx/modules/video.mk b/target/linux/bcm27xx/modules/video.mk index f1da7d83211..f7286cee3c7 100644 --- a/target/linux/bcm27xx/modules/video.mk +++ b/target/linux/bcm27xx/modules/video.mk @@ -33,12 +33,13 @@ define KernelPackage/drm-vc4 +kmod-sound-soc-core KCONFIG:= \ CONFIG_DRM_VC4 \ - CONFIG_DRM_VC4_HDMI_CEC=n \ + CONFIG_DRM_VC4_HDMI_CEC=y \ CONFIG_DRM_V3D=n \ CONFIG_DRM_TVE200=n FILES:= \ $(LINUX_DIR)/drivers/gpu/drm/vc4/vc4.ko \ - $(LINUX_DIR)/drivers/gpu/drm/drm_kms_helper.ko + $(LINUX_DIR)/drivers/gpu/drm/drm_kms_helper.ko \ + $(LINUX_DIR)/drivers/media/cec/cec.ko AUTOLOAD:=$(call AutoProbe,vc4) endef diff --git a/target/linux/bcm27xx/patches-5.4/950-0351-v3d_drv-Allow-clock-retrieval-by-name.patch b/target/linux/bcm27xx/patches-5.4/950-0351-v3d_drv-Allow-clock-retrieval-by-name.patch deleted file mode 100644 index 4529471b6c0..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0351-v3d_drv-Allow-clock-retrieval-by-name.patch +++ /dev/null @@ -1,23 +0,0 @@ -From a19956ff2941b73204c96127a22edef71b5d0d34 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 9 Sep 2019 23:50:44 +0100 -Subject: [PATCH] v3d_drv: Allow clock retrieval by name - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_drv.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -285,7 +285,9 @@ static int v3d_platform_drm_probe(struct - } - } - -- v3d->clk = devm_clk_get(dev, NULL); -+ v3d->clk = devm_clk_get(dev, "v3d"); -+ if (!v3d->clk) -+ v3d->clk = devm_clk_get(dev, NULL); - if (IS_ERR_OR_NULL(v3d->clk)) { - if (PTR_ERR(v3d->clk) != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk)); diff --git a/target/linux/bcm27xx/patches-5.4/950-0352-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch b/target/linux/bcm27xx/patches-5.4/950-0351-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0352-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch rename to target/linux/bcm27xx/patches-5.4/950-0351-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0355-clk-bcm2835-Disable-v3d-clock.patch b/target/linux/bcm27xx/patches-5.4/950-0352-clk-bcm2835-Disable-v3d-clock.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0355-clk-bcm2835-Disable-v3d-clock.patch rename to target/linux/bcm27xx/patches-5.4/950-0352-clk-bcm2835-Disable-v3d-clock.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0356-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch b/target/linux/bcm27xx/patches-5.4/950-0353-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0356-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch rename to target/linux/bcm27xx/patches-5.4/950-0353-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0357-arm-dts-Correct-Pi-4B-LED-values.patch b/target/linux/bcm27xx/patches-5.4/950-0354-arm-dts-Correct-Pi-4B-LED-values.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0357-arm-dts-Correct-Pi-4B-LED-values.patch rename to target/linux/bcm27xx/patches-5.4/950-0354-arm-dts-Correct-Pi-4B-LED-values.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0354-clk-raspberrypi-Also-support-v3d-clock.patch b/target/linux/bcm27xx/patches-5.4/950-0354-clk-raspberrypi-Also-support-v3d-clock.patch deleted file mode 100644 index b2a9363ad43..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0354-clk-raspberrypi-Also-support-v3d-clock.patch +++ /dev/null @@ -1,647 +0,0 @@ -From e2262c8ab4755ab574580611d7da22509f07871c Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 21 Aug 2019 14:55:56 +0100 -Subject: [PATCH] clk-raspberrypi: Also support v3d clock - -Signed-off-by: popcornmix ---- - drivers/clk/bcm/clk-raspberrypi.c | 501 ++++++++++++++++++++++++------ - 1 file changed, 412 insertions(+), 89 deletions(-) - ---- a/drivers/clk/bcm/clk-raspberrypi.c -+++ b/drivers/clk/bcm/clk-raspberrypi.c -@@ -15,33 +15,103 @@ - #include - #include - #include -- -+#include - #include - - #define RPI_FIRMWARE_ARM_CLK_ID 0x00000003 -+#define RPI_FIRMWARE_V3D_CLK_ID 0x00000005 - - #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) - #define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) - --/* -- * Even though the firmware interface alters 'pllb' the frequencies are -- * provided as per 'pllb_arm'. We need to scale before passing them trough. -- */ --#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2 -- - #define A2W_PLL_FRAC_BITS 20 - -+#define SOC_BCM2835 BIT(0) -+#define SOC_BCM2711 BIT(1) -+#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711) -+ - struct raspberrypi_clk { - struct device *dev; - struct rpi_firmware *firmware; - struct platform_device *cpufreq; -+}; -+ -+typedef int (*raspberrypi_clk_register)(struct raspberrypi_clk *rpi, -+ const void *data); -+ -+ -+/* assignment helper macros for different clock types */ -+#define _REGISTER(f, s, ...) { .clk_register = (raspberrypi_clk_register)f, \ -+ .supported = s, \ -+ .data = __VA_ARGS__ } -+#define REGISTER_PLL(s, ...) _REGISTER(&raspberrypi_register_pll, \ -+ s, \ -+ &(struct raspberrypi_pll_data) \ -+ {__VA_ARGS__}) -+#define REGISTER_PLL_DIV(s, ...) _REGISTER(&raspberrypi_register_pll_divider, \ -+ s, \ -+ &(struct raspberrypi_pll_divider_data) \ -+ {__VA_ARGS__}) -+#define REGISTER_CLK(s, ...) _REGISTER(&raspberrypi_register_clock, \ -+ s, \ -+ &(struct raspberrypi_clock_data) \ -+ {__VA_ARGS__}) -+ -+ -+struct raspberrypi_pll_data { -+ const char *name; -+ const char *const *parents; -+ int num_parents; -+ u32 clock_id; -+}; -+ -+struct raspberrypi_clock_data { -+ const char *name; -+ const char *const *parents; -+ int num_parents; -+ u32 flags; -+ u32 clock_id; -+}; -+ -+struct raspberrypi_pll_divider_data { -+ const char *name; -+ const char *divider_name; -+ const char *lookup; -+ const char *source_pll; -+ -+ u32 fixed_divider; -+ u32 flags; -+ u32 clock_id; -+}; - -- unsigned long min_rate; -- unsigned long max_rate; -+struct raspberrypi_clk_desc { -+ raspberrypi_clk_register clk_register; -+ unsigned int supported; -+ const void *data; -+}; - -- struct clk_hw pllb; -- struct clk_hw *pllb_arm; -- struct clk_lookup *pllb_arm_lookup; -+struct raspberrypi_clock { -+ struct clk_hw hw; -+ struct raspberrypi_clk *rpi; -+ u32 min_rate; -+ u32 max_rate; -+ const struct raspberrypi_clock_data *data; -+}; -+ -+struct raspberrypi_pll { -+ struct clk_hw hw; -+ struct raspberrypi_clk *rpi; -+ u32 min_rate; -+ u32 max_rate; -+ const struct raspberrypi_pll_data *data; -+}; -+ -+struct raspberrypi_pll_divider { -+ struct clk_divider div; -+ struct raspberrypi_clk *rpi; -+ u32 min_rate; -+ u32 max_rate; -+ const struct raspberrypi_pll_divider_data *data; - }; - - /* -@@ -83,56 +153,49 @@ static int raspberrypi_clock_property(st - return 0; - } - --static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) -+static int raspberrypi_fw_is_on(struct raspberrypi_clk *rpi, u32 clock_id, const char *name) - { -- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, -- pllb); - u32 val = 0; - int ret; - - ret = raspberrypi_clock_property(rpi->firmware, - RPI_FIRMWARE_GET_CLOCK_STATE, -- RPI_FIRMWARE_ARM_CLK_ID, &val); -+ clock_id, &val); - if (ret) - return 0; - - return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); - } - -- --static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, -- unsigned long parent_rate) -+static unsigned long raspberrypi_fw_get_rate(struct raspberrypi_clk *rpi, -+ u32 clock_id, const char *name, unsigned long parent_rate) - { -- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, -- pllb); - u32 val = 0; - int ret; - - ret = raspberrypi_clock_property(rpi->firmware, - RPI_FIRMWARE_GET_CLOCK_RATE, -- RPI_FIRMWARE_ARM_CLK_ID, -+ clock_id, - &val); - if (ret) -- return ret; -- -- return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; -+ dev_err_ratelimited(rpi->dev, "Failed to get %s frequency: %d", -+ name, ret); -+ return val; - } - --static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, -- unsigned long parent_rate) -+static int raspberrypi_fw_set_rate(struct raspberrypi_clk *rpi, -+ u32 clock_id, const char *name, u32 rate, -+ unsigned long parent_rate) - { -- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, -- pllb); -- u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; - int ret; - - ret = raspberrypi_clock_property(rpi->firmware, - RPI_FIRMWARE_SET_CLOCK_RATE, -- RPI_FIRMWARE_ARM_CLK_ID, -- &new_rate); -+ clock_id, -+ &rate); - if (ret) - dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", -- clk_hw_get_name(hw), ret); -+ name, ret); - - return ret; - } -@@ -141,16 +204,18 @@ static int raspberrypi_fw_pll_set_rate(s - * Sadly there is no firmware rate rounding interface. We borrowed it from - * clk-bcm2835. - */ --static int raspberrypi_pll_determine_rate(struct clk_hw *hw, -+static int raspberrypi_determine_rate(struct raspberrypi_clk *rpi, -+ u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate, - struct clk_rate_request *req) - { -- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, -- pllb); -+#if 1 -+ req->rate = clamp(req->rate, min_rate, max_rate); -+#else - u64 div, final_rate; - u32 ndiv, fdiv; - - /* We can't use req->rate directly as it would overflow */ -- final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate); -+ final_rate = clamp(req->rate, min_rate, max_rate); - - div = (u64)final_rate << A2W_PLL_FRAC_BITS; - do_div(div, req->best_parent_rate); -@@ -163,9 +228,129 @@ static int raspberrypi_pll_determine_rat - - req->rate = final_rate >> A2W_PLL_FRAC_BITS; - -+#endif - return 0; - } - -+static int raspberrypi_fw_clock_is_on(struct clk_hw *hw) -+{ -+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_clock_data *data = pll->data; -+ -+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name); -+} -+ -+static unsigned long raspberrypi_fw_clock_get_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_clock_data *data = pll->data; -+ -+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate); -+} -+ -+static int raspberrypi_fw_clock_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_clock_data *data = pll->data; -+ -+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate); -+} -+ -+static int raspberrypi_clock_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ struct raspberrypi_clock *pll = container_of(hw, struct raspberrypi_clock, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_clock_data *data = pll->data; -+ -+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req); -+} -+ -+static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) -+{ -+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_data *data = pll->data; -+ -+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name); -+} -+ -+static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_data *data = pll->data; -+ -+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate); -+} -+ -+static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_data *data = pll->data; -+ -+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate); -+} -+ -+static int raspberrypi_pll_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ struct raspberrypi_pll *pll = container_of(hw, struct raspberrypi_pll, hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_data *data = pll->data; -+ -+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req); -+} -+ -+ -+static int raspberrypi_fw_pll_div_is_on(struct clk_hw *hw) -+{ -+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_divider_data *data = pll->data; -+ -+ return raspberrypi_fw_is_on(rpi, data->clock_id, data->name); -+} -+ -+static unsigned long raspberrypi_fw_pll_div_get_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_divider_data *data = pll->data; -+ -+ return raspberrypi_fw_get_rate(rpi, data->clock_id, data->name, parent_rate); -+} -+ -+static int raspberrypi_fw_pll_div_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_divider_data *data = pll->data; -+ -+ return raspberrypi_fw_set_rate(rpi, data->clock_id, data->name, rate, parent_rate); -+} -+ -+static int raspberrypi_pll_div_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ struct raspberrypi_pll_divider *pll = container_of(hw, struct raspberrypi_pll_divider, div.hw); -+ struct raspberrypi_clk *rpi = pll->rpi; -+ const struct raspberrypi_pll_divider_data *data = pll->data; -+ -+ return raspberrypi_determine_rate(rpi, data->clock_id, data->name, pll->min_rate, pll->max_rate, req); -+} -+ -+ - static const struct clk_ops raspberrypi_firmware_pll_clk_ops = { - .is_prepared = raspberrypi_fw_pll_is_on, - .recalc_rate = raspberrypi_fw_pll_get_rate, -@@ -173,87 +358,225 @@ static const struct clk_ops raspberrypi_ - .determine_rate = raspberrypi_pll_determine_rate, - }; - --static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) -+static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = { -+ .is_prepared = raspberrypi_fw_pll_div_is_on, -+ .recalc_rate = raspberrypi_fw_pll_div_get_rate, -+ .set_rate = raspberrypi_fw_pll_div_set_rate, -+ .determine_rate = raspberrypi_pll_div_determine_rate, -+}; -+ -+static const struct clk_ops raspberrypi_firmware_clk_ops = { -+ .is_prepared = raspberrypi_fw_clock_is_on, -+ .recalc_rate = raspberrypi_fw_clock_get_rate, -+ .set_rate = raspberrypi_fw_clock_set_rate, -+ .determine_rate = raspberrypi_clock_determine_rate, -+}; -+ -+ -+static int raspberrypi_get_clock_range(struct raspberrypi_clk *rpi, u32 clock_id, u32 *min_rate, u32 *max_rate) - { -- u32 min_rate = 0, max_rate = 0; -+ int ret; -+ -+ /* Get min & max rates set by the firmware */ -+ ret = raspberrypi_clock_property(rpi->firmware, -+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE, -+ clock_id, -+ min_rate); -+ if (ret) { -+ dev_err(rpi->dev, "Failed to get clock %d min freq: %d (%d)\n", -+ clock_id, *min_rate, ret); -+ return ret; -+ } -+ -+ ret = raspberrypi_clock_property(rpi->firmware, -+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE, -+ clock_id, -+ max_rate); -+ if (ret) { -+ dev_err(rpi->dev, "Failed to get clock %d max freq: %d (%d)\n", -+ clock_id, *max_rate, ret); -+ return ret; -+ } -+ return 0; -+} -+ -+ -+static int raspberrypi_register_pll(struct raspberrypi_clk *rpi, -+ const struct raspberrypi_pll_data *data) -+{ -+ struct raspberrypi_pll *pll; - struct clk_init_data init; - int ret; - - memset(&init, 0, sizeof(init)); - - /* All of the PLLs derive from the external oscillator. */ -- init.parent_names = (const char *[]){ "osc" }; -- init.num_parents = 1; -- init.name = "pllb"; -+ init.parent_names = data->parents; -+ init.num_parents = data->num_parents; -+ init.name = data->name; - init.ops = &raspberrypi_firmware_pll_clk_ops; - init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED; - -- /* Get min & max rates set by the firmware */ -- ret = raspberrypi_clock_property(rpi->firmware, -- RPI_FIRMWARE_GET_MIN_CLOCK_RATE, -- RPI_FIRMWARE_ARM_CLK_ID, -- &min_rate); -+ pll = kzalloc(sizeof(*pll), GFP_KERNEL); -+ if (!pll) -+ return -ENOMEM; -+ pll->rpi = rpi; -+ pll->data = data; -+ pll->hw.init = &init; -+ -+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &pll->min_rate, &pll->max_rate); - if (ret) { -- dev_err(rpi->dev, "Failed to get %s min freq: %d\n", -- init.name, ret); -+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret); - return ret; - } - -- ret = raspberrypi_clock_property(rpi->firmware, -- RPI_FIRMWARE_GET_MAX_CLOCK_RATE, -- RPI_FIRMWARE_ARM_CLK_ID, -- &max_rate); -+ ret = devm_clk_hw_register(rpi->dev, &pll->hw); - if (ret) { -- dev_err(rpi->dev, "Failed to get %s max freq: %d\n", -- init.name, ret); -+ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret); - return ret; - } -+ return 0; -+} - -- if (!min_rate || !max_rate) { -- dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n", -- min_rate, max_rate); -- return -EINVAL; -- } -+static int -+raspberrypi_register_pll_divider(struct raspberrypi_clk *rpi, -+ const struct raspberrypi_pll_divider_data *data) -+{ -+ struct raspberrypi_pll_divider *divider; -+ struct clk_init_data init; -+ int ret; -+ -+ memset(&init, 0, sizeof(init)); -+ -+ init.parent_names = &data->source_pll; -+ init.num_parents = 1; -+ init.name = data->name; -+ init.ops = &raspberrypi_firmware_pll_divider_clk_ops; -+ init.flags = data->flags | CLK_IGNORE_UNUSED; - -- dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n", -- min_rate, max_rate); -+ divider = devm_kzalloc(rpi->dev, sizeof(*divider), GFP_KERNEL); -+ if (!divider) -+ return -ENOMEM; -+ -+ divider->div.hw.init = &init; -+ divider->rpi = rpi; -+ divider->data = data; -+ -+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, ÷r->min_rate, ÷r->max_rate); -+ if (ret) { -+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret); -+ return ret; -+ } - -- rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; -- rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; -+ ret = devm_clk_hw_register(rpi->dev, ÷r->div.hw); -+ if (ret) { -+ dev_err(rpi->dev, "%s: devm_clk_hw_register(%s) failed: %d\n", __func__, init.name, ret); -+ return ret; -+ } - -- rpi->pllb.init = &init; -+ /* -+ * PLLH's channels have a fixed divide by 10 afterwards, which -+ * is what our consumers are actually using. -+ */ -+ if (data->fixed_divider != 0) { -+ struct clk_lookup *lookup; -+ struct clk_hw *clk = clk_hw_register_fixed_factor(rpi->dev, -+ data->divider_name, -+ data->name, -+ CLK_SET_RATE_PARENT, -+ 1, -+ data->fixed_divider); -+ if (IS_ERR(clk)) { -+ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk)); -+ return PTR_ERR(clk); -+ } -+ if (data->lookup) { -+ lookup = clkdev_hw_create(clk, NULL, data->lookup); -+ if (IS_ERR(lookup)) { -+ dev_err(rpi->dev, "%s: clk_hw_register_fixed_factor(%s) failed: %ld\n", __func__, init.name, PTR_ERR(lookup)); -+ return PTR_ERR(lookup); -+ } -+ } -+ } - -- return devm_clk_hw_register(rpi->dev, &rpi->pllb); -+ return 0; - } - --static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) -+static int raspberrypi_register_clock(struct raspberrypi_clk *rpi, -+ const struct raspberrypi_clock_data *data) - { -- rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev, -- "pllb_arm", "pllb", -- CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, -- 1, 2); -- if (IS_ERR(rpi->pllb_arm)) { -- dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); -- return PTR_ERR(rpi->pllb_arm); -- } -+ struct raspberrypi_clock *clock; -+ struct clk_init_data init; -+ struct clk *clk; -+ int ret; -+ -+ memset(&init, 0, sizeof(init)); -+ init.parent_names = data->parents; -+ init.num_parents = data->num_parents; -+ init.name = data->name; -+ init.flags = data->flags | CLK_IGNORE_UNUSED; - -- rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); -- if (!rpi->pllb_arm_lookup) { -- dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); -- clk_hw_unregister_fixed_factor(rpi->pllb_arm); -+ init.ops = &raspberrypi_firmware_clk_ops; -+ -+ clock = devm_kzalloc(rpi->dev, sizeof(*clock), GFP_KERNEL); -+ if (!clock) - return -ENOMEM; -- } - -+ clock->rpi = rpi; -+ clock->data = data; -+ clock->hw.init = &init; -+ -+ ret = raspberrypi_get_clock_range(rpi, data->clock_id, &clock->min_rate, &clock->max_rate); -+ if (ret) { -+ dev_err(rpi->dev, "%s: raspberrypi_get_clock_range(%s) failed: %d\n", __func__, init.name, ret); -+ return ret; -+ } -+ clk = devm_clk_register(rpi->dev, &clock->hw); -+ if (IS_ERR(clk)) { -+ dev_err(rpi->dev, "%s: devm_clk_register(%s) failed: %ld\n", __func__, init.name, PTR_ERR(clk)); -+ return PTR_ERR(clk); -+ } -+ ret = clk_register_clkdev(clk, init.name, NULL); -+ if (ret) { -+ dev_err(rpi->dev, "%s: clk_register_clkdev(%s) failed: %d\n", __func__, init.name, ret); -+ return ret; -+ } - return 0; - } - -+ -+/* -+ * the real definition of all the pll, pll_dividers and clocks -+ * these make use of the above REGISTER_* macros -+ */ -+static const struct raspberrypi_clk_desc clk_desc_array[] = { -+ /* the PLL + PLL dividers */ -+ [BCM2835_CLOCK_V3D] = REGISTER_CLK( -+ SOC_ALL, -+ .name = "v3d", -+ .parents = (const char *[]){ "osc" }, -+ .num_parents = 1, -+ .clock_id = RPI_FIRMWARE_V3D_CLK_ID), -+ [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV( -+ SOC_ALL, -+ .name = "pllb", -+ .source_pll = "osc", -+ .divider_name = "pllb_arm", -+ .lookup = "cpu0", -+ .fixed_divider = 1, -+ .clock_id = RPI_FIRMWARE_ARM_CLK_ID, -+ .flags = CLK_SET_RATE_PARENT), -+}; -+ - static int raspberrypi_clk_probe(struct platform_device *pdev) - { - struct device_node *firmware_node; - struct device *dev = &pdev->dev; - struct rpi_firmware *firmware; - struct raspberrypi_clk *rpi; -- int ret; -+ const struct raspberrypi_clk_desc *desc; -+ const size_t asize = ARRAY_SIZE(clk_desc_array); -+ int i; - - firmware_node = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); -@@ -275,16 +598,16 @@ static int raspberrypi_clk_probe(struct - rpi->firmware = firmware; - platform_set_drvdata(pdev, rpi); - -- ret = raspberrypi_register_pllb(rpi); -- if (ret) { -- dev_err(dev, "Failed to initialize pllb, %d\n", ret); -- return ret; -+ for (i = 0; i < asize; i++) { -+ desc = &clk_desc_array[i]; -+ if (desc->clk_register && desc->data /*&& -+ (desc->supported & pdata->soc)*/) { -+ int ret = desc->clk_register(rpi, desc->data); -+ if (ret) -+ return ret; -+ } - } - -- ret = raspberrypi_register_pllb_arm(rpi); -- if (ret) -- return ret; -- - rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", - -1, NULL, 0); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0358-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch b/target/linux/bcm27xx/patches-5.4/950-0355-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0358-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch rename to target/linux/bcm27xx/patches-5.4/950-0355-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0359-arm-dts-2711-Add-pcie0-alias.patch b/target/linux/bcm27xx/patches-5.4/950-0356-arm-dts-2711-Add-pcie0-alias.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0359-arm-dts-2711-Add-pcie0-alias.patch rename to target/linux/bcm27xx/patches-5.4/950-0356-arm-dts-2711-Add-pcie0-alias.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0360-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch b/target/linux/bcm27xx/patches-5.4/950-0357-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0360-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch rename to target/linux/bcm27xx/patches-5.4/950-0357-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0361-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0358-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0361-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch rename to target/linux/bcm27xx/patches-5.4/950-0358-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0362-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch b/target/linux/bcm27xx/patches-5.4/950-0359-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0362-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch rename to target/linux/bcm27xx/patches-5.4/950-0359-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0363-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch b/target/linux/bcm27xx/patches-5.4/950-0360-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0363-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch rename to target/linux/bcm27xx/patches-5.4/950-0360-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0364-overlays-Make-mcp342x-run-time-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0361-overlays-Make-mcp342x-run-time-compatible.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0364-overlays-Make-mcp342x-run-time-compatible.patch rename to target/linux/bcm27xx/patches-5.4/950-0361-overlays-Make-mcp342x-run-time-compatible.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0365-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch b/target/linux/bcm27xx/patches-5.4/950-0362-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0365-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch rename to target/linux/bcm27xx/patches-5.4/950-0362-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0366-sound-soc-only-first-codec-is-master-in-multicodec-s.patch b/target/linux/bcm27xx/patches-5.4/950-0363-sound-soc-only-first-codec-is-master-in-multicodec-s.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0366-sound-soc-only-first-codec-is-master-in-multicodec-s.patch rename to target/linux/bcm27xx/patches-5.4/950-0363-sound-soc-only-first-codec-is-master-in-multicodec-s.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0367-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch b/target/linux/bcm27xx/patches-5.4/950-0364-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0367-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch rename to target/linux/bcm27xx/patches-5.4/950-0364-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0368-overlays-dht11-Allow-multiple-instantiation.patch b/target/linux/bcm27xx/patches-5.4/950-0365-overlays-dht11-Allow-multiple-instantiation.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0368-overlays-dht11-Allow-multiple-instantiation.patch rename to target/linux/bcm27xx/patches-5.4/950-0365-overlays-dht11-Allow-multiple-instantiation.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0369-overlays-i2c-rtc-Add-pcf85363-support.patch b/target/linux/bcm27xx/patches-5.4/950-0366-overlays-i2c-rtc-Add-pcf85363-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0369-overlays-i2c-rtc-Add-pcf85363-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0366-overlays-i2c-rtc-Add-pcf85363-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0370-pinctrl-bcm2835-Remove-gpiochip-on-error.patch b/target/linux/bcm27xx/patches-5.4/950-0367-pinctrl-bcm2835-Remove-gpiochip-on-error.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0370-pinctrl-bcm2835-Remove-gpiochip-on-error.patch rename to target/linux/bcm27xx/patches-5.4/950-0367-pinctrl-bcm2835-Remove-gpiochip-on-error.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0371-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch b/target/linux/bcm27xx/patches-5.4/950-0368-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0371-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch rename to target/linux/bcm27xx/patches-5.4/950-0368-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0372-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch b/target/linux/bcm27xx/patches-5.4/950-0369-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0372-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch rename to target/linux/bcm27xx/patches-5.4/950-0369-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch rename to target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch rename to target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0372-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch rename to target/linux/bcm27xx/patches-5.4/950-0372-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch b/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch rename to target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0377-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch b/target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0377-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch rename to target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch rename to target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0379-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0379-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch rename to target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0380-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch b/target/linux/bcm27xx/patches-5.4/950-0377-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0380-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch rename to target/linux/bcm27xx/patches-5.4/950-0377-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0381-net-bcmgenet-Add-RGMII_RXID-support.patch b/target/linux/bcm27xx/patches-5.4/950-0378-net-bcmgenet-Add-RGMII_RXID-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0381-net-bcmgenet-Add-RGMII_RXID-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0378-net-bcmgenet-Add-RGMII_RXID-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0382-ARM-dts-bcm2838-Backport-genet-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0379-ARM-dts-bcm2838-Backport-genet-from-upstream.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0382-ARM-dts-bcm2838-Backport-genet-from-upstream.patch rename to target/linux/bcm27xx/patches-5.4/950-0379-ARM-dts-bcm2838-Backport-genet-from-upstream.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0383-ARM-bcm-Backport-BCM2711-support-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0380-ARM-bcm-Backport-BCM2711-support-from-upstream.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0383-ARM-bcm-Backport-BCM2711-support-from-upstream.patch rename to target/linux/bcm27xx/patches-5.4/950-0380-ARM-bcm-Backport-BCM2711-support-from-upstream.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0384-hwrng-iproc-rng200-Add-support-for-BCM2711.patch b/target/linux/bcm27xx/patches-5.4/950-0381-hwrng-iproc-rng200-Add-support-for-BCM2711.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0384-hwrng-iproc-rng200-Add-support-for-BCM2711.patch rename to target/linux/bcm27xx/patches-5.4/950-0381-hwrng-iproc-rng200-Add-support-for-BCM2711.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0385-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0382-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0385-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch rename to target/linux/bcm27xx/patches-5.4/950-0382-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch b/target/linux/bcm27xx/patches-5.4/950-0383-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch rename to target/linux/bcm27xx/patches-5.4/950-0383-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch b/target/linux/bcm27xx/patches-5.4/950-0384-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch rename to target/linux/bcm27xx/patches-5.4/950-0384-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0388-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch b/target/linux/bcm27xx/patches-5.4/950-0385-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0388-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch rename to target/linux/bcm27xx/patches-5.4/950-0385-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0389-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch b/target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0389-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch rename to target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0390-driver-char-rpimem-Add-SPDX-licence-header.patch b/target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpimem-Add-SPDX-licence-header.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0390-driver-char-rpimem-Add-SPDX-licence-header.patch rename to target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpimem-Add-SPDX-licence-header.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0391-driver-char-rpivid-Fix-access-to-freed-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0388-driver-char-rpivid-Fix-access-to-freed-memory.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0391-driver-char-rpivid-Fix-access-to-freed-memory.patch rename to target/linux/bcm27xx/patches-5.4/950-0388-driver-char-rpivid-Fix-access-to-freed-memory.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0392-add-BME680-to-i2c-sensor-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0389-add-BME680-to-i2c-sensor-overlay.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0392-add-BME680-to-i2c-sensor-overlay.patch rename to target/linux/bcm27xx/patches-5.4/950-0389-add-BME680-to-i2c-sensor-overlay.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0393-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch b/target/linux/bcm27xx/patches-5.4/950-0390-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0393-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch rename to target/linux/bcm27xx/patches-5.4/950-0390-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0394-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch b/target/linux/bcm27xx/patches-5.4/950-0391-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0394-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch rename to target/linux/bcm27xx/patches-5.4/950-0391-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0395-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch b/target/linux/bcm27xx/patches-5.4/950-0392-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0395-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch rename to target/linux/bcm27xx/patches-5.4/950-0392-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0396-Add-universal-device-tree-overlay-for-SPI-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0393-Add-universal-device-tree-overlay-for-SPI-devices.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0396-Add-universal-device-tree-overlay-for-SPI-devices.patch rename to target/linux/bcm27xx/patches-5.4/950-0393-Add-universal-device-tree-overlay-for-SPI-devices.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0397-sound-Add-the-HiFiBerry-DAC-HD-version.patch b/target/linux/bcm27xx/patches-5.4/950-0394-sound-Add-the-HiFiBerry-DAC-HD-version.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0397-sound-Add-the-HiFiBerry-DAC-HD-version.patch rename to target/linux/bcm27xx/patches-5.4/950-0394-sound-Add-the-HiFiBerry-DAC-HD-version.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0398-Initialise-rpi-firmware-before-clk-bcm2835.patch b/target/linux/bcm27xx/patches-5.4/950-0395-Initialise-rpi-firmware-before-clk-bcm2835.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0398-Initialise-rpi-firmware-before-clk-bcm2835.patch rename to target/linux/bcm27xx/patches-5.4/950-0395-Initialise-rpi-firmware-before-clk-bcm2835.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0399-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch b/target/linux/bcm27xx/patches-5.4/950-0396-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0399-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch rename to target/linux/bcm27xx/patches-5.4/950-0396-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0400-overlays-Use-preferred-compatible-strings.patch b/target/linux/bcm27xx/patches-5.4/950-0397-overlays-Use-preferred-compatible-strings.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0400-overlays-Use-preferred-compatible-strings.patch rename to target/linux/bcm27xx/patches-5.4/950-0397-overlays-Use-preferred-compatible-strings.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0401-tty-amba-pl011-Add-un-throttle-support.patch b/target/linux/bcm27xx/patches-5.4/950-0398-tty-amba-pl011-Add-un-throttle-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0401-tty-amba-pl011-Add-un-throttle-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0398-tty-amba-pl011-Add-un-throttle-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0402-Fix-i2c-pwm-pca9685a-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0399-Fix-i2c-pwm-pca9685a-overlay.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0402-Fix-i2c-pwm-pca9685a-overlay.patch rename to target/linux/bcm27xx/patches-5.4/950-0399-Fix-i2c-pwm-pca9685a-overlay.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0403-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0403-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch rename to target/linux/bcm27xx/patches-5.4/950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0404-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch b/target/linux/bcm27xx/patches-5.4/950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0404-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch rename to target/linux/bcm27xx/patches-5.4/950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0405-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0402-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0405-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch rename to target/linux/bcm27xx/patches-5.4/950-0402-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0406-pisound-Added-reading-Pisound-board-hardware-revisio.patch b/target/linux/bcm27xx/patches-5.4/950-0403-pisound-Added-reading-Pisound-board-hardware-revisio.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0406-pisound-Added-reading-Pisound-board-hardware-revisio.patch rename to target/linux/bcm27xx/patches-5.4/950-0403-pisound-Added-reading-Pisound-board-hardware-revisio.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0407-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch b/target/linux/bcm27xx/patches-5.4/950-0404-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0407-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch rename to target/linux/bcm27xx/patches-5.4/950-0404-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0408-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch b/target/linux/bcm27xx/patches-5.4/950-0405-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0408-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch rename to target/linux/bcm27xx/patches-5.4/950-0405-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0409-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0406-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0409-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch rename to target/linux/bcm27xx/patches-5.4/950-0406-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch b/target/linux/bcm27xx/patches-5.4/950-0407-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch rename to target/linux/bcm27xx/patches-5.4/950-0407-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0411-tty-amba-pl011-Avoid-rare-write-when-full-error.patch b/target/linux/bcm27xx/patches-5.4/950-0408-tty-amba-pl011-Avoid-rare-write-when-full-error.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0411-tty-amba-pl011-Avoid-rare-write-when-full-error.patch rename to target/linux/bcm27xx/patches-5.4/950-0408-tty-amba-pl011-Avoid-rare-write-when-full-error.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0412-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch b/target/linux/bcm27xx/patches-5.4/950-0409-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0412-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch rename to target/linux/bcm27xx/patches-5.4/950-0409-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0413-overlays-Correct-the-eth_led-colour-assignments.patch b/target/linux/bcm27xx/patches-5.4/950-0410-overlays-Correct-the-eth_led-colour-assignments.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0413-overlays-Correct-the-eth_led-colour-assignments.patch rename to target/linux/bcm27xx/patches-5.4/950-0410-overlays-Correct-the-eth_led-colour-assignments.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0411-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch rename to target/linux/bcm27xx/patches-5.4/950-0411-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0415-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch b/target/linux/bcm27xx/patches-5.4/950-0412-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0415-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch rename to target/linux/bcm27xx/patches-5.4/950-0412-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0416-overlays-dwc2-Increase-RX-FIFO-size.patch b/target/linux/bcm27xx/patches-5.4/950-0413-overlays-dwc2-Increase-RX-FIFO-size.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0416-overlays-dwc2-Increase-RX-FIFO-size.patch rename to target/linux/bcm27xx/patches-5.4/950-0413-overlays-dwc2-Increase-RX-FIFO-size.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0417-overlays-Fix-mcp23017-s-addr-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0414-overlays-Fix-mcp23017-s-addr-parameter.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0417-overlays-Fix-mcp23017-s-addr-parameter.patch rename to target/linux/bcm27xx/patches-5.4/950-0414-overlays-Fix-mcp23017-s-addr-parameter.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0418-SQUASH-Fix-spi-driver-compiler-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0415-SQUASH-Fix-spi-driver-compiler-warnings.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0418-SQUASH-Fix-spi-driver-compiler-warnings.patch rename to target/linux/bcm27xx/patches-5.4/950-0415-SQUASH-Fix-spi-driver-compiler-warnings.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0419-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0416-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0419-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch rename to target/linux/bcm27xx/patches-5.4/950-0416-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch b/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch rename to target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch b/target/linux/bcm27xx/patches-5.4/950-0418-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch rename to target/linux/bcm27xx/patches-5.4/950-0418-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch b/target/linux/bcm27xx/patches-5.4/950-0419-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0419-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch rename to target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch b/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch b/target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch rename to target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Rebuild-downstream-DTS-files.patch b/target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Rebuild-downstream-DTS-files.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Rebuild-downstream-DTS-files.patch rename to target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Rebuild-downstream-DTS-files.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0424-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch rename to target/linux/bcm27xx/patches-5.4/950-0424-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0428-thermal-brcmstb_thermal-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0425-thermal-brcmstb_thermal-Correct-SoC-name.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0428-thermal-brcmstb_thermal-Correct-SoC-name.patch rename to target/linux/bcm27xx/patches-5.4/950-0425-thermal-brcmstb_thermal-Correct-SoC-name.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0429-hwrng-iproc-rng200-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0426-hwrng-iproc-rng200-Correct-SoC-name.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0429-hwrng-iproc-rng200-Correct-SoC-name.patch rename to target/linux/bcm27xx/patches-5.4/950-0426-hwrng-iproc-rng200-Correct-SoC-name.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0427-ARM-dts-Correct-SoC-name.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-Correct-SoC-name.patch rename to target/linux/bcm27xx/patches-5.4/950-0427-ARM-dts-Correct-SoC-name.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0431-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch b/target/linux/bcm27xx/patches-5.4/950-0428-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0431-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch rename to target/linux/bcm27xx/patches-5.4/950-0428-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0432-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0429-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0432-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch rename to target/linux/bcm27xx/patches-5.4/950-0429-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0433-staging-vchiq_arm-Add-a-matching-unregister-call.patch b/target/linux/bcm27xx/patches-5.4/950-0430-staging-vchiq_arm-Add-a-matching-unregister-call.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0433-staging-vchiq_arm-Add-a-matching-unregister-call.patch rename to target/linux/bcm27xx/patches-5.4/950-0430-staging-vchiq_arm-Add-a-matching-unregister-call.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0434-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch b/target/linux/bcm27xx/patches-5.4/950-0431-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0434-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch rename to target/linux/bcm27xx/patches-5.4/950-0431-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch b/target/linux/bcm27xx/patches-5.4/950-0432-ARM-dts-overlays-Create-custom-clocks-in.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch rename to target/linux/bcm27xx/patches-5.4/950-0432-ARM-dts-overlays-Create-custom-clocks-in.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0433-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch rename to target/linux/bcm27xx/patches-5.4/950-0433-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0434-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch rename to target/linux/bcm27xx/patches-5.4/950-0434-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0435-of-overlay-Correct-symbol-path-fixups.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0438-of-overlay-Correct-symbol-path-fixups.patch rename to target/linux/bcm27xx/patches-5.4/950-0435-of-overlay-Correct-symbol-path-fixups.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0436-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch rename to target/linux/bcm27xx/patches-5.4/950-0436-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0437-of-address-Introduce-of_get_next_dma_parent-helper.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch rename to target/linux/bcm27xx/patches-5.4/950-0437-of-address-Introduce-of_get_next_dma_parent-helper.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0438-of-address-Follow-DMA-parent-for-dma-coherent.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch rename to target/linux/bcm27xx/patches-5.4/950-0438-of-address-Follow-DMA-parent-for-dma-coherent.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0439-of-Factor-out-addr-size-cells-parsing.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0442-of-Factor-out-addr-size-cells-parsing.patch rename to target/linux/bcm27xx/patches-5.4/950-0439-of-Factor-out-addr-size-cells-parsing.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0440-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch rename to target/linux/bcm27xx/patches-5.4/950-0440-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0441-of-Make-of_dma_get_range-work-on-bus-nodes.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch rename to target/linux/bcm27xx/patches-5.4/950-0441-of-Make-of_dma_get_range-work-on-bus-nodes.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0442-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch rename to target/linux/bcm27xx/patches-5.4/950-0442-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0443-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch rename to target/linux/bcm27xx/patches-5.4/950-0443-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0444-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch rename to target/linux/bcm27xx/patches-5.4/950-0444-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0445-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch rename to target/linux/bcm27xx/patches-5.4/950-0445-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0446-resource-Add-a-resource_list_first_type-helper.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0449-resource-Add-a-resource_list_first_type-helper.patch rename to target/linux/bcm27xx/patches-5.4/950-0446-resource-Add-a-resource_list_first_type-helper.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0447-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch rename to target/linux/bcm27xx/patches-5.4/950-0447-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0448-x86-PCI-sta2x11-use-default-DMA-address-translation.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch rename to target/linux/bcm27xx/patches-5.4/950-0448-x86-PCI-sta2x11-use-default-DMA-address-translation.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0449-PCI-of-Add-inbound-resource-parsing-to-helpers.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch rename to target/linux/bcm27xx/patches-5.4/950-0449-PCI-of-Add-inbound-resource-parsing-to-helpers.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0453-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-unify-the-dma_capable-definitions.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0453-dma-direct-unify-the-dma_capable-definitions.patch rename to target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-unify-the-dma_capable-definitions.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch rename to target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0452-dma-direct-exclude-dma_direct_map_resource-from-the-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch rename to target/linux/bcm27xx/patches-5.4/950-0452-dma-direct-exclude-dma_direct_map_resource-from-the-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0453-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch rename to target/linux/bcm27xx/patches-5.4/950-0453-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0454-ARM-dts-bcm2711-Enable-PCIe-controller.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch rename to target/linux/bcm27xx/patches-5.4/950-0454-ARM-dts-bcm2711-Enable-PCIe-controller.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0455-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch rename to target/linux/bcm27xx/patches-5.4/950-0455-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0456-PCI-brcmstb-Add-MSI-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-MSI-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0456-PCI-brcmstb-Add-MSI-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch b/target/linux/bcm27xx/patches-5.4/950-0457-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch rename to target/linux/bcm27xx/patches-5.4/950-0457-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch b/target/linux/bcm27xx/patches-5.4/950-0458-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch rename to target/linux/bcm27xx/patches-5.4/950-0458-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch b/target/linux/bcm27xx/patches-5.4/950-0459-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch rename to target/linux/bcm27xx/patches-5.4/950-0459-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch b/target/linux/bcm27xx/patches-5.4/950-0460-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch rename to target/linux/bcm27xx/patches-5.4/950-0460-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0464-overlays-imx219-Correct-link-frequency-to-match-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0461-overlays-imx219-Correct-link-frequency-to-match-the-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0464-overlays-imx219-Correct-link-frequency-to-match-the-.patch rename to target/linux/bcm27xx/patches-5.4/950-0461-overlays-imx219-Correct-link-frequency-to-match-the-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0465-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch b/target/linux/bcm27xx/patches-5.4/950-0462-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0465-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch rename to target/linux/bcm27xx/patches-5.4/950-0462-Kbuild-Allow-.dtbo-overlays-to-be-built-adjust.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0466-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch b/target/linux/bcm27xx/patches-5.4/950-0463-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0466-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch rename to target/linux/bcm27xx/patches-5.4/950-0463-media-ov5647-Fix-return-codes-from-ov5647_write-ov56.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch b/target/linux/bcm27xx/patches-5.4/950-0464-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch rename to target/linux/bcm27xx/patches-5.4/950-0464-media-ov5647-Add-basic-support-for-multiple-sensor-m.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0468-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch b/target/linux/bcm27xx/patches-5.4/950-0465-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0468-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch rename to target/linux/bcm27xx/patches-5.4/950-0465-media-ov5647-Add-V4L2-controls-for-analogue-gain-exp.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0469-media-ov5647-Add-extra-10-bit-sensor-modes.patch b/target/linux/bcm27xx/patches-5.4/950-0466-media-ov5647-Add-extra-10-bit-sensor-modes.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0469-media-ov5647-Add-extra-10-bit-sensor-modes.patch rename to target/linux/bcm27xx/patches-5.4/950-0466-media-ov5647-Add-extra-10-bit-sensor-modes.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0470-media-ov5647-change-defaults-to-better-match-raw-cam.patch b/target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-change-defaults-to-better-match-raw-cam.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0470-media-ov5647-change-defaults-to-better-match-raw-cam.patch rename to target/linux/bcm27xx/patches-5.4/950-0467-media-ov5647-change-defaults-to-better-match-raw-cam.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0471-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch b/target/linux/bcm27xx/patches-5.4/950-0468-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0471-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch rename to target/linux/bcm27xx/patches-5.4/950-0468-drm-vc4-fkms-Change-crtc_state-structure-name-to-avo.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0472-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch b/target/linux/bcm27xx/patches-5.4/950-0469-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0472-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch rename to target/linux/bcm27xx/patches-5.4/950-0469-drm-fourcc-Add-packed-10bit-YUV-4-2-0-format.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0473-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0470-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0473-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch rename to target/linux/bcm27xx/patches-5.4/950-0470-drm-vc4-Add-DRM_FORMAT_P030-support-to-firmware-kms.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0474-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch b/target/linux/bcm27xx/patches-5.4/950-0471-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0474-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch rename to target/linux/bcm27xx/patches-5.4/950-0471-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0475-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch b/target/linux/bcm27xx/patches-5.4/950-0472-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0475-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch rename to target/linux/bcm27xx/patches-5.4/950-0472-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0476-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch b/target/linux/bcm27xx/patches-5.4/950-0473-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0476-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch rename to target/linux/bcm27xx/patches-5.4/950-0473-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch b/target/linux/bcm27xx/patches-5.4/950-0474-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch rename to target/linux/bcm27xx/patches-5.4/950-0474-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0478-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch b/target/linux/bcm27xx/patches-5.4/950-0475-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0478-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch rename to target/linux/bcm27xx/patches-5.4/950-0475-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0479-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch b/target/linux/bcm27xx/patches-5.4/950-0476-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0479-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch rename to target/linux/bcm27xx/patches-5.4/950-0476-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch b/target/linux/bcm27xx/patches-5.4/950-0477-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch rename to target/linux/bcm27xx/patches-5.4/950-0477-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch b/target/linux/bcm27xx/patches-5.4/950-0478-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch rename to target/linux/bcm27xx/patches-5.4/950-0478-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Accept-extras-directly-after.patch b/target/linux/bcm27xx/patches-5.4/950-0479-drm-modes-parse_cmdline-Accept-extras-directly-after.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Accept-extras-directly-after.patch rename to target/linux/bcm27xx/patches-5.4/950-0479-drm-modes-parse_cmdline-Accept-extras-directly-after.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch b/target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch rename to target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch b/target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch rename to target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch b/target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch rename to target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch b/target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch rename to target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch b/target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch rename to target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch b/target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch rename to target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch b/target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch rename to target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0490-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch b/target/linux/bcm27xx/patches-5.4/950-0487-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0490-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch rename to target/linux/bcm27xx/patches-5.4/950-0487-drm-v3d-Replace-wait_for-macros-to-remove-use-of-msl.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0491-Reduce-noise-from-rpi-poe-hat-fan.patch b/target/linux/bcm27xx/patches-5.4/950-0488-Reduce-noise-from-rpi-poe-hat-fan.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0491-Reduce-noise-from-rpi-poe-hat-fan.patch rename to target/linux/bcm27xx/patches-5.4/950-0488-Reduce-noise-from-rpi-poe-hat-fan.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0492-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0489-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0492-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch rename to target/linux/bcm27xx/patches-5.4/950-0489-add-Sensirion-SPS30-to-i2c-sensor-overlay.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0493-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch b/target/linux/bcm27xx/patches-5.4/950-0490-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0493-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch rename to target/linux/bcm27xx/patches-5.4/950-0490-media-add-V4L2_CTRL_TYPE_AREA-control-type.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0494-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch b/target/linux/bcm27xx/patches-5.4/950-0491-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0494-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch rename to target/linux/bcm27xx/patches-5.4/950-0491-media-add-V4L2_CID_UNIT_CELL_SIZE-control.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-common-add-pixel-encoding-support.patch b/target/linux/bcm27xx/patches-5.4/950-0492-media-v4l2-common-add-pixel-encoding-support.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-common-add-pixel-encoding-support.patch rename to target/linux/bcm27xx/patches-5.4/950-0492-media-v4l2-common-add-pixel-encoding-support.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0496-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch b/target/linux/bcm27xx/patches-5.4/950-0493-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0496-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch rename to target/linux/bcm27xx/patches-5.4/950-0493-media-v4l2-common-add-RGB565-and-RGB55-to-v4l2_forma.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0497-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch b/target/linux/bcm27xx/patches-5.4/950-0494-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0497-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch rename to target/linux/bcm27xx/patches-5.4/950-0494-media-vb2-add-V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0498-media-v4l2-mem2mem-support-held-capture-buffers.patch b/target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0498-media-v4l2-mem2mem-support-held-capture-buffers.patch rename to target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0499-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch b/target/linux/bcm27xx/patches-5.4/950-0496-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0499-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch rename to target/linux/bcm27xx/patches-5.4/950-0496-media-videodev2.h-add-V4L2_DEC_CMD_FLUSH.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0500-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch b/target/linux/bcm27xx/patches-5.4/950-0497-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0500-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch rename to target/linux/bcm27xx/patches-5.4/950-0497-media-v4l2-mem2mem-add-stateless_-try_-decoder_cmd-i.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0501-media-v4l2-mem2mem-add-new_frame-detection.patch b/target/linux/bcm27xx/patches-5.4/950-0498-media-v4l2-mem2mem-add-new_frame-detection.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0501-media-v4l2-mem2mem-add-new_frame-detection.patch rename to target/linux/bcm27xx/patches-5.4/950-0498-media-v4l2-mem2mem-add-new_frame-detection.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0502-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch b/target/linux/bcm27xx/patches-5.4/950-0499-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0502-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch rename to target/linux/bcm27xx/patches-5.4/950-0499-media-Documentation-media-Document-V4L2_CTRL_TYPE_AR.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0503-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch b/target/linux/bcm27xx/patches-5.4/950-0500-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0503-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch rename to target/linux/bcm27xx/patches-5.4/950-0500-media-v4l-Add-definitions-for-HEVC-stateless-decodin.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0504-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch b/target/linux/bcm27xx/patches-5.4/950-0501-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0504-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch rename to target/linux/bcm27xx/patches-5.4/950-0501-media-v4l2-mem2mem-Fix-hold-buf-flag-checks.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0505-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch b/target/linux/bcm27xx/patches-5.4/950-0502-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0505-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch rename to target/linux/bcm27xx/patches-5.4/950-0502-media-pixfmt-Document-the-HEVC-slice-pixel-format.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0506-media-uapi-hevc-Add-scaling-matrix-control.patch b/target/linux/bcm27xx/patches-5.4/950-0503-media-uapi-hevc-Add-scaling-matrix-control.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0506-media-uapi-hevc-Add-scaling-matrix-control.patch rename to target/linux/bcm27xx/patches-5.4/950-0503-media-uapi-hevc-Add-scaling-matrix-control.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0507-media-uapi-hevc-Add-segment-address-field.patch b/target/linux/bcm27xx/patches-5.4/950-0504-media-uapi-hevc-Add-segment-address-field.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0507-media-uapi-hevc-Add-segment-address-field.patch rename to target/linux/bcm27xx/patches-5.4/950-0504-media-uapi-hevc-Add-segment-address-field.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0508-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch b/target/linux/bcm27xx/patches-5.4/950-0505-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0508-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch rename to target/linux/bcm27xx/patches-5.4/950-0505-media-hevc_ctrls-Add-slice-param-dependent-slice-seg.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0509-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch b/target/linux/bcm27xx/patches-5.4/950-0506-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0509-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch rename to target/linux/bcm27xx/patches-5.4/950-0506-media-uapi-Add-hevc-ctrls-for-WPP-decoding.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0510-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch b/target/linux/bcm27xx/patches-5.4/950-0507-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0510-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch rename to target/linux/bcm27xx/patches-5.4/950-0507-media-videodev2.h-Add-a-format-for-column-YUV4-2-0-m.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0511-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch b/target/linux/bcm27xx/patches-5.4/950-0508-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0511-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch rename to target/linux/bcm27xx/patches-5.4/950-0508-media-v4l2-mem2mem-allow-request-job-buffer-processi.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0512-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch b/target/linux/bcm27xx/patches-5.4/950-0509-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0512-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch rename to target/linux/bcm27xx/patches-5.4/950-0509-media-dt-bindings-media-Add-binding-for-the-Raspberr.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0513-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch b/target/linux/bcm27xx/patches-5.4/950-0510-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0513-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch rename to target/linux/bcm27xx/patches-5.4/950-0510-staging-media-Add-Raspberry-Pi-V4L2-H265-decoder.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0514-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch b/target/linux/bcm27xx/patches-5.4/950-0511-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch similarity index 100% rename from target/linux/bcm27xx/patches-5.4/950-0514-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch rename to target/linux/bcm27xx/patches-5.4/950-0511-dtoverlays-Add-overlay-to-enable-the-HEVC-V4L2-drive.patch diff --git a/target/linux/bcm27xx/patches-5.4/950-0512-mmc-sdhci-Silence-MMC-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0512-mmc-sdhci-Silence-MMC-warnings.patch new file mode 100644 index 00000000000..41fa6cb3d2c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0512-mmc-sdhci-Silence-MMC-warnings.patch @@ -0,0 +1,42 @@ +From c99941ee53a8c6fcc466a088f8bd7108f04824e5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 6 Dec 2019 13:05:27 +0100 +Subject: [PATCH] mmc: sdhci: Silence MMC warnings + +When the MMC isn't plugged in, the driver will spam the console which is +pretty annoying when using NFS. + +Signed-off-by: Maxime Ripard +--- + drivers/mmc/host/sdhci.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -39,7 +39,7 @@ + pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) + + #define SDHCI_DUMP(f, x...) \ +- pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) ++ pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) + + #define MAX_TUNING_LOOP 40 + +@@ -2754,7 +2754,7 @@ static void sdhci_timeout_timer(struct t + spin_lock_irqsave(&host->lock, flags); + + if (host->cmd && !sdhci_data_line_cmd(host->cmd)) { +- pr_err("%s: Timeout waiting for hardware cmd interrupt.\n", ++ pr_debug("%s: Timeout waiting for hardware cmd interrupt.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + +@@ -2776,7 +2776,7 @@ static void sdhci_timeout_data_timer(str + + if (host->data || host->data_cmd || + (host->cmd && sdhci_data_line_cmd(host->cmd))) { +- pr_err("%s: Timeout waiting for hardware interrupt.\n", ++ pr_debug("%s: Timeout waiting for hardware interrupt.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0513-dt-bindings-i2c-brcmstb-Convert-the-BRCMSTB-binding-.patch b/target/linux/bcm27xx/patches-5.4/950-0513-dt-bindings-i2c-brcmstb-Convert-the-BRCMSTB-binding-.patch new file mode 100644 index 00000000000..01bdfee303e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0513-dt-bindings-i2c-brcmstb-Convert-the-BRCMSTB-binding-.patch @@ -0,0 +1,126 @@ +From 1a2a857af4fe6748fea53799e0007672faa7aa57 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 16:55:01 +0100 +Subject: [PATCH] dt-bindings: i2c: brcmstb: Convert the BRCMSTB + binding to a schema + +Switch the DT binding to a YAML schema to enable the DT validation. + +Cc: Kamal Dasu +Cc: Wolfram Sang +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: linux-i2c@vger.kernel.org +Cc: devicetree@vger.kernel.org +Acked-by: Florian Fainelli +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../bindings/i2c/brcm,brcmstb-i2c.yaml | 59 +++++++++++++++++++ + .../devicetree/bindings/i2c/i2c-brcmstb.txt | 26 -------- + MAINTAINERS | 2 +- + 3 files changed, 60 insertions(+), 27 deletions(-) + create mode 100644 Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml + delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml +@@ -0,0 +1,59 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/i2c/brcm,brcmstb-i2c.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom STB BSC IIC Master Controller ++ ++maintainers: ++ - Kamal Dasu ++ ++allOf: ++ - $ref: /schemas/i2c/i2c-controller.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - brcm,brcmstb-i2c ++ - brcm,brcmper-i2c ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ interrupt-names: ++ maxItems: 1 ++ ++ clock-frequency: ++ enum: ++ - 46875 ++ - 50000 ++ - 93750 ++ - 97500 ++ - 187500 ++ - 200000 ++ - 375000 ++ - 390000 ++ ++required: ++ - compatible ++ - reg ++ - clock-frequency ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ bsca: i2c@f0406200 { ++ clock-frequency = <390000>; ++ compatible = "brcm,brcmstb-i2c"; ++ interrupt-parent = <&irq0_intc>; ++ reg = <0xf0406200 0x58>; ++ interrupts = <0x18>; ++ interrupt-names = "upg_bsca"; ++ }; ++ ++... +--- a/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt ++++ /dev/null +@@ -1,26 +0,0 @@ +-Broadcom stb bsc iic master controller +- +-Required properties: +- +-- compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c" +-- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz +- valid values are 375000, 390000, 187500, 200000 +- 93750, 97500, 46875 and 50000 +-- reg: specifies the base physical address and size of the registers +- +-Optional properties : +- +-- interrupts: specifies the interrupt number, the irq line to be used +-- interrupt-names: Interrupt name string +- +-Example: +- +-bsca: i2c@f0406200 { +- clock-frequency = <390000>; +- compatible = "brcm,brcmstb-i2c"; +- interrupt-parent = <&irq0_intc>; +- reg = <0xf0406200 0x58>; +- interrupts = <0x18>; +- interrupt-names = "upg_bsca"; +-}; +- +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3349,7 +3349,7 @@ L: linux-i2c@vger.kernel.org + L: bcm-kernel-feedback-list@broadcom.com + S: Supported + F: drivers/i2c/busses/i2c-brcmstb.c +-F: Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt ++F: Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml + + BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER + M: Al Cooper diff --git a/target/linux/bcm27xx/patches-5.4/950-0514-dt-bindings-i2c-brcmstb-Add-BCM2711-BSC-AUTO-I2C-bin.patch b/target/linux/bcm27xx/patches-5.4/950-0514-dt-bindings-i2c-brcmstb-Add-BCM2711-BSC-AUTO-I2C-bin.patch new file mode 100644 index 00000000000..2716a13d25d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0514-dt-bindings-i2c-brcmstb-Add-BCM2711-BSC-AUTO-I2C-bin.patch @@ -0,0 +1,96 @@ +From 16a6810e521eaf24249085b93b467f7bdf8e8a47 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 17 Dec 2019 09:58:34 +0100 +Subject: [PATCH] dt-bindings: i2c: brcmstb: Add BCM2711 BSC/AUTO-I2C + binding + +The HDMI blocks in the BCM2771 have an i2c controller to retrieve the +EDID. This block is split into two parts, the BSC and the AUTO_I2C, +lying in two separate register areas. + +The AUTO_I2C block has a mailbox-like interface and will take away the +BSC control from the CPU if enabled. However, the BSC is the actually +the same controller than the one supported by the brcmstb driver, and +the AUTO_I2C doesn't really bring any immediate benefit. + +We can model it in the DT as a single device with two register range, +which will allow us to use or or the other in the driver without +changing anything in the DT. + +Cc: Kamal Dasu +Cc: Wolfram Sang +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: linux-i2c@vger.kernel.org +Cc: devicetree@vger.kernel.org +Acked-by: Florian Fainelli +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../bindings/i2c/brcm,brcmstb-i2c.yaml | 40 ++++++++++++++++++- + 1 file changed, 39 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml ++++ b/Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml +@@ -15,11 +15,21 @@ allOf: + properties: + compatible: + enum: ++ - brcm,bcm2711-hdmi-i2c + - brcm,brcmstb-i2c + - brcm,brcmper-i2c + + reg: +- maxItems: 1 ++ minItems: 1 ++ maxItems: 2 ++ items: ++ - description: BSC register range ++ - description: Auto-I2C register range ++ ++ reg-names: ++ items: ++ - const: bsc ++ - const: auto-i2c + + interrupts: + maxItems: 1 +@@ -45,6 +55,26 @@ required: + + unevaluatedProperties: false + ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - brcm,bcm2711-hdmi-i2c ++ ++then: ++ properties: ++ reg: ++ minItems: 2 ++ ++ required: ++ - reg-names ++ ++else: ++ properties: ++ reg: ++ maxItems: 1 ++ + examples: + - | + bsca: i2c@f0406200 { +@@ -56,4 +86,12 @@ examples: + interrupt-names = "upg_bsca"; + }; + ++ - | ++ ddc0: i2c@7ef04500 { ++ compatible = "brcm,bcm2711-hdmi-i2c"; ++ reg = <0x7ef04500 0x100>, <0x7ef00b00 0x300>; ++ reg-names = "bsc", "auto-i2c"; ++ clock-frequency = <390000>; ++ }; ++ + ... diff --git a/target/linux/bcm27xx/patches-5.4/950-0515-i2c-brcmstb-Support-BCM2711-HDMI-BSC-controllers.patch b/target/linux/bcm27xx/patches-5.4/950-0515-i2c-brcmstb-Support-BCM2711-HDMI-BSC-controllers.patch new file mode 100644 index 00000000000..76ce7403da9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0515-i2c-brcmstb-Support-BCM2711-HDMI-BSC-controllers.patch @@ -0,0 +1,87 @@ +From 4633a7bc5ffc15fe24c05e52f17a72c346baab6b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 17 Dec 2019 09:58:34 +0100 +Subject: [PATCH] i2c: brcmstb: Support BCM2711 HDMI BSC controllers + +The HDMI blocks in the BCM2771 have an i2c controller to retrieve the +EDID. This block is split into two parts, the BSC and the AUTO_I2C, +lying in two separate register areas. + +The AUTO_I2C block has a mailbox-like interface and will take away the +BSC control from the CPU if enabled. However, the BSC is the actually +the same controller than the one supported by the brcmstb driver, and +the AUTO_I2C doesn't really bring any immediate benefit. + +Let's use the BSC then, but let's also tie the AUTO_I2C registers with a +separate compatible so that we can enable AUTO_I2C if needed in the +future. + +The AUTO_I2C is enabled by default at boot though, so we first need to +release the BSC from the AUTO_I2C control. + +Cc: Kamal Dasu +Cc: Wolfram Sang +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: linux-i2c@vger.kernel.org +Acked-by: Florian Fainelli +Signed-off-by: Maxime Ripard +--- + drivers/i2c/busses/i2c-brcmstb.c | 33 ++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/drivers/i2c/busses/i2c-brcmstb.c ++++ b/drivers/i2c/busses/i2c-brcmstb.c +@@ -580,6 +580,31 @@ static void brcmstb_i2c_set_bsc_reg_defa + brcmstb_i2c_set_bus_speed(dev); + } + ++#define AUTOI2C_CTRL0 0x26c ++#define AUTOI2C_CTRL0_RELEASE_BSC BIT(1) ++ ++static int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev->device); ++ struct resource *iomem; ++ void __iomem *autoi2c; ++ ++ /* Map hardware registers */ ++ iomem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "auto-i2c"); ++ autoi2c = devm_ioremap_resource(&pdev->dev, iomem); ++ if (IS_ERR(autoi2c)) ++ return PTR_ERR(autoi2c); ++ ++ writel(AUTOI2C_CTRL0_RELEASE_BSC, autoi2c + AUTOI2C_CTRL0); ++ devm_iounmap(&pdev->dev, autoi2c); ++ ++ /* We need to reset the controller after the release */ ++ dev->bsc_regmap->iic_enable = 0; ++ bsc_writel(dev, dev->bsc_regmap->iic_enable, iic_enable); ++ ++ return 0; ++} ++ + static int brcmstb_i2c_probe(struct platform_device *pdev) + { + int rc = 0; +@@ -609,6 +634,13 @@ static int brcmstb_i2c_probe(struct plat + goto probe_errorout; + } + ++ if (of_device_is_compatible(dev->device->of_node, ++ "brcm,bcm2711-hdmi-i2c")) { ++ rc = bcm2711_release_bsc(dev); ++ if (rc) ++ goto probe_errorout; ++ } ++ + rc = of_property_read_string(dev->device->of_node, "interrupt-names", + &int_name); + if (rc < 0) +@@ -705,6 +737,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, + static const struct of_device_id brcmstb_i2c_of_match[] = { + {.compatible = "brcm,brcmstb-i2c"}, + {.compatible = "brcm,brcmper-i2c"}, ++ {.compatible = "brcm,bcm2711-hdmi-i2c"}, + {}, + }; + MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0516-i2c-brcmstb-Allow-to-compile-it-on-BCM2835.patch b/target/linux/bcm27xx/patches-5.4/950-0516-i2c-brcmstb-Allow-to-compile-it-on-BCM2835.patch new file mode 100644 index 00000000000..a21035b69be --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0516-i2c-brcmstb-Allow-to-compile-it-on-BCM2835.patch @@ -0,0 +1,31 @@ +From ec7414dd69a7ea701d0d5676fdb32332cd5f10ec Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 14 Jan 2020 13:36:42 +0100 +Subject: [PATCH] i2c: brcmstb: Allow to compile it on BCM2835 + +The BCM2711, supported by ARCH_BCM2835, also has a controller by the +brcmstb driver so let's allow it to be compiled on that platform. + +Cc: Kamal Dasu +Cc: Wolfram Sang +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: linux-i2c@vger.kernel.org +Acked-by: Florian Fainelli +Signed-off-by: Maxime Ripard +--- + drivers/i2c/busses/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -491,8 +491,8 @@ config I2C_BCM_KONA + + config I2C_BRCMSTB + tristate "BRCM Settop/DSL I2C controller" +- depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \ +- COMPILE_TEST ++ depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC || \ ++ ARCH_BCM_63XX || COMPILE_TEST + default y + help + If you say yes to this option, support will be included for the diff --git a/target/linux/bcm27xx/patches-5.4/950-0517-dt-bindings-clock-Add-a-binding-for-the-RPi-Firmware.patch b/target/linux/bcm27xx/patches-5.4/950-0517-dt-bindings-clock-Add-a-binding-for-the-RPi-Firmware.patch new file mode 100644 index 00000000000..f3587060d18 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0517-dt-bindings-clock-Add-a-binding-for-the-RPi-Firmware.patch @@ -0,0 +1,63 @@ +From 9d4360fc454056fffa9ca487270aca9179906f5d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 17:51:09 +0100 +Subject: [PATCH] dt-bindings: clock: Add a binding for the RPi + Firmware clocks + +The firmare running on the RPi VideoCore can be used to discover and +change the various clocks running in the BCM2711. Since devices will +need to use them through the DT, let's add a pretty simple binding. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: Rob Herring +Cc: linux-clk@vger.kernel.org +Cc: devicetree@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + .../clock/raspberrypi,firmware-clocks.yaml | 39 +++++++++++++++++++ + 1 file changed, 39 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/raspberrypi,firmware-clocks.yaml +@@ -0,0 +1,39 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/raspberrypi,firmware-clocks.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: RaspberryPi Firmware Clocks Device Tree Bindings ++ ++maintainers: ++ - Maxime Ripard ++ ++properties: ++ "#clock-cells": ++ const: 1 ++ ++ compatible: ++ const: raspberrypi,firmware-clocks ++ ++ raspberrypi,firmware: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: > ++ Phandle to the mailbox node to communicate with the firmware. ++ ++required: ++ - "#clock-cells" ++ - compatible ++ - raspberrypi,firmware ++ ++additionalProperties: false ++ ++examples: ++ - | ++ firmware_clocks: firmware-clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ raspberrypi,firmware = <&firmware>; ++ #clock-cells = <1>; ++ }; ++ ++... diff --git a/target/linux/bcm27xx/patches-5.4/950-0518-clk-bcm-rpi-Allow-the-driver-to-be-probed-by-DT.patch b/target/linux/bcm27xx/patches-5.4/950-0518-clk-bcm-rpi-Allow-the-driver-to-be-probed-by-DT.patch new file mode 100644 index 00000000000..d622d9ded55 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0518-clk-bcm-rpi-Allow-the-driver-to-be-probed-by-DT.patch @@ -0,0 +1,60 @@ +From faeea753ba262e2a781570f9db23c5773c5d20e7 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 23 Dec 2019 19:58:08 +0100 +Subject: [PATCH] clk: bcm: rpi: Allow the driver to be probed by DT + +The current firmware clock driver for the RaspberryPi can only be probed by +manually registering an associated platform_device. + +While this works fine for cpufreq where the device gets attached a clkdev +lookup, it would be tedious to maintain a table of all the devices using +one of the clocks exposed by the firmware. + +Since the DT on the other hand is the perfect place to store those +associations, make the firmware clocks driver probe-able through the device +tree so that we can represent it as a node. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: linux-clk@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -255,15 +255,13 @@ static int raspberrypi_clk_probe(struct + struct raspberrypi_clk *rpi; + int ret; + +- firmware_node = of_find_compatible_node(NULL, NULL, +- "raspberrypi,bcm2835-firmware"); ++ firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = rpi_firmware_get(firmware_node); +- of_node_put(firmware_node); + if (!firmware) + return -EPROBE_DEFER; + +@@ -300,9 +298,16 @@ static int raspberrypi_clk_remove(struct + return 0; + } + ++static const struct of_device_id raspberrypi_clk_match[] = { ++ { .compatible = "raspberrypi,firmware-clocks" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, raspberrypi_clk_match); ++ + static struct platform_driver raspberrypi_clk_driver = { + .driver = { + .name = "raspberrypi-clk", ++ .of_match_table = raspberrypi_clk_match, + }, + .probe = raspberrypi_clk_probe, + .remove = raspberrypi_clk_remove, diff --git a/target/linux/bcm27xx/patches-5.4/950-0519-clk-bcm-rpi-Statically-init-clk_init_data.patch b/target/linux/bcm27xx/patches-5.4/950-0519-clk-bcm-rpi-Statically-init-clk_init_data.patch new file mode 100644 index 00000000000..5c7cb2b4375 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0519-clk-bcm-rpi-Statically-init-clk_init_data.patch @@ -0,0 +1,32 @@ +From 7916b5f66f3becb9f223e8a6d8c0a6c0edd8964c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 14:17:54 +0100 +Subject: [PATCH] clk: bcm: rpi: Statically init clk_init_data + +Instead of declaring the clk_init_data and then calling memset on it, just +initialise properly. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -175,11 +175,10 @@ static const struct clk_ops raspberrypi_ + + static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) + { ++ struct clk_init_data init = {}; + u32 min_rate = 0, max_rate = 0; +- struct clk_init_data init; + int ret; + +- memset(&init, 0, sizeof(init)); + + /* All of the PLLs derive from the external oscillator. */ + init.parent_names = (const char *[]){ "osc" }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0520-clk-bcm-rpi-Use-clk_hw_register-for-pllb_arm.patch b/target/linux/bcm27xx/patches-5.4/950-0520-clk-bcm-rpi-Use-clk_hw_register-for-pllb_arm.patch new file mode 100644 index 00000000000..55f86ae3407 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0520-clk-bcm-rpi-Use-clk_hw_register-for-pllb_arm.patch @@ -0,0 +1,56 @@ +From 3a4163613b7f6e628e7b5a0d3a546523d1d03bb7 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 15:40:00 +0100 +Subject: [PATCH] clk: bcm: rpi: Use clk_hw_register for pllb_arm + +The pllb_arm clock is defined as a fixed factor clock with the pllb clock +as a parent. However, all its configuration is entirely static, and thus we +don't really need to call clk_hw_register_fixed_factor() but can simply call +clk_hw_register() with a static clk_fixed_factor structure. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -225,16 +225,28 @@ static int raspberrypi_register_pllb(str + return devm_clk_hw_register(rpi->dev, &rpi->pllb); + } + ++static struct clk_fixed_factor raspberrypi_clk_pllb_arm = { ++ .mult = 1, ++ .div = 2, ++ .hw.init = &(struct clk_init_data) { ++ .name = "pllb_arm", ++ .parent_names = (const char *[]){ "pllb" }, ++ .num_parents = 1, ++ .ops = &clk_fixed_factor_ops, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ }, ++}; ++ + static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) + { +- rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev, +- "pllb_arm", "pllb", +- CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, +- 1, 2); +- if (IS_ERR(rpi->pllb_arm)) { ++ int ret; ++ ++ ret = clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); ++ if (ret) { + dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); +- return PTR_ERR(rpi->pllb_arm); ++ return ret; + } ++ rpi->pllb_arm = &raspberrypi_clk_pllb_arm.hw; + + rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); + if (!rpi->pllb_arm_lookup) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0521-clk-bcm-rpi-Remove-global-pllb_arm-clock-pointer.patch b/target/linux/bcm27xx/patches-5.4/950-0521-clk-bcm-rpi-Remove-global-pllb_arm-clock-pointer.patch new file mode 100644 index 00000000000..32fc94c675f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0521-clk-bcm-rpi-Remove-global-pllb_arm-clock-pointer.patch @@ -0,0 +1,45 @@ +From 5272507555c0ecf02c0dfd78303e86e8eb096191 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 15:41:37 +0100 +Subject: [PATCH] clk: bcm: rpi: Remove global pllb_arm clock pointer + +The pllb_arm clk_hw pointer in the raspberry_clk structure isn't used +anywhere but in the raspberrypi_register_pllb_arm. + +Let's remove it, this will make our lives easier in future patches. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -40,7 +40,6 @@ struct raspberrypi_clk { + unsigned long max_rate; + + struct clk_hw pllb; +- struct clk_hw *pllb_arm; + struct clk_lookup *pllb_arm_lookup; + }; + +@@ -246,12 +245,12 @@ static int raspberrypi_register_pllb_arm + dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); + return ret; + } +- rpi->pllb_arm = &raspberrypi_clk_pllb_arm.hw; + +- rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); ++ rpi->pllb_arm_lookup = clkdev_hw_create(&raspberrypi_clk_pllb_arm.hw, ++ NULL, "cpu0"); + if (!rpi->pllb_arm_lookup) { + dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); +- clk_hw_unregister_fixed_factor(rpi->pllb_arm); ++ clk_hw_unregister_fixed_factor(&raspberrypi_clk_pllb_arm.hw); + return -ENOMEM; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0522-clk-bcm-rpi-Make-sure-pllb_arm-is-removed.patch b/target/linux/bcm27xx/patches-5.4/950-0522-clk-bcm-rpi-Make-sure-pllb_arm-is-removed.patch new file mode 100644 index 00000000000..425830d5c43 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0522-clk-bcm-rpi-Make-sure-pllb_arm-is-removed.patch @@ -0,0 +1,40 @@ +From aeb75ab90c35c7bd9778a71d606d52ac3e8ff02d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 15:42:40 +0100 +Subject: [PATCH] clk: bcm: rpi: Make sure pllb_arm is removed + +The pllb_arm clock was created at probe time, but was never removed if +something went wrong later in probe, or if the driver was ever removed from +the system. + +Now that we are using clk_hw_register, we can just use its managed variant +to take care of that for us. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -240,7 +240,7 @@ static int raspberrypi_register_pllb_arm + { + int ret; + +- ret = clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); ++ ret = devm_clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); + if (ret) { + dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); + return ret; +@@ -250,7 +250,6 @@ static int raspberrypi_register_pllb_arm + NULL, "cpu0"); + if (!rpi->pllb_arm_lookup) { + dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); +- clk_hw_unregister_fixed_factor(&raspberrypi_clk_pllb_arm.hw); + return -ENOMEM; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0523-clk-bcm-rpi-Remove-pllb_arm_lookup-global-pointer.patch b/target/linux/bcm27xx/patches-5.4/950-0523-clk-bcm-rpi-Remove-pllb_arm_lookup-global-pointer.patch new file mode 100644 index 00000000000..e193b7906ad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0523-clk-bcm-rpi-Remove-pllb_arm_lookup-global-pointer.patch @@ -0,0 +1,51 @@ +From 35be338b9532bb1fda95b9f1123758f57f785f93 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 15:46:24 +0100 +Subject: [PATCH] clk: bcm: rpi: Remove pllb_arm_lookup global pointer + +The pllb_arm_lookup pointer in the struct raspberrypi_clk is not used for +anything but to store the returned pointer to clkdev_hw_create, and is not +used anywhere else in the driver. + +Let's remove that global pointer from the structure. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -40,7 +40,6 @@ struct raspberrypi_clk { + unsigned long max_rate; + + struct clk_hw pllb; +- struct clk_lookup *pllb_arm_lookup; + }; + + /* +@@ -238,6 +237,7 @@ static struct clk_fixed_factor raspberry + + static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) + { ++ struct clk_lookup *pllb_arm_lookup; + int ret; + + ret = devm_clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); +@@ -246,9 +246,9 @@ static int raspberrypi_register_pllb_arm + return ret; + } + +- rpi->pllb_arm_lookup = clkdev_hw_create(&raspberrypi_clk_pllb_arm.hw, +- NULL, "cpu0"); +- if (!rpi->pllb_arm_lookup) { ++ pllb_arm_lookup = clkdev_hw_create(&raspberrypi_clk_pllb_arm.hw, ++ NULL, "cpu0"); ++ if (!pllb_arm_lookup) { + dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); + return -ENOMEM; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0524-clk-bcm-rpi-Switch-to-clk_hw_register_clkdev.patch b/target/linux/bcm27xx/patches-5.4/950-0524-clk-bcm-rpi-Switch-to-clk_hw_register_clkdev.patch new file mode 100644 index 00000000000..e4a129f2336 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0524-clk-bcm-rpi-Switch-to-clk_hw_register_clkdev.patch @@ -0,0 +1,45 @@ +From 2d1c30a79cb9d390d2425852ff8c9527c31b3ab8 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 12 Feb 2020 14:21:45 +0100 +Subject: [PATCH] clk: bcm: rpi: Switch to clk_hw_register_clkdev + +Since we don't care about retrieving the clk_lookup structure pointer +returned by clkdev_hw_create, we can just use the clk_hw_register_clkdev +function. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -237,7 +237,6 @@ static struct clk_fixed_factor raspberry + + static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) + { +- struct clk_lookup *pllb_arm_lookup; + int ret; + + ret = devm_clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); +@@ -246,11 +245,11 @@ static int raspberrypi_register_pllb_arm + return ret; + } + +- pllb_arm_lookup = clkdev_hw_create(&raspberrypi_clk_pllb_arm.hw, +- NULL, "cpu0"); +- if (!pllb_arm_lookup) { +- dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); +- return -ENOMEM; ++ ret = clk_hw_register_clkdev(&raspberrypi_clk_pllb_arm.hw, ++ NULL, "cpu0"); ++ if (ret) { ++ dev_err(rpi->dev, "Failed to initialize clkdev\n"); ++ return ret; + } + + return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0525-clk-bcm-rpi-Make-sure-the-clkdev-lookup-is-removed.patch b/target/linux/bcm27xx/patches-5.4/950-0525-clk-bcm-rpi-Make-sure-the-clkdev-lookup-is-removed.patch new file mode 100644 index 00000000000..7c887795ee7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0525-clk-bcm-rpi-Make-sure-the-clkdev-lookup-is-removed.patch @@ -0,0 +1,34 @@ +From 31fe609e3f5f9d4e52f0f88f8ebfd20fb606c672 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 15:47:13 +0100 +Subject: [PATCH] clk: bcm: rpi: Make sure the clkdev lookup is removed + +The clkdev lookup created for the cpufreq device is never removed if +there's an issue later in probe or at module removal time. + +Let's convert to the managed variant of the clk_hw_register_clkdev function +to make sure it happens. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -245,8 +245,9 @@ static int raspberrypi_register_pllb_arm + return ret; + } + +- ret = clk_hw_register_clkdev(&raspberrypi_clk_pllb_arm.hw, +- NULL, "cpu0"); ++ ret = devm_clk_hw_register_clkdev(rpi->dev, ++ &raspberrypi_clk_pllb_arm.hw, ++ NULL, "cpu0"); + if (ret) { + dev_err(rpi->dev, "Failed to initialize clkdev\n"); + return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0526-clk-bcm-rpi-Create-a-data-structure-for-the-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0526-clk-bcm-rpi-Create-a-data-structure-for-the-clocks.patch new file mode 100644 index 00000000000..85b6f4a6e21 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0526-clk-bcm-rpi-Create-a-data-structure-for-the-clocks.patch @@ -0,0 +1,126 @@ +From 8af8b61bf6b5689af9f29f0e04e57c832dad0406 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 16:01:33 +0100 +Subject: [PATCH] clk: bcm: rpi: Create a data structure for the clocks + +So far the driver has really only been providing a single clock, and stored +both the data associated to that clock in particular with the data +associated to the "controller". + +Since we will change that in the future, let's decouple the clock data from +the provider data. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 40 ++++++++++++++++++++----------- + 1 file changed, 26 insertions(+), 14 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -35,11 +35,15 @@ struct raspberrypi_clk { + struct device *dev; + struct rpi_firmware *firmware; + struct platform_device *cpufreq; ++}; ++ ++struct raspberrypi_clk_data { ++ struct clk_hw hw; + + unsigned long min_rate; + unsigned long max_rate; + +- struct clk_hw pllb; ++ struct raspberrypi_clk *rpi; + }; + + /* +@@ -83,8 +87,9 @@ static int raspberrypi_clock_property(st + + static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) + { +- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, +- pllb); ++ struct raspberrypi_clk_data *data = ++ container_of(hw, struct raspberrypi_clk_data, hw); ++ struct raspberrypi_clk *rpi = data->rpi; + u32 val = 0; + int ret; + +@@ -101,8 +106,9 @@ static int raspberrypi_fw_pll_is_on(stru + static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, +- pllb); ++ struct raspberrypi_clk_data *data = ++ container_of(hw, struct raspberrypi_clk_data, hw); ++ struct raspberrypi_clk *rpi = data->rpi; + u32 val = 0; + int ret; + +@@ -119,8 +125,9 @@ static unsigned long raspberrypi_fw_pll_ + static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, +- pllb); ++ struct raspberrypi_clk_data *data = ++ container_of(hw, struct raspberrypi_clk_data, hw); ++ struct raspberrypi_clk *rpi = data->rpi; + u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + int ret; + +@@ -142,13 +149,13 @@ static int raspberrypi_fw_pll_set_rate(s + static int raspberrypi_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +- struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, +- pllb); ++ struct raspberrypi_clk_data *data = ++ container_of(hw, struct raspberrypi_clk_data, hw); + u64 div, final_rate; + u32 ndiv, fdiv; + + /* We can't use req->rate directly as it would overflow */ +- final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate); ++ final_rate = clamp(req->rate, data->min_rate, data->max_rate); + + div = (u64)final_rate << A2W_PLL_FRAC_BITS; + do_div(div, req->best_parent_rate); +@@ -173,10 +180,15 @@ static const struct clk_ops raspberrypi_ + + static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) + { ++ struct raspberrypi_clk_data *data; + struct clk_init_data init = {}; + u32 min_rate = 0, max_rate = 0; + int ret; + ++ data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ data->rpi = rpi; + + /* All of the PLLs derive from the external oscillator. */ + init.parent_names = (const char *[]){ "osc" }; +@@ -215,12 +227,12 @@ static int raspberrypi_register_pllb(str + dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n", + min_rate, max_rate); + +- rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; +- rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++ data->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++ data->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + +- rpi->pllb.init = &init; ++ data->hw.init = &init; + +- return devm_clk_hw_register(rpi->dev, &rpi->pllb); ++ return devm_clk_hw_register(rpi->dev, &data->hw); + } + + static struct clk_fixed_factor raspberrypi_clk_pllb_arm = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0527-clk-bcm-rpi-Add-clock-id-to-data.patch b/target/linux/bcm27xx/patches-5.4/950-0527-clk-bcm-rpi-Add-clock-id-to-data.patch new file mode 100644 index 00000000000..09f023e09ce --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0527-clk-bcm-rpi-Add-clock-id-to-data.patch @@ -0,0 +1,86 @@ +From 98d529ffea66937e8a9ba8b69172bb9c599cfa39 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 16:04:16 +0100 +Subject: [PATCH] clk: bcm: rpi: Add clock id to data + +The driver has really only supported one clock so far and has hardcoded the +ID used in communications with the firmware in all the functions +implementing the clock framework hooks. Let's store that in the clock data +structure so that we can support more clocks later on. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -39,6 +39,7 @@ struct raspberrypi_clk { + + struct raspberrypi_clk_data { + struct clk_hw hw; ++ unsigned id; + + unsigned long min_rate; + unsigned long max_rate; +@@ -95,7 +96,7 @@ static int raspberrypi_fw_pll_is_on(stru + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_CLOCK_STATE, +- RPI_FIRMWARE_ARM_CLK_ID, &val); ++ data->id, &val); + if (ret) + return 0; + +@@ -114,8 +115,7 @@ static unsigned long raspberrypi_fw_pll_ + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_CLOCK_RATE, +- RPI_FIRMWARE_ARM_CLK_ID, +- &val); ++ data->id, &val); + if (ret) + return ret; + +@@ -133,8 +133,7 @@ static int raspberrypi_fw_pll_set_rate(s + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_SET_CLOCK_RATE, +- RPI_FIRMWARE_ARM_CLK_ID, +- &new_rate); ++ data->id, &new_rate); + if (ret) + dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", + clk_hw_get_name(hw), ret); +@@ -189,6 +188,7 @@ static int raspberrypi_register_pllb(str + if (!data) + return -ENOMEM; + data->rpi = rpi; ++ data->id = RPI_FIRMWARE_ARM_CLK_ID; + + /* All of the PLLs derive from the external oscillator. */ + init.parent_names = (const char *[]){ "osc" }; +@@ -200,8 +200,7 @@ static int raspberrypi_register_pllb(str + /* Get min & max rates set by the firmware */ + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE, +- RPI_FIRMWARE_ARM_CLK_ID, +- &min_rate); ++ data->id, &min_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s min freq: %d\n", + init.name, ret); +@@ -210,8 +209,7 @@ static int raspberrypi_register_pllb(str + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, +- RPI_FIRMWARE_ARM_CLK_ID, +- &max_rate); ++ data->id, &max_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s max freq: %d\n", + init.name, ret); diff --git a/target/linux/bcm27xx/patches-5.4/950-0528-clk-bcm-rpi-Pass-the-clocks-data-to-the-firmware-fun.patch b/target/linux/bcm27xx/patches-5.4/950-0528-clk-bcm-rpi-Pass-the-clocks-data-to-the-firmware-fun.patch new file mode 100644 index 00000000000..7822ff0d119 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0528-clk-bcm-rpi-Pass-the-clocks-data-to-the-firmware-fun.patch @@ -0,0 +1,96 @@ +From 1231dbeb8bfeda68c53854cc68016acd74665079 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 16:08:17 +0100 +Subject: [PATCH] clk: bcm: rpi: Pass the clocks data to the firmware + function + +The raspberry_clock_property only takes the clock ID as an argument, but +now that we have a clock data structure it makes more sense to just pass +that structure instead. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 29 ++++++++++++++--------------- + 1 file changed, 14 insertions(+), 15 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -67,11 +67,12 @@ struct raspberrypi_firmware_prop { + __le32 disable_turbo; + } __packed; + +-static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag, +- u32 clk, u32 *val) ++static int raspberrypi_clock_property(struct rpi_firmware *firmware, ++ const struct raspberrypi_clk_data *data, ++ u32 tag, u32 *val) + { + struct raspberrypi_firmware_prop msg = { +- .id = cpu_to_le32(clk), ++ .id = cpu_to_le32(data->id), + .val = cpu_to_le32(*val), + .disable_turbo = cpu_to_le32(1), + }; +@@ -94,9 +95,8 @@ static int raspberrypi_fw_pll_is_on(stru + u32 val = 0; + int ret; + +- ret = raspberrypi_clock_property(rpi->firmware, +- RPI_FIRMWARE_GET_CLOCK_STATE, +- data->id, &val); ++ ret = raspberrypi_clock_property(rpi->firmware, data, ++ RPI_FIRMWARE_GET_CLOCK_STATE, &val); + if (ret) + return 0; + +@@ -113,9 +113,8 @@ static unsigned long raspberrypi_fw_pll_ + u32 val = 0; + int ret; + +- ret = raspberrypi_clock_property(rpi->firmware, +- RPI_FIRMWARE_GET_CLOCK_RATE, +- data->id, &val); ++ ret = raspberrypi_clock_property(rpi->firmware, data, ++ RPI_FIRMWARE_GET_CLOCK_RATE, &val); + if (ret) + return ret; + +@@ -131,9 +130,9 @@ static int raspberrypi_fw_pll_set_rate(s + u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + int ret; + +- ret = raspberrypi_clock_property(rpi->firmware, ++ ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_SET_CLOCK_RATE, +- data->id, &new_rate); ++ &new_rate); + if (ret) + dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", + clk_hw_get_name(hw), ret); +@@ -198,18 +197,18 @@ static int raspberrypi_register_pllb(str + init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED; + + /* Get min & max rates set by the firmware */ +- ret = raspberrypi_clock_property(rpi->firmware, ++ ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE, +- data->id, &min_rate); ++ &min_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s min freq: %d\n", + init.name, ret); + return ret; + } + +- ret = raspberrypi_clock_property(rpi->firmware, ++ ret = raspberrypi_clock_property(rpi->firmware, data, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, +- data->id, &max_rate); ++ &max_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s max freq: %d\n", + init.name, ret); diff --git a/target/linux/bcm27xx/patches-5.4/950-0529-clk-bcm-rpi-Rename-is_prepared-function.patch b/target/linux/bcm27xx/patches-5.4/950-0529-clk-bcm-rpi-Rename-is_prepared-function.patch new file mode 100644 index 00000000000..1a6c9813de0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0529-clk-bcm-rpi-Rename-is_prepared-function.patch @@ -0,0 +1,40 @@ +From c37a4cc3fc34b6c53c331d0d079df322082ff183 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 20 Feb 2020 12:45:47 +0100 +Subject: [PATCH] clk: bcm: rpi: Rename is_prepared function + +The raspberrypi_fw_pll_is_on function doesn't only apply to PLL +registered in the driver, but any clock exposed by the firmware. + +Since we also implement the is_prepared hook, make the function +consistent with the other function names. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Acked-by: Nicolas Saenz Julienne +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -87,7 +87,7 @@ static int raspberrypi_clock_property(st + return 0; + } + +-static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) ++static int raspberrypi_fw_is_prepared(struct clk_hw *hw) + { + struct raspberrypi_clk_data *data = + container_of(hw, struct raspberrypi_clk_data, hw); +@@ -170,7 +170,7 @@ static int raspberrypi_pll_determine_rat + } + + static const struct clk_ops raspberrypi_firmware_pll_clk_ops = { +- .is_prepared = raspberrypi_fw_pll_is_on, ++ .is_prepared = raspberrypi_fw_is_prepared, + .recalc_rate = raspberrypi_fw_pll_get_rate, + .set_rate = raspberrypi_fw_pll_set_rate, + .determine_rate = raspberrypi_pll_determine_rate, diff --git a/target/linux/bcm27xx/patches-5.4/950-0530-clk-bcm-rpi-Split-pllb-clock-hooks.patch b/target/linux/bcm27xx/patches-5.4/950-0530-clk-bcm-rpi-Split-pllb-clock-hooks.patch new file mode 100644 index 00000000000..38720b89bdc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0530-clk-bcm-rpi-Split-pllb-clock-hooks.patch @@ -0,0 +1,80 @@ +From e2537b383e247198347e7124876b9ead531dbeef Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 16:14:18 +0100 +Subject: [PATCH] clk: bcm: rpi: Split pllb clock hooks + +The driver only supports the pllb for now and all the clock framework hooks +are a mix of the generic firmware interface and the specifics of the pllb. +Since we will support more clocks in the future let's split the generic and +specific hooks + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 30 ++++++++++++++++++++++-------- + 1 file changed, 22 insertions(+), 8 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -104,8 +104,8 @@ static int raspberrypi_fw_is_prepared(st + } + + +-static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, +- unsigned long parent_rate) ++static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) + { + struct raspberrypi_clk_data *data = + container_of(hw, struct raspberrypi_clk_data, hw); +@@ -118,21 +118,27 @@ static unsigned long raspberrypi_fw_pll_ + if (ret) + return ret; + +- return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++ return val; + } + +-static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long parent_rate) ++static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return raspberrypi_fw_get_rate(hw, parent_rate) * ++ RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++} ++ ++static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) + { + struct raspberrypi_clk_data *data = + container_of(hw, struct raspberrypi_clk_data, hw); + struct raspberrypi_clk *rpi = data->rpi; +- u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++ u32 _rate = rate; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, data, +- RPI_FIRMWARE_SET_CLOCK_RATE, +- &new_rate); ++ RPI_FIRMWARE_SET_CLOCK_RATE, &_rate); + if (ret) + dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", + clk_hw_get_name(hw), ret); +@@ -140,6 +146,14 @@ static int raspberrypi_fw_pll_set_rate(s + return ret; + } + ++static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; ++ ++ return raspberrypi_fw_set_rate(hw, new_rate, parent_rate); ++} ++ + /* + * Sadly there is no firmware rate rounding interface. We borrowed it from + * clk-bcm2835. diff --git a/target/linux/bcm27xx/patches-5.4/950-0531-clk-bcm-rpi-Make-the-PLLB-registration-function-retu.patch b/target/linux/bcm27xx/patches-5.4/950-0531-clk-bcm-rpi-Make-the-PLLB-registration-function-retu.patch new file mode 100644 index 00000000000..633cf187825 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0531-clk-bcm-rpi-Make-the-PLLB-registration-function-retu.patch @@ -0,0 +1,144 @@ +From 5272bad5ff927362e5d12da82eb819a8d1444da6 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 16:30:01 +0100 +Subject: [PATCH] clk: bcm: rpi: Make the PLLB registration function + return a clk_hw + +The raspberrypi_register_pllb has been returning an integer so far to +notify whether the functions has exited successfully or not. + +However, the OF provider functions in the clock framework require access to +the clk_hw structure so that we can expose those clocks to device tree +consumers. + +Since we'll want that for the future clocks, let's return a clk_hw pointer +instead of the return code. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 40 +++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 18 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -190,7 +190,7 @@ static const struct clk_ops raspberrypi_ + .determine_rate = raspberrypi_pll_determine_rate, + }; + +-static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) ++static struct clk_hw *raspberrypi_register_pllb(struct raspberrypi_clk *rpi) + { + struct raspberrypi_clk_data *data; + struct clk_init_data init = {}; +@@ -199,7 +199,7 @@ static int raspberrypi_register_pllb(str + + data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); + if (!data) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + data->rpi = rpi; + data->id = RPI_FIRMWARE_ARM_CLK_ID; + +@@ -217,7 +217,7 @@ static int raspberrypi_register_pllb(str + if (ret) { + dev_err(rpi->dev, "Failed to get %s min freq: %d\n", + init.name, ret); +- return ret; ++ return ERR_PTR(ret); + } + + ret = raspberrypi_clock_property(rpi->firmware, data, +@@ -226,13 +226,13 @@ static int raspberrypi_register_pllb(str + if (ret) { + dev_err(rpi->dev, "Failed to get %s max freq: %d\n", + init.name, ret); +- return ret; ++ return ERR_PTR(ret); + } + + if (!min_rate || !max_rate) { + dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n", + min_rate, max_rate); +- return -EINVAL; ++ return ERR_PTR(-EINVAL); + } + + dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n", +@@ -243,7 +243,11 @@ static int raspberrypi_register_pllb(str + + data->hw.init = &init; + +- return devm_clk_hw_register(rpi->dev, &data->hw); ++ ret = devm_clk_hw_register(rpi->dev, &data->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &data->hw; + } + + static struct clk_fixed_factor raspberrypi_clk_pllb_arm = { +@@ -258,14 +262,14 @@ static struct clk_fixed_factor raspberry + }, + }; + +-static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) ++static struct clk_hw *raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) + { + int ret; + + ret = devm_clk_hw_register(rpi->dev, &raspberrypi_clk_pllb_arm.hw); + if (ret) { + dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); +- return ret; ++ return ERR_PTR(ret); + } + + ret = devm_clk_hw_register_clkdev(rpi->dev, +@@ -273,10 +277,10 @@ static int raspberrypi_register_pllb_arm + NULL, "cpu0"); + if (ret) { + dev_err(rpi->dev, "Failed to initialize clkdev\n"); +- return ret; ++ return ERR_PTR(ret); + } + +- return 0; ++ return &raspberrypi_clk_pllb_arm.hw; + } + + static int raspberrypi_clk_probe(struct platform_device *pdev) +@@ -285,7 +289,7 @@ static int raspberrypi_clk_probe(struct + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_clk *rpi; +- int ret; ++ struct clk_hw *hw; + + firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0); + if (!firmware_node) { +@@ -305,15 +309,15 @@ static int raspberrypi_clk_probe(struct + rpi->firmware = firmware; + platform_set_drvdata(pdev, rpi); + +- ret = raspberrypi_register_pllb(rpi); +- if (ret) { +- dev_err(dev, "Failed to initialize pllb, %d\n", ret); +- return ret; ++ hw = raspberrypi_register_pllb(rpi); ++ if (IS_ERR(hw)) { ++ dev_err(dev, "Failed to initialize pllb, %ld\n", PTR_ERR(hw)); ++ return PTR_ERR(hw); + } + +- ret = raspberrypi_register_pllb_arm(rpi); +- if (ret) +- return ret; ++ hw = raspberrypi_register_pllb_arm(rpi); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); + + rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", + -1, NULL, 0); diff --git a/target/linux/bcm27xx/patches-5.4/950-0532-clk-bcm-rpi-Add-DT-provider-for-the-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0532-clk-bcm-rpi-Add-DT-provider-for-the-clocks.patch new file mode 100644 index 00000000000..99fdf8fbd61 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0532-clk-bcm-rpi-Add-DT-provider-for-the-clocks.patch @@ -0,0 +1,67 @@ +From 19f7515528fbd1dc0d45e4b5ce6531c1406fc8d8 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 7 Feb 2020 17:03:46 +0100 +Subject: [PATCH] clk: bcm: rpi: Add DT provider for the clocks + +For the upcoming registration of the clocks provided by the firmware, make +sure it's exposed to the device tree providers. + +Cc: Michael Turquette +Cc: linux-clk@vger.kernel.org +Reviewed-by: Stephen Boyd +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -31,6 +31,8 @@ + + #define A2W_PLL_FRAC_BITS 20 + ++#define NUM_FW_CLKS 16 ++ + struct raspberrypi_clk { + struct device *dev; + struct rpi_firmware *firmware; +@@ -285,11 +287,13 @@ static struct clk_hw *raspberrypi_regist + + static int raspberrypi_clk_probe(struct platform_device *pdev) + { ++ struct clk_hw_onecell_data *clk_data; + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_clk *rpi; + struct clk_hw *hw; ++ int ret; + + firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0); + if (!firmware_node) { +@@ -309,6 +313,11 @@ static int raspberrypi_clk_probe(struct + rpi->firmware = firmware; + platform_set_drvdata(pdev, rpi); + ++ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, NUM_FW_CLKS), ++ GFP_KERNEL); ++ if (!clk_data) ++ return -ENOMEM; ++ + hw = raspberrypi_register_pllb(rpi); + if (IS_ERR(hw)) { + dev_err(dev, "Failed to initialize pllb, %ld\n", PTR_ERR(hw)); +@@ -318,6 +327,13 @@ static int raspberrypi_clk_probe(struct + hw = raspberrypi_register_pllb_arm(rpi); + if (IS_ERR(hw)) + return PTR_ERR(hw); ++ clk_data->hws[RPI_FIRMWARE_ARM_CLK_ID] = hw; ++ clk_data->num = RPI_FIRMWARE_ARM_CLK_ID + 1; ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, ++ clk_data); ++ if (ret) ++ return ret; + + rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", + -1, NULL, 0); diff --git a/target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch new file mode 100644 index 00000000000..eaa4a811413 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0533-clk-bcm-rpi-Discover-the-firmware-clocks.patch @@ -0,0 +1,173 @@ +From 54276fe20c0735dd18d298891b71b664ea54962d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 10 Feb 2020 14:06:09 +0100 +Subject: [PATCH] clk: bcm: rpi: Discover the firmware clocks + +The RaspberryPi4 firmware actually exposes more clocks than are currently +handled by the driver and we will need to change some of them directly +based on the pixel rate for the display related clocks, or the load for the +GPU. + +This rate change can have a number of side-effects, including adjusting the +various PLL voltages or the PLL parents. The firmware will also update +those clocks by itself for example if the SoC runs too hot. + +In order to make Linux play as nice as possible with those constraints, it +makes sense to rely on the firmware clocks as much as possible. + +Fortunately,t he firmware has an interface to discover the clocks it +exposes. + +Let's use it to discover, register the clocks in the clocks framework and +then expose them through the device tree for consumers to use them. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: linux-clk@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/clk-raspberrypi.c | 104 ++++++++++++++++++--- + include/soc/bcm2835/raspberrypi-firmware.h | 5 + + 2 files changed, 97 insertions(+), 12 deletions(-) + +--- a/drivers/clk/bcm/clk-raspberrypi.c ++++ b/drivers/clk/bcm/clk-raspberrypi.c +@@ -285,6 +285,95 @@ static struct clk_hw *raspberrypi_regist + return &raspberrypi_clk_pllb_arm.hw; + } + ++static long raspberrypi_fw_dumb_round_rate(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ /* ++ * The firmware will do the rounding but that isn't part of ++ * the interface with the firmware, so we just do our best ++ * here. ++ */ ++ return rate; ++} ++ ++static const struct clk_ops raspberrypi_firmware_clk_ops = { ++ .is_prepared = raspberrypi_fw_is_prepared, ++ .recalc_rate = raspberrypi_fw_get_rate, ++ .round_rate = raspberrypi_fw_dumb_round_rate, ++ .set_rate = raspberrypi_fw_set_rate, ++}; ++ ++static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi, ++ unsigned int parent, ++ unsigned int id) ++{ ++ struct raspberrypi_clk_data *data; ++ struct clk_init_data init = {}; ++ int ret; ++ ++ if (id == RPI_FIRMWARE_ARM_CLK_ID) { ++ struct clk_hw *hw; ++ ++ hw = raspberrypi_register_pllb(rpi); ++ if (IS_ERR(hw)) { ++ dev_err(rpi->dev, "Failed to initialize pllb, %ld\n", ++ PTR_ERR(hw)); ++ return hw; ++ } ++ ++ return raspberrypi_register_pllb_arm(rpi); ++ } ++ ++ data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return ERR_PTR(-ENOMEM); ++ data->rpi = rpi; ++ data->id = id; ++ ++ init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, "fw-clk-%u", id); ++ init.ops = &raspberrypi_firmware_clk_ops; ++ init.flags = CLK_GET_RATE_NOCACHE; ++ ++ data->hw.init = &init; ++ ++ ret = devm_clk_hw_register(rpi->dev, &data->hw); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return &data->hw; ++} ++ ++static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, ++ struct clk_hw_onecell_data *data) ++{ ++ struct rpi_firmware_get_clocks_response *clks; ++ int ret; ++ ++ clks = devm_kcalloc(rpi->dev, sizeof(*clks), NUM_FW_CLKS, GFP_KERNEL); ++ if (!clks) ++ return -ENOMEM; ++ ++ ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS, ++ clks, sizeof(*clks) * NUM_FW_CLKS); ++ if (ret) ++ return ret; ++ ++ while (clks->id) { ++ struct clk_hw *hw; ++ ++ hw = raspberrypi_clk_register(rpi, clks->parent, clks->id); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); ++ ++ data->hws[clks->id] = hw; ++ data->num = clks->id + 1; ++ clks++; ++ } ++ ++ return 0; ++} ++ + static int raspberrypi_clk_probe(struct platform_device *pdev) + { + struct clk_hw_onecell_data *clk_data; +@@ -292,7 +381,6 @@ static int raspberrypi_clk_probe(struct + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_clk *rpi; +- struct clk_hw *hw; + int ret; + + firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0); +@@ -318,17 +406,9 @@ static int raspberrypi_clk_probe(struct + if (!clk_data) + return -ENOMEM; + +- hw = raspberrypi_register_pllb(rpi); +- if (IS_ERR(hw)) { +- dev_err(dev, "Failed to initialize pllb, %ld\n", PTR_ERR(hw)); +- return PTR_ERR(hw); +- } +- +- hw = raspberrypi_register_pllb_arm(rpi); +- if (IS_ERR(hw)) +- return PTR_ERR(hw); +- clk_data->hws[RPI_FIRMWARE_ARM_CLK_ID] = hw; +- clk_data->num = RPI_FIRMWARE_ARM_CLK_ID + 1; ++ ret = raspberrypi_discover_clocks(rpi, clk_data); ++ if (ret) ++ return ret; + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clk_data); +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -160,6 +160,11 @@ enum rpi_firmware_property_tag { + + #define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64 + ++struct rpi_firmware_get_clocks_response { ++ __le32 parent; ++ __le32 id; ++}; ++ + #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) + int rpi_firmware_property(struct rpi_firmware *fw, + u32 tag, void *data, size_t len); diff --git a/target/linux/bcm27xx/patches-5.4/950-0534-ARM-dts-bcm2711-Add-firmware-clocks-node.patch b/target/linux/bcm27xx/patches-5.4/950-0534-ARM-dts-bcm2711-Add-firmware-clocks-node.patch new file mode 100644 index 00000000000..098903d2e11 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0534-ARM-dts-bcm2711-Add-firmware-clocks-node.patch @@ -0,0 +1,39 @@ +From a0ebfa1829b5d3a1f698426c29f99078640b498f Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 23 Dec 2019 19:58:30 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Add firmware clocks node + +Now that we have a clock driver for the clocks exposed by the firmware, +let's add the device tree nodes for it. + +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 2 +- + arch/arm/boot/dts/bcm2711.dtsi | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -33,7 +33,7 @@ + + power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; + resets = <&pm BCM2835_RESET_V3D>; +- clocks = <&clocks BCM2835_CLOCK_V3D>; ++ clocks = <&firmware_clocks 5>; + interrupts = ; + status = "disabled"; + }; +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -31,6 +31,11 @@ + }; + }; + ++ firmware_clocks: firmware-clocks { ++ compatible = "raspberrypi,firmware-clocks"; ++ raspberrypi,firmware = <&firmware>; ++ #clock-cells = <1>; ++ }; + + soc { + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0535-reset-Move-reset-simple-header-out-of-drivers-reset.patch b/target/linux/bcm27xx/patches-5.4/950-0535-reset-Move-reset-simple-header-out-of-drivers-reset.patch new file mode 100644 index 00000000000..3df4fde4394 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0535-reset-Move-reset-simple-header-out-of-drivers-reset.patch @@ -0,0 +1,168 @@ +From e108e2c34b3acc70ec55b7d0772abb79c96319b2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 28 Jan 2020 09:33:52 +0100 +Subject: [PATCH] reset: Move reset-simple header out of drivers/reset + +The reset-simple code can be useful for drivers outside of drivers/reset +that have a few reset controls as part of their features. Let's move it to +include/linux/reset. + +Cc: Philipp Zabel +Signed-off-by: Maxime Ripard +--- + drivers/reset/reset-simple.c | 3 +-- + drivers/reset/reset-socfpga.c | 3 +-- + drivers/reset/reset-sunxi.c | 3 +-- + drivers/reset/reset-uniphier-glue.c | 3 +-- + {drivers => include/linux}/reset/reset-simple.h | 0 + 5 files changed, 4 insertions(+), 8 deletions(-) + rename {drivers => include/linux}/reset/reset-simple.h (100%) + +--- a/drivers/reset/reset-simple.c ++++ b/drivers/reset/reset-simple.c +@@ -18,10 +18,9 @@ + #include + #include + #include ++#include + #include + +-#include "reset-simple.h" +- + static inline struct reset_simple_data * + to_reset_simple_data(struct reset_controller_dev *rcdev) + { +--- a/drivers/reset/reset-socfpga.c ++++ b/drivers/reset/reset-socfpga.c +@@ -11,13 +11,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + +-#include "reset-simple.h" +- + #define SOCFPGA_NR_BANKS 8 + + static int a10_reset_init(struct device_node *np) +--- a/drivers/reset/reset-sunxi.c ++++ b/drivers/reset/reset-sunxi.c +@@ -14,13 +14,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + +-#include "reset-simple.h" +- + static int sunxi_reset_init(struct device_node *np) + { + struct reset_simple_data *data; +--- a/drivers/reset/reset-uniphier-glue.c ++++ b/drivers/reset/reset-uniphier-glue.c +@@ -9,8 +9,7 @@ + #include + #include + #include +- +-#include "reset-simple.h" ++#include + + #define MAX_CLKS 2 + #define MAX_RSTS 2 +--- a/drivers/reset/reset-simple.h ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Simple Reset Controller ops +- * +- * Based on Allwinner SoCs Reset Controller driver +- * +- * Copyright 2013 Maxime Ripard +- * +- * Maxime Ripard +- */ +- +-#ifndef __RESET_SIMPLE_H__ +-#define __RESET_SIMPLE_H__ +- +-#include +-#include +-#include +- +-/** +- * struct reset_simple_data - driver data for simple reset controllers +- * @lock: spinlock to protect registers during read-modify-write cycles +- * @membase: memory mapped I/O register range +- * @rcdev: reset controller device base structure +- * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits +- * are set to assert the reset. Note that this says nothing about +- * the voltage level of the actual reset line. +- * @status_active_low: if true, bits read back as cleared while the reset is +- * asserted. Otherwise, bits read back as set while the +- * reset is asserted. +- */ +-struct reset_simple_data { +- spinlock_t lock; +- void __iomem *membase; +- struct reset_controller_dev rcdev; +- bool active_low; +- bool status_active_low; +-}; +- +-extern const struct reset_control_ops reset_simple_ops; +- +-#endif /* __RESET_SIMPLE_H__ */ +--- /dev/null ++++ b/include/linux/reset/reset-simple.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Simple Reset Controller ops ++ * ++ * Based on Allwinner SoCs Reset Controller driver ++ * ++ * Copyright 2013 Maxime Ripard ++ * ++ * Maxime Ripard ++ */ ++ ++#ifndef __RESET_SIMPLE_H__ ++#define __RESET_SIMPLE_H__ ++ ++#include ++#include ++#include ++ ++/** ++ * struct reset_simple_data - driver data for simple reset controllers ++ * @lock: spinlock to protect registers during read-modify-write cycles ++ * @membase: memory mapped I/O register range ++ * @rcdev: reset controller device base structure ++ * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits ++ * are set to assert the reset. Note that this says nothing about ++ * the voltage level of the actual reset line. ++ * @status_active_low: if true, bits read back as cleared while the reset is ++ * asserted. Otherwise, bits read back as set while the ++ * reset is asserted. ++ */ ++struct reset_simple_data { ++ spinlock_t lock; ++ void __iomem *membase; ++ struct reset_controller_dev rcdev; ++ bool active_low; ++ bool status_active_low; ++}; ++ ++extern const struct reset_control_ops reset_simple_ops; ++ ++#endif /* __RESET_SIMPLE_H__ */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0536-reset-simple-Add-reset-callback.patch b/target/linux/bcm27xx/patches-5.4/950-0536-reset-simple-Add-reset-callback.patch new file mode 100644 index 00000000000..035c9d6aa0a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0536-reset-simple-Add-reset-callback.patch @@ -0,0 +1,85 @@ +From 66deff85fee24ecd7b0ffa2901711aa8f026fcfa Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 28 Jan 2020 16:22:20 +0100 +Subject: [PATCH] reset: simple: Add reset callback + +The reset-simple code lacks a reset callback that is still pretty easy to +implement. The only real thing to consider is the delay needed for a device +to be reset, so let's expose that as part of the reset-simple driver data. + +Cc: Philipp Zabel +Signed-off-by: Maxime Ripard +--- + drivers/reset/reset-simple.c | 24 ++++++++++++++++++++++++ + include/linux/reset/reset-simple.h | 6 ++++++ + 2 files changed, 30 insertions(+) + +--- a/drivers/reset/reset-simple.c ++++ b/drivers/reset/reset-simple.c +@@ -11,6 +11,7 @@ + * Maxime Ripard + */ + ++#include + #include + #include + #include +@@ -63,6 +64,28 @@ static int reset_simple_deassert(struct + return reset_simple_update(rcdev, id, false); + } + ++static int reset_simple_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct reset_simple_data *data = to_reset_simple_data(rcdev); ++ int ret; ++ ++ if (!data->reset_us) ++ return -ENOTSUPP; ++ ++ ret = reset_simple_assert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ usleep_range(data->reset_us, data->reset_us * 2); ++ ++ ret = reset_simple_deassert(rcdev, id); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + static int reset_simple_status(struct reset_controller_dev *rcdev, + unsigned long id) + { +@@ -80,6 +103,7 @@ static int reset_simple_status(struct re + const struct reset_control_ops reset_simple_ops = { + .assert = reset_simple_assert, + .deassert = reset_simple_deassert, ++ .reset = reset_simple_reset, + .status = reset_simple_status, + }; + EXPORT_SYMBOL_GPL(reset_simple_ops); +--- a/include/linux/reset/reset-simple.h ++++ b/include/linux/reset/reset-simple.h +@@ -27,6 +27,11 @@ + * @status_active_low: if true, bits read back as cleared while the reset is + * asserted. Otherwise, bits read back as set while the + * reset is asserted. ++ * @reset_us: Minimum delay in microseconds needed that needs to be ++ * waited for between an assert and a deassert to reset the ++ * device. If multiple consumers with different delay ++ * requirements are connected to this controller, it must ++ * be the largest minimum delay. + */ + struct reset_simple_data { + spinlock_t lock; +@@ -34,6 +39,7 @@ struct reset_simple_data { + struct reset_controller_dev rcdev; + bool active_low; + bool status_active_low; ++ unsigned int reset_us; + }; + + extern const struct reset_control_ops reset_simple_ops; diff --git a/target/linux/bcm27xx/patches-5.4/950-0537-dt-bindings-clock-Add-BCM2711-DVP-binding.patch b/target/linux/bcm27xx/patches-5.4/950-0537-dt-bindings-clock-Add-BCM2711-DVP-binding.patch new file mode 100644 index 00000000000..ca87cbac839 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0537-dt-bindings-clock-Add-BCM2711-DVP-binding.patch @@ -0,0 +1,68 @@ +From 67405a5468f8972f3a3db44292aff8fc05188db9 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 17:50:31 +0100 +Subject: [PATCH] dt-bindings: clock: Add BCM2711 DVP binding + +The BCM2711 has a unit controlling the HDMI0 and HDMI1 clock and reset +signals. Let's add a binding for it. + +Cc: Philipp Zabel +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../bindings/clock/brcm,bcm2711-dvp.yaml | 47 +++++++++++++++++++ + 1 file changed, 47 insertions(+) + create mode 100644 Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/brcm,bcm2711-dvp.yaml +@@ -0,0 +1,47 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/brcm,bcm2711-dvp.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom BCM2711 HDMI DVP Device Tree Bindings ++ ++maintainers: ++ - Maxime Ripard ++ ++properties: ++ "#clock-cells": ++ const: 1 ++ ++ "#reset-cells": ++ const: 1 ++ ++ compatible: ++ const: brcm,brcm2711-dvp ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++required: ++ - "#clock-cells" ++ - "#reset-cells" ++ - compatible ++ - reg ++ - clocks ++ ++additionalProperties: false ++ ++examples: ++ - | ++ dvp: clock@7ef00000 { ++ compatible = "brcm,brcm2711-dvp"; ++ reg = <0x7ef00000 0x10>; ++ clocks = <&clk_108MHz>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++... diff --git a/target/linux/bcm27xx/patches-5.4/950-0538-clk-bcm-Add-BCM2711-DVP-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0538-clk-bcm-Add-BCM2711-DVP-driver.patch new file mode 100644 index 00000000000..23105057a9f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0538-clk-bcm-Add-BCM2711-DVP-driver.patch @@ -0,0 +1,172 @@ +From 0a2b9668e391b5fef4c54f992d7f8f99e5f50ef3 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 28 Jan 2020 09:36:27 +0100 +Subject: [PATCH] clk: bcm: Add BCM2711 DVP driver + +The HDMI block has a block that controls clocks and reset signals to the +HDMI0 and HDMI1 controllers. + +Let's expose that through a clock driver implementing a clock and reset +provider. + +Cc: Michael Turquette +Cc: Stephen Boyd +Cc: Rob Herring +Cc: linux-clk@vger.kernel.org +Cc: devicetree@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + drivers/clk/bcm/Kconfig | 1 + + drivers/clk/bcm/Makefile | 1 + + drivers/clk/bcm/clk-bcm2711-dvp.c | 125 ++++++++++++++++++++++++++++++ + 3 files changed, 127 insertions(+) + create mode 100644 drivers/clk/bcm/clk-bcm2711-dvp.c + +--- a/drivers/clk/bcm/Kconfig ++++ b/drivers/clk/bcm/Kconfig +@@ -4,6 +4,7 @@ config CLK_BCM2835 + depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST + depends on COMMON_CLK + default ARCH_BCM2835 || ARCH_BRCMSTB ++ select RESET_SIMPLE + help + Enable common clock framework support for Broadcom BCM2835 + SoCs. +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-s + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o + obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o ++obj-$(CONFIG_CLK_BCM2835) += clk-bcm2711-dvp.o + obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o + obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o + obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o +--- /dev/null ++++ b/drivers/clk/bcm/clk-bcm2711-dvp.c +@@ -0,0 +1,125 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright 2020 Cerno ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define DVP_HT_RPI_SW_INIT 0x04 ++#define DVP_HT_RPI_MISC_CONFIG 0x08 ++ ++#define NR_CLOCKS 2 ++#define NR_RESETS 6 ++ ++struct clk_dvp { ++ struct clk_hw_onecell_data *data; ++ struct reset_simple_data reset; ++}; ++ ++static int clk_dvp_probe(struct platform_device *pdev) ++{ ++ struct clk_hw_onecell_data *data; ++ struct resource *res; ++ struct clk_dvp *dvp; ++ void __iomem *base; ++ const char *parent; ++ int ret; ++ ++ dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL); ++ if (!dvp) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, dvp); ++ ++ dvp->data = devm_kzalloc(&pdev->dev, ++ struct_size(dvp->data, hws, NR_CLOCKS), ++ GFP_KERNEL); ++ if (!dvp->data) ++ return -ENOMEM; ++ data = dvp->data; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ dvp->reset.rcdev.owner = THIS_MODULE; ++ dvp->reset.rcdev.nr_resets = NR_RESETS; ++ dvp->reset.rcdev.ops = &reset_simple_ops; ++ dvp->reset.rcdev.of_node = pdev->dev.of_node; ++ dvp->reset.membase = base + DVP_HT_RPI_SW_INIT; ++ spin_lock_init(&dvp->reset.lock); ++ ++ ret = reset_controller_register(&dvp->reset.rcdev); ++ if (ret) ++ return ret; ++ ++ parent = of_clk_get_parent_name(pdev->dev.of_node, 0); ++ if (!parent) ++ goto unregister_reset; ++ ++ data->hws[0] = clk_hw_register_gate(&pdev->dev, "hdmi0-108MHz", ++ parent, 0, ++ base + DVP_HT_RPI_MISC_CONFIG, 3, ++ CLK_GATE_SET_TO_DISABLE, &dvp->reset.lock); ++ if (IS_ERR(data->hws[0])) { ++ ret = PTR_ERR(data->hws[0]); ++ goto unregister_reset; ++ } ++ ++ data->hws[1] = clk_hw_register_gate(&pdev->dev, "hdmi1-108MHz", ++ parent, 0, ++ base + DVP_HT_RPI_MISC_CONFIG, 4, ++ CLK_GATE_SET_TO_DISABLE, &dvp->reset.lock); ++ if (IS_ERR(data->hws[1])) { ++ ret = PTR_ERR(data->hws[1]); ++ goto unregister_clk0; ++ } ++ ++ data->num = NR_CLOCKS; ++ ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, ++ data); ++ if (ret) ++ goto unregister_clk1; ++ ++ return 0; ++ ++ ++unregister_clk1: ++ clk_hw_unregister_gate(data->hws[1]); ++ ++unregister_clk0: ++ clk_hw_unregister_gate(data->hws[0]); ++ ++unregister_reset: ++ reset_controller_unregister(&dvp->reset.rcdev); ++ return ret; ++}; ++ ++static int clk_dvp_remove(struct platform_device *pdev) ++{ ++ struct clk_dvp *dvp = platform_get_drvdata(pdev); ++ struct clk_hw_onecell_data *data = dvp->data; ++ ++ clk_hw_unregister_gate(data->hws[1]); ++ clk_hw_unregister_gate(data->hws[0]); ++ reset_controller_unregister(&dvp->reset.rcdev); ++ ++ return 0; ++} ++ ++static const struct of_device_id clk_dvp_dt_ids[] = { ++ { .compatible = "brcm,brcm2711-dvp", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver clk_dvp_driver = { ++ .probe = clk_dvp_probe, ++ .remove = clk_dvp_remove, ++ .driver = { ++ .name = "brcm2711-dvp", ++ .of_match_table = clk_dvp_dt_ids, ++ }, ++}; ++module_platform_driver(clk_dvp_driver); diff --git a/target/linux/bcm27xx/patches-5.4/950-0539-ARM-dts-bcm2711-Add-HDMI-DVP.patch b/target/linux/bcm27xx/patches-5.4/950-0539-ARM-dts-bcm2711-Add-HDMI-DVP.patch new file mode 100644 index 00000000000..c4d230e7308 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0539-ARM-dts-bcm2711-Add-HDMI-DVP.patch @@ -0,0 +1,43 @@ +From 119c9cdf9beab785d10ebf8a804ce20b3b0fd779 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 28 Jan 2020 09:37:06 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Add HDMI DVP + +Now that we have a driver for the DVP, let's add its DT node. + +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/bcm2711.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -31,6 +31,13 @@ + }; + }; + ++ clk_108MHz: clk-108M { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <108000000>; ++ clock-output-names = "108MHz-clock"; ++ }; ++ + firmware_clocks: firmware-clocks { + compatible = "raspberrypi,firmware-clocks"; + raspberrypi,firmware = <&firmware>; +@@ -268,6 +275,14 @@ + hvs@7e400000 { + interrupts = ; + }; ++ ++ dvp: clock@7ef00000 { ++ compatible = "brcm,brcm2711-dvp"; ++ reg = <0x7ef00000 0x10>; ++ clocks = <&clk_108MHz>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; + }; + + arm-pmu { diff --git a/target/linux/bcm27xx/patches-5.4/950-0540-dt-bindings-display-Convert-VC4-bindings-to-schemas.patch b/target/linux/bcm27xx/patches-5.4/950-0540-dt-bindings-display-Convert-VC4-bindings-to-schemas.patch new file mode 100644 index 00000000000..3e47c475ffc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0540-dt-bindings-display-Convert-VC4-bindings-to-schemas.patch @@ -0,0 +1,706 @@ +From 193065956ba3e285df2c67f7c3bdeb3bdaae6ee9 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 15:42:05 +0100 +Subject: [PATCH] dt-bindings: display: Convert VC4 bindings to schemas + +The BCM283x SoCs have a display pipeline composed of several controllers +with device tree bindings that are supported by Linux. + +Now that we have the DT validation in place, let's split into separate +files and convert the device tree bindings for those controllers to +schemas. + +This is just a 1:1 conversion though, and some bindings were incomplete so +it results in example validation warnings that are going to be addressed in +the following patches. + +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + .../bindings/display/brcm,bcm-vc4.txt | 174 ------------------ + .../bindings/display/brcm,bcm2835-dpi.yaml | 66 +++++++ + .../bindings/display/brcm,bcm2835-dsi0.yaml | 73 ++++++++ + .../bindings/display/brcm,bcm2835-hdmi.yaml | 75 ++++++++ + .../bindings/display/brcm,bcm2835-hvs.yaml | 37 ++++ + .../display/brcm,bcm2835-pixelvalve0.yaml | 40 ++++ + .../bindings/display/brcm,bcm2835-txp.yaml | 37 ++++ + .../bindings/display/brcm,bcm2835-v3d.yaml | 42 +++++ + .../bindings/display/brcm,bcm2835-vc4.yaml | 34 ++++ + .../bindings/display/brcm,bcm2835-vec.yaml | 44 +++++ + MAINTAINERS | 2 +- + 11 files changed, 449 insertions(+), 175 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-v3d.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml + create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml + +--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt ++++ /dev/null +@@ -1,174 +0,0 @@ +-Broadcom VC4 (VideoCore4) GPU +- +-The VC4 device present on the Raspberry Pi includes a display system +-with HDMI output and the HVS (Hardware Video Scaler) for compositing +-display planes. +- +-Required properties for VC4: +-- compatible: Should be "brcm,bcm2835-vc4" or "brcm,cygnus-vc4" +- +-Required properties for Pixel Valve: +-- compatible: Should be one of "brcm,bcm2835-pixelvalve0", +- "brcm,bcm2835-pixelvalve1", or "brcm,bcm2835-pixelvalve2" +-- reg: Physical base address and length of the PV's registers +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- +-Required properties for HVS: +-- compatible: Should be "brcm,bcm2835-hvs" +-- reg: Physical base address and length of the HVS's registers +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- +-Required properties for HDMI +-- compatible: Should be "brcm,bcm2835-hdmi" +-- reg: Physical base address and length of the two register ranges +- ("HDMI" and "HD", in that order) +-- interrupts: The interrupt numbers +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +-- ddc: phandle of the I2C controller used for DDC EDID probing +-- clocks: a) hdmi: The HDMI state machine clock +- b) pixel: The pixel clock. +- +-Optional properties for HDMI: +-- hpd-gpios: The GPIO pin for HDMI hotplug detect (if it doesn't appear +- as an interrupt/status bit in the HDMI controller +- itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt +-- dmas: Should contain one entry pointing to the DMA channel used to +- transfer audio data +-- dma-names: Should contain "audio-rx" +- +-Required properties for DPI: +-- compatible: Should be "brcm,bcm2835-dpi" +-- reg: Physical base address and length of the registers +-- clocks: a) core: The core clock the unit runs on +- b) pixel: The pixel clock that feeds the pixelvalve +-- port: Port node with a single endpoint connecting to the panel +- device, as defined in [1] +- +-Required properties for VEC: +-- compatible: Should be "brcm,bcm2835-vec" +-- reg: Physical base address and length of the registers +-- clocks: The core clock the unit runs on +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- +-Required properties for V3D: +-- compatible: Should be "brcm,bcm2835-v3d" or "brcm,cygnus-v3d" +-- reg: Physical base address and length of the V3D's registers +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- +-Optional properties for V3D: +-- clocks: The clock the unit runs on +- +-Required properties for DSI: +-- compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1" +-- reg: Physical base address and length of the DSI block's registers +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +-- clocks: a) phy: The DSI PLL clock feeding the DSI analog PHY +- b) escape: The DSI ESC clock from CPRMAN +- c) pixel: The DSI pixel clock from CPRMAN +-- clock-output-names: +- The 3 clocks output from the DSI analog PHY: dsi[01]_byte, +- dsi[01]_ddr2, and dsi[01]_ddr +- +-Required properties for the TXP (writeback) block: +-- compatible: Should be "brcm,bcm2835-txp" +-- reg: Physical base address and length of the TXP block's registers +-- interrupts: The interrupt number +- See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- +-[1] Documentation/devicetree/bindings/media/video-interfaces.txt +- +-Example: +-pixelvalve@7e807000 { +- compatible = "brcm,bcm2835-pixelvalve2"; +- reg = <0x7e807000 0x100>; +- interrupts = <2 10>; /* pixelvalve */ +-}; +- +-hvs@7e400000 { +- compatible = "brcm,bcm2835-hvs"; +- reg = <0x7e400000 0x6000>; +- interrupts = <2 1>; +-}; +- +-hdmi: hdmi@7e902000 { +- compatible = "brcm,bcm2835-hdmi"; +- reg = <0x7e902000 0x600>, +- <0x7e808000 0x100>; +- interrupts = <2 8>, <2 9>; +- ddc = <&i2c2>; +- hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; +- clocks = <&clocks BCM2835_PLLH_PIX>, +- <&clocks BCM2835_CLOCK_HSM>; +- clock-names = "pixel", "hdmi"; +-}; +- +-dpi: dpi@7e208000 { +- compatible = "brcm,bcm2835-dpi"; +- reg = <0x7e208000 0x8c>; +- clocks = <&clocks BCM2835_CLOCK_VPU>, +- <&clocks BCM2835_CLOCK_DPI>; +- clock-names = "core", "pixel"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- port { +- dpi_out: endpoint@0 { +- remote-endpoint = <&panel_in>; +- }; +- }; +-}; +- +-dsi1: dsi@7e700000 { +- compatible = "brcm,bcm2835-dsi1"; +- reg = <0x7e700000 0x8c>; +- interrupts = <2 12>; +- #address-cells = <1>; +- #size-cells = <0>; +- #clock-cells = <1>; +- +- clocks = <&clocks BCM2835_PLLD_DSI1>, +- <&clocks BCM2835_CLOCK_DSI1E>, +- <&clocks BCM2835_CLOCK_DSI1P>; +- clock-names = "phy", "escape", "pixel"; +- +- clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr"; +- +- pitouchscreen: panel@0 { +- compatible = "raspberrypi,touchscreen"; +- reg = <0>; +- +- <...> +- }; +-}; +- +-vec: vec@7e806000 { +- compatible = "brcm,bcm2835-vec"; +- reg = <0x7e806000 0x1000>; +- clocks = <&clocks BCM2835_CLOCK_VEC>; +- interrupts = <2 27>; +-}; +- +-v3d: v3d@7ec00000 { +- compatible = "brcm,bcm2835-v3d"; +- reg = <0x7ec00000 0x1000>; +- interrupts = <1 10>; +-}; +- +-vc4: gpu { +- compatible = "brcm,bcm2835-vc4"; +-}; +- +-panel: panel { +- compatible = "ontat,yx700wv03", "simple-panel"; +- +- port { +- panel_in: endpoint { +- remote-endpoint = <&dpi_out>; +- }; +- }; +-}; +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml +@@ -0,0 +1,66 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-dpi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) DPI Controller ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ const: brcm,bcm2835-dpi ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: The core clock the unit runs on ++ - description: The pixel clock that feeds the pixelvalve ++ ++ port: ++ type: object ++ description: > ++ Port node with a single endpoint connecting to the panel, as ++ defined in Documentation/devicetree/bindings/media/video-interfaces.txt. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ panel: panel { ++ compatible = "ontat,yx700wv03", "simple-panel"; ++ ++ port { ++ panel_in: endpoint { ++ remote-endpoint = <&dpi_out>; ++ }; ++ }; ++ }; ++ ++ dpi: dpi@7e208000 { ++ compatible = "brcm,bcm2835-dpi"; ++ reg = <0x7e208000 0x8c>; ++ clocks = <&clocks BCM2835_CLOCK_VPU>, ++ <&clocks BCM2835_CLOCK_DPI>; ++ clock-names = "core", "pixel"; ++ ++ port { ++ dpi_out: endpoint { ++ remote-endpoint = <&panel_in>; ++ }; ++ }; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml +@@ -0,0 +1,73 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-dsi0.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) DSI Controller ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ enum: ++ - brcm,bcm2835-dsi0 ++ - brcm,bcm2835-dsi1 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: The DSI PLL clock feeding the DSI analog PHY ++ - description: The DSI ESC clock ++ - description: The DSI pixel clock ++ ++ clock-output-names: true ++ # FIXME: The meta-schemas don't seem to allow it for now ++ # items: ++ # - description: The DSI byte clock for the PHY ++ # - description: The DSI DDR2 clock ++ # - description: The DSI DDR clock ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-output-names ++ - interrupts ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include ++ ++ dsi1: dsi@7e700000 { ++ compatible = "brcm,bcm2835-dsi1"; ++ reg = <0x7e700000 0x8c>; ++ interrupts = <2 12>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ ++ clocks = <&clocks BCM2835_PLLD_DSI1>, ++ <&clocks BCM2835_CLOCK_DSI1E>, ++ <&clocks BCM2835_CLOCK_DSI1P>; ++ clock-names = "phy", "escape", "pixel"; ++ ++ clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr"; ++ ++ pitouchscreen: panel@0 { ++ compatible = "raspberrypi,touchscreen"; ++ reg = <0>; ++ ++ /* ... */ ++ }; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml +@@ -0,0 +1,75 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-hdmi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) HDMI Controller ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ const: brcm,bcm2835-hdmi ++ ++ reg: ++ items: ++ - description: HDMI register range ++ - description: HD register range ++ ++ interrupts: ++ minItems: 2 ++ ++ clocks: ++ items: ++ - description: The HDMI state machine clock ++ - description: The pixel clock ++ ++ ddc: ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/phandle ++ description: > ++ Phandle of the I2C controller used for DDC EDID probing ++ ++ hpd-gpios: ++ description: > ++ The GPIO pin for the HDMI hotplug detect (if it doesn't appear ++ as an interrupt/status bit in the HDMI controller itself) ++ ++ dmas: ++ maxItems: 1 ++ description: > ++ Should contain one entry pointing to the DMA channel used to ++ transfer audio data. ++ ++ dma-names: ++ const: audio-rx ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - ddc ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ hdmi: hdmi@7e902000 { ++ compatible = "brcm,bcm2835-hdmi"; ++ reg = <0x7e902000 0x600>, ++ <0x7e808000 0x100>; ++ interrupts = <2 8>, <2 9>; ++ ddc = <&i2c2>; ++ hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; ++ clocks = <&clocks BCM2835_PLLH_PIX>, ++ <&clocks BCM2835_CLOCK_HSM>; ++ clock-names = "pixel", "hdmi"; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-hvs.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) Hardware Video Scaler ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ const: brcm,bcm2835-hvs ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ hvs@7e400000 { ++ compatible = "brcm,bcm2835-hvs"; ++ reg = <0x7e400000 0x6000>; ++ interrupts = <2 1>; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml +@@ -0,0 +1,40 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-pixelvalve0.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) PixelValve ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ enum: ++ - brcm,bcm2835-pixelvalve0 ++ - brcm,bcm2835-pixelvalve1 ++ - brcm,bcm2835-pixelvalve2 ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ pixelvalve@7e807000 { ++ compatible = "brcm,bcm2835-pixelvalve2"; ++ reg = <0x7e807000 0x100>; ++ interrupts = <2 10>; /* pixelvalve */ ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-txp.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) TXP (writeback) Controller ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ const: brcm,bcm2835-txp ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ txp: txp@7e004000 { ++ compatible = "brcm,bcm2835-txp"; ++ reg = <0x7e004000 0x20>; ++ interrupts = <1 11>; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-v3d.yaml +@@ -0,0 +1,42 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-v3d.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) V3D GPU ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ enum: ++ - brcm,bcm2835-v3d ++ - brcm,cygnus-v3d ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ v3d: v3d@7ec00000 { ++ compatible = "brcm,bcm2835-v3d"; ++ reg = <0x7ec00000 0x1000>; ++ interrupts = <1 10>; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml +@@ -0,0 +1,34 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-vc4.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) GPU ++ ++maintainers: ++ - Eric Anholt ++ ++description: > ++ The VC4 device present on the Raspberry Pi includes a display system ++ with HDMI output and the HVS (Hardware Video Scaler) for compositing ++ display planes. ++ ++properties: ++ compatible: ++ enum: ++ - brcm,bcm2835-vc4 ++ - brcm,cygnus-vc4 ++ ++required: ++ - compatible ++ ++additionalProperties: false ++ ++examples: ++ - | ++ vc4: gpu { ++ compatible = "brcm,bcm2835-vc4"; ++ }; ++ ++... +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml +@@ -0,0 +1,44 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/brcm,bcm2835-vec.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom VC4 (VideoCore4) VEC ++ ++maintainers: ++ - Eric Anholt ++ ++properties: ++ compatible: ++ const: brcm,bcm2835-vec ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ vec: vec@7e806000 { ++ compatible = "brcm,bcm2835-vec"; ++ reg = <0x7e806000 0x1000>; ++ clocks = <&clocks BCM2835_CLOCK_VEC>; ++ interrupts = <2 27>; ++ }; ++ ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -5573,7 +5573,7 @@ T: git git://github.com/anholt/linux + S: Supported + F: drivers/gpu/drm/vc4/ + F: include/uapi/drm/vc4_drm.h +-F: Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt ++F: Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml + T: git git://anongit.freedesktop.org/drm/drm-misc + + DRM DRIVERS FOR VIVANTE GPU IP diff --git a/target/linux/bcm27xx/patches-5.4/950-0541-dt-bindings-display-vc4-dpi-Add-missing-clock-names-.patch b/target/linux/bcm27xx/patches-5.4/950-0541-dt-bindings-display-vc4-dpi-Add-missing-clock-names-.patch new file mode 100644 index 00000000000..2150f0abecb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0541-dt-bindings-display-vc4-dpi-Add-missing-clock-names-.patch @@ -0,0 +1,38 @@ +From 9a624b11291306b4b4c49c70bc75ef7d72d81405 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 15:47:18 +0100 +Subject: [PATCH] dt-bindings: display: vc4: dpi: Add missing + clock-names property + +While the device tree and the driver expected a clock-names property, it +wasn't explicitly documented in the previous binding. Make sure it is now. + +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2835-dpi.yaml | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml +@@ -21,6 +21,11 @@ properties: + - description: The core clock the unit runs on + - description: The pixel clock that feeds the pixelvalve + ++ clock-names: ++ items: ++ - const: core ++ - const: pixel ++ + port: + type: object + description: > +@@ -31,6 +36,7 @@ required: + - compatible + - reg + - clocks ++ - clock-names + - port + + additionalProperties: false diff --git a/target/linux/bcm27xx/patches-5.4/950-0542-dt-bindings-display-vc4-dsi-Add-missing-clock-proper.patch b/target/linux/bcm27xx/patches-5.4/950-0542-dt-bindings-display-vc4-dsi-Add-missing-clock-proper.patch new file mode 100644 index 00000000000..4cb313f1529 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0542-dt-bindings-display-vc4-dsi-Add-missing-clock-proper.patch @@ -0,0 +1,54 @@ +From 12abb6775e99482ff9fc71e16292ccf4dfeacee5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 15:47:18 +0100 +Subject: [PATCH] dt-bindings: display: vc4: dsi: Add missing clock + properties + +While the device tree and the driver expected a clock-names and a +clock-cells properties, it wasn't explicitly documented in the previous +binding. Make sure it is now. + +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../bindings/display/brcm,bcm2835-dsi0.yaml | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml +@@ -10,6 +10,9 @@ maintainers: + - Eric Anholt + + properties: ++ "#clock-cells": ++ const: 1 ++ + compatible: + enum: + - brcm,bcm2835-dsi0 +@@ -24,6 +27,12 @@ properties: + - description: The DSI ESC clock + - description: The DSI pixel clock + ++ clock-names: ++ items: ++ - const: phy ++ - const: escape ++ - const: pixel ++ + clock-output-names: true + # FIXME: The meta-schemas don't seem to allow it for now + # items: +@@ -35,9 +44,11 @@ properties: + maxItems: 1 + + required: ++ - "#clock-cells" + - compatible + - reg + - clocks ++ - clock-names + - clock-output-names + - interrupts + diff --git a/target/linux/bcm27xx/patches-5.4/950-0543-dt-bindings-display-vc4-hdmi-Add-missing-clock-names.patch b/target/linux/bcm27xx/patches-5.4/950-0543-dt-bindings-display-vc4-hdmi-Add-missing-clock-names.patch new file mode 100644 index 00000000000..5ef4eaeab9f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0543-dt-bindings-display-vc4-hdmi-Add-missing-clock-names.patch @@ -0,0 +1,34 @@ +From 293db446089f00599f0a22b933a6a5a13ccfc5e2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 15:47:18 +0100 +Subject: [PATCH] dt-bindings: display: vc4: hdmi: Add missing + clock-names property + +While the device tree and the driver expected a clock-names property, it +wasn't explicitly documented in the previous binding. The documented order +was wrong too, so make sure clock-names is there and in the proper order. + +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../devicetree/bindings/display/brcm,bcm2835-hdmi.yaml | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml +@@ -23,8 +23,13 @@ properties: + + clocks: + items: +- - description: The HDMI state machine clock + - description: The pixel clock ++ - description: The HDMI state machine clock ++ ++ clock-names: ++ items: ++ - const: pixel ++ - const: hdmi + + ddc: + allOf: diff --git a/target/linux/bcm27xx/patches-5.4/950-0544-dt-bindings-display-vc4-Document-BCM2711-VC5.patch b/target/linux/bcm27xx/patches-5.4/950-0544-dt-bindings-display-vc4-Document-BCM2711-VC5.patch new file mode 100644 index 00000000000..2499dee0c93 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0544-dt-bindings-display-vc4-Document-BCM2711-VC5.patch @@ -0,0 +1,24 @@ +From a12c5df87364ef6965a750345b1e28a5aba5cb14 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 17:40:56 +0100 +Subject: [PATCH] dt-bindings: display: vc4: Document BCM2711 VC5 + +The BCM2711 comes with a new VideoCore. Add a compatible for it. + +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml +@@ -17,6 +17,7 @@ description: > + properties: + compatible: + enum: ++ - brcm,bcm2711-vc5 + - brcm,bcm2835-vc4 + - brcm,cygnus-vc4 + diff --git a/target/linux/bcm27xx/patches-5.4/950-0545-drm-vc4-drv-Add-include-guards.patch b/target/linux/bcm27xx/patches-5.4/950-0545-drm-vc4-drv-Add-include-guards.patch new file mode 100644 index 00000000000..16f8b0ad820 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0545-drm-vc4-drv-Add-include-guards.patch @@ -0,0 +1,30 @@ +From 42566c11972c9edace45d5a787e276588214cb79 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 19 Dec 2019 18:08:48 +0100 +Subject: [PATCH] drm/vc4: drv: Add include guards + +vc4_drv.h doesn't have any include guards which prevents it from being +included twice. Let's add them. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -2,6 +2,8 @@ + /* + * Copyright (C) 2015 Broadcom + */ ++#ifndef _VC4_DRV_H_ ++#define _VC4_DRV_H_ + + #include + #include +@@ -899,3 +901,5 @@ int vc4_perfmon_destroy_ioctl(struct drm + struct drm_file *file_priv); + int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); ++ ++#endif /* _VC4_DRV_H_ */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0546-drm-vc4-drv-Support-BCM2711.patch b/target/linux/bcm27xx/patches-5.4/950-0546-drm-vc4-drv-Support-BCM2711.patch new file mode 100644 index 00000000000..00bac3a2b93 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0546-drm-vc4-drv-Support-BCM2711.patch @@ -0,0 +1,109 @@ +From d52f29a5e0ee9882f6f734c057224686b9820152 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 15:40:34 +0100 +Subject: [PATCH] drm/vc4: drv: Support BCM2711 + +The BCM2711 has a reworked display pipeline, and the load tracker needs +some adjustement to operate properly. Let's add a compatible for BCM2711 +and disable the load tracker until properly supported. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.c | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 3 +++ + drivers/gpu/drm/vc4/vc4_kms.c | 32 +++++++++++++++++++++----------- + drivers/gpu/drm/vc4/vc4_plane.c | 5 +++++ + 4 files changed, 30 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -368,6 +368,7 @@ static int vc4_platform_drm_remove(struc + } + + static const struct of_device_id vc4_of_match[] = { ++ { .compatible = "brcm,bcm2711-vc5", }, + { .compatible = "brcm,bcm2835-vc4", }, + { .compatible = "brcm,cygnus-vc4", }, + {}, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -205,6 +205,9 @@ struct vc4_dev { + + int power_refcount; + ++ /* Set to true when the load tracker is supported. */ ++ bool load_tracker_available; ++ + /* Set to true when the load tracker is active. */ + bool load_tracker_enabled; + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -421,6 +421,9 @@ static int vc4_load_tracker_atomic_check + struct drm_plane *plane; + int i; + ++ if (!vc4->load_tracker_available) ++ return 0; ++ + priv_state = drm_atomic_get_private_obj_state(state, + &vc4->load_tracker); + if (IS_ERR(priv_state)) +@@ -520,10 +523,14 @@ int vc4_kms_load(struct drm_device *dev) + struct vc4_load_tracker_state *load_state; + int ret; + +- /* Start with the load tracker enabled. Can be disabled through the +- * debugfs load_tracker file. +- */ +- vc4->load_tracker_enabled = true; ++ if (!of_device_is_compatible(dev->dev->of_node, "brcm,bcm2711-vc5")) { ++ vc4->load_tracker_available = true; ++ ++ /* Start with the load tracker enabled. Can be ++ * disabled through the debugfs load_tracker file. ++ */ ++ vc4->load_tracker_enabled = true; ++ } + + sema_init(&vc4->async_modeset, 1); + +@@ -560,14 +567,17 @@ int vc4_kms_load(struct drm_device *dev) + drm_atomic_private_obj_init(dev, &vc4->ctm_manager, &ctm_state->base, + &vc4_ctm_state_funcs); + +- load_state = kzalloc(sizeof(*load_state), GFP_KERNEL); +- if (!load_state) { +- drm_atomic_private_obj_fini(&vc4->ctm_manager); +- return -ENOMEM; +- } ++ if (vc4->load_tracker_available) { ++ load_state = kzalloc(sizeof(*load_state), GFP_KERNEL); ++ if (!load_state) { ++ drm_atomic_private_obj_fini(&vc4->ctm_manager); ++ return -ENOMEM; ++ } + +- drm_atomic_private_obj_init(dev, &vc4->load_tracker, &load_state->base, +- &vc4_load_tracker_state_funcs); ++ drm_atomic_private_obj_init(dev, &vc4->load_tracker, ++ &load_state->base, ++ &vc4_load_tracker_state_funcs); ++ } + + drm_mode_config_reset(dev); + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -492,6 +492,11 @@ static void vc4_plane_calc_load(struct d + struct vc4_plane_state *vc4_state; + struct drm_crtc_state *crtc_state; + unsigned int vscale_factor; ++ struct vc4_dev *vc4; ++ ++ vc4 = to_vc4_dev(state->plane->dev); ++ if (!vc4->load_tracker_available) ++ return; + + vc4_state = to_vc4_plane_state(state); + crtc_state = drm_atomic_get_existing_crtc_state(state->state, diff --git a/target/linux/bcm27xx/patches-5.4/950-0547-drm-vc4-drv-Add-support-for-the-BCM2711-HVS5.patch b/target/linux/bcm27xx/patches-5.4/950-0547-drm-vc4-drv-Add-support-for-the-BCM2711-HVS5.patch new file mode 100644 index 00000000000..0f6259e347d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0547-drm-vc4-drv-Add-support-for-the-BCM2711-HVS5.patch @@ -0,0 +1,497 @@ +From 354d70a82947041b3d7b87f69641a6741febfc95 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 8 Aug 2019 17:51:07 +0100 +Subject: [PATCH] drm/vc4: drv: Add support for the BCM2711 HVS5 + +The HVS found in the BCM2711 is slightly different from the previous +generations. + +Most notably, the display list layout changes a bit, the LBM doesn't have +the same size and the formats ordering for some formats is swapped. + +Signed-off-by: Dave Stevenson +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 24 +++- + drivers/gpu/drm/vc4/vc4_drv.h | 4 + + drivers/gpu/drm/vc4/vc4_hvs.c | 17 ++- + drivers/gpu/drm/vc4/vc4_plane.c | 194 +++++++++++++++++++++++--------- + drivers/gpu/drm/vc4/vc4_regs.h | 67 +++++++++++ + 5 files changed, 247 insertions(+), 59 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -550,6 +550,7 @@ static void vc4_crtc_atomic_enable(struc + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; ++ u32 dispctrl; + + require_hvs_enabled(dev); + +@@ -564,11 +565,24 @@ static void vc4_crtc_atomic_enable(struc + * When feeding the transposer, we should operate in oneshot + * mode. + */ +- HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), +- VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | +- VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | +- SCALER_DISPCTRLX_ENABLE | +- (vc4_state->feed_txp ? SCALER_DISPCTRLX_ONESHOT : 0)); ++ dispctrl = SCALER_DISPCTRLX_ENABLE; ++ ++ if (!vc4->hvs->hvs5) ++ dispctrl |= VC4_SET_FIELD(mode->hdisplay, ++ SCALER_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, ++ SCALER_DISPCTRLX_HEIGHT) | ++ (vc4_state->feed_txp ? ++ SCALER_DISPCTRLX_ONESHOT : 0); ++ else ++ dispctrl |= VC4_SET_FIELD(mode->hdisplay, ++ SCALER5_DISPCTRLX_WIDTH) | ++ VC4_SET_FIELD(mode->vdisplay, ++ SCALER5_DISPCTRLX_HEIGHT) | ++ (vc4_state->feed_txp ? ++ SCALER5_DISPCTRLX_ONESHOT : 0); ++ ++ HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), dispctrl); + + /* When feeding the transposer block the pixelvalve is unneeded and + * should not be enabled. +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -336,7 +336,11 @@ struct vc4_hvs { + spinlock_t mm_lock; + + struct drm_mm_node mitchell_netravali_filter; ++ + struct debugfs_regset32 regset; ++ ++ /* HVS version 5 flag, therefore requires updated dlist structures */ ++ bool hvs5; + }; + + struct vc4_plane { +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -223,6 +223,7 @@ static int vc4_hvs_bind(struct device *d + struct vc4_hvs *hvs = NULL; + int ret; + u32 dispctrl; ++ unsigned int hvs_version; + + hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); + if (!hvs) +@@ -238,7 +239,14 @@ static int vc4_hvs_bind(struct device *d + hvs->regset.regs = hvs_regs; + hvs->regset.nregs = ARRAY_SIZE(hvs_regs); + +- hvs->dlist = hvs->regs + SCALER_DLIST_START; ++ hvs_version = readl(hvs->regs + SCALER_DISPLSTAT) >> 24; ++ if (hvs_version >= 0x40) ++ hvs->hvs5 = true; ++ ++ if (!hvs->hvs5) ++ hvs->dlist = hvs->regs + SCALER_DLIST_START; ++ else ++ hvs->dlist = hvs->regs + SCALER5_DLIST_START; + + spin_lock_init(&hvs->mm_lock); + +@@ -256,7 +264,12 @@ static int vc4_hvs_bind(struct device *d + * between planes when they don't overlap on the screen, but + * for now we just allocate globally. + */ +- drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024); ++ if (!hvs->hvs5) ++ /* 96kB */ ++ drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024); ++ else ++ /* 70k words */ ++ drm_mm_init(&hvs->lbm_mm, 0, 70 * 2 * 1024); + + /* Upload filter kernels. We only have the one for now, so we + * keep it around for the lifetime of the driver. +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -32,45 +32,60 @@ static const struct hvs_format { + u32 drm; /* DRM_FORMAT_* */ + u32 hvs; /* HVS_FORMAT_* */ + u32 pixel_order; ++ u32 pixel_order_hvs5; + } hvs_formats[] = { + { +- .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .drm = DRM_FORMAT_XRGB8888, ++ .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ABGR, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, + }, + { +- .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .drm = DRM_FORMAT_ARGB8888, ++ .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ABGR, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB, + }, + { +- .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .drm = DRM_FORMAT_ABGR8888, ++ .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ARGB, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, + }, + { +- .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, ++ .drm = DRM_FORMAT_XBGR8888, ++ .hvs = HVS_PIXEL_FORMAT_RGBA8888, + .pixel_order = HVS_PIXEL_ORDER_ARGB, ++ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR, + }, + { +- .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .drm = DRM_FORMAT_RGB565, ++ .hvs = HVS_PIXEL_FORMAT_RGB565, + .pixel_order = HVS_PIXEL_ORDER_XRGB, + }, + { +- .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, ++ .drm = DRM_FORMAT_BGR565, ++ .hvs = HVS_PIXEL_FORMAT_RGB565, + .pixel_order = HVS_PIXEL_ORDER_XBGR, + }, + { +- .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .drm = DRM_FORMAT_ARGB1555, ++ .hvs = HVS_PIXEL_FORMAT_RGBA5551, + .pixel_order = HVS_PIXEL_ORDER_ABGR, + }, + { +- .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, ++ .drm = DRM_FORMAT_XRGB1555, ++ .hvs = HVS_PIXEL_FORMAT_RGBA5551, + .pixel_order = HVS_PIXEL_ORDER_ABGR, + }, + { +- .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, ++ .drm = DRM_FORMAT_RGB888, ++ .hvs = HVS_PIXEL_FORMAT_RGB888, + .pixel_order = HVS_PIXEL_ORDER_XRGB, + }, + { +- .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, ++ .drm = DRM_FORMAT_BGR888, ++ .hvs = HVS_PIXEL_FORMAT_RGB888, + .pixel_order = HVS_PIXEL_ORDER_XBGR, + }, + { +@@ -828,35 +843,6 @@ static int vc4_plane_mode_set(struct drm + return -EINVAL; + } + +- /* Control word */ +- vc4_dlist_write(vc4_state, +- SCALER_CTL0_VALID | +- (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) | +- (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) | +- VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | +- (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | +- (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | +- VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | +- (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | +- VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | +- VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); +- +- /* Position Word 0: Image Positions and Alpha Value */ +- vc4_state->pos0_offset = vc4_state->dlist_count; +- vc4_dlist_write(vc4_state, +- VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | +- VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | +- VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); +- +- /* Position Word 1: Scaled Image Dimensions. */ +- if (!vc4_state->is_unity) { +- vc4_dlist_write(vc4_state, +- VC4_SET_FIELD(vc4_state->crtc_w, +- SCALER_POS1_SCL_WIDTH) | +- VC4_SET_FIELD(vc4_state->crtc_h, +- SCALER_POS1_SCL_HEIGHT)); +- } +- + /* Don't waste cycles mixing with plane alpha if the set alpha + * is opaque or there is no per-pixel alpha information. + * In any case we use the alpha property value as the fixed alpha. +@@ -864,20 +850,120 @@ static int vc4_plane_mode_set(struct drm + mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && + fb->format->has_alpha; + +- /* Position Word 2: Source Image Size, Alpha */ +- vc4_state->pos2_offset = vc4_state->dlist_count; +- vc4_dlist_write(vc4_state, +- VC4_SET_FIELD(fb->format->has_alpha ? +- SCALER_POS2_ALPHA_MODE_PIPELINE : +- SCALER_POS2_ALPHA_MODE_FIXED, +- SCALER_POS2_ALPHA_MODE) | +- (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | +- (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | +- VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | +- VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); ++ if (!vc4->hvs->hvs5) { ++ /* Control word */ ++ vc4_dlist_write(vc4_state, ++ SCALER_CTL0_VALID | ++ (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) | ++ (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) | ++ VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | ++ (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | ++ (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | ++ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | ++ (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | ++ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | ++ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); ++ ++ /* Position Word 0: Image Positions and Alpha Value */ ++ vc4_state->pos0_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | ++ VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | ++ VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); ++ ++ /* Position Word 1: Scaled Image Dimensions. */ ++ if (!vc4_state->is_unity) { ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_w, ++ SCALER_POS1_SCL_WIDTH) | ++ VC4_SET_FIELD(vc4_state->crtc_h, ++ SCALER_POS1_SCL_HEIGHT)); ++ } ++ ++ /* Position Word 2: Source Image Size, Alpha */ ++ vc4_state->pos2_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(fb->format->has_alpha ? ++ SCALER_POS2_ALPHA_MODE_PIPELINE : ++ SCALER_POS2_ALPHA_MODE_FIXED, ++ SCALER_POS2_ALPHA_MODE) | ++ (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | ++ (fb->format->has_alpha ? ++ SCALER_POS2_ALPHA_PREMULT : 0) | ++ VC4_SET_FIELD(vc4_state->src_w[0], ++ SCALER_POS2_WIDTH) | ++ VC4_SET_FIELD(vc4_state->src_h[0], ++ SCALER_POS2_HEIGHT)); + +- /* Position Word 3: Context. Written by the HVS. */ +- vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ /* Position Word 3: Context. Written by the HVS. */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ ++ } else { ++ u32 hvs_pixel_order = format->pixel_order; ++ ++ if (format->pixel_order_hvs5) ++ hvs_pixel_order = format->pixel_order_hvs5; ++ ++ /* Control word */ ++ vc4_dlist_write(vc4_state, ++ SCALER_CTL0_VALID | ++ (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) | ++ (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | ++ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | ++ (vc4_state->is_unity ? ++ SCALER5_CTL0_UNITY : 0) | ++ VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | ++ VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) | ++ SCALER5_CTL0_ALPHA_EXPAND | ++ SCALER5_CTL0_RGB_EXPAND); ++ ++ /* Position Word 0: Image Positions and Alpha Value */ ++ vc4_state->pos0_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ (rotation & DRM_MODE_REFLECT_Y ? ++ SCALER5_POS0_VFLIP : 0) | ++ VC4_SET_FIELD(vc4_state->crtc_x, ++ SCALER_POS0_START_X) | ++ (rotation & DRM_MODE_REFLECT_X ? ++ SCALER5_POS0_HFLIP : 0) | ++ VC4_SET_FIELD(vc4_state->crtc_y, ++ SCALER5_POS0_START_Y) ++ ); ++ ++ /* Control Word 2 */ ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(state->alpha >> 4, ++ SCALER5_CTL2_ALPHA) | ++ fb->format->has_alpha ? ++ SCALER5_CTL2_ALPHA_PREMULT : 0 | ++ (mix_plane_alpha ? ++ SCALER5_CTL2_ALPHA_MIX : 0) | ++ VC4_SET_FIELD(fb->format->has_alpha ? ++ SCALER5_CTL2_ALPHA_MODE_PIPELINE : ++ SCALER5_CTL2_ALPHA_MODE_FIXED, ++ SCALER5_CTL2_ALPHA_MODE) ++ ); ++ ++ /* Position Word 1: Scaled Image Dimensions. */ ++ if (!vc4_state->is_unity) { ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->crtc_w, ++ SCALER_POS1_SCL_WIDTH) | ++ VC4_SET_FIELD(vc4_state->crtc_h, ++ SCALER_POS1_SCL_HEIGHT)); ++ } ++ ++ /* Position Word 2: Source Image Size */ ++ vc4_state->pos2_offset = vc4_state->dlist_count; ++ vc4_dlist_write(vc4_state, ++ VC4_SET_FIELD(vc4_state->src_w[0], ++ SCALER5_POS2_WIDTH) | ++ VC4_SET_FIELD(vc4_state->src_h[0], ++ SCALER5_POS2_HEIGHT)); ++ ++ /* Position Word 3: Context. Written by the HVS. */ ++ vc4_dlist_write(vc4_state, 0xc0c0c0c0); ++ } + + + /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers +@@ -1266,6 +1352,10 @@ static bool vc4_format_mod_supported(str + default: + return false; + } ++ case DRM_FORMAT_RGBX1010102: ++ case DRM_FORMAT_BGRX1010102: ++ case DRM_FORMAT_RGBA1010102: ++ case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YVU422: + case DRM_FORMAT_YUV420: +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -328,6 +328,20 @@ + # define SCALER_DISPCTRLX_HEIGHT_MASK VC4_MASK(11, 0) + # define SCALER_DISPCTRLX_HEIGHT_SHIFT 0 + ++# define SCALER5_DISPCTRLX_WIDTH_MASK VC4_MASK(28, 16) ++# define SCALER5_DISPCTRLX_WIDTH_SHIFT 16 ++/* Generates a single frame when VSTART is seen and stops at the last ++ * pixel read from the FIFO. ++ */ ++# define SCALER5_DISPCTRLX_ONESHOT BIT(15) ++/* Processes a single context in the dlist and then task switch, ++ * instead of an entire line. ++ */ ++# define SCALER5_DISPCTRLX_ONECTX_MASK VC4_MASK(14, 13) ++# define SCALER5_DISPCTRLX_ONECTX_SHIFT 13 ++# define SCALER5_DISPCTRLX_HEIGHT_MASK VC4_MASK(12, 0) ++# define SCALER5_DISPCTRLX_HEIGHT_SHIFT 0 ++ + #define SCALER_DISPBKGND0 0x00000044 + # define SCALER_DISPBKGND_AUTOHS BIT(31) + # define SCALER_DISPBKGND_INTERLACE BIT(30) +@@ -461,6 +475,8 @@ + #define SCALER_DLIST_START 0x00002000 + #define SCALER_DLIST_SIZE 0x00004000 + ++#define SCALER5_DLIST_START 0x00004000 ++ + #define VC4_HDMI_CORE_REV 0x000 + + #define VC4_HDMI_SW_RESET_CONTROL 0x004 +@@ -826,6 +842,8 @@ enum hvs_pixel_format { + HVS_PIXEL_FORMAT_PALETTE = 13, + HVS_PIXEL_FORMAT_YUV444_RGB = 14, + HVS_PIXEL_FORMAT_AYUV444_RGB = 15, ++ HVS_PIXEL_FORMAT_RGBA1010102 = 16, ++ HVS_PIXEL_FORMAT_YCBCR_10BIT = 17, + }; + + /* Note: the LSB is the rightmost character shown. Only valid for +@@ -880,6 +898,10 @@ enum hvs_pixel_format { + #define SCALER_CTL0_RGBA_EXPAND_MSB 2 + #define SCALER_CTL0_RGBA_EXPAND_ROUND 3 + ++#define SCALER5_CTL0_ALPHA_EXPAND BIT(12) ++ ++#define SCALER5_CTL0_RGB_EXPAND BIT(11) ++ + #define SCALER_CTL0_SCL1_MASK VC4_MASK(10, 8) + #define SCALER_CTL0_SCL1_SHIFT 8 + +@@ -897,10 +919,13 @@ enum hvs_pixel_format { + + /* Set to indicate no scaling. */ + #define SCALER_CTL0_UNITY BIT(4) ++#define SCALER5_CTL0_UNITY BIT(15) + + #define SCALER_CTL0_PIXEL_FORMAT_MASK VC4_MASK(3, 0) + #define SCALER_CTL0_PIXEL_FORMAT_SHIFT 0 + ++#define SCALER5_CTL0_PIXEL_FORMAT_MASK VC4_MASK(4, 0) ++ + #define SCALER_POS0_FIXED_ALPHA_MASK VC4_MASK(31, 24) + #define SCALER_POS0_FIXED_ALPHA_SHIFT 24 + +@@ -910,12 +935,48 @@ enum hvs_pixel_format { + #define SCALER_POS0_START_X_MASK VC4_MASK(11, 0) + #define SCALER_POS0_START_X_SHIFT 0 + ++#define SCALER5_POS0_START_Y_MASK VC4_MASK(27, 16) ++#define SCALER5_POS0_START_Y_SHIFT 16 ++ ++#define SCALER5_POS0_START_X_MASK VC4_MASK(13, 0) ++#define SCALER5_POS0_START_X_SHIFT 0 ++ ++#define SCALER5_POS0_VFLIP BIT(31) ++#define SCALER5_POS0_HFLIP BIT(15) ++ ++#define SCALER5_CTL2_ALPHA_MODE_MASK VC4_MASK(31, 30) ++#define SCALER5_CTL2_ALPHA_MODE_SHIFT 30 ++#define SCALER5_CTL2_ALPHA_MODE_PIPELINE 0 ++#define SCALER5_CTL2_ALPHA_MODE_FIXED 1 ++#define SCALER5_CTL2_ALPHA_MODE_FIXED_NONZERO 2 ++#define SCALER5_CTL2_ALPHA_MODE_FIXED_OVER_0x07 3 ++ ++#define SCALER5_CTL2_ALPHA_PREMULT BIT(29) ++ ++#define SCALER5_CTL2_ALPHA_MIX BIT(28) ++ ++#define SCALER5_CTL2_ALPHA_LOC BIT(25) ++ ++#define SCALER5_CTL2_MAP_SEL_MASK VC4_MASK(18, 17) ++#define SCALER5_CTL2_MAP_SEL_SHIFT 17 ++ ++#define SCALER5_CTL2_GAMMA BIT(16) ++ ++#define SCALER5_CTL2_ALPHA_MASK VC4_MASK(15, 4) ++#define SCALER5_CTL2_ALPHA_SHIFT 4 ++ + #define SCALER_POS1_SCL_HEIGHT_MASK VC4_MASK(27, 16) + #define SCALER_POS1_SCL_HEIGHT_SHIFT 16 + + #define SCALER_POS1_SCL_WIDTH_MASK VC4_MASK(11, 0) + #define SCALER_POS1_SCL_WIDTH_SHIFT 0 + ++#define SCALER5_POS1_SCL_HEIGHT_MASK VC4_MASK(28, 16) ++#define SCALER5_POS1_SCL_HEIGHT_SHIFT 16 ++ ++#define SCALER5_POS1_SCL_WIDTH_MASK VC4_MASK(12, 0) ++#define SCALER5_POS1_SCL_WIDTH_SHIFT 0 ++ + #define SCALER_POS2_ALPHA_MODE_MASK VC4_MASK(31, 30) + #define SCALER_POS2_ALPHA_MODE_SHIFT 30 + #define SCALER_POS2_ALPHA_MODE_PIPELINE 0 +@@ -931,6 +992,12 @@ enum hvs_pixel_format { + #define SCALER_POS2_WIDTH_MASK VC4_MASK(11, 0) + #define SCALER_POS2_WIDTH_SHIFT 0 + ++#define SCALER5_POS2_HEIGHT_MASK VC4_MASK(28, 16) ++#define SCALER5_POS2_HEIGHT_SHIFT 16 ++ ++#define SCALER5_POS2_WIDTH_MASK VC4_MASK(12, 0) ++#define SCALER5_POS2_WIDTH_SHIFT 0 ++ + /* Color Space Conversion words. Some values are S2.8 signed + * integers, except that the 2 integer bits map as {0x0: 0, 0x1: 1, + * 0x2: 2, 0x3: -1} diff --git a/target/linux/bcm27xx/patches-5.4/950-0548-drm-vc4-plane-Improve-LBM-usage.patch b/target/linux/bcm27xx/patches-5.4/950-0548-drm-vc4-plane-Improve-LBM-usage.patch new file mode 100644 index 00000000000..df7a98fc548 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0548-drm-vc4-plane-Improve-LBM-usage.patch @@ -0,0 +1,98 @@ +From 81072e19a85bfa3f80c23acdff6156522d945efa Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 11 Feb 2020 16:55:02 +0000 +Subject: [PATCH] drm/vc4: plane: Improve LBM usage + +LBM allocations were always taking the worst case sizing of +max(src_width, dst_width) * 16. This is significantly over +the required sizing, and stops us rendering multiple 4k images +to the screen. + +Add some of the additional constraints to more accurately +describe the LBM requirements. + +Signed-off-by: Dave Stevenson +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -142,9 +142,10 @@ static const struct hvs_format *vc4_get_ + return NULL; + } + +-static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) ++static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst, ++ bool chroma_vrep) + { +- if (dst == src) ++ if (dst == src && !chroma_vrep) + return VC4_SCALING_NONE; + if (3 * dst >= 2 * src) + return VC4_SCALING_PPF; +@@ -369,9 +370,11 @@ static int vc4_plane_setup_clipping_and_ + return ret; + + vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], +- vc4_state->crtc_w); ++ vc4_state->crtc_w, ++ false); + vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0], +- vc4_state->crtc_h); ++ vc4_state->crtc_h, ++ false); + + vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && + vc4_state->y_scaling[0] == VC4_SCALING_NONE); +@@ -384,10 +387,12 @@ static int vc4_plane_setup_clipping_and_ + + vc4_state->x_scaling[1] = + vc4_get_scaling_mode(vc4_state->src_w[1], +- vc4_state->crtc_w); ++ vc4_state->crtc_w, ++ v_subsample == 2); + vc4_state->y_scaling[1] = + vc4_get_scaling_mode(vc4_state->src_h[1], +- vc4_state->crtc_h); ++ vc4_state->crtc_h, ++ v_subsample == 2); + + /* YUV conversion requires that horizontal scaling be enabled + * on the UV plane even if vc4_get_scaling_mode() returned +@@ -437,10 +442,7 @@ static void vc4_write_ppf(struct vc4_pla + static u32 vc4_lbm_size(struct drm_plane_state *state) + { + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); +- /* This is the worst case number. One of the two sizes will +- * be used depending on the scaling configuration. +- */ +- u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); ++ u32 pix_per_line; + u32 lbm; + + /* LBM is not needed when there's no vertical scaling. */ +@@ -448,6 +450,11 @@ static u32 vc4_lbm_size(struct drm_plane + vc4_state->y_scaling[1] == VC4_SCALING_NONE) + return 0; + ++ if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ) ++ pix_per_line = vc4_state->crtc_w; ++ else ++ pix_per_line = vc4_state->src_w[0]; ++ + if (!vc4_state->is_yuv) { + if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) + lbm = pix_per_line * 8; +@@ -583,7 +590,9 @@ static int vc4_plane_allocate_lbm(struct + spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, + &vc4_state->lbm, +- lbm_size, 32, 0, 0); ++ lbm_size, ++ vc4->hvs->hvs5 ? 64 : 32, ++ 0, 0); + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); + + if (ret) diff --git a/target/linux/bcm27xx/patches-5.4/950-0549-drm-vc4-plane-Move-planes-creation-to-its-own-functi.patch b/target/linux/bcm27xx/patches-5.4/950-0549-drm-vc4-plane-Move-planes-creation-to-its-own-functi.patch new file mode 100644 index 00000000000..7c3c4708498 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0549-drm-vc4-plane-Move-planes-creation-to-its-own-functi.patch @@ -0,0 +1,125 @@ +From ac2c812856c3a496354b9f19d0a43458e108844d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 14:32:57 +0100 +Subject: [PATCH] drm/vc4: plane: Move planes creation to its own + function + +The planes so far were created as part of the CRTC binding code with +each planes created associated only to one CRTC. However, the hardware +in the vc4 doesn't really have such constraint and can be used with any +CRTC. + +In order to rework this, let's first move the overlay and cursor planes +creation to a function of its own. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 33 ++++------------------------ + drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ + drivers/gpu/drm/vc4/vc4_plane.c | 38 +++++++++++++++++++++++++++++++++ + 3 files changed, 44 insertions(+), 29 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1142,7 +1142,7 @@ static int vc4_crtc_bind(struct device * + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_crtc *vc4_crtc; + struct drm_crtc *crtc; +- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp; ++ struct drm_plane *primary_plane, *destroy_plane, *temp; + const struct of_device_id *match; + int ret, i; + +@@ -1190,34 +1190,9 @@ static int vc4_crtc_bind(struct device * + */ + drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); + +- /* Set up some arbitrary number of planes. We're not limited +- * by a set number of physical registers, just the space in +- * the HVS (16k) and how small an plane can be (28 bytes). +- * However, each plane we set up takes up some memory, and +- * increases the cost of looping over planes, which atomic +- * modesetting does quite a bit. As a result, we pick a +- * modest number of planes to expose, that should hopefully +- * still cover any sane usecase. +- */ +- for (i = 0; i < 8; i++) { +- struct drm_plane *plane = +- vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); +- +- if (IS_ERR(plane)) +- continue; +- +- plane->possible_crtcs = drm_crtc_mask(crtc); +- } +- +- /* Set up the legacy cursor after overlay initialization, +- * since we overlay planes on the CRTC in the order they were +- * initialized. +- */ +- cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); +- if (!IS_ERR(cursor_plane)) { +- cursor_plane->possible_crtcs = drm_crtc_mask(crtc); +- crtc->cursor = cursor_plane; +- } ++ ret = vc4_plane_create_additional_planes(drm, crtc); ++ if (ret) ++ goto err_destroy_planes; + + vc4_crtc_get_cob_allocation(vc4_crtc); + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -855,6 +855,8 @@ int vc4_kms_load(struct drm_device *dev) + /* vc4_plane.c */ + struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type); ++int vc4_plane_create_additional_planes(struct drm_device *dev, ++ struct drm_crtc *crtc); + u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); + u32 vc4_plane_dlist_size(const struct drm_plane_state *state); + void vc4_plane_async_set_fb(struct drm_plane *plane, +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1437,3 +1437,41 @@ struct drm_plane *vc4_plane_init(struct + + return plane; + } ++ ++int vc4_plane_create_additional_planes(struct drm_device *drm, ++ struct drm_crtc *crtc) ++{ ++ struct drm_plane *cursor_plane; ++ unsigned int i; ++ ++ /* Set up some arbitrary number of planes. We're not limited ++ * by a set number of physical registers, just the space in ++ * the HVS (16k) and how small an plane can be (28 bytes). ++ * However, each plane we set up takes up some memory, and ++ * increases the cost of looping over planes, which atomic ++ * modesetting does quite a bit. As a result, we pick a ++ * modest number of planes to expose, that should hopefully ++ * still cover any sane usecase. ++ */ ++ for (i = 0; i < 8; i++) { ++ struct drm_plane *plane = ++ vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); ++ ++ if (IS_ERR(plane)) ++ continue; ++ ++ plane->possible_crtcs = drm_crtc_mask(crtc); ++ } ++ ++ /* Set up the legacy cursor after overlay initialization, ++ * since we overlay planes on the CRTC in the order they were ++ * initialized. ++ */ ++ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); ++ if (!IS_ERR(cursor_plane)) { ++ cursor_plane->possible_crtcs = drm_crtc_mask(crtc); ++ crtc->cursor = cursor_plane; ++ } ++ ++ return 0; ++} diff --git a/target/linux/bcm27xx/patches-5.4/950-0550-drm-vc4-plane-Move-additional-planes-creation-to-dri.patch b/target/linux/bcm27xx/patches-5.4/950-0550-drm-vc4-plane-Move-additional-planes-creation-to-dri.patch new file mode 100644 index 00000000000..b2e9f15647b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0550-drm-vc4-plane-Move-additional-planes-creation-to-dri.patch @@ -0,0 +1,75 @@ +From 5331cbb3d9cfb172ed134f08a35740e0a52d1107 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 14:41:41 +0100 +Subject: [PATCH] drm/vc4: plane: Move additional planes creation to + driver + +So far the plane creation was done when each CRTC was bound, and those +planes were only tied to the CRTC that was registering them. + +This causes two main issues: + - The planes in the vc4 hardware are actually not tied to any CRTC, but + can be used with every combination + + - More importantly, so far, we allocate 10 planes per CRTC, with 3 CRTCs. + However, the next generation of hardware will have 5 CRTCs, putting us + well above the maximum of 32 planes currently allowed by DRM. + +This patch is the first one in a series of patches that will take down both +of these issues so that we can support the next generation of hardware +while keeping a good amount of planes. + +We start by changing the way the planes are registered to first registering +the primary planes for each CRTC in the CRTC bind function as we used to, +but moving the overlay and cursor creation to the main driver bind +function, after all the CRTCs have been bound. + +This will slightly change the ID order of the planes, since the primary +planes of all CRTCs will be first, and then a pattern of 8 overlays, 1 +cursor plane for each CRTC. + +This shouldn't cause any trouble since the ordering between the planes is +preserved though. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 4 ---- + drivers/gpu/drm/vc4/vc4_drv.c | 7 +++++++ + 2 files changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1190,10 +1190,6 @@ static int vc4_crtc_bind(struct device * + */ + drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); + +- ret = vc4_plane_create_additional_planes(drm, crtc); +- if (ret) +- goto err_destroy_planes; +- + vc4_crtc_get_cob_allocation(vc4_crtc); + + CRTC_WRITE(PV_INTEN, 0); +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -253,6 +253,7 @@ static int vc4_drm_bind(struct device *d + { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm; ++ struct drm_crtc *crtc; + struct vc4_dev *vc4; + struct device_node *node; + int ret = 0; +@@ -291,6 +292,12 @@ static int vc4_drm_bind(struct device *d + if (ret) + goto gem_destroy; + ++ drm_for_each_crtc(crtc, drm) { ++ ret = vc4_plane_create_additional_planes(drm, crtc); ++ if (ret) ++ continue; ++ } ++ + drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false); + + ret = vc4_kms_load(drm); diff --git a/target/linux/bcm27xx/patches-5.4/950-0551-drm-vc4-plane-Register-all-the-planes-at-once.patch b/target/linux/bcm27xx/patches-5.4/950-0551-drm-vc4-plane-Register-all-the-planes-at-once.patch new file mode 100644 index 00000000000..e917410b864 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0551-drm-vc4-plane-Register-all-the-planes-at-once.patch @@ -0,0 +1,128 @@ +From bb2b068209d73b320cac7222a3b8ecef9b0dcc9a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 14:46:14 +0100 +Subject: [PATCH] drm/vc4: plane: Register all the planes at once + +Instead of creating planes for each CRTC, we eventually want to create all +the planes for each CRTCs. + +In order to make that more convenient, let's iterate on the CRTCs in the +plane creation function instead of its caller. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.c | 9 ++---- + drivers/gpu/drm/vc4/vc4_drv.h | 3 +- + drivers/gpu/drm/vc4/vc4_plane.c | 54 +++++++++++++++++---------------- + 3 files changed, 32 insertions(+), 34 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -253,7 +253,6 @@ static int vc4_drm_bind(struct device *d + { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm; +- struct drm_crtc *crtc; + struct vc4_dev *vc4; + struct device_node *node; + int ret = 0; +@@ -292,11 +291,9 @@ static int vc4_drm_bind(struct device *d + if (ret) + goto gem_destroy; + +- drm_for_each_crtc(crtc, drm) { +- ret = vc4_plane_create_additional_planes(drm, crtc); +- if (ret) +- continue; +- } ++ ret = vc4_plane_create_additional_planes(drm); ++ if (ret) ++ goto unbind_all; + + drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false); + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -855,8 +855,7 @@ int vc4_kms_load(struct drm_device *dev) + /* vc4_plane.c */ + struct drm_plane *vc4_plane_init(struct drm_device *dev, + enum drm_plane_type type); +-int vc4_plane_create_additional_planes(struct drm_device *dev, +- struct drm_crtc *crtc); ++int vc4_plane_create_additional_planes(struct drm_device *dev); + u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); + u32 vc4_plane_dlist_size(const struct drm_plane_state *state); + void vc4_plane_async_set_fb(struct drm_plane *plane, +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1438,39 +1438,41 @@ struct drm_plane *vc4_plane_init(struct + return plane; + } + +-int vc4_plane_create_additional_planes(struct drm_device *drm, +- struct drm_crtc *crtc) ++int vc4_plane_create_additional_planes(struct drm_device *drm) + { + struct drm_plane *cursor_plane; ++ struct drm_crtc *crtc; + unsigned int i; + +- /* Set up some arbitrary number of planes. We're not limited +- * by a set number of physical registers, just the space in +- * the HVS (16k) and how small an plane can be (28 bytes). +- * However, each plane we set up takes up some memory, and +- * increases the cost of looping over planes, which atomic +- * modesetting does quite a bit. As a result, we pick a +- * modest number of planes to expose, that should hopefully +- * still cover any sane usecase. +- */ +- for (i = 0; i < 8; i++) { +- struct drm_plane *plane = +- vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); +- +- if (IS_ERR(plane)) +- continue; +- +- plane->possible_crtcs = drm_crtc_mask(crtc); +- } +- +- /* Set up the legacy cursor after overlay initialization, +- * since we overlay planes on the CRTC in the order they were +- * initialized. +- */ +- cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); +- if (!IS_ERR(cursor_plane)) { +- cursor_plane->possible_crtcs = drm_crtc_mask(crtc); +- crtc->cursor = cursor_plane; ++ drm_for_each_crtc(crtc, drm) { ++ /* Set up some arbitrary number of planes. We're not limited ++ * by a set number of physical registers, just the space in ++ * the HVS (16k) and how small an plane can be (28 bytes). ++ * However, each plane we set up takes up some memory, and ++ * increases the cost of looping over planes, which atomic ++ * modesetting does quite a bit. As a result, we pick a ++ * modest number of planes to expose, that should hopefully ++ * still cover any sane usecase. ++ */ ++ for (i = 0; i < 8; i++) { ++ struct drm_plane *plane = ++ vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); ++ ++ if (IS_ERR(plane)) ++ continue; ++ ++ plane->possible_crtcs = drm_crtc_mask(crtc); ++ } ++ ++ /* Set up the legacy cursor after overlay initialization, ++ * since we overlay planes on the CRTC in the order they were ++ * initialized. ++ */ ++ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); ++ if (!IS_ERR(cursor_plane)) { ++ cursor_plane->possible_crtcs = drm_crtc_mask(crtc); ++ crtc->cursor = cursor_plane; ++ } + } + + return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0552-drm-vc4-plane-Create-overlays-for-any-CRTC.patch b/target/linux/bcm27xx/patches-5.4/950-0552-drm-vc4-plane-Create-overlays-for-any-CRTC.patch new file mode 100644 index 00000000000..54d04e59e15 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0552-drm-vc4-plane-Create-overlays-for-any-CRTC.patch @@ -0,0 +1,70 @@ +From b65167e0bcce67f2e7b7e813dba536f1cca3ef9f Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 14:50:06 +0100 +Subject: [PATCH] drm/vc4: plane: Create overlays for any CRTC + +Now that we have everything in place, we can now register all the overlay +planes that can be assigned to all the CRTCs. + +This has two side effects: + + - The number of overlay planes is reduced from 24 to 8. This is temporary + and will be increased again in the next patch. + + - The ID of the various planes is changed again, and we will now have all + the primary planes, then all the overlay planes and finally the cursor + planes. This shouldn't cause any issue since the ordering between + primary, overlay and cursor planes is preserved. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 35 +++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 17 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1444,26 +1444,27 @@ int vc4_plane_create_additional_planes(s + struct drm_crtc *crtc; + unsigned int i; + +- drm_for_each_crtc(crtc, drm) { +- /* Set up some arbitrary number of planes. We're not limited +- * by a set number of physical registers, just the space in +- * the HVS (16k) and how small an plane can be (28 bytes). +- * However, each plane we set up takes up some memory, and +- * increases the cost of looping over planes, which atomic +- * modesetting does quite a bit. As a result, we pick a +- * modest number of planes to expose, that should hopefully +- * still cover any sane usecase. +- */ +- for (i = 0; i < 8; i++) { +- struct drm_plane *plane = +- vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); ++ /* Set up some arbitrary number of planes. We're not limited ++ * by a set number of physical registers, just the space in ++ * the HVS (16k) and how small an plane can be (28 bytes). ++ * However, each plane we set up takes up some memory, and ++ * increases the cost of looping over planes, which atomic ++ * modesetting does quite a bit. As a result, we pick a ++ * modest number of planes to expose, that should hopefully ++ * still cover any sane usecase. ++ */ ++ for (i = 0; i < 8; i++) { ++ struct drm_plane *plane = ++ vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); + +- if (IS_ERR(plane)) +- continue; ++ if (IS_ERR(plane)) ++ continue; + +- plane->possible_crtcs = drm_crtc_mask(crtc); +- } ++ plane->possible_crtcs = ++ GENMASK(drm->mode_config.num_crtc - 1, 0); ++ } + ++ drm_for_each_crtc(crtc, drm) { + /* Set up the legacy cursor after overlay initialization, + * since we overlay planes on the CRTC in the order they were + * initialized. diff --git a/target/linux/bcm27xx/patches-5.4/950-0553-drm-vc4-plane-Create-more-planes.patch b/target/linux/bcm27xx/patches-5.4/950-0553-drm-vc4-plane-Create-more-planes.patch new file mode 100644 index 00000000000..08383e37084 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0553-drm-vc4-plane-Create-more-planes.patch @@ -0,0 +1,32 @@ +From b79a33509a3aa863cdf54d24e1a4a0cc2c6fe84c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 14:52:42 +0100 +Subject: [PATCH] drm/vc4: plane: Create more planes + +Let's now create more planes that can be affected to all the CRTCs. + +vc4 has 3 CRTCs, 1 primary and 1 cursor each, and was having 24 (8 +planes per CRTC) overlays. + +However, vc5 has 5 CRTCs, so keeping the same logic would put us at 50 +planes which is well above the 32 planes limit imposed by DRM. + +Using 16 seems like a good tradeoff between staying under 32 and yet +providing enough planes. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_plane.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1453,7 +1453,7 @@ int vc4_plane_create_additional_planes(s + * modest number of planes to expose, that should hopefully + * still cover any sane usecase. + */ +- for (i = 0; i < 8; i++) { ++ for (i = 0; i < 16; i++) { + struct drm_plane *plane = + vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0554-drm-vc4-crtc-Rename-SoC-data-structures.patch b/target/linux/bcm27xx/patches-5.4/950-0554-drm-vc4-crtc-Rename-SoC-data-structures.patch new file mode 100644 index 00000000000..8b8eeea7374 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0554-drm-vc4-crtc-Rename-SoC-data-structures.patch @@ -0,0 +1,56 @@ +From f071c70678b875d2e5411ead123015381647e9f9 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 11:45:04 +0100 +Subject: [PATCH] drm/vc4: crtc: Rename SoC data structures + +Since we're going to introduce pixelvalve data structures for other SoCs +than the BCM2835, let's rename the structures defined in the code to +make it obvious which SoC we're targetting. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1056,7 +1056,7 @@ static const struct drm_crtc_helper_func + .atomic_disable = vc4_crtc_atomic_disable, + }; + +-static const struct vc4_crtc_data pv0_data = { ++static const struct vc4_crtc_data bcm2835_pv0_data = { + .hvs_channel = 0, + .debugfs_name = "crtc0_regs", + .encoder_types = { +@@ -1065,7 +1065,7 @@ static const struct vc4_crtc_data pv0_da + }, + }; + +-static const struct vc4_crtc_data pv1_data = { ++static const struct vc4_crtc_data bcm2835_pv1_data = { + .hvs_channel = 2, + .debugfs_name = "crtc1_regs", + .encoder_types = { +@@ -1074,7 +1074,7 @@ static const struct vc4_crtc_data pv1_da + }, + }; + +-static const struct vc4_crtc_data pv2_data = { ++static const struct vc4_crtc_data bcm2835_pv2_data = { + .hvs_channel = 1, + .debugfs_name = "crtc2_regs", + .encoder_types = { +@@ -1084,9 +1084,9 @@ static const struct vc4_crtc_data pv2_da + }; + + static const struct of_device_id vc4_crtc_dt_match[] = { +- { .compatible = "brcm,bcm2835-pixelvalve0", .data = &pv0_data }, +- { .compatible = "brcm,bcm2835-pixelvalve1", .data = &pv1_data }, +- { .compatible = "brcm,bcm2835-pixelvalve2", .data = &pv2_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, ++ { .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data }, + {} + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Move-crtc-state-to-common-header.patch b/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Move-crtc-state-to-common-header.patch new file mode 100644 index 00000000000..6108f867877 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Move-crtc-state-to-common-header.patch @@ -0,0 +1,74 @@ +From 05293c3b61cdeb0004722cc86e03123183557de1 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 15:45:04 +0100 +Subject: [PATCH] drm/vc4: crtc: Move crtc state to common header + +We'll need to access the crtc_state from outside of vc4_crtc.c, so let's +move it to vc4_drv.h + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 21 --------------------- + drivers/gpu/drm/vc4/vc4_drv.h | 21 +++++++++++++++++++++ + 2 files changed, 21 insertions(+), 21 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -44,27 +44,6 @@ + #include "vc4_drv.h" + #include "vc4_regs.h" + +-struct vc4_crtc_state { +- struct drm_crtc_state base; +- /* Dlist area for this CRTC configuration. */ +- struct drm_mm_node mm; +- bool feed_txp; +- bool txp_armed; +- +- struct { +- unsigned int left; +- unsigned int right; +- unsigned int top; +- unsigned int bottom; +- } margins; +-}; +- +-static inline struct vc4_crtc_state * +-to_vc4_crtc_state(struct drm_crtc_state *crtc_state) +-{ +- return (struct vc4_crtc_state *)crtc_state; +-} +- + #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) + #define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -488,6 +488,27 @@ to_vc4_crtc(struct drm_crtc *crtc) + return (struct vc4_crtc *)crtc; + } + ++struct vc4_crtc_state { ++ struct drm_crtc_state base; ++ /* Dlist area for this CRTC configuration. */ ++ struct drm_mm_node mm; ++ bool feed_txp; ++ bool txp_armed; ++ ++ struct { ++ unsigned int left; ++ unsigned int right; ++ unsigned int top; ++ unsigned int bottom; ++ } margins; ++}; ++ ++static inline struct vc4_crtc_state * ++to_vc4_crtc_state(struct drm_crtc_state *crtc_state) ++{ ++ return (struct vc4_crtc_state *)crtc_state; ++} ++ + #define V3D_READ(offset) readl(vc4->v3d->regs + offset) + #define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset) + #define HVS_READ(offset) readl(vc4->hvs->regs + offset) diff --git a/target/linux/bcm27xx/patches-5.4/950-0556-drm-vc4-crtc-Deal-with-different-number-of-pixel-per.patch b/target/linux/bcm27xx/patches-5.4/950-0556-drm-vc4-crtc-Deal-with-different-number-of-pixel-per.patch new file mode 100644 index 00000000000..5949e616f9c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0556-drm-vc4-crtc-Deal-with-different-number-of-pixel-per.patch @@ -0,0 +1,86 @@ +From b8714036be64c86a274ea49ba0066af0a81c6b98 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 11:36:50 +0100 +Subject: [PATCH] drm/vc4: crtc: Deal with different number of pixel + per clock + +Some of the HDMI pixelvalves in vc5 output two pixels per clock cycle. +Let's put the number of pixel output per clock cycle in the CRTC data and +update the various calculations to reflect that. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 17 ++++++++++------- + drivers/gpu/drm/vc4/vc4_drv.h | 3 +++ + 2 files changed, 13 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -281,6 +281,7 @@ static void vc4_crtc_config_pv(struct dr + bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || + vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); + u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; ++ u8 ppc = vc4_crtc->data->pixels_per_clock; + + /* Reset the PV fifo. */ + CRTC_WRITE(PV_CONTROL, 0); +@@ -288,17 +289,16 @@ static void vc4_crtc_config_pv(struct dr + CRTC_WRITE(PV_CONTROL, 0); + + CRTC_WRITE(PV_HORZA, +- VC4_SET_FIELD((mode->htotal - +- mode->hsync_end) * pixel_rep, ++ VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc, + PV_HORZA_HBP) | +- VC4_SET_FIELD((mode->hsync_end - +- mode->hsync_start) * pixel_rep, ++ VC4_SET_FIELD((mode->hsync_end - mode->hsync_start) * pixel_rep / ppc, + PV_HORZA_HSYNC)); ++ + CRTC_WRITE(PV_HORZB, +- VC4_SET_FIELD((mode->hsync_start - +- mode->hdisplay) * pixel_rep, ++ VC4_SET_FIELD((mode->hsync_start - mode->hdisplay) * pixel_rep / ppc, + PV_HORZB_HFP) | +- VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE)); ++ VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc, ++ PV_HORZB_HACTIVE)); + + CRTC_WRITE(PV_VERTA, + VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, +@@ -1038,6 +1038,7 @@ static const struct drm_crtc_helper_func + static const struct vc4_crtc_data bcm2835_pv0_data = { + .hvs_channel = 0, + .debugfs_name = "crtc0_regs", ++ .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI, +@@ -1047,6 +1048,7 @@ static const struct vc4_crtc_data bcm283 + static const struct vc4_crtc_data bcm2835_pv1_data = { + .hvs_channel = 2, + .debugfs_name = "crtc1_regs", ++ .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI, +@@ -1056,6 +1058,7 @@ static const struct vc4_crtc_data bcm283 + static const struct vc4_crtc_data bcm2835_pv2_data = { + .hvs_channel = 1, + .debugfs_name = "crtc2_regs", ++ .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -455,6 +455,9 @@ struct vc4_crtc_data { + /* Which channel of the HVS this pixelvalve sources from. */ + int hvs_channel; + ++ /* Number of pixels output per clock period */ ++ u8 pixels_per_clock; ++ + enum vc4_encoder_type encoder_types[4]; + const char *debugfs_name; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0557-drm-vc4-crtc-Use-a-shared-interrupt.patch b/target/linux/bcm27xx/patches-5.4/950-0557-drm-vc4-crtc-Use-a-shared-interrupt.patch new file mode 100644 index 00000000000..b517b5414bb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0557-drm-vc4-crtc-Use-a-shared-interrupt.patch @@ -0,0 +1,26 @@ +From 5451dc04ff87dcf514c422f180ea5e23b7b60151 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 9 Jan 2020 18:40:49 +0100 +Subject: [PATCH] drm/vc4: crtc: Use a shared interrupt + +Some pixelvalves in vc5 use the same interrupt line so let's register our +interrupt handler as a shared one. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1177,7 +1177,9 @@ static int vc4_crtc_bind(struct device * + CRTC_WRITE(PV_INTEN, 0); + CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc); ++ vc4_crtc_irq_handler, ++ IRQF_SHARED, ++ "vc4 crtc", vc4_crtc); + if (ret) + goto err_destroy_planes; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0558-drm-vc4-crtc-Turn-static-const-variable-into-a-defin.patch b/target/linux/bcm27xx/patches-5.4/950-0558-drm-vc4-crtc-Turn-static-const-variable-into-a-defin.patch new file mode 100644 index 00000000000..3deefc361f0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0558-drm-vc4-crtc-Turn-static-const-variable-into-a-defin.patch @@ -0,0 +1,50 @@ +From c017882242d671cf81256301a3e9a6fc9eefdc13 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 13 Jan 2020 13:39:32 +0100 +Subject: [PATCH] drm/vc4: crtc: Turn static const variable into a + define + +The hvs_latency_pix variable doesn't need to be a variable and can just be +defined. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -44,6 +44,8 @@ + #include "vc4_drv.h" + #include "vc4_regs.h" + ++#define HVS_FIFO_LATENCY_PIX 6 ++ + #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) + #define CRTC_READ(offset) readl(vc4_crtc->regs + (offset)) + +@@ -227,21 +229,21 @@ vc4_crtc_update_gamma_lut(struct drm_crt + vc4_crtc_lut_load(crtc); + } + ++ + static u32 vc4_get_fifo_full_level(u32 format) + { + static const u32 fifo_len_bytes = 64; +- static const u32 hvs_latency_pix = 6; + + switch (format) { + case PV_CONTROL_FORMAT_DSIV_16: + case PV_CONTROL_FORMAT_DSIC_16: +- return fifo_len_bytes - 2 * hvs_latency_pix; ++ return fifo_len_bytes - 2 * HVS_FIFO_LATENCY_PIX; + case PV_CONTROL_FORMAT_DSIV_18: + return fifo_len_bytes - 14; + case PV_CONTROL_FORMAT_24: + case PV_CONTROL_FORMAT_DSIV_24: + default: +- return fifo_len_bytes - 3 * hvs_latency_pix; ++ return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; + } + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0559-drm-vc4-crtc-Move-the-cob-allocation-outside-of-bind.patch b/target/linux/bcm27xx/patches-5.4/950-0559-drm-vc4-crtc-Move-the-cob-allocation-outside-of-bind.patch new file mode 100644 index 00000000000..83c49132a37 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0559-drm-vc4-crtc-Move-the-cob-allocation-outside-of-bind.patch @@ -0,0 +1,110 @@ +From e93fc4ed811c7dcc6b0c93716f760431fc645ba2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 15:48:09 +0100 +Subject: [PATCH] drm/vc4: crtc: Move the cob allocation outside of + bind + +The COB allocation depends on the HVS channel used for a given +pixelvalve. + +While the channel allocation was entirely static in vc4, vc5 changes +that and at bind time, a pixelvalve can be assigned to multiple +HVS channels. + +Let's prepare that rework by allocating the COB when it's actually +needed. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 39 +++++++++++++++++----------------- + drivers/gpu/drm/vc4/vc4_drv.h | 2 -- + 2 files changed, 20 insertions(+), 21 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -65,6 +65,23 @@ static const struct debugfs_reg32 crtc_r + VC4_REG32(PV_HACT_ACT), + }; + ++static unsigned int ++vc4_crtc_get_cob_allocation(struct vc4_crtc *vc4_crtc, unsigned int channel) ++{ ++ struct drm_device *drm = vc4_crtc->base.dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ ++ u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel)); ++ /* Top/base are supposed to be 4-pixel aligned, but the ++ * Raspberry Pi firmware fills the low bits (which are ++ * presumably ignored). ++ */ ++ u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; ++ u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; ++ ++ return top - base + 4; ++} ++ + bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, + bool in_vblank_irq, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, +@@ -73,6 +90,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ unsigned int cob_size; + u32 val; + int fifo_lines; + int vblank_lines; +@@ -108,8 +126,9 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + *hpos += mode->crtc_htotal / 2; + } + ++ cob_size = vc4_crtc_get_cob_allocation(vc4_crtc, vc4_crtc->channel); + /* This is the offset we need for translating hvs -> pv scanout pos. */ +- fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay; ++ fifo_lines = cob_size / mode->crtc_hdisplay; + + if (fifo_lines > 0) + ret = true; +@@ -1104,22 +1123,6 @@ static void vc4_set_crtc_possible_masks( + } + } + +-static void +-vc4_crtc_get_cob_allocation(struct vc4_crtc *vc4_crtc) +-{ +- struct drm_device *drm = vc4_crtc->base.dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); +- u32 dispbase = HVS_READ(SCALER_DISPBASEX(vc4_crtc->channel)); +- /* Top/base are supposed to be 4-pixel aligned, but the +- * Raspberry Pi firmware fills the low bits (which are +- * presumably ignored). +- */ +- u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3; +- u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3; +- +- vc4_crtc->cob_size = top - base + 4; +-} +- + static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -1174,8 +1177,6 @@ static int vc4_crtc_bind(struct device * + */ + drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); + +- vc4_crtc_get_cob_allocation(vc4_crtc); +- + CRTC_WRITE(PV_INTEN, 0); + CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -477,8 +477,6 @@ struct vc4_crtc { + u8 lut_r[256]; + u8 lut_g[256]; + u8 lut_b[256]; +- /* Size in pixels of the COB memory allocated to this CRTC. */ +- u32 cob_size; + + struct drm_pending_vblank_event *event; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0560-drm-vc4-crtc-Rename-HVS-channel-to-output.patch b/target/linux/bcm27xx/patches-5.4/950-0560-drm-vc4-crtc-Rename-HVS-channel-to-output.patch new file mode 100644 index 00000000000..cf854fceb88 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0560-drm-vc4-crtc-Rename-HVS-channel-to-output.patch @@ -0,0 +1,80 @@ +From a106e57a643c957af9a71eb2ec3a62df69a1f371 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 13:49:17 +0100 +Subject: [PATCH] drm/vc4: crtc: Rename HVS channel to output + +In vc5, the HVS has 6 outputs and 3 FIFOs (or channels), with +pixelvalves each being assigned to a given output, but each output can +then be muxed to feed from multiple FIFOs. + +Since vc4 had that entirely static, both were probably equivalent, but +since that changes, let's rename hvs_channel to hvs_output in the +vc4_crtc_data, since a pixelvalve is really connected to an output, and +not to a FIFO. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 10 +++++----- + drivers/gpu/drm/vc4/vc4_drv.h | 4 ++-- + 2 files changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1057,7 +1057,7 @@ static const struct drm_crtc_helper_func + }; + + static const struct vc4_crtc_data bcm2835_pv0_data = { +- .hvs_channel = 0, ++ .hvs_output = 0, + .debugfs_name = "crtc0_regs", + .pixels_per_clock = 1, + .encoder_types = { +@@ -1067,7 +1067,7 @@ static const struct vc4_crtc_data bcm283 + }; + + static const struct vc4_crtc_data bcm2835_pv1_data = { +- .hvs_channel = 2, ++ .hvs_output = 2, + .debugfs_name = "crtc1_regs", + .pixels_per_clock = 1, + .encoder_types = { +@@ -1077,7 +1077,7 @@ static const struct vc4_crtc_data bcm283 + }; + + static const struct vc4_crtc_data bcm2835_pv2_data = { +- .hvs_channel = 1, ++ .hvs_output = 1, + .debugfs_name = "crtc2_regs", + .pixels_per_clock = 1, + .encoder_types = { +@@ -1106,7 +1106,7 @@ static void vc4_set_crtc_possible_masks( + int i; + + /* HVS FIFO2 can feed the TXP IP. */ +- if (crtc_data->hvs_channel == 2 && ++ if (crtc_data->hvs_output == 2 && + encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) { + encoder->possible_crtcs |= drm_crtc_mask(crtc); + continue; +@@ -1168,7 +1168,7 @@ static int vc4_crtc_bind(struct device * + drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, + &vc4_crtc_funcs, NULL); + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); +- vc4_crtc->channel = vc4_crtc->data->hvs_channel; ++ vc4_crtc->channel = vc4_crtc->data->hvs_output; + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -452,8 +452,8 @@ to_vc4_encoder(struct drm_encoder *encod + } + + struct vc4_crtc_data { +- /* Which channel of the HVS this pixelvalve sources from. */ +- int hvs_channel; ++ /* Which output of the HVS this pixelvalve sources from. */ ++ int hvs_output; + + /* Number of pixels output per clock period */ + u8 pixels_per_clock; diff --git a/target/linux/bcm27xx/patches-5.4/950-0561-drm-vc4-crtc-Use-local-chan-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0561-drm-vc4-crtc-Use-local-chan-variable.patch new file mode 100644 index 00000000000..6f77bace017 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0561-drm-vc4-crtc-Use-local-chan-variable.patch @@ -0,0 +1,24 @@ +From 888e5149bdb810e67996828bb26955a57a482d4c Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 14 Jan 2020 13:37:27 +0100 +Subject: [PATCH] drm/vc4: crtc: Use local chan variable + +The vc4_crtc_handle_page_flip already has a local variable holding the +value of vc4_crtc->channel, so let's use it instead. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -816,7 +816,7 @@ static void vc4_crtc_handle_page_flip(st + * underruns. This can be seen when reconfiguring the CRTC. + */ + if (vc4->hvs) +- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel); ++ vc4_hvs_unmask_underrun(dev, chan); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0562-drm-vc4-crtc-Enable-and-disable-the-PV-in-atomic_ena.patch b/target/linux/bcm27xx/patches-5.4/950-0562-drm-vc4-crtc-Enable-and-disable-the-PV-in-atomic_ena.patch new file mode 100644 index 00000000000..c5f06f20ea8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0562-drm-vc4-crtc-Enable-and-disable-the-PV-in-atomic_ena.patch @@ -0,0 +1,55 @@ +From 7bbbfef1c98e832cbd55e66ac2d7f13ec0a2b11e Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 21 Feb 2020 14:34:31 +0100 +Subject: [PATCH] drm/vc4: crtc: Enable and disable the PV in + atomic_enable / disable + +The VIDEN bit in the pixelvalve currently being used to enable or disable +the pixelvalve seems to not be enough in some situations, which whill end +up with the pixelvalve stalling. + +In such a case, even re-enabling VIDEN doesn't bring it back and we need to +clear the FIFO. This can only be done if the pixelvalve is disabled though. + +In order to overcome this, we can configure the pixelvalve during +mode_set_no_fb, but only enable it in atomic_enable and flush the FIFO +there, and in atomic_disable disable the pixelvalve again. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -374,9 +374,7 @@ static void vc4_crtc_config_pv(struct dr + PV_CONTROL_TRIGGER_UNDERFLOW | + PV_CONTROL_WAIT_HSTART | + VC4_SET_FIELD(vc4_encoder->clock_select, +- PV_CONTROL_CLK_SELECT) | +- PV_CONTROL_FIFO_CLR | +- PV_CONTROL_EN); ++ PV_CONTROL_CLK_SELECT)); + } + + static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) +@@ -467,6 +465,8 @@ static void vc4_crtc_atomic_disable(stru + ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); + WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n"); + ++ CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) & ~PV_CONTROL_EN); ++ + if (HVS_READ(SCALER_DISPCTRLX(chan)) & + SCALER_DISPCTRLX_ENABLE) { + HVS_WRITE(SCALER_DISPCTRLX(chan), +@@ -554,6 +554,10 @@ static void vc4_crtc_atomic_enable(struc + + require_hvs_enabled(dev); + ++ /* Reset the PV fifo. */ ++ CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | ++ PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); ++ + /* Enable vblank irq handling before crtc is started otherwise + * drm_crtc_get_vblank() fails in vc4_crtc_update_dlist(). + */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0563-drm-vc4-crtc-Assign-output-to-channel-automatically.patch b/target/linux/bcm27xx/patches-5.4/950-0563-drm-vc4-crtc-Assign-output-to-channel-automatically.patch new file mode 100644 index 00000000000..d470f3b7f07 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0563-drm-vc4-crtc-Assign-output-to-channel-automatically.patch @@ -0,0 +1,459 @@ +From 9efecb2ccd14a6d226ba2afa04f6e70b96026b3e Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 17:53:18 +0100 +Subject: [PATCH] drm/vc4: crtc: Assign output to channel automatically + +The HVS found in the BCM2711 has 6 outputs and 3 FIFOs, with each output +being connected to a pixelvalve, and some muxing between the FIFOs and +outputs. + +Any output cannot feed from any FIFO though, and they all have a bunch of +constraints. + +In order to support this, let's store the possible FIFOs each output can be +assigned to in the vc4_crtc_data, and use that information at atomic_check +time to iterate over all the CRTCs enabled and assign them FIFOs. + +The channel assigned is then set in the vc4_crtc_state so that the rest of +the driver can use it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 37 +++++---- + drivers/gpu/drm/vc4/vc4_drv.h | 7 +- + drivers/gpu/drm/vc4/vc4_kms.c | 146 +++++++++++++++++++++++++++++++-- + drivers/gpu/drm/vc4/vc4_regs.h | 10 +++ + 4 files changed, 175 insertions(+), 25 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -90,6 +90,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); + unsigned int cob_size; + u32 val; + int fifo_lines; +@@ -106,7 +107,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + * Read vertical scanline which is currently composed for our + * pixelvalve by the HVS, and also the scaler status. + */ +- val = HVS_READ(SCALER_DISPSTATX(vc4_crtc->channel)); ++ val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel)); + + /* Get optional system timestamp after query. */ + if (etime) +@@ -126,7 +127,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + *hpos += mode->crtc_htotal / 2; + } + +- cob_size = vc4_crtc_get_cob_allocation(vc4_crtc, vc4_crtc->channel); ++ cob_size = vc4_crtc_get_cob_allocation(vc4_crtc, vc4_crtc_state->assigned_channel); + /* This is the offset we need for translating hvs -> pv scanout pos. */ + fifo_lines = cob_size / mode->crtc_hdisplay; + +@@ -213,6 +214,7 @@ vc4_crtc_lut_load(struct drm_crtc *crtc) + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); + u32 i; + + /* The LUT memory is laid out with each HVS channel in order, +@@ -221,7 +223,7 @@ vc4_crtc_lut_load(struct drm_crtc *crtc) + */ + HVS_WRITE(SCALER_GAMADDR, + SCALER_GAMADDR_AUTOINC | +- (vc4_crtc->channel * 3 * crtc->gamma_size)); ++ (vc4_crtc_state->assigned_channel * 3 * crtc->gamma_size)); + + for (i = 0; i < crtc->gamma_size; i++) + HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]); +@@ -394,7 +396,7 @@ static void vc4_crtc_mode_set_nofb(struc + drm_print_regset32(&p, &vc4_crtc->regset); + } + +- if (vc4_crtc->channel == 2) { ++ if (vc4_crtc->data->hvs_output == 2) { + u32 dispctrl; + u32 dsp3_mux; + +@@ -421,7 +423,7 @@ static void vc4_crtc_mode_set_nofb(struc + if (!vc4_state->feed_txp) + vc4_crtc_config_pv(crtc); + +- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), ++ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), + SCALER_DISPBKGND_AUTOHS | + SCALER_DISPBKGND_GAMMA | + (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); +@@ -453,7 +455,8 @@ static void vc4_crtc_atomic_disable(stru + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +- u32 chan = vc4_crtc->channel; ++ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(old_state); ++ u32 chan = vc4_crtc_state->assigned_channel; + int ret; + require_hvs_enabled(dev); + +@@ -532,12 +535,12 @@ static void vc4_crtc_update_dlist(struct + crtc->state->event = NULL; + } + +- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), + vc4_state->mm.start); + + spin_unlock_irqrestore(&dev->event_lock, flags); + } else { +- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), ++ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), + vc4_state->mm.start); + } + } +@@ -586,7 +589,7 @@ static void vc4_crtc_atomic_enable(struc + (vc4_state->feed_txp ? + SCALER5_DISPCTRLX_ONESHOT : 0); + +- HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), dispctrl); ++ HVS_WRITE(SCALER_DISPCTRLX(vc4_state->assigned_channel), dispctrl); + + /* When feeding the transposer block the pixelvalve is unneeded and + * should not be enabled. +@@ -702,7 +705,6 @@ static void vc4_crtc_atomic_flush(struct + { + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_plane *plane; + struct vc4_plane_state *vc4_plane_state; +@@ -744,8 +746,8 @@ static void vc4_crtc_atomic_flush(struct + /* This sets a black background color fill, as is the case + * with other DRM drivers. + */ +- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), +- HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) | ++ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), ++ HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) | + SCALER_DISPBKGND_FILL); + + /* Only update DISPLIST if the CRTC was already running and is not +@@ -759,7 +761,7 @@ static void vc4_crtc_atomic_flush(struct + vc4_crtc_update_dlist(crtc); + + if (crtc->state->color_mgmt_changed) { +- u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)); ++ u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)); + + if (crtc->state->gamma_lut) { + vc4_crtc_update_gamma_lut(crtc); +@@ -771,7 +773,7 @@ static void vc4_crtc_atomic_flush(struct + */ + dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; + } +- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), dispbkgndx); ++ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx); + } + + if (debug_dump_regs) { +@@ -802,7 +804,7 @@ static void vc4_crtc_handle_page_flip(st + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); +- u32 chan = vc4_crtc->channel; ++ u32 chan = vc4_state->assigned_channel; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); +@@ -1002,6 +1004,7 @@ static struct drm_crtc_state *vc4_crtc_d + old_vc4_state = to_vc4_crtc_state(crtc->state); + vc4_state->feed_txp = old_vc4_state->feed_txp; + vc4_state->margins = old_vc4_state->margins; ++ vc4_state->assigned_channel = old_vc4_state->assigned_channel; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); + return &vc4_state->base; +@@ -1061,6 +1064,7 @@ static const struct drm_crtc_helper_func + }; + + static const struct vc4_crtc_data bcm2835_pv0_data = { ++ .hvs_available_channels = BIT(0), + .hvs_output = 0, + .debugfs_name = "crtc0_regs", + .pixels_per_clock = 1, +@@ -1071,6 +1075,7 @@ static const struct vc4_crtc_data bcm283 + }; + + static const struct vc4_crtc_data bcm2835_pv1_data = { ++ .hvs_available_channels = BIT(2), + .hvs_output = 2, + .debugfs_name = "crtc1_regs", + .pixels_per_clock = 1, +@@ -1081,6 +1086,7 @@ static const struct vc4_crtc_data bcm283 + }; + + static const struct vc4_crtc_data bcm2835_pv2_data = { ++ .hvs_available_channels = BIT(1), + .hvs_output = 1, + .debugfs_name = "crtc2_regs", + .pixels_per_clock = 1, +@@ -1172,7 +1178,6 @@ static int vc4_crtc_bind(struct device * + drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, + &vc4_crtc_funcs, NULL); + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); +- vc4_crtc->channel = vc4_crtc->data->hvs_output; + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -452,6 +452,9 @@ to_vc4_encoder(struct drm_encoder *encod + } + + struct vc4_crtc_data { ++ /* Which channels of the HVS can the output source from */ ++ unsigned int hvs_available_channels; ++ + /* Which output of the HVS this pixelvalve sources from. */ + int hvs_output; + +@@ -471,9 +474,6 @@ struct vc4_crtc { + /* Timestamp at start of vblank irq - unaffected by lock delays. */ + ktime_t t_vblank; + +- /* Which HVS channel we're using for our CRTC. */ +- int channel; +- + u8 lut_r[256]; + u8 lut_g[256]; + u8 lut_b[256]; +@@ -495,6 +495,7 @@ struct vc4_crtc_state { + struct drm_mm_node mm; + bool feed_txp; + bool txp_armed; ++ unsigned int assigned_channel; + + struct { + unsigned int left; +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -11,6 +11,9 @@ + * crtc, HDMI encoder). + */ + ++#include ++#include ++ + #include + #include + #include +@@ -148,6 +151,72 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru + VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO)); + } + ++static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, ++ struct drm_atomic_state *state) ++{ ++ struct drm_crtc_state *crtc_state; ++ struct drm_crtc *crtc; ++ unsigned char dsp2_mux = 0; ++ unsigned char dsp3_mux = 3; ++ unsigned char dsp4_mux = 3; ++ unsigned char dsp5_mux = 3; ++ unsigned int i; ++ u32 reg; ++ ++ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ ++ if (!crtc_state->active) ++ continue; ++ ++ switch (vc4_crtc->data->hvs_output) { ++ case 2: ++ dsp2_mux = (vc4_state->assigned_channel == 2) ? 1 : 0; ++ break; ++ ++ case 3: ++ dsp3_mux = vc4_state->assigned_channel; ++ break; ++ ++ case 4: ++ dsp4_mux = vc4_state->assigned_channel; ++ break; ++ ++ case 5: ++ dsp5_mux = vc4_state->assigned_channel; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ reg = HVS_READ(SCALER_DISPECTRL); ++ if (FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg) != dsp2_mux) ++ HVS_WRITE(SCALER_DISPECTRL, ++ (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | ++ VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX)); ++ ++ reg = HVS_READ(SCALER_DISPCTRL); ++ if (FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg) != dsp3_mux) ++ HVS_WRITE(SCALER_DISPCTRL, ++ (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | ++ VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX)); ++ ++ reg = HVS_READ(SCALER_DISPEOLN); ++ if (FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg) != dsp4_mux) ++ HVS_WRITE(SCALER_DISPEOLN, ++ (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | ++ VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX)); ++ ++ reg = HVS_READ(SCALER_DISPDITHER); ++ if (FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg) != dsp5_mux) ++ HVS_WRITE(SCALER_DISPDITHER, ++ (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | ++ VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX)); ++} ++ + static void + vc4_atomic_complete_commit(struct drm_atomic_state *state) + { +@@ -157,11 +226,15 @@ vc4_atomic_complete_commit(struct drm_at + int i; + + for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) { +- if (!state->crtcs[i].ptr || !state->crtcs[i].commit) ++ struct __drm_crtcs_state *_state = &state->crtcs[i]; ++ struct vc4_crtc_state *vc4_crtc_state; ++ ++ if (!_state->ptr || !_state->commit) + continue; + +- vc4_crtc = to_vc4_crtc(state->crtcs[i].ptr); +- vc4_hvs_mask_underrun(dev, vc4_crtc->channel); ++ vc4_crtc = to_vc4_crtc(_state->ptr); ++ vc4_crtc_state = to_vc4_crtc_state(_state->state); ++ vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel); + } + + drm_atomic_helper_wait_for_fences(dev, state, false); +@@ -170,8 +243,10 @@ vc4_atomic_complete_commit(struct drm_at + + drm_atomic_helper_commit_modeset_disables(dev, state); + +- if (!vc4->firmware_kms) ++ if (!vc4->firmware_kms) { + vc4_ctm_commit(vc4, state); ++ vc4_hvs_pv_muxing_commit(vc4, state); ++ } + + drm_atomic_helper_commit_planes(dev, state, 0); + +@@ -380,8 +455,11 @@ vc4_ctm_atomic_check(struct drm_device * + + /* CTM is being enabled or the matrix changed. */ + if (new_crtc_state->ctm) { ++ struct vc4_crtc_state *vc4_crtc_state = ++ to_vc4_crtc_state(new_crtc_state); ++ + /* fifo is 1-based since 0 disables CTM. */ +- int fifo = to_vc4_crtc(crtc)->channel + 1; ++ int fifo = vc4_crtc_state->assigned_channel + 1; + + /* Check userland isn't trying to turn on CTM for more + * than one CRTC at a time. +@@ -494,10 +572,66 @@ static const struct drm_private_state_fu + .atomic_destroy_state = vc4_load_tracker_destroy_state, + }; + ++#define NUM_OUTPUTS 6 ++#define NUM_CHANNELS 3 ++ + static int + vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) + { +- int ret; ++ unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0); ++ struct drm_crtc_state *crtc_state; ++ struct drm_crtc *crtc; ++ int i, ret; ++ ++ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { ++ struct vc4_crtc_state *vc4_crtc_state = ++ to_vc4_crtc_state(crtc_state); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ bool is_assigned = false; ++ unsigned int channel; ++ ++ if (!crtc_state->active) ++ continue; ++ ++ /* ++ * The problem we have to solve here is that we have ++ * up to 7 encoders, connected to up to 6 CRTCs. ++ * ++ * Those CRTCs, depending on the instance, can be ++ * routed to 1, 2 or 3 HVS FIFOs, and we need to set ++ * the change the muxing between FIFOs and outputs in ++ * the HVS accordingly. ++ * ++ * It would be pretty hard to come up with an ++ * algorithm that would generically solve ++ * this. However, the current routing trees we support ++ * allow us to simplify a bit the problem. ++ * ++ * Indeed, with the current supported layouts, if we ++ * try to assign in the ascending crtc index order the ++ * FIFOs, we can't fall into the situation where an ++ * earlier CRTC that had multiple routes is assigned ++ * one that was the only option for a later CRTC. ++ * ++ * If the layout changes and doesn't give us that in ++ * the future, we will need to have something smarter, ++ * but it works so far. ++ */ ++ for_each_set_bit(channel, &unassigned_channels, ++ sizeof(unassigned_channels)) { ++ ++ if (!(BIT(channel) & vc4_crtc->data->hvs_available_channels)) ++ continue; ++ ++ vc4_crtc_state->assigned_channel = channel; ++ unassigned_channels &= ~BIT(channel); ++ is_assigned = true; ++ break; ++ } ++ ++ if (!is_assigned) ++ return -EINVAL; ++ } + + ret = vc4_ctm_atomic_check(dev, state); + if (ret < 0) +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -287,9 +287,19 @@ + + #define SCALER_DISPID 0x00000008 + #define SCALER_DISPECTRL 0x0000000c ++# define SCALER_DISPECTRL_DSP2_MUX_SHIFT 31 ++# define SCALER_DISPECTRL_DSP2_MUX_MASK VC4_MASK(31, 31) ++ + #define SCALER_DISPPROF 0x00000010 ++ + #define SCALER_DISPDITHER 0x00000014 ++# define SCALER_DISPDITHER_DSP5_MUX_SHIFT 30 ++# define SCALER_DISPDITHER_DSP5_MUX_MASK VC4_MASK(31, 30) ++ + #define SCALER_DISPEOLN 0x00000018 ++# define SCALER_DISPEOLN_DSP4_MUX_SHIFT 30 ++# define SCALER_DISPEOLN_DSP4_MUX_MASK VC4_MASK(31, 30) ++ + #define SCALER_DISPLIST0 0x00000020 + #define SCALER_DISPLIST1 0x00000024 + #define SCALER_DISPLIST2 0x00000028 diff --git a/target/linux/bcm27xx/patches-5.4/950-0564-drm-vc4-crtc-Add-FIFO-depth-to-vc4_crtc_data.patch b/target/linux/bcm27xx/patches-5.4/950-0564-drm-vc4-crtc-Add-FIFO-depth-to-vc4_crtc_data.patch new file mode 100644 index 00000000000..e920a0be647 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0564-drm-vc4-crtc-Add-FIFO-depth-to-vc4_crtc_data.patch @@ -0,0 +1,86 @@ +From a294de7c4782f91fe724e4e5b05fd99798d50760 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 13 Jan 2020 13:39:20 +0100 +Subject: [PATCH] drm/vc4: crtc: Add FIFO depth to vc4_crtc_data + +Not all pixelvalve FIFOs in vc5 have the same depth, so we need to add that +to our vc4_crtc_data structure to be able to compute the fill level +properly later on. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 20 ++++++++++++++++---- + drivers/gpu/drm/vc4/vc4_drv.h | 3 +++ + 2 files changed, 19 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -250,11 +250,20 @@ vc4_crtc_update_gamma_lut(struct drm_crt + vc4_crtc_lut_load(crtc); + } + +- +-static u32 vc4_get_fifo_full_level(u32 format) ++static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format) + { +- static const u32 fifo_len_bytes = 64; ++ u32 fifo_len_bytes = vc4_crtc->data->fifo_depth; + ++ /* ++ * Pixels are pulled from the HVS if the number of bytes is ++ * lower than the FIFO full level. ++ * ++ * The latency of the pixel fetch mechanism is 6 pixels, so we ++ * need to convert those 6 pixels in bytes, depending on the ++ * format, and then substract that from the length of the FIFO ++ * to make sure we never end up in a situation where the FIFO ++ * is full. ++ */ + switch (format) { + case PV_CONTROL_FORMAT_DSIV_16: + case PV_CONTROL_FORMAT_DSIC_16: +@@ -369,7 +378,7 @@ static void vc4_crtc_config_pv(struct dr + + CRTC_WRITE(PV_CONTROL, + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | +- VC4_SET_FIELD(vc4_get_fifo_full_level(format), ++ VC4_SET_FIELD(vc4_get_fifo_full_level(vc4_crtc, format), + PV_CONTROL_FIFO_LEVEL) | + VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) | + PV_CONTROL_CLR_AT_START | +@@ -1067,6 +1076,7 @@ static const struct vc4_crtc_data bcm283 + .hvs_available_channels = BIT(0), + .hvs_output = 0, + .debugfs_name = "crtc0_regs", ++ .fifo_depth = 64, + .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0, +@@ -1078,6 +1088,7 @@ static const struct vc4_crtc_data bcm283 + .hvs_available_channels = BIT(2), + .hvs_output = 2, + .debugfs_name = "crtc1_regs", ++ .fifo_depth = 64, + .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1, +@@ -1089,6 +1100,7 @@ static const struct vc4_crtc_data bcm283 + .hvs_available_channels = BIT(1), + .hvs_output = 1, + .debugfs_name = "crtc2_regs", ++ .fifo_depth = 64, + .pixels_per_clock = 1, + .encoder_types = { + [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -452,6 +452,9 @@ to_vc4_encoder(struct drm_encoder *encod + } + + struct vc4_crtc_data { ++ /* Depth of the PixelValve FIFO in bytes */ ++ unsigned int fifo_depth; ++ + /* Which channels of the HVS can the output source from */ + unsigned int hvs_available_channels; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0565-drm-vc4-crtc-Add-function-to-compute-FIFO-level-bits.patch b/target/linux/bcm27xx/patches-5.4/950-0565-drm-vc4-crtc-Add-function-to-compute-FIFO-level-bits.patch new file mode 100644 index 00000000000..77952c0eea9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0565-drm-vc4-crtc-Add-function-to-compute-FIFO-level-bits.patch @@ -0,0 +1,44 @@ +From 2c241c25b76d105f798881e1a3c6e3c09c3b27ff Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 13 Jan 2020 13:40:37 +0100 +Subject: [PATCH] drm/vc4: crtc: Add function to compute FIFO level + bits + +The longer FIFOs in vc5 pixelvalves means that the FIFO full level +doesn't fit in the original register field and that we also have a +secondary field. In order to prepare for this, let's move the registers +fill part to a helper function. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -277,6 +277,14 @@ static u32 vc4_get_fifo_full_level(struc + } + } + ++static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc, ++ u32 format) ++{ ++ u32 level = vc4_get_fifo_full_level(vc4_crtc, format); ++ return VC4_SET_FIELD(level & 0x3f, ++ PV_CONTROL_FIFO_LEVEL); ++} ++ + /* + * Returns the encoder attached to the CRTC. + * +@@ -377,9 +385,8 @@ static void vc4_crtc_config_pv(struct dr + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); + + CRTC_WRITE(PV_CONTROL, ++ vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) | + VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | +- VC4_SET_FIELD(vc4_get_fifo_full_level(vc4_crtc, format), +- PV_CONTROL_FIFO_LEVEL) | + VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) | + PV_CONTROL_CLR_AT_START | + PV_CONTROL_TRIGGER_UNDERFLOW | diff --git a/target/linux/bcm27xx/patches-5.4/950-0566-drm-vc4-crtc-Rename-HDMI-encoder-type-to-HDMI0.patch b/target/linux/bcm27xx/patches-5.4/950-0566-drm-vc4-crtc-Rename-HDMI-encoder-type-to-HDMI0.patch new file mode 100644 index 00000000000..17362dafe35 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0566-drm-vc4-crtc-Rename-HDMI-encoder-type-to-HDMI0.patch @@ -0,0 +1,49 @@ +From ad4c39a27e141626c93b7b97df621d258bfdcbbe Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 9 Jan 2020 18:35:13 +0100 +Subject: [PATCH] drm/vc4: crtc: Rename HDMI encoder type to HDMI0 + +The previous generations were only supporting a single HDMI controller, but +that's about to change, so put an index as well to differentiate between +the two controllers. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 2 +- + drivers/gpu/drm/vc4/vc4_drv.h | 2 +- + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1110,7 +1110,7 @@ static const struct vc4_crtc_data bcm283 + .fifo_depth = 64, + .pixels_per_clock = 1, + .encoder_types = { +- [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI, ++ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0, + [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC, + }, + }; +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -431,7 +431,7 @@ to_vc4_plane_state(struct drm_plane_stat + + enum vc4_encoder_type { + VC4_ENCODER_TYPE_NONE, +- VC4_ENCODER_TYPE_HDMI, ++ VC4_ENCODER_TYPE_HDMI0, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_DSI1, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1319,7 +1319,7 @@ static int vc4_hdmi_bind(struct device * + GFP_KERNEL); + if (!vc4_hdmi_encoder) + return -ENOMEM; +- vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI; ++ vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI0; + hdmi->encoder = &vc4_hdmi_encoder->base.base; + + hdmi->pdev = pdev; diff --git a/target/linux/bcm27xx/patches-5.4/950-0567-drm-vc4-crtc-Add-HDMI1-encoder-type.patch b/target/linux/bcm27xx/patches-5.4/950-0567-drm-vc4-crtc-Add-HDMI1-encoder-type.patch new file mode 100644 index 00000000000..00ad755492b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0567-drm-vc4-crtc-Add-HDMI1-encoder-type.patch @@ -0,0 +1,23 @@ +From 9df4f0e2da72c825d86f4f637983c712173ed272 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 9 Jan 2020 18:39:30 +0100 +Subject: [PATCH] drm/vc4: crtc: Add HDMI1 encoder type + +The BCM2711 sports a second HDMI controller, so let's add that second HDMI +encoder type. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -432,6 +432,7 @@ to_vc4_plane_state(struct drm_plane_stat + enum vc4_encoder_type { + VC4_ENCODER_TYPE_NONE, + VC4_ENCODER_TYPE_HDMI0, ++ VC4_ENCODER_TYPE_HDMI1, + VC4_ENCODER_TYPE_VEC, + VC4_ENCODER_TYPE_DSI0, + VC4_ENCODER_TYPE_DSI1, diff --git a/target/linux/bcm27xx/patches-5.4/950-0568-drm-vc4-crtc-Remove-redundant-call-to-drm_crtc_enabl.patch b/target/linux/bcm27xx/patches-5.4/950-0568-drm-vc4-crtc-Remove-redundant-call-to-drm_crtc_enabl.patch new file mode 100644 index 00000000000..5704952569b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0568-drm-vc4-crtc-Remove-redundant-call-to-drm_crtc_enabl.patch @@ -0,0 +1,24 @@ +From 278c3da2ce8c2cda6cb60946c55b5e7040dfc35a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 21 Feb 2020 16:48:19 +0100 +Subject: [PATCH] drm/vc4: crtc: Remove redundant call to + drm_crtc_enable_color_mgmt + +The driver calls the helper to add the color management properties twice, +which is redundant. Remove the first one. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -1198,7 +1198,6 @@ static int vc4_crtc_bind(struct device * + &vc4_crtc_funcs, NULL); + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); +- drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + + /* We support CTM, but only for one CRTC at a time. It's therefore + * implemented as private driver state in vc4_kms, not here. diff --git a/target/linux/bcm27xx/patches-5.4/950-0569-drm-vc4-crtc-Disable-color-management-for-HVS5.patch b/target/linux/bcm27xx/patches-5.4/950-0569-drm-vc4-crtc-Disable-color-management-for-HVS5.patch new file mode 100644 index 00000000000..bd487df5c44 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0569-drm-vc4-crtc-Disable-color-management-for-HVS5.patch @@ -0,0 +1,54 @@ +From 9e134cea82d5c69e5d564e87cda2b5cf3ec14768 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 21 Feb 2020 16:54:21 +0100 +Subject: [PATCH] drm/vc4: crtc: Disable color management for HVS5 + +The HVS5 uses different color matrices. Disable color management support +for now. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -441,7 +441,7 @@ static void vc4_crtc_mode_set_nofb(struc + + HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), + SCALER_DISPBKGND_AUTOHS | +- SCALER_DISPBKGND_GAMMA | ++ ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) | + (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); + + /* Reload the LUT, since the SRAMs would have been disabled if +@@ -1156,6 +1156,7 @@ static int vc4_crtc_bind(struct device * + { + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_crtc *vc4_crtc; + struct drm_crtc *crtc; + struct drm_plane *primary_plane, *destroy_plane, *temp; +@@ -1197,12 +1198,16 @@ static int vc4_crtc_bind(struct device * + drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, + &vc4_crtc_funcs, NULL); + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); +- drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); + +- /* We support CTM, but only for one CRTC at a time. It's therefore +- * implemented as private driver state in vc4_kms, not here. +- */ +- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); ++ if (!vc4->hvs->hvs5) { ++ drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); ++ ++ /* We support CTM, but only for one CRTC at a ++ * time. It's therefore implemented as private driver ++ * state in vc4_kms, not here. ++ */ ++ drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); ++ } + + CRTC_WRITE(PV_INTEN, 0); + CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); diff --git a/target/linux/bcm27xx/patches-5.4/950-0570-dt-bindings-display-vc4-pv-Add-BCM2711-pixel-valves.patch b/target/linux/bcm27xx/patches-5.4/950-0570-dt-bindings-display-vc4-pv-Add-BCM2711-pixel-valves.patch new file mode 100644 index 00000000000..6bf6ab74c43 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0570-dt-bindings-display-vc4-pv-Add-BCM2711-pixel-valves.patch @@ -0,0 +1,30 @@ +From 26613c79b74224154703d75c4f2d2aa120cc2e84 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 17:07:02 +0100 +Subject: [PATCH] dt-bindings: display: vc4: pv: Add BCM2711 pixel + valves + +The BCM2711 comes with other pixelvalves that have different requirements +and capabilities. Let's document their compatible. + +Cc: devicetree@vger.kernel.org +Reviewed-by: Rob Herring +Signed-off-by: Maxime Ripard +--- + .../bindings/display/brcm,bcm2835-pixelvalve0.yaml | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml +@@ -15,6 +15,11 @@ properties: + - brcm,bcm2835-pixelvalve0 + - brcm,bcm2835-pixelvalve1 + - brcm,bcm2835-pixelvalve2 ++ - brcm,bcm2711-pixelvalve0 ++ - brcm,bcm2711-pixelvalve1 ++ - brcm,bcm2711-pixelvalve2 ++ - brcm,bcm2711-pixelvalve3 ++ - brcm,bcm2711-pixelvalve4 + + reg: + maxItems: 1 diff --git a/target/linux/bcm27xx/patches-5.4/950-0571-drm-vc4-crtc-Add-BCM2711-pixelvalves.patch b/target/linux/bcm27xx/patches-5.4/950-0571-drm-vc4-crtc-Add-BCM2711-pixelvalves.patch new file mode 100644 index 00000000000..3ff57ef3df3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0571-drm-vc4-crtc-Add-BCM2711-pixelvalves.patch @@ -0,0 +1,152 @@ +From aa43601d97bf9136b657259f44c03a6a30b70d07 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 11:35:58 +0100 +Subject: [PATCH] drm/vc4: crtc: Add BCM2711 pixelvalves + +The BCM2711 has 5 pixelvalves, so now that our driver is ready, let's add +support for them. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 82 +++++++++++++++++++++++++++++++++- + drivers/gpu/drm/vc4/vc4_regs.h | 6 +++ + 2 files changed, 86 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -273,6 +273,13 @@ static u32 vc4_get_fifo_full_level(struc + case PV_CONTROL_FORMAT_24: + case PV_CONTROL_FORMAT_DSIV_24: + default: ++ /* ++ * For some reason, the pixelvalve4 doesn't work with ++ * the usual formula and will only work with 32. ++ */ ++ if (vc4_crtc->data->hvs_output == 5) ++ return 32; ++ + return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX; + } + } +@@ -281,8 +288,14 @@ static u32 vc4_crtc_get_fifo_full_level_ + u32 format) + { + u32 level = vc4_get_fifo_full_level(vc4_crtc, format); +- return VC4_SET_FIELD(level & 0x3f, +- PV_CONTROL_FIFO_LEVEL); ++ u32 ret = 0; ++ ++ if (level > 0x3f) ++ ret |= VC4_SET_FIELD((level >> 6) & 0x3, ++ PV5_CONTROL_FIFO_LEVEL_HIGH); ++ ++ return ret | VC4_SET_FIELD(level & 0x3f, ++ PV_CONTROL_FIFO_LEVEL); + } + + /* +@@ -328,6 +341,9 @@ static void vc4_crtc_config_pv(struct dr + CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); + CRTC_WRITE(PV_CONTROL, 0); + ++ CRTC_WRITE(PV_MUX_CFG, ++ VC4_SET_FIELD(8, PV_MUX_CFG_RGB_PIXEL_MUX_MODE)); ++ + CRTC_WRITE(PV_HORZA, + VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc, + PV_HORZA_HBP) | +@@ -1115,10 +1131,72 @@ static const struct vc4_crtc_data bcm283 + }, + }; + ++static const struct vc4_crtc_data bcm2711_pv0_data = { ++ .debugfs_name = "crtc0_regs", ++ .hvs_available_channels = BIT(0), ++ .hvs_output = 0, ++ .fifo_depth = 64, ++ .pixels_per_clock = 1, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_DSI0, ++ [1] = VC4_ENCODER_TYPE_DPI, ++ }, ++}; ++ ++static const struct vc4_crtc_data bcm2711_pv1_data = { ++ .debugfs_name = "crtc1_regs", ++ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), ++ .hvs_output = 3, ++ .fifo_depth = 64, ++ .pixels_per_clock = 1, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_DSI1, ++ [1] = VC4_ENCODER_TYPE_SMI, ++ }, ++}; ++ ++static const struct vc4_crtc_data bcm2711_pv2_data = { ++ .debugfs_name = "crtc2_regs", ++ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), ++ .hvs_output = 4, ++ .fifo_depth = 256, ++ .pixels_per_clock = 2, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_HDMI0, ++ }, ++}; ++ ++static const struct vc4_crtc_data bcm2711_pv3_data = { ++ .debugfs_name = "crtc3_regs", ++ .hvs_available_channels = BIT(1), ++ .hvs_output = 1, ++ .fifo_depth = 64, ++ .pixels_per_clock = 1, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_VEC, ++ }, ++}; ++ ++static const struct vc4_crtc_data bcm2711_pv4_data = { ++ .debugfs_name = "crtc4_regs", ++ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), ++ .hvs_output = 5, ++ .fifo_depth = 64, ++ .pixels_per_clock = 2, ++ .encoder_types = { ++ [0] = VC4_ENCODER_TYPE_HDMI1, ++ }, ++}; ++ + static const struct of_device_id vc4_crtc_dt_match[] = { + { .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data }, + { .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data }, + { .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data }, ++ { .compatible = "brcm,bcm2711-pixelvalve0", .data = &bcm2711_pv0_data }, ++ { .compatible = "brcm,bcm2711-pixelvalve1", .data = &bcm2711_pv1_data }, ++ { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data }, ++ { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data }, ++ { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -130,6 +130,8 @@ + #define V3D_ERRSTAT 0x00f20 + + #define PV_CONTROL 0x00 ++# define PV5_CONTROL_FIFO_LEVEL_HIGH_MASK VC4_MASK(26, 25) ++# define PV5_CONTROL_FIFO_LEVEL_HIGH_SHIFT 25 + # define PV_CONTROL_FORMAT_MASK VC4_MASK(23, 21) + # define PV_CONTROL_FORMAT_SHIFT 21 + # define PV_CONTROL_FORMAT_24 0 +@@ -209,6 +211,10 @@ + + #define PV_HACT_ACT 0x30 + ++#define PV_MUX_CFG 0x34 ++# define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_MASK VC4_MASK(5, 2) ++# define PV_MUX_CFG_RGB_PIXEL_MUX_MODE_SHIFT 2 ++ + #define SCALER_CHANNELS_COUNT 3 + + #define SCALER_DISPCTRL 0x00000000 diff --git a/target/linux/bcm27xx/patches-5.4/950-0572-drm-vc4-hdmi-Use-debugfs-private-field.patch b/target/linux/bcm27xx/patches-5.4/950-0572-drm-vc4-hdmi-Use-debugfs-private-field.patch new file mode 100644 index 00000000000..89d8aae28d0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0572-drm-vc4-hdmi-Use-debugfs-private-field.patch @@ -0,0 +1,30 @@ +From 26fbd25a3f99a85c09d5f1ed44980c506a3eac81 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 14 Jan 2020 17:24:32 +0100 +Subject: [PATCH] drm/vc4: hdmi: Use debugfs private field + +We're calling vc4_debugfs_add_file with our struct vc4_hdmi pointer set +in the private field, but we don't use that field and go through the +main struct vc4_dev to get it. + +Let's use the private field directly, that will save us some trouble +later on. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -182,9 +182,7 @@ static const struct debugfs_reg32 hd_reg + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + { + struct drm_info_node *node = (struct drm_info_node *)m->private; +- struct drm_device *dev = node->minor->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *hdmi = node->info_ent->data; + struct drm_printer p = drm_seq_file_printer(m); + + drm_print_regset32(&p, &hdmi->hdmi_regset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0573-drm-vc4-hdmi-Move-structure-to-header.patch b/target/linux/bcm27xx/patches-5.4/950-0573-drm-vc4-hdmi-Move-structure-to-header.patch new file mode 100644 index 00000000000..430fc0459ea --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0573-drm-vc4-hdmi-Move-structure-to-header.patch @@ -0,0 +1,195 @@ +From 13bb65d33681b0095214033a5e80186faa325854 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 18 Dec 2019 18:35:12 +0100 +Subject: [PATCH] drm/vc4: hdmi: Move structure to header + +We will need to share the vc4_hdmi and related structures with multiple +files, so let's create a header for it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 76 +----------------------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 86 ++++++++++++++++++++++++++++++++++ + 2 files changed, 87 insertions(+), 75 deletions(-) + create mode 100644 drivers/gpu/drm/vc4/vc4_hdmi.h + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -48,87 +48,13 @@ + #include + #include "media/cec.h" + #include "vc4_drv.h" ++#include "vc4_hdmi.h" + #include "vc4_regs.h" + + #define HSM_CLOCK_FREQ 163682864 + #define CEC_CLOCK_FREQ 40000 + #define CEC_CLOCK_DIV (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ) + +-/* HDMI audio information */ +-struct vc4_hdmi_audio { +- struct snd_soc_card card; +- struct snd_soc_dai_link link; +- struct snd_soc_dai_link_component cpu; +- struct snd_soc_dai_link_component codec; +- struct snd_soc_dai_link_component platform; +- int samplerate; +- int channels; +- struct snd_dmaengine_dai_dma_data dma_data; +- struct snd_pcm_substream *substream; +-}; +- +-/* General HDMI hardware state. */ +-struct vc4_hdmi { +- struct platform_device *pdev; +- +- struct drm_encoder *encoder; +- struct drm_connector *connector; +- +- struct vc4_hdmi_audio audio; +- +- struct i2c_adapter *ddc; +- void __iomem *hdmicore_regs; +- void __iomem *hd_regs; +- int hpd_gpio; +- bool hpd_active_low; +- +- struct cec_adapter *cec_adap; +- struct cec_msg cec_rx_msg; +- bool cec_tx_ok; +- bool cec_irq_was_rx; +- +- struct clk *pixel_clock; +- struct clk *hsm_clock; +- +- struct debugfs_regset32 hdmi_regset; +- struct debugfs_regset32 hd_regset; +-}; +- +-#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) +-#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) +-#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) +-#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) +- +-/* VC4 HDMI encoder KMS struct */ +-struct vc4_hdmi_encoder { +- struct vc4_encoder base; +- bool hdmi_monitor; +- bool limited_rgb_range; +-}; +- +-static inline struct vc4_hdmi_encoder * +-to_vc4_hdmi_encoder(struct drm_encoder *encoder) +-{ +- return container_of(encoder, struct vc4_hdmi_encoder, base.base); +-} +- +-/* VC4 HDMI connector KMS struct */ +-struct vc4_hdmi_connector { +- struct drm_connector base; +- +- /* Since the connector is attached to just the one encoder, +- * this is the reference to it so we can do the best_encoder() +- * hook. +- */ +- struct drm_encoder *encoder; +-}; +- +-static inline struct vc4_hdmi_connector * +-to_vc4_hdmi_connector(struct drm_connector *connector) +-{ +- return container_of(connector, struct vc4_hdmi_connector, base); +-} +- + static const struct debugfs_reg32 hdmi_regs[] = { + VC4_REG32(VC4_HDMI_CORE_REV), + VC4_REG32(VC4_HDMI_SW_RESET_CONTROL), +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -0,0 +1,86 @@ ++#ifndef _VC4_HDMI_H_ ++#define _VC4_HDMI_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "vc4_drv.h" ++ ++/* HDMI audio information */ ++struct vc4_hdmi_audio { ++ struct snd_soc_card card; ++ struct snd_soc_dai_link link; ++ struct snd_soc_dai_link_component cpu; ++ struct snd_soc_dai_link_component codec; ++ struct snd_soc_dai_link_component platform; ++ int samplerate; ++ int channels; ++ struct snd_dmaengine_dai_dma_data dma_data; ++ struct snd_pcm_substream *substream; ++}; ++ ++/* General HDMI hardware state. */ ++struct vc4_hdmi { ++ struct platform_device *pdev; ++ ++ struct drm_encoder *encoder; ++ struct drm_connector *connector; ++ ++ struct vc4_hdmi_audio audio; ++ ++ struct i2c_adapter *ddc; ++ void __iomem *hdmicore_regs; ++ void __iomem *hd_regs; ++ int hpd_gpio; ++ bool hpd_active_low; ++ ++ struct cec_adapter *cec_adap; ++ struct cec_msg cec_rx_msg; ++ bool cec_tx_ok; ++ bool cec_irq_was_rx; ++ ++ struct clk *pixel_clock; ++ struct clk *hsm_clock; ++ ++ struct debugfs_regset32 hdmi_regset; ++ struct debugfs_regset32 hd_regset; ++}; ++ ++#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) ++#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) ++#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) ++#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) ++ ++/* VC4 HDMI encoder KMS struct */ ++struct vc4_hdmi_encoder { ++ struct vc4_encoder base; ++ bool hdmi_monitor; ++ bool limited_rgb_range; ++}; ++ ++static inline struct vc4_hdmi_encoder * ++to_vc4_hdmi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_hdmi_encoder, base.base); ++} ++ ++/* VC4 HDMI connector KMS struct */ ++struct vc4_hdmi_connector { ++ struct drm_connector base; ++ ++ /* Since the connector is attached to just the one encoder, ++ * this is the reference to it so we can do the best_encoder() ++ * hook. ++ */ ++ struct drm_encoder *encoder; ++}; ++ ++static inline struct vc4_hdmi_connector * ++to_vc4_hdmi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_hdmi_connector, base); ++} ++ ++#endif /* _VC4_HDMI_H_ */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0574-drm-vc4-hdmi-rework-connectors-and-encoders.patch b/target/linux/bcm27xx/patches-5.4/950-0574-drm-vc4-hdmi-rework-connectors-and-encoders.patch new file mode 100644 index 00000000000..71125e3e25d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0574-drm-vc4-hdmi-rework-connectors-and-encoders.patch @@ -0,0 +1,348 @@ +From 50e7e810cf403c4b217c68c8ae2544d16f8063d1 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 17:17:29 +0100 +Subject: [PATCH] drm/vc4: hdmi: rework connectors and encoders + +the vc4_hdmi driver has some custom structures to hold the data it needs to +associate with the drm_encoder and drm_connector structures. + +However, it allocates them separately from the vc4_hdmi structure which +makes it more complicated than it needs to be. + +Move those structures to be contained by vc4_hdmi and update the code +accordingly. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 84 ++++++++++++++++------------------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 64 +++++++++++++------------- + 2 files changed, 71 insertions(+), 77 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -190,19 +190,14 @@ static const struct drm_connector_helper + .get_modes = vc4_hdmi_connector_get_modes, + }; + +-static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, +- struct drm_encoder *encoder) ++static int vc4_hdmi_connector_init(struct drm_device *dev, ++ struct vc4_hdmi *vc4_hdmi) + { +- struct drm_connector *connector; +- struct vc4_hdmi_connector *hdmi_connector; ++ struct vc4_hdmi_connector *hdmi_connector = &vc4_hdmi->connector; ++ struct drm_connector *connector = &hdmi_connector->base; ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + int ret; + +- hdmi_connector = devm_kzalloc(dev->dev, sizeof(*hdmi_connector), +- GFP_KERNEL); +- if (!hdmi_connector) +- return ERR_PTR(-ENOMEM); +- connector = &hdmi_connector->base; +- + hdmi_connector->encoder = encoder; + + drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, +@@ -212,7 +207,7 @@ static struct drm_connector *vc4_hdmi_co + /* Create and attach TV margin props to this connector. */ + ret = drm_mode_create_tv_margin_properties(dev); + if (ret) +- return ERR_PTR(ret); ++ return ret; + + drm_connector_attach_tv_margin_properties(connector); + +@@ -224,7 +219,7 @@ static struct drm_connector *vc4_hdmi_co + + drm_connector_attach_encoder(connector, encoder); + +- return connector; ++ return 0; + } + + static void vc4_hdmi_encoder_destroy(struct drm_encoder *encoder) +@@ -303,21 +298,22 @@ static void vc4_hdmi_set_avi_infoframe(s + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct vc4_dev *vc4 = encoder->dev->dev_private; + struct vc4_hdmi *hdmi = vc4->hdmi; +- struct drm_connector_state *cstate = hdmi->connector->state; ++ struct drm_connector *connector = &hdmi->connector.base; ++ struct drm_connector_state *cstate = connector->state; + struct drm_crtc *crtc = encoder->crtc; + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + union hdmi_infoframe frame; + int ret; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, +- hdmi->connector, mode); ++ connector, mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return; + } + + drm_hdmi_avi_infoframe_quant_range(&frame.avi, +- hdmi->connector, mode, ++ connector, mode, + vc4_encoder->limited_rgb_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); +@@ -636,7 +632,8 @@ static const struct drm_encoder_helper_f + /* HDMI audio codec callbacks */ + static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi) + { +- struct drm_device *drm = hdmi->encoder->dev; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + u32 hsm_clock = clk_get_rate(hdmi->hsm_clock); + unsigned long n, m; +@@ -655,7 +652,7 @@ static void vc4_hdmi_audio_set_mai_clock + + static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi) + { +- struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; + struct drm_crtc *crtc = encoder->crtc; + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); +@@ -693,7 +690,8 @@ static int vc4_hdmi_audio_startup(struct + struct snd_soc_dai *dai) + { + struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct drm_connector *connector = &hdmi->connector.base; + struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); + int ret; + +@@ -710,8 +708,7 @@ static int vc4_hdmi_audio_startup(struct + VC4_HDMI_RAM_PACKET_ENABLE)) + return -ENODEV; + +- ret = snd_pcm_hw_constraint_eld(substream->runtime, +- hdmi->connector->eld); ++ ret = snd_pcm_hw_constraint_eld(substream->runtime, connector->eld); + if (ret) + return ret; + +@@ -725,7 +722,7 @@ static int vc4_hdmi_audio_set_fmt(struct + + static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi) + { +- struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; + struct device *dev = &hdmi->pdev->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); +@@ -759,7 +756,7 @@ static int vc4_hdmi_audio_hw_params(stru + struct snd_soc_dai *dai) + { + struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; + struct device *dev = &hdmi->pdev->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); +@@ -832,7 +829,7 @@ static int vc4_hdmi_audio_trigger(struct + struct snd_soc_dai *dai) + { + struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_encoder *encoder = &hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + +@@ -876,9 +873,10 @@ static int vc4_hdmi_audio_eld_ctl_info(s + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ struct drm_connector *connector = &hdmi->connector.base; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; +- uinfo->count = sizeof(hdmi->connector->eld); ++ uinfo->count = sizeof(connector->eld); + + return 0; + } +@@ -888,9 +886,10 @@ static int vc4_hdmi_audio_eld_ctl_get(st + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ struct drm_connector *connector = &hdmi->connector.base; + +- memcpy(ucontrol->value.bytes.data, hdmi->connector->eld, +- sizeof(hdmi->connector->eld)); ++ memcpy(ucontrol->value.bytes.data, connector->eld, ++ sizeof(connector->eld)); + + return 0; + } +@@ -1230,7 +1229,7 @@ static int vc4_hdmi_bind(struct device * + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *hdmi; +- struct vc4_hdmi_encoder *vc4_hdmi_encoder; ++ struct drm_encoder *encoder; + struct device_node *ddc_node; + u32 value; + int ret; +@@ -1239,14 +1238,10 @@ static int vc4_hdmi_bind(struct device * + if (!hdmi) + return -ENOMEM; + +- vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder), +- GFP_KERNEL); +- if (!vc4_hdmi_encoder) +- return -ENOMEM; +- vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI0; +- hdmi->encoder = &vc4_hdmi_encoder->base.base; +- + hdmi->pdev = pdev; ++ encoder = &hdmi->encoder.base.base; ++ encoder->base.type = VC4_ENCODER_TYPE_HDMI0; ++ + hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(hdmi->hdmicore_regs)) + return PTR_ERR(hdmi->hdmicore_regs); +@@ -1332,15 +1327,14 @@ static int vc4_hdmi_bind(struct device * + } + pm_runtime_enable(dev); + +- drm_encoder_init(drm, hdmi->encoder, &vc4_hdmi_encoder_funcs, ++ drm_encoder_init(drm, encoder, &vc4_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); +- drm_encoder_helper_add(hdmi->encoder, &vc4_hdmi_encoder_helper_funcs); ++ drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs); + +- hdmi->connector = vc4_hdmi_connector_init(drm, hdmi->encoder); +- if (IS_ERR(hdmi->connector)) { +- ret = PTR_ERR(hdmi->connector); ++ ret = vc4_hdmi_connector_init(drm, hdmi); ++ if (ret) + goto err_destroy_encoder; +- } ++ + #ifdef CONFIG_DRM_VC4_HDMI_CEC + hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, + vc4, "vc4", +@@ -1350,7 +1344,7 @@ static int vc4_hdmi_bind(struct device * + if (ret < 0) + goto err_destroy_conn; + +- cec_fill_conn_info_from_drm(&conn_info, hdmi->connector); ++ cec_fill_conn_info_from_drm(&conn_info, &hdmi->connector.base); + cec_s_conn_info(hdmi->cec_adap, &conn_info); + + HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff); +@@ -1387,10 +1381,10 @@ static int vc4_hdmi_bind(struct device * + err_delete_cec_adap: + cec_delete_adapter(hdmi->cec_adap); + err_destroy_conn: +- vc4_hdmi_connector_destroy(hdmi->connector); ++ vc4_hdmi_connector_destroy(&hdmi->connector.base); + #endif + err_destroy_encoder: +- vc4_hdmi_encoder_destroy(hdmi->encoder); ++ vc4_hdmi_encoder_destroy(encoder); + err_unprepare_hsm: + clk_disable_unprepare(hdmi->hsm_clock); + pm_runtime_disable(dev); +@@ -1408,8 +1402,8 @@ static void vc4_hdmi_unbind(struct devic + struct vc4_hdmi *hdmi = vc4->hdmi; + + cec_unregister_adapter(hdmi->cec_adap); +- vc4_hdmi_connector_destroy(hdmi->connector); +- vc4_hdmi_encoder_destroy(hdmi->encoder); ++ vc4_hdmi_connector_destroy(&hdmi->connector.base); ++ vc4_hdmi_encoder_destroy(&hdmi->encoder.base.base); + + clk_disable_unprepare(hdmi->hsm_clock); + pm_runtime_disable(dev); +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -8,6 +8,36 @@ + + #include "vc4_drv.h" + ++/* VC4 HDMI encoder KMS struct */ ++struct vc4_hdmi_encoder { ++ struct vc4_encoder base; ++ bool hdmi_monitor; ++ bool limited_rgb_range; ++}; ++ ++static inline struct vc4_hdmi_encoder * ++to_vc4_hdmi_encoder(struct drm_encoder *encoder) ++{ ++ return container_of(encoder, struct vc4_hdmi_encoder, base.base); ++} ++ ++/* VC4 HDMI connector KMS struct */ ++struct vc4_hdmi_connector { ++ struct drm_connector base; ++ ++ /* Since the connector is attached to just the one encoder, ++ * this is the reference to it so we can do the best_encoder() ++ * hook. ++ */ ++ struct drm_encoder *encoder; ++}; ++ ++static inline struct vc4_hdmi_connector * ++to_vc4_hdmi_connector(struct drm_connector *connector) ++{ ++ return container_of(connector, struct vc4_hdmi_connector, base); ++} ++ + /* HDMI audio information */ + struct vc4_hdmi_audio { + struct snd_soc_card card; +@@ -25,8 +55,8 @@ struct vc4_hdmi_audio { + struct vc4_hdmi { + struct platform_device *pdev; + +- struct drm_encoder *encoder; +- struct drm_connector *connector; ++ struct vc4_hdmi_encoder encoder; ++ struct vc4_hdmi_connector connector; + + struct vc4_hdmi_audio audio; + +@@ -53,34 +83,4 @@ struct vc4_hdmi { + #define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) + #define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) + +-/* VC4 HDMI encoder KMS struct */ +-struct vc4_hdmi_encoder { +- struct vc4_encoder base; +- bool hdmi_monitor; +- bool limited_rgb_range; +-}; +- +-static inline struct vc4_hdmi_encoder * +-to_vc4_hdmi_encoder(struct drm_encoder *encoder) +-{ +- return container_of(encoder, struct vc4_hdmi_encoder, base.base); +-} +- +-/* VC4 HDMI connector KMS struct */ +-struct vc4_hdmi_connector { +- struct drm_connector base; +- +- /* Since the connector is attached to just the one encoder, +- * this is the reference to it so we can do the best_encoder() +- * hook. +- */ +- struct drm_encoder *encoder; +-}; +- +-static inline struct vc4_hdmi_connector * +-to_vc4_hdmi_connector(struct drm_connector *connector) +-{ +- return container_of(connector, struct vc4_hdmi_connector, base); +-} +- + #endif /* _VC4_HDMI_H_ */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0575-drm-vc4-hdmi-Rename-hdmi-to-vc4_hdmi.patch b/target/linux/bcm27xx/patches-5.4/950-0575-drm-vc4-hdmi-Rename-hdmi-to-vc4_hdmi.patch new file mode 100644 index 00000000000..75c44a564a8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0575-drm-vc4-hdmi-Rename-hdmi-to-vc4_hdmi.patch @@ -0,0 +1,682 @@ +From 02b7a6ed6b9fc110dd26598d26c31c0837af6184 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:07:05 +0100 +Subject: [PATCH] drm/vc4: hdmi: Rename hdmi to vc4_hdmi + +The driver isn't consistent with the name given to the vc4_hdmi +structure pointer in its functions. Make sure to use a consistent name. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 271 +++++++++++++++++---------------- + 1 file changed, 136 insertions(+), 135 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -108,11 +108,11 @@ static const struct debugfs_reg32 hd_reg + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + { + struct drm_info_node *node = (struct drm_info_node *)m->private; +- struct vc4_hdmi *hdmi = node->info_ent->data; ++ struct vc4_hdmi *vc4_hdmi = node->info_ent->data; + struct drm_printer p = drm_seq_file_printer(m); + +- drm_print_regset32(&p, &hdmi->hdmi_regset); +- drm_print_regset32(&p, &hdmi->hd_regset); ++ drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); ++ drm_print_regset32(&p, &vc4_hdmi->hd_regset); + + return 0; + } +@@ -297,8 +297,8 @@ static void vc4_hdmi_set_avi_infoframe(s + { + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct vc4_dev *vc4 = encoder->dev->dev_private; +- struct vc4_hdmi *hdmi = vc4->hdmi; +- struct drm_connector *connector = &hdmi->connector.base; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct drm_connector *connector = &vc4_hdmi->connector.base; + struct drm_connector_state *cstate = connector->state; + struct drm_crtc *crtc = encoder->crtc; + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; +@@ -346,7 +346,7 @@ static void vc4_hdmi_set_audio_infoframe + { + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = drm->dev_private; +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + union hdmi_infoframe frame; + int ret; + +@@ -355,7 +355,7 @@ static void vc4_hdmi_set_audio_infoframe + frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; +- frame.audio.channels = hdmi->audio.channels; ++ frame.audio.channels = vc4_hdmi->audio.channels; + + vc4_hdmi_write_infoframe(encoder, &frame); + } +@@ -370,7 +370,7 @@ static void vc4_hdmi_encoder_disable(str + { + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + int ret; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); +@@ -379,9 +379,9 @@ static void vc4_hdmi_encoder_disable(str + HD_WRITE(VC4_HD_VID_CTL, + HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + +- clk_disable_unprepare(hdmi->pixel_clock); ++ clk_disable_unprepare(vc4_hdmi->pixel_clock); + +- ret = pm_runtime_put(&hdmi->pdev->dev); ++ ret = pm_runtime_put(&vc4_hdmi->pdev->dev); + if (ret < 0) + DRM_ERROR("Failed to release power domain: %d\n", ret); + } +@@ -392,7 +392,7 @@ static void vc4_hdmi_encoder_enable(stru + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + bool debug_dump_regs = false; + bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; + bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; +@@ -414,13 +414,13 @@ static void vc4_hdmi_encoder_enable(stru + u32 csc_ctl; + int ret; + +- ret = pm_runtime_get_sync(&hdmi->pdev->dev); ++ ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); + if (ret < 0) { + DRM_ERROR("Failed to retain power domain: %d\n", ret); + return; + } + +- ret = clk_set_rate(hdmi->pixel_clock, ++ ret = clk_set_rate(vc4_hdmi->pixel_clock, + mode->clock * 1000 * + ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); + if (ret) { +@@ -428,7 +428,7 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + +- ret = clk_prepare_enable(hdmi->pixel_clock); ++ ret = clk_prepare_enable(vc4_hdmi->pixel_clock); + if (ret) { + DRM_ERROR("Failed to turn on pixel clock: %d\n", ret); + return; +@@ -448,11 +448,11 @@ static void vc4_hdmi_encoder_enable(stru + HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); + + if (debug_dump_regs) { +- struct drm_printer p = drm_info_printer(&hdmi->pdev->dev); ++ struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev); + +- dev_info(&hdmi->pdev->dev, "HDMI regs before:\n"); +- drm_print_regset32(&p, &hdmi->hdmi_regset); +- drm_print_regset32(&p, &hdmi->hd_regset); ++ dev_info(&vc4_hdmi->pdev->dev, "HDMI regs before:\n"); ++ drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); ++ drm_print_regset32(&p, &vc4_hdmi->hd_regset); + } + + HD_WRITE(VC4_HD_VID_CTL, 0); +@@ -527,11 +527,11 @@ static void vc4_hdmi_encoder_enable(stru + HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); + + if (debug_dump_regs) { +- struct drm_printer p = drm_info_printer(&hdmi->pdev->dev); ++ struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev); + +- dev_info(&hdmi->pdev->dev, "HDMI regs after:\n"); +- drm_print_regset32(&p, &hdmi->hdmi_regset); +- drm_print_regset32(&p, &hdmi->hd_regset); ++ dev_info(&vc4_hdmi->pdev->dev, "HDMI regs after:\n"); ++ drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); ++ drm_print_regset32(&p, &vc4_hdmi->hd_regset); + } + + HD_WRITE(VC4_HD_VID_CTL, +@@ -630,15 +630,15 @@ static const struct drm_encoder_helper_f + }; + + /* HDMI audio codec callbacks */ +-static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi) ++static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi) + { +- struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); +- u32 hsm_clock = clk_get_rate(hdmi->hsm_clock); ++ u32 hsm_clock = clk_get_rate(vc4_hdmi->hsm_clock); + unsigned long n, m; + +- rational_best_approximation(hsm_clock, hdmi->audio.samplerate, ++ rational_best_approximation(hsm_clock, vc4_hdmi->audio.samplerate, + VC4_HD_MAI_SMP_N_MASK >> + VC4_HD_MAI_SMP_N_SHIFT, + (VC4_HD_MAI_SMP_M_MASK >> +@@ -650,14 +650,14 @@ static void vc4_hdmi_audio_set_mai_clock + VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); + } + +-static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi) ++static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi) + { +- struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_crtc *crtc = encoder->crtc; + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; +- u32 samplerate = hdmi->audio.samplerate; ++ u32 samplerate = vc4_hdmi->audio.samplerate; + u32 n, cts; + u64 tmp; + +@@ -689,16 +689,16 @@ static inline struct vc4_hdmi *dai_to_hd + static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { +- struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = &hdmi->encoder.base.base; +- struct drm_connector *connector = &hdmi->connector.base; ++ struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; ++ struct drm_connector *connector = &vc4_hdmi->connector.base; + struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); + int ret; + +- if (hdmi->audio.substream && hdmi->audio.substream != substream) ++ if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream) + return -EINVAL; + +- hdmi->audio.substream = substream; ++ vc4_hdmi->audio.substream = substream; + + /* + * If the HDMI encoder hasn't probed, or the encoder is +@@ -720,11 +720,11 @@ static int vc4_hdmi_audio_set_fmt(struct + return 0; + } + +-static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi) ++static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) + { +- struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; +- struct device *dev = &hdmi->pdev->dev; ++ struct device *dev = &vc4_hdmi->pdev->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + int ret; + +@@ -740,14 +740,14 @@ static void vc4_hdmi_audio_reset(struct + static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { +- struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + +- if (substream != hdmi->audio.substream) ++ if (substream != vc4_hdmi->audio.substream) + return; + +- vc4_hdmi_audio_reset(hdmi); ++ vc4_hdmi_audio_reset(vc4_hdmi); + +- hdmi->audio.substream = NULL; ++ vc4_hdmi->audio.substream = NULL; + } + + /* HDMI audio codec callbacks */ +@@ -755,23 +755,23 @@ static int vc4_hdmi_audio_hw_params(stru + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) + { +- struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; +- struct device *dev = &hdmi->pdev->dev; ++ struct device *dev = &vc4_hdmi->pdev->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + u32 audio_packet_config, channel_mask; + u32 channel_map, i; + +- if (substream != hdmi->audio.substream) ++ if (substream != vc4_hdmi->audio.substream) + return -EINVAL; + + dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, + params_rate(params), params_width(params), + params_channels(params)); + +- hdmi->audio.channels = params_channels(params); +- hdmi->audio.samplerate = params_rate(params); ++ vc4_hdmi->audio.channels = params_channels(params); ++ vc4_hdmi->audio.samplerate = params_rate(params); + + HD_WRITE(VC4_HD_MAI_CTL, + VC4_HD_MAI_CTL_RESET | +@@ -780,23 +780,23 @@ static int vc4_hdmi_audio_hw_params(stru + VC4_HD_MAI_CTL_ERRORE | + VC4_HD_MAI_CTL_ERRORF); + +- vc4_hdmi_audio_set_mai_clock(hdmi); ++ vc4_hdmi_audio_set_mai_clock(vc4_hdmi); + + audio_packet_config = + VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT | + VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | + VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); + +- channel_mask = GENMASK(hdmi->audio.channels - 1, 0); ++ channel_mask = GENMASK(vc4_hdmi->audio.channels - 1, 0); + audio_packet_config |= VC4_SET_FIELD(channel_mask, + VC4_HDMI_AUDIO_PACKET_CEA_MASK); + + /* Set the MAI threshold. This logic mimics the firmware's. */ +- if (hdmi->audio.samplerate > 96000) { ++ if (vc4_hdmi->audio.samplerate > 96000) { + HD_WRITE(VC4_HD_MAI_THR, + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) | + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); +- } else if (hdmi->audio.samplerate > 48000) { ++ } else if (vc4_hdmi->audio.samplerate > 48000) { + HD_WRITE(VC4_HD_MAI_THR, + VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) | + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); +@@ -820,7 +820,7 @@ static int vc4_hdmi_audio_hw_params(stru + + HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map); + HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); +- vc4_hdmi_set_n_cts(hdmi); ++ vc4_hdmi_set_n_cts(vc4_hdmi); + + return 0; + } +@@ -828,8 +828,8 @@ static int vc4_hdmi_audio_hw_params(stru + static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) + { +- struct vc4_hdmi *hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = &hdmi->encoder.base.base; ++ struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_device *drm = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + +@@ -840,7 +840,7 @@ static int vc4_hdmi_audio_trigger(struct + HDMI_READ(VC4_HDMI_TX_PHY_CTL0) & + ~VC4_HDMI_TX_PHY_RNG_PWRDN); + HD_WRITE(VC4_HD_MAI_CTL, +- VC4_SET_FIELD(hdmi->audio.channels, ++ VC4_SET_FIELD(vc4_hdmi->audio.channels, + VC4_HD_MAI_CTL_CHNUM) | + VC4_HD_MAI_CTL_ENABLE); + break; +@@ -872,8 +872,8 @@ static int vc4_hdmi_audio_eld_ctl_info(s + struct snd_ctl_elem_info *uinfo) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &hdmi->connector.base; ++ struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); ++ struct drm_connector *connector = &vc4_hdmi->connector.base; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(connector->eld); +@@ -885,8 +885,8 @@ static int vc4_hdmi_audio_eld_ctl_get(st + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); +- struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &hdmi->connector.base; ++ struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); ++ struct drm_connector *connector = &vc4_hdmi->connector.base; + + memcpy(ucontrol->value.bytes.data, connector->eld, + sizeof(connector->eld)); +@@ -954,9 +954,9 @@ static const struct snd_soc_component_dr + + static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) + { +- struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + +- snd_soc_dai_init_dma_data(dai, &hdmi->audio.dma_data, NULL); ++ snd_soc_dai_init_dma_data(dai, &vc4_hdmi->audio.dma_data, NULL); + + return 0; + } +@@ -982,11 +982,11 @@ static const struct snd_dmaengine_pcm_co + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + }; + +-static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi) ++static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + { +- struct snd_soc_dai_link *dai_link = &hdmi->audio.link; +- struct snd_soc_card *card = &hdmi->audio.card; +- struct device *dev = &hdmi->pdev->dev; ++ struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link; ++ struct snd_soc_card *card = &vc4_hdmi->audio.card; ++ struct device *dev = &vc4_hdmi->pdev->dev; + const __be32 *addr; + int ret; + int len; +@@ -1006,9 +1006,9 @@ static int vc4_hdmi_audio_init(struct vc + * This VC/MMU should probably be exposed to avoid this kind of hacks. + */ + addr = of_get_address(dev->of_node, 1, NULL, NULL); +- hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; +- hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- hdmi->audio.dma_data.maxburst = 2; ++ vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; ++ vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ vc4_hdmi->audio.dma_data.maxburst = 2; + + ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); + if (ret) { +@@ -1031,9 +1031,9 @@ static int vc4_hdmi_audio_init(struct vc + return ret; + } + +- dai_link->cpus = &hdmi->audio.cpu; +- dai_link->codecs = &hdmi->audio.codec; +- dai_link->platforms = &hdmi->audio.platform; ++ dai_link->cpus = &vc4_hdmi->audio.cpu; ++ dai_link->codecs = &vc4_hdmi->audio.codec; ++ dai_link->platforms = &vc4_hdmi->audio.platform; + + dai_link->num_cpus = 1; + dai_link->num_codecs = 1; +@@ -1058,7 +1058,7 @@ static int vc4_hdmi_audio_init(struct vc + * now stored in card->drvdata and should be retrieved with + * snd_soc_card_get_drvdata() if needed. + */ +- snd_soc_card_set_drvdata(card, hdmi); ++ snd_soc_card_set_drvdata(card, vc4_hdmi); + ret = devm_snd_soc_register_card(dev, card); + if (ret) + dev_err(dev, "Could not register sound card: %d\n", ret); +@@ -1071,20 +1071,21 @@ static int vc4_hdmi_audio_init(struct vc + static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) + { + struct vc4_dev *vc4 = priv; +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + +- if (hdmi->cec_irq_was_rx) { +- if (hdmi->cec_rx_msg.len) +- cec_received_msg(hdmi->cec_adap, &hdmi->cec_rx_msg); +- } else if (hdmi->cec_tx_ok) { +- cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_OK, ++ if (vc4_hdmi->cec_irq_was_rx) { ++ if (vc4_hdmi->cec_rx_msg.len) ++ cec_received_msg(vc4_hdmi->cec_adap, ++ &vc4_hdmi->cec_rx_msg); ++ } else if (vc4_hdmi->cec_tx_ok) { ++ cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK, + 0, 0, 0, 0); + } else { + /* + * This CEC implementation makes 1 retry, so if we + * get a NACK, then that means it made 2 attempts. + */ +- cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_NACK, ++ cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_NACK, + 0, 2, 0, 0); + } + return IRQ_HANDLED; +@@ -1110,23 +1111,23 @@ static void vc4_cec_read_msg(struct vc4_ + static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) + { + struct vc4_dev *vc4 = priv; +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS); + u32 cntrl1, cntrl5; + + if (!(stat & VC4_HDMI_CPU_CEC)) + return IRQ_NONE; +- hdmi->cec_rx_msg.len = 0; ++ vc4_hdmi->cec_rx_msg.len = 0; + cntrl1 = HDMI_READ(VC4_HDMI_CEC_CNTRL_1); + cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); +- hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; +- if (hdmi->cec_irq_was_rx) { ++ vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; ++ if (vc4_hdmi->cec_irq_was_rx) { + vc4_cec_read_msg(vc4, cntrl1); + cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1); + cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + } else { +- hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; ++ vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; + cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; + } + HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1); +@@ -1228,44 +1229,44 @@ static int vc4_hdmi_bind(struct device * + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; +- struct vc4_hdmi *hdmi; ++ struct vc4_hdmi *vc4_hdmi; + struct drm_encoder *encoder; + struct device_node *ddc_node; + u32 value; + int ret; + +- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); +- if (!hdmi) ++ vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); ++ if (!vc4_hdmi) + return -ENOMEM; + +- hdmi->pdev = pdev; +- encoder = &hdmi->encoder.base.base; ++ vc4_hdmi->pdev = pdev; ++ encoder = &vc4_hdmi->encoder.base.base; + encoder->base.type = VC4_ENCODER_TYPE_HDMI0; + +- hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(hdmi->hdmicore_regs)) +- return PTR_ERR(hdmi->hdmicore_regs); +- +- hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); +- if (IS_ERR(hdmi->hd_regs)) +- return PTR_ERR(hdmi->hd_regs); +- +- hdmi->hdmi_regset.base = hdmi->hdmicore_regs; +- hdmi->hdmi_regset.regs = hdmi_regs; +- hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs); +- hdmi->hd_regset.base = hdmi->hd_regs; +- hdmi->hd_regset.regs = hd_regs; +- hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs); ++ vc4_hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(vc4_hdmi->hdmicore_regs)) ++ return PTR_ERR(vc4_hdmi->hdmicore_regs); ++ ++ vc4_hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); ++ if (IS_ERR(vc4_hdmi->hd_regs)) ++ return PTR_ERR(vc4_hdmi->hd_regs); ++ ++ vc4_hdmi->hdmi_regset.base = vc4_hdmi->hdmicore_regs; ++ vc4_hdmi->hdmi_regset.regs = hdmi_regs; ++ vc4_hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs); ++ vc4_hdmi->hd_regset.base = vc4_hdmi->hd_regs; ++ vc4_hdmi->hd_regset.regs = hd_regs; ++ vc4_hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs); + +- hdmi->pixel_clock = devm_clk_get(dev, "pixel"); +- if (IS_ERR(hdmi->pixel_clock)) { ++ vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel"); ++ if (IS_ERR(vc4_hdmi->pixel_clock)) { + DRM_ERROR("Failed to get pixel clock\n"); +- return PTR_ERR(hdmi->pixel_clock); ++ return PTR_ERR(vc4_hdmi->pixel_clock); + } +- hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); +- if (IS_ERR(hdmi->hsm_clock)) { ++ vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); ++ if (IS_ERR(vc4_hdmi->hsm_clock)) { + DRM_ERROR("Failed to get HDMI state machine clock\n"); +- return PTR_ERR(hdmi->hsm_clock); ++ return PTR_ERR(vc4_hdmi->hsm_clock); + } + + ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); +@@ -1274,9 +1275,9 @@ static int vc4_hdmi_bind(struct device * + return -ENODEV; + } + +- hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); ++ vc4_hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); + of_node_put(ddc_node); +- if (!hdmi->ddc) { ++ if (!vc4_hdmi->ddc) { + DRM_DEBUG("Failed to get ddc i2c adapter by node\n"); + return -EPROBE_DEFER; + } +@@ -1285,13 +1286,13 @@ static int vc4_hdmi_bind(struct device * + * needs to be a bit higher than the pixel clock rate + * (generally 148.5Mhz). + */ +- ret = clk_set_rate(hdmi->hsm_clock, HSM_CLOCK_FREQ); ++ ret = clk_set_rate(vc4_hdmi->hsm_clock, HSM_CLOCK_FREQ); + if (ret) { + DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); + goto err_put_i2c; + } + +- ret = clk_prepare_enable(hdmi->hsm_clock); ++ ret = clk_prepare_enable(vc4_hdmi->hsm_clock); + if (ret) { + DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", + ret); +@@ -1304,18 +1305,18 @@ static int vc4_hdmi_bind(struct device * + if (of_find_property(dev->of_node, "hpd-gpios", &value)) { + enum of_gpio_flags hpd_gpio_flags; + +- hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node, ++ vc4_hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node, + "hpd-gpios", 0, + &hpd_gpio_flags); +- if (hdmi->hpd_gpio < 0) { +- ret = hdmi->hpd_gpio; ++ if (vc4_hdmi->hpd_gpio < 0) { ++ ret = vc4_hdmi->hpd_gpio; + goto err_unprepare_hsm; + } + +- hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; ++ vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; + } + +- vc4->hdmi = hdmi; ++ vc4->hdmi = vc4_hdmi; + + /* HDMI core must be enabled. */ + if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) { +@@ -1331,21 +1332,21 @@ static int vc4_hdmi_bind(struct device * + DRM_MODE_ENCODER_TMDS, NULL); + drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs); + +- ret = vc4_hdmi_connector_init(drm, hdmi); ++ ret = vc4_hdmi_connector_init(drm, vc4_hdmi); + if (ret) + goto err_destroy_encoder; + + #ifdef CONFIG_DRM_VC4_HDMI_CEC +- hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, ++ vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, + vc4, "vc4", + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); +- ret = PTR_ERR_OR_ZERO(hdmi->cec_adap); ++ ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap); + if (ret < 0) + goto err_destroy_conn; + +- cec_fill_conn_info_from_drm(&conn_info, &hdmi->connector.base); +- cec_s_conn_info(hdmi->cec_adap, &conn_info); ++ cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector.base); ++ cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); + + HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff); + value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1); +@@ -1364,32 +1365,32 @@ static int vc4_hdmi_bind(struct device * + "vc4 hdmi cec", vc4); + if (ret) + goto err_delete_cec_adap; +- ret = cec_register_adapter(hdmi->cec_adap, dev); ++ ret = cec_register_adapter(vc4_hdmi->cec_adap, dev); + if (ret < 0) + goto err_delete_cec_adap; + #endif + +- ret = vc4_hdmi_audio_init(hdmi); ++ ret = vc4_hdmi_audio_init(vc4_hdmi); + if (ret) + goto err_destroy_encoder; + +- vc4_debugfs_add_file(drm, "hdmi_regs", vc4_hdmi_debugfs_regs, hdmi); ++ vc4_debugfs_add_file(drm, "hdmi_regs", vc4_hdmi_debugfs_regs, vc4_hdmi); + + return 0; + + #ifdef CONFIG_DRM_VC4_HDMI_CEC + err_delete_cec_adap: +- cec_delete_adapter(hdmi->cec_adap); ++ cec_delete_adapter(vc4_hdmi->cec_adap); + err_destroy_conn: +- vc4_hdmi_connector_destroy(&hdmi->connector.base); ++ vc4_hdmi_connector_destroy(&vc4_hdmi->connector.base); + #endif + err_destroy_encoder: + vc4_hdmi_encoder_destroy(encoder); + err_unprepare_hsm: +- clk_disable_unprepare(hdmi->hsm_clock); ++ clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); + err_put_i2c: +- put_device(&hdmi->ddc->dev); ++ put_device(&vc4_hdmi->ddc->dev); + + return ret; + } +@@ -1399,16 +1400,16 @@ static void vc4_hdmi_unbind(struct devic + { + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = drm->dev_private; +- struct vc4_hdmi *hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + +- cec_unregister_adapter(hdmi->cec_adap); +- vc4_hdmi_connector_destroy(&hdmi->connector.base); +- vc4_hdmi_encoder_destroy(&hdmi->encoder.base.base); ++ cec_unregister_adapter(vc4_hdmi->cec_adap); ++ vc4_hdmi_connector_destroy(&vc4_hdmi->connector.base); ++ vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); + +- clk_disable_unprepare(hdmi->hsm_clock); ++ clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); + +- put_device(&hdmi->ddc->dev); ++ put_device(&vc4_hdmi->ddc->dev); + + vc4->hdmi = NULL; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0576-drm-vc4-hdmi-Move-accessors-to-vc4_hdmi.patch b/target/linux/bcm27xx/patches-5.4/950-0576-drm-vc4-hdmi-Move-accessors-to-vc4_hdmi.patch new file mode 100644 index 00000000000..53296ecb4b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0576-drm-vc4-hdmi-Move-accessors-to-vc4_hdmi.patch @@ -0,0 +1,152 @@ +From d1ced662ff5ed90a489b6610144d480bfd7a64e9 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:21:44 +0100 +Subject: [PATCH] drm/vc4: hdmi: Move accessors to vc4_hdmi + +The current driver only supports a single HDMI controller, and part of +the issue is that the main vc4_dev structure holds a pointer to its +(only) HDMI controller, and the HDMI registers accessors will use it to +retrieve the mapped addresses. + +Let's modify those accessors to use directly the vc4_hdmi structure so +that we can eventually get rid of that single global pointer. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 22 ++++++++-------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 8 ++++---- + 2 files changed, 12 insertions(+), 18 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -122,6 +122,7 @@ vc4_hdmi_connector_detect(struct drm_con + { + struct drm_device *dev = connector->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + + if (vc4->hdmi->hpd_gpio) { + if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^ +@@ -236,6 +237,7 @@ static int vc4_hdmi_stop_packet(struct d + { + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + u32 packet_id = type - 0x80; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, +@@ -250,6 +252,7 @@ static void vc4_hdmi_write_infoframe(str + { + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + u32 packet_id = frame->any.type - 0x80; + u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; +@@ -632,9 +635,6 @@ static const struct drm_encoder_helper_f + /* HDMI audio codec callbacks */ + static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi) + { +- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_device *drm = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); + u32 hsm_clock = clk_get_rate(vc4_hdmi->hsm_clock); + unsigned long n, m; + +@@ -654,8 +654,6 @@ static void vc4_hdmi_set_n_cts(struct vc + { + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_crtc *crtc = encoder->crtc; +- struct drm_device *drm = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u32 samplerate = vc4_hdmi->audio.samplerate; + u32 n, cts; +@@ -692,7 +690,6 @@ static int vc4_hdmi_audio_startup(struct + struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + struct drm_connector *connector = &vc4_hdmi->connector.base; +- struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); + int ret; + + if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream) +@@ -723,9 +720,7 @@ static int vc4_hdmi_audio_set_fmt(struct + static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) + { + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_device *drm = encoder->dev; + struct device *dev = &vc4_hdmi->pdev->dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); + int ret; + + ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); +@@ -756,10 +751,7 @@ static int vc4_hdmi_audio_hw_params(stru + struct snd_soc_dai *dai) + { + struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); +- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_device *drm = encoder->dev; + struct device *dev = &vc4_hdmi->pdev->dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); + u32 audio_packet_config, channel_mask; + u32 channel_map, i; + +@@ -830,8 +822,6 @@ static int vc4_hdmi_audio_trigger(struct + { + struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_device *drm = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(drm); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +@@ -1093,7 +1083,8 @@ static irqreturn_t vc4_cec_irq_handler_t + + static void vc4_cec_read_msg(struct vc4_dev *vc4, u32 cntrl1) + { +- struct cec_msg *msg = &vc4->hdmi->cec_rx_msg; ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct cec_msg *msg = &vc4_hdmi->cec_rx_msg; + unsigned int i; + + msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >> +@@ -1139,6 +1130,7 @@ static irqreturn_t vc4_cec_irq_handler(i + static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) + { + struct vc4_dev *vc4 = cec_get_drvdata(adap); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + /* clock period in microseconds */ + const u32 usecs = 1000000 / CEC_CLOCK_FREQ; + u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); +@@ -1182,6 +1174,7 @@ static int vc4_hdmi_cec_adap_enable(stru + static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) + { + struct vc4_dev *vc4 = cec_get_drvdata(adap); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + + HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, + (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | +@@ -1193,6 +1186,7 @@ static int vc4_hdmi_cec_adap_transmit(st + u32 signal_free_time, struct cec_msg *msg) + { + struct vc4_dev *vc4 = cec_get_drvdata(adap); ++ struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + u32 val; + unsigned int i; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -78,9 +78,9 @@ struct vc4_hdmi { + struct debugfs_regset32 hd_regset; + }; + +-#define HDMI_READ(offset) readl(vc4->hdmi->hdmicore_regs + offset) +-#define HDMI_WRITE(offset, val) writel(val, vc4->hdmi->hdmicore_regs + offset) +-#define HD_READ(offset) readl(vc4->hdmi->hd_regs + offset) +-#define HD_WRITE(offset, val) writel(val, vc4->hdmi->hd_regs + offset) ++#define HDMI_READ(offset) readl(vc4_hdmi->hdmicore_regs + offset) ++#define HDMI_WRITE(offset, val) writel(val, vc4_hdmi->hdmicore_regs + offset) ++#define HD_READ(offset) readl(vc4_hdmi->hd_regs + offset) ++#define HD_WRITE(offset, val) writel(val, vc4_hdmi->hd_regs + offset) + + #endif /* _VC4_HDMI_H_ */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0577-drm-vc4-hdmi-Use-local-vc4_hdmi-directly.patch b/target/linux/bcm27xx/patches-5.4/950-0577-drm-vc4-hdmi-Use-local-vc4_hdmi-directly.patch new file mode 100644 index 00000000000..9b60fbb72bc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0577-drm-vc4-hdmi-Use-local-vc4_hdmi-directly.patch @@ -0,0 +1,45 @@ +From 985efd0f9da3d2b60e34d10efee969e4dfd85a12 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:44:36 +0100 +Subject: [PATCH] drm/vc4: hdmi: Use local vc4_hdmi directly + +The function vc4_hdmi_connector_detect access its vc4_hdmi struct by +dereferencing the pointer in the structure vc4_dev. This will cause some +issues when we will have multiple HDMI controllers, so let's just use the +local variable for now instead of dereferencing that pointer all the time, +and we'll fix the local variable later. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -124,20 +124,20 @@ vc4_hdmi_connector_detect(struct drm_con + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + +- if (vc4->hdmi->hpd_gpio) { +- if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^ +- vc4->hdmi->hpd_active_low) ++ if (vc4_hdmi->hpd_gpio) { ++ if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ ++ vc4_hdmi->hpd_active_low) + return connector_status_connected; +- cec_phys_addr_invalidate(vc4->hdmi->cec_adap); ++ cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + return connector_status_disconnected; + } + +- if (drm_probe_ddc(vc4->hdmi->ddc)) ++ if (drm_probe_ddc(vc4_hdmi->ddc)) + return connector_status_connected; + + if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) + return connector_status_connected; +- cec_phys_addr_invalidate(vc4->hdmi->cec_adap); ++ cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + return connector_status_disconnected; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0578-drm-vc4-hdmi-Add-container_of-macros-for-encoders-an.patch b/target/linux/bcm27xx/patches-5.4/950-0578-drm-vc4-hdmi-Add-container_of-macros-for-encoders-an.patch new file mode 100644 index 00000000000..1d70ca851cc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0578-drm-vc4-hdmi-Add-container_of-macros-for-encoders-an.patch @@ -0,0 +1,151 @@ +From fe19f02dbfd020df9b028cf2c580417c4edc31b3 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:45:46 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add container_of macros for encoders + and connectors + +Whenever the code needs to access the vc4_hdmi structure from a DRM +connector or encoder, it first accesses the drm_device associated to the +connector, then retrieve the drm_dev private data which gives it a +pointer to our vc4_dev, and will finally follow the vc4_hdmi pointer in +that structure. + +That will also give us some trouble when having multiple controllers, +but now that we have our encoder and connector structures that are part +of vc4_hdmi, we can simply call container_of on the DRM connector or +encoder and retrieve the vc4_hdmi structure directly. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 41 ++++++++++------------------------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 16 +++++++++++++ + 2 files changed, 28 insertions(+), 29 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -120,9 +120,7 @@ static int vc4_hdmi_debugfs_regs(struct + static enum drm_connector_status + vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +- struct drm_device *dev = connector->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); + + if (vc4_hdmi->hpd_gpio) { + if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ +@@ -149,17 +147,13 @@ static void vc4_hdmi_connector_destroy(s + + static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) + { +- struct vc4_hdmi_connector *vc4_connector = +- to_vc4_hdmi_connector(connector); +- struct drm_encoder *encoder = vc4_connector->encoder; +- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); +- struct drm_device *dev = connector->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); ++ struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; + int ret = 0; + struct edid *edid; + +- edid = drm_get_edid(connector, vc4->hdmi->ddc); +- cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); ++ edid = drm_get_edid(connector, vc4_hdmi->ddc); ++ cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); + if (!edid) + return -ENODEV; + +@@ -235,9 +229,7 @@ static const struct drm_encoder_funcs vc + static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, + enum hdmi_infoframe_type type) + { +- struct drm_device *dev = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + u32 packet_id = type - 0x80; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, +@@ -250,9 +242,7 @@ static int vc4_hdmi_stop_packet(struct d + static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, + union hdmi_infoframe *frame) + { +- struct drm_device *dev = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + u32 packet_id = frame->any.type - 0x80; + u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; +@@ -298,9 +288,8 @@ static void vc4_hdmi_write_infoframe(str + + static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) + { ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); +- struct vc4_dev *vc4 = encoder->dev->dev_private; +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + struct drm_connector *connector = &vc4_hdmi->connector.base; + struct drm_connector_state *cstate = connector->state; + struct drm_crtc *crtc = encoder->crtc; +@@ -347,9 +336,7 @@ static void vc4_hdmi_set_spd_infoframe(s + + static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) + { +- struct drm_device *drm = encoder->dev; +- struct vc4_dev *vc4 = drm->dev_private; +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + union hdmi_infoframe frame; + int ret; + +@@ -371,9 +358,7 @@ static void vc4_hdmi_set_infoframes(stru + + static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) + { +- struct drm_device *dev = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + int ret; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); +@@ -392,10 +377,8 @@ static void vc4_hdmi_encoder_disable(str + static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) + { + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; +- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); +- struct drm_device *dev = encoder->dev; +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; + bool debug_dump_regs = false; + bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; + bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -78,6 +78,22 @@ struct vc4_hdmi { + struct debugfs_regset32 hd_regset; + }; + ++static inline struct vc4_hdmi * ++connector_to_vc4_hdmi(struct drm_connector *connector) ++{ ++ struct vc4_hdmi_connector *_connector = to_vc4_hdmi_connector(connector); ++ ++ return container_of(_connector, struct vc4_hdmi, connector); ++} ++ ++static inline struct vc4_hdmi * ++encoder_to_vc4_hdmi(struct drm_encoder *encoder) ++{ ++ struct vc4_hdmi_encoder *_encoder = to_vc4_hdmi_encoder(encoder); ++ ++ return container_of(_encoder, struct vc4_hdmi, encoder); ++} ++ + #define HDMI_READ(offset) readl(vc4_hdmi->hdmicore_regs + offset) + #define HDMI_WRITE(offset, val) writel(val, vc4_hdmi->hdmicore_regs + offset) + #define HD_READ(offset) readl(vc4_hdmi->hd_regs + offset) diff --git a/target/linux/bcm27xx/patches-5.4/950-0579-drm-vc4-hdmi-Pass-vc4_hdmi-to-CEC-code.patch b/target/linux/bcm27xx/patches-5.4/950-0579-drm-vc4-hdmi-Pass-vc4_hdmi-to-CEC-code.patch new file mode 100644 index 00000000000..b0abafc6998 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0579-drm-vc4-hdmi-Pass-vc4_hdmi-to-CEC-code.patch @@ -0,0 +1,107 @@ +From 8af2552e862100e843b8d1f36543b718dde393ad Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:47:53 +0100 +Subject: [PATCH] drm/vc4: hdmi: Pass vc4_hdmi to CEC code + +Our CEC code also retrieves the associated vc4_hdmi by setting the +vc4_dev pointer as its private data, and then dereferences its vc4_hdmi +pointer. + +In order to eventually get rid of that pointer, we can simply pass the +vc4_hdmi pointer directly. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1043,8 +1043,7 @@ static int vc4_hdmi_audio_init(struct vc + #ifdef CONFIG_DRM_VC4_HDMI_CEC + static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv) + { +- struct vc4_dev *vc4 = priv; +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = priv; + + if (vc4_hdmi->cec_irq_was_rx) { + if (vc4_hdmi->cec_rx_msg.len) +@@ -1064,9 +1063,8 @@ static irqreturn_t vc4_cec_irq_handler_t + return IRQ_HANDLED; + } + +-static void vc4_cec_read_msg(struct vc4_dev *vc4, u32 cntrl1) ++static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) + { +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; + struct cec_msg *msg = &vc4_hdmi->cec_rx_msg; + unsigned int i; + +@@ -1084,8 +1082,7 @@ static void vc4_cec_read_msg(struct vc4_ + + static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) + { +- struct vc4_dev *vc4 = priv; +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = priv; + u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS); + u32 cntrl1, cntrl5; + +@@ -1096,7 +1093,7 @@ static irqreturn_t vc4_cec_irq_handler(i + cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); + vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; + if (vc4_hdmi->cec_irq_was_rx) { +- vc4_cec_read_msg(vc4, cntrl1); ++ vc4_cec_read_msg(vc4_hdmi, cntrl1); + cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1); + cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; +@@ -1112,8 +1109,7 @@ static irqreturn_t vc4_cec_irq_handler(i + + static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) + { +- struct vc4_dev *vc4 = cec_get_drvdata(adap); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + /* clock period in microseconds */ + const u32 usecs = 1000000 / CEC_CLOCK_FREQ; + u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); +@@ -1156,8 +1152,7 @@ static int vc4_hdmi_cec_adap_enable(stru + + static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) + { +- struct vc4_dev *vc4 = cec_get_drvdata(adap); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + + HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, + (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | +@@ -1168,8 +1163,7 @@ static int vc4_hdmi_cec_adap_log_addr(st + static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) + { +- struct vc4_dev *vc4 = cec_get_drvdata(adap); +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + u32 val; + unsigned int i; + +@@ -1315,7 +1309,7 @@ static int vc4_hdmi_bind(struct device * + + #ifdef CONFIG_DRM_VC4_HDMI_CEC + vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, +- vc4, "vc4", ++ vc4_hdmi, "vc4", + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); + ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap); +@@ -1339,7 +1333,7 @@ static int vc4_hdmi_bind(struct device * + ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), + vc4_cec_irq_handler, + vc4_cec_irq_handler_thread, 0, +- "vc4 hdmi cec", vc4); ++ "vc4 hdmi cec", vc4_hdmi); + if (ret) + goto err_delete_cec_adap; + ret = cec_register_adapter(vc4_hdmi->cec_adap, dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0580-drm-vc4-hdmi-Remove-vc4_dev-hdmi-pointer.patch b/target/linux/bcm27xx/patches-5.4/950-0580-drm-vc4-hdmi-Remove-vc4_dev-hdmi-pointer.patch new file mode 100644 index 00000000000..ff9fa1a1580 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0580-drm-vc4-hdmi-Remove-vc4_dev-hdmi-pointer.patch @@ -0,0 +1,67 @@ +From 9e56da09cb8d8f65a26cfa0a957e295646ca47f8 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:49:11 +0100 +Subject: [PATCH] drm/vc4: hdmi: Remove vc4_dev hdmi pointer + +Now that we don't have any users anymore, we can kill that pointer. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 - + drivers/gpu/drm/vc4/vc4_hdmi.c | 14 ++++++-------- + 2 files changed, 6 insertions(+), 9 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -76,7 +76,6 @@ struct vc4_dev { + bool firmware_kms; + struct rpi_firmware *firmware; + +- struct vc4_hdmi *hdmi; + struct vc4_hvs *hvs; + struct vc4_v3d *v3d; + struct vc4_dpi *dpi; +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1199,7 +1199,6 @@ static int vc4_hdmi_bind(struct device * + #endif + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); +- struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *vc4_hdmi; + struct drm_encoder *encoder; + struct device_node *ddc_node; +@@ -1287,8 +1286,6 @@ static int vc4_hdmi_bind(struct device * + vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; + } + +- vc4->hdmi = vc4_hdmi; +- + /* HDMI core must be enabled. */ + if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) { + HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST); +@@ -1369,9 +1366,12 @@ err_put_i2c: + static void vc4_hdmi_unbind(struct device *dev, struct device *master, + void *data) + { +- struct drm_device *drm = dev_get_drvdata(master); +- struct vc4_dev *vc4 = drm->dev_private; +- struct vc4_hdmi *vc4_hdmi = vc4->hdmi; ++ /* ++ * snd_soc_register_card will set the device drvdata pointer ++ * to the card being registered. ++ */ ++ struct snd_soc_card *card = dev_get_drvdata(dev); ++ struct vc4_hdmi *vc4_hdmi = snd_soc_card_get_drvdata(card); + + cec_unregister_adapter(vc4_hdmi->cec_adap); + vc4_hdmi_connector_destroy(&vc4_hdmi->connector.base); +@@ -1381,8 +1381,6 @@ static void vc4_hdmi_unbind(struct devic + pm_runtime_disable(dev); + + put_device(&vc4_hdmi->ddc->dev); +- +- vc4->hdmi = NULL; + } + + static const struct component_ops vc4_hdmi_ops = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0581-drm-vc4-hdmi-Remove-vc4_hdmi_connector.patch b/target/linux/bcm27xx/patches-5.4/950-0581-drm-vc4-hdmi-Remove-vc4_hdmi_connector.patch new file mode 100644 index 00000000000..4ef3d69b2cb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0581-drm-vc4-hdmi-Remove-vc4_hdmi_connector.patch @@ -0,0 +1,141 @@ +From 6fdf2c94a028e04e1e20791aae5e0adaf905df77 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 18:57:16 +0100 +Subject: [PATCH] drm/vc4: hdmi: Remove vc4_hdmi_connector + +The vc4_hdmi_connector was only used to switch between drm_connector to +drm_encoder. However, we can now use vc4_hdmi to do the switch, so that +structure is redundant. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 19 ++++++++----------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 23 ++--------------------- + 2 files changed, 10 insertions(+), 32 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -188,13 +188,10 @@ static const struct drm_connector_helper + static int vc4_hdmi_connector_init(struct drm_device *dev, + struct vc4_hdmi *vc4_hdmi) + { +- struct vc4_hdmi_connector *hdmi_connector = &vc4_hdmi->connector; +- struct drm_connector *connector = &hdmi_connector->base; ++ struct drm_connector *connector = &vc4_hdmi->connector; + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + int ret; + +- hdmi_connector->encoder = encoder; +- + drm_connector_init(dev, connector, &vc4_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); +@@ -290,7 +287,7 @@ static void vc4_hdmi_set_avi_infoframe(s + { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); +- struct drm_connector *connector = &vc4_hdmi->connector.base; ++ struct drm_connector *connector = &vc4_hdmi->connector; + struct drm_connector_state *cstate = connector->state; + struct drm_crtc *crtc = encoder->crtc; + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; +@@ -672,7 +669,7 @@ static int vc4_hdmi_audio_startup(struct + { + struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; +- struct drm_connector *connector = &vc4_hdmi->connector.base; ++ struct drm_connector *connector = &vc4_hdmi->connector; + int ret; + + if (vc4_hdmi->audio.substream && vc4_hdmi->audio.substream != substream) +@@ -846,7 +843,7 @@ static int vc4_hdmi_audio_eld_ctl_info(s + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &vc4_hdmi->connector.base; ++ struct drm_connector *connector = &vc4_hdmi->connector; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(connector->eld); +@@ -859,7 +856,7 @@ static int vc4_hdmi_audio_eld_ctl_get(st + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct vc4_hdmi *vc4_hdmi = snd_component_to_hdmi(component); +- struct drm_connector *connector = &vc4_hdmi->connector.base; ++ struct drm_connector *connector = &vc4_hdmi->connector; + + memcpy(ucontrol->value.bytes.data, connector->eld, + sizeof(connector->eld)); +@@ -1313,7 +1310,7 @@ static int vc4_hdmi_bind(struct device * + if (ret < 0) + goto err_destroy_conn; + +- cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector.base); ++ cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); + cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); + + HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff); +@@ -1350,7 +1347,7 @@ static int vc4_hdmi_bind(struct device * + err_delete_cec_adap: + cec_delete_adapter(vc4_hdmi->cec_adap); + err_destroy_conn: +- vc4_hdmi_connector_destroy(&vc4_hdmi->connector.base); ++ vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + #endif + err_destroy_encoder: + vc4_hdmi_encoder_destroy(encoder); +@@ -1374,7 +1371,7 @@ static void vc4_hdmi_unbind(struct devic + struct vc4_hdmi *vc4_hdmi = snd_soc_card_get_drvdata(card); + + cec_unregister_adapter(vc4_hdmi->cec_adap); +- vc4_hdmi_connector_destroy(&vc4_hdmi->connector.base); ++ vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); + + clk_disable_unprepare(vc4_hdmi->hsm_clock); +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -21,23 +21,6 @@ to_vc4_hdmi_encoder(struct drm_encoder * + return container_of(encoder, struct vc4_hdmi_encoder, base.base); + } + +-/* VC4 HDMI connector KMS struct */ +-struct vc4_hdmi_connector { +- struct drm_connector base; +- +- /* Since the connector is attached to just the one encoder, +- * this is the reference to it so we can do the best_encoder() +- * hook. +- */ +- struct drm_encoder *encoder; +-}; +- +-static inline struct vc4_hdmi_connector * +-to_vc4_hdmi_connector(struct drm_connector *connector) +-{ +- return container_of(connector, struct vc4_hdmi_connector, base); +-} +- + /* HDMI audio information */ + struct vc4_hdmi_audio { + struct snd_soc_card card; +@@ -56,7 +39,7 @@ struct vc4_hdmi { + struct platform_device *pdev; + + struct vc4_hdmi_encoder encoder; +- struct vc4_hdmi_connector connector; ++ struct drm_connector connector; + + struct vc4_hdmi_audio audio; + +@@ -81,9 +64,7 @@ struct vc4_hdmi { + static inline struct vc4_hdmi * + connector_to_vc4_hdmi(struct drm_connector *connector) + { +- struct vc4_hdmi_connector *_connector = to_vc4_hdmi_connector(connector); +- +- return container_of(_connector, struct vc4_hdmi, connector); ++ return container_of(connector, struct vc4_hdmi, connector); + } + + static inline struct vc4_hdmi * diff --git a/target/linux/bcm27xx/patches-5.4/950-0582-drm-vc4-hdmi-Introduce-resource-init-and-variant.patch b/target/linux/bcm27xx/patches-5.4/950-0582-drm-vc4-hdmi-Introduce-resource-init-and-variant.patch new file mode 100644 index 00000000000..82fae402465 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0582-drm-vc4-hdmi-Introduce-resource-init-and-variant.patch @@ -0,0 +1,151 @@ +From 9fa3342da883f6e111952768b36ca1df4d529660 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 18 Dec 2019 11:30:54 +0100 +Subject: [PATCH] drm/vc4: hdmi: Introduce resource init and variant + +The HDMI controllers found in the BCM2711 has a pretty different clock and +registers areas than found in the older BCM283x SoCs. + +Let's create a variant structure to store the various adjustments we'll +need later on, and a function to get the resources needed for one +particular version. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 67 ++++++++++++++++++++++------------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 10 +++++ + 2 files changed, 54 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1189,38 +1189,23 @@ static const struct cec_adap_ops vc4_hdm + }; + #endif + +-static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) ++static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) + { +-#ifdef CONFIG_DRM_VC4_HDMI_CEC +- struct cec_connector_info conn_info; +-#endif +- struct platform_device *pdev = to_platform_device(dev); +- struct drm_device *drm = dev_get_drvdata(master); +- struct vc4_hdmi *vc4_hdmi; +- struct drm_encoder *encoder; +- struct device_node *ddc_node; +- u32 value; +- int ret; +- +- vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); +- if (!vc4_hdmi) +- return -ENOMEM; +- +- vc4_hdmi->pdev = pdev; +- encoder = &vc4_hdmi->encoder.base.base; +- encoder->base.type = VC4_ENCODER_TYPE_HDMI0; ++ struct platform_device *pdev = vc4_hdmi->pdev; ++ struct device *dev = &pdev->dev; + + vc4_hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(vc4_hdmi->hdmicore_regs)) + return PTR_ERR(vc4_hdmi->hdmicore_regs); + ++ vc4_hdmi->hdmi_regset.base = vc4_hdmi->hdmicore_regs; ++ vc4_hdmi->hdmi_regset.regs = hdmi_regs; ++ vc4_hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs); ++ + vc4_hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); + if (IS_ERR(vc4_hdmi->hd_regs)) + return PTR_ERR(vc4_hdmi->hd_regs); + +- vc4_hdmi->hdmi_regset.base = vc4_hdmi->hdmicore_regs; +- vc4_hdmi->hdmi_regset.regs = hdmi_regs; +- vc4_hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs); + vc4_hdmi->hd_regset.base = vc4_hdmi->hd_regs; + vc4_hdmi->hd_regset.regs = hd_regs; + vc4_hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs); +@@ -1230,12 +1215,44 @@ static int vc4_hdmi_bind(struct device * + DRM_ERROR("Failed to get pixel clock\n"); + return PTR_ERR(vc4_hdmi->pixel_clock); + } ++ + vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); + if (IS_ERR(vc4_hdmi->hsm_clock)) { + DRM_ERROR("Failed to get HDMI state machine clock\n"); + return PTR_ERR(vc4_hdmi->hsm_clock); + } + ++ return 0; ++} ++ ++static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) ++{ ++#ifdef CONFIG_DRM_VC4_HDMI_CEC ++ struct cec_connector_info conn_info; ++#endif ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ const struct vc4_hdmi_variant *variant; ++ struct vc4_hdmi *vc4_hdmi; ++ struct drm_encoder *encoder; ++ struct device_node *ddc_node; ++ u32 value; ++ int ret; ++ ++ vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); ++ if (!vc4_hdmi) ++ return -ENOMEM; ++ ++ vc4_hdmi->pdev = pdev; ++ variant = of_device_get_match_data(dev); ++ vc4_hdmi->variant = variant; ++ vc4_hdmi->encoder.base.type = VC4_ENCODER_TYPE_HDMI0; ++ encoder = &vc4_hdmi->encoder.base.base; ++ ++ ret = variant->init_resources(vc4_hdmi); ++ if (ret) ++ return ret; ++ + ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); + if (!ddc_node) { + DRM_ERROR("Failed to find ddc node in device tree\n"); +@@ -1396,8 +1413,12 @@ static int vc4_hdmi_dev_remove(struct pl + return 0; + } + ++static const struct vc4_hdmi_variant bcm2835_variant = { ++ .init_resources = vc4_hdmi_init_resources, ++}; ++ + static const struct of_device_id vc4_hdmi_dt_match[] = { +- { .compatible = "brcm,bcm2835-hdmi" }, ++ { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -21,6 +21,15 @@ to_vc4_hdmi_encoder(struct drm_encoder * + return container_of(encoder, struct vc4_hdmi_encoder, base.base); + } + ++struct vc4_hdmi; ++ ++struct vc4_hdmi_variant { ++ /* Callback to get the resources (memory region, interrupts, ++ * clocks, etc) for that variant. ++ */ ++ int (*init_resources)(struct vc4_hdmi *vc4_hdmi); ++}; ++ + /* HDMI audio information */ + struct vc4_hdmi_audio { + struct snd_soc_card card; +@@ -37,6 +46,7 @@ struct vc4_hdmi_audio { + /* General HDMI hardware state. */ + struct vc4_hdmi { + struct platform_device *pdev; ++ const struct vc4_hdmi_variant *variant; + + struct vc4_hdmi_encoder encoder; + struct drm_connector connector; diff --git a/target/linux/bcm27xx/patches-5.4/950-0583-drm-vc4-hdmi-Implement-a-register-layout-abstraction.patch b/target/linux/bcm27xx/patches-5.4/950-0583-drm-vc4-hdmi-Implement-a-register-layout-abstraction.patch new file mode 100644 index 00000000000..eaeca92bfd3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0583-drm-vc4-hdmi-Implement-a-register-layout-abstraction.patch @@ -0,0 +1,1310 @@ +From 261b3072275937fe64af287c1b61cbb63aca830e Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 18 Dec 2019 19:15:08 +0100 +Subject: [PATCH] drm/vc4: hdmi: Implement a register layout + abstraction + +The HDMI controllers found in the BCM2711 have most of the registers +reorganized in multiple registers areas and at different offsets than +previously found. + +The logic however remains pretty much the same, so it doesn't really make +sense to create a whole new driver and we should share the code as much as +possible. + +Let's implement some indirection to wrap around a register and depending on +the variant will lookup the associated register on that particular variant. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 354 ++++++++++++++-------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 12 +- + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 250 ++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_regs.h | 92 -------- + 4 files changed, 437 insertions(+), 271 deletions(-) + create mode 100644 drivers/gpu/drm/vc4/vc4_hdmi_regs.h + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -49,62 +49,13 @@ + #include "media/cec.h" + #include "vc4_drv.h" + #include "vc4_hdmi.h" ++#include "vc4_hdmi_regs.h" + #include "vc4_regs.h" + + #define HSM_CLOCK_FREQ 163682864 + #define CEC_CLOCK_FREQ 40000 + #define CEC_CLOCK_DIV (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ) + +-static const struct debugfs_reg32 hdmi_regs[] = { +- VC4_REG32(VC4_HDMI_CORE_REV), +- VC4_REG32(VC4_HDMI_SW_RESET_CONTROL), +- VC4_REG32(VC4_HDMI_HOTPLUG_INT), +- VC4_REG32(VC4_HDMI_HOTPLUG), +- VC4_REG32(VC4_HDMI_MAI_CHANNEL_MAP), +- VC4_REG32(VC4_HDMI_MAI_CONFIG), +- VC4_REG32(VC4_HDMI_MAI_FORMAT), +- VC4_REG32(VC4_HDMI_AUDIO_PACKET_CONFIG), +- VC4_REG32(VC4_HDMI_RAM_PACKET_CONFIG), +- VC4_REG32(VC4_HDMI_HORZA), +- VC4_REG32(VC4_HDMI_HORZB), +- VC4_REG32(VC4_HDMI_FIFO_CTL), +- VC4_REG32(VC4_HDMI_SCHEDULER_CONTROL), +- VC4_REG32(VC4_HDMI_VERTA0), +- VC4_REG32(VC4_HDMI_VERTA1), +- VC4_REG32(VC4_HDMI_VERTB0), +- VC4_REG32(VC4_HDMI_VERTB1), +- VC4_REG32(VC4_HDMI_TX_PHY_RESET_CTL), +- VC4_REG32(VC4_HDMI_TX_PHY_CTL0), +- +- VC4_REG32(VC4_HDMI_CEC_CNTRL_1), +- VC4_REG32(VC4_HDMI_CEC_CNTRL_2), +- VC4_REG32(VC4_HDMI_CEC_CNTRL_3), +- VC4_REG32(VC4_HDMI_CEC_CNTRL_4), +- VC4_REG32(VC4_HDMI_CEC_CNTRL_5), +- VC4_REG32(VC4_HDMI_CPU_STATUS), +- VC4_REG32(VC4_HDMI_CPU_MASK_STATUS), +- +- VC4_REG32(VC4_HDMI_CEC_RX_DATA_1), +- VC4_REG32(VC4_HDMI_CEC_RX_DATA_2), +- VC4_REG32(VC4_HDMI_CEC_RX_DATA_3), +- VC4_REG32(VC4_HDMI_CEC_RX_DATA_4), +- VC4_REG32(VC4_HDMI_CEC_TX_DATA_1), +- VC4_REG32(VC4_HDMI_CEC_TX_DATA_2), +- VC4_REG32(VC4_HDMI_CEC_TX_DATA_3), +- VC4_REG32(VC4_HDMI_CEC_TX_DATA_4), +-}; +- +-static const struct debugfs_reg32 hd_regs[] = { +- VC4_REG32(VC4_HD_M_CTL), +- VC4_REG32(VC4_HD_MAI_CTL), +- VC4_REG32(VC4_HD_MAI_THR), +- VC4_REG32(VC4_HD_MAI_FMT), +- VC4_REG32(VC4_HD_MAI_SMP), +- VC4_REG32(VC4_HD_VID_CTL), +- VC4_REG32(VC4_HD_CSC_CTL), +- VC4_REG32(VC4_HD_FRAME_COUNT), +-}; +- + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + { + struct drm_info_node *node = (struct drm_info_node *)m->private; +@@ -133,7 +84,7 @@ vc4_hdmi_connector_detect(struct drm_con + if (drm_probe_ddc(vc4_hdmi->ddc)) + return connector_status_connected; + +- if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) ++ if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) + return connector_status_connected; + cec_phys_addr_invalidate(vc4_hdmi->cec_adap); + return connector_status_disconnected; +@@ -229,10 +180,10 @@ static int vc4_hdmi_stop_packet(struct d + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + u32 packet_id = type - 0x80; + +- HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, +- HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); ++ HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, ++ HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + +- return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & ++ return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); + } + +@@ -241,12 +192,16 @@ static void vc4_hdmi_write_infoframe(str + { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + u32 packet_id = frame->any.type - 0x80; +- u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); ++ const struct vc4_hdmi_register *ram_packet_start = ++ &vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START]; ++ u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id; ++ void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi, ++ ram_packet_start->reg); + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + ssize_t len, i; + int ret; + +- WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & + VC4_HDMI_RAM_PACKET_ENABLE), + "Packet RAM has to be on to store the packet."); + +@@ -261,23 +216,23 @@ static void vc4_hdmi_write_infoframe(str + } + + for (i = 0; i < len; i += 7) { +- HDMI_WRITE(packet_reg, +- buffer[i + 0] << 0 | +- buffer[i + 1] << 8 | +- buffer[i + 2] << 16); ++ writel(buffer[i + 0] << 0 | ++ buffer[i + 1] << 8 | ++ buffer[i + 2] << 16, ++ base + packet_reg); + packet_reg += 4; + +- HDMI_WRITE(packet_reg, +- buffer[i + 3] << 0 | +- buffer[i + 4] << 8 | +- buffer[i + 5] << 16 | +- buffer[i + 6] << 24); ++ writel(buffer[i + 3] << 0 | ++ buffer[i + 4] << 8 | ++ buffer[i + 5] << 16 | ++ buffer[i + 6] << 24, ++ base + packet_reg); + packet_reg += 4; + } + +- HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, +- HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); +- ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & ++ HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, ++ HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); ++ ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); + if (ret) + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); +@@ -358,11 +313,11 @@ static void vc4_hdmi_encoder_disable(str + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + int ret; + +- HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); ++ HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); + +- HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); +- HD_WRITE(VC4_HD_VID_CTL, +- HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + + clk_disable_unprepare(vc4_hdmi->pixel_clock); + +@@ -417,18 +372,18 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + +- HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, ++ HDMI_WRITE(HDMI_SW_RESET_CONTROL, + VC4_HDMI_SW_RESET_HDMI | + VC4_HDMI_SW_RESET_FORMAT_DETECT); + +- HDMI_WRITE(VC4_HDMI_SW_RESET_CONTROL, 0); ++ HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); + + /* PHY should be in reset, like + * vc4_hdmi_encoder_disable() does. + */ +- HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); + +- HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0); ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); + + if (debug_dump_regs) { + struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev); +@@ -438,20 +393,20 @@ static void vc4_hdmi_encoder_enable(stru + drm_print_regset32(&p, &vc4_hdmi->hd_regset); + } + +- HD_WRITE(VC4_HD_VID_CTL, 0); ++ HDMI_WRITE(HDMI_VID_CTL, 0); + +- HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, +- HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ HDMI_WRITE(HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | + VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); + +- HDMI_WRITE(VC4_HDMI_HORZA, ++ HDMI_WRITE(HDMI_HORZA, + (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | + (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | + VC4_SET_FIELD(mode->hdisplay * pixel_rep, + VC4_HDMI_HORZA_HAP)); + +- HDMI_WRITE(VC4_HDMI_HORZB, ++ HDMI_WRITE(HDMI_HORZB, + VC4_SET_FIELD((mode->htotal - + mode->hsync_end) * pixel_rep, + VC4_HDMI_HORZB_HBP) | +@@ -462,13 +417,13 @@ static void vc4_hdmi_encoder_enable(stru + mode->hdisplay) * pixel_rep, + VC4_HDMI_HORZB_HFP)); + +- HDMI_WRITE(VC4_HDMI_VERTA0, verta); +- HDMI_WRITE(VC4_HDMI_VERTA1, verta); ++ HDMI_WRITE(HDMI_VERTA0, verta); ++ HDMI_WRITE(HDMI_VERTA1, verta); + +- HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even); +- HDMI_WRITE(VC4_HDMI_VERTB1, vertb); ++ HDMI_WRITE(HDMI_VERTB0, vertb_even); ++ HDMI_WRITE(HDMI_VERTB1, vertb); + +- HD_WRITE(VC4_HD_VID_CTL, ++ HDMI_WRITE(HDMI_VID_CTL, + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + +@@ -493,21 +448,21 @@ static void vc4_hdmi_encoder_enable(stru + csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, + VC4_HD_CSC_CTL_MODE); + +- HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000); +- HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0); +- HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000); +- HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000); +- HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0); +- HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000); + vc4_encoder->limited_rgb_range = true; + } else { + vc4_encoder->limited_rgb_range = false; + } + + /* The RGB order applies even when CSC is disabled. */ +- HD_WRITE(VC4_HD_CSC_CTL, csc_ctl); ++ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + +- HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); ++ HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); + + if (debug_dump_regs) { + struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev); +@@ -517,30 +472,30 @@ static void vc4_hdmi_encoder_enable(stru + drm_print_regset32(&p, &vc4_hdmi->hd_regset); + } + +- HD_WRITE(VC4_HD_VID_CTL, +- HD_READ(VC4_HD_VID_CTL) | +- VC4_HD_VID_CTL_ENABLE | +- VC4_HD_VID_CTL_UNDERFLOW_ENABLE | +- VC4_HD_VID_CTL_FRAME_COUNTER_RESET); ++ HDMI_WRITE(HDMI_VID_CTL, ++ HDMI_READ(HDMI_VID_CTL) | ++ VC4_HD_VID_CTL_ENABLE | ++ VC4_HD_VID_CTL_UNDERFLOW_ENABLE | ++ VC4_HD_VID_CTL_FRAME_COUNTER_RESET); + + if (vc4_encoder->hdmi_monitor) { +- HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, +- HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ HDMI_WRITE(HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + +- ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000); + WARN_ONCE(ret, "Timeout waiting for " + "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); + } else { +- HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, +- HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, ++ HDMI_READ(HDMI_RAM_PACKET_CONFIG) & + ~(VC4_HDMI_RAM_PACKET_ENABLE)); +- HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, +- HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ HDMI_WRITE(HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(HDMI_SCHEDULER_CONTROL) & + ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + +- ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000); + WARN_ONCE(ret, "Timeout waiting for " + "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); +@@ -549,31 +504,31 @@ static void vc4_hdmi_encoder_enable(stru + if (vc4_encoder->hdmi_monitor) { + u32 drift; + +- WARN_ON(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & ++ WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); +- HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, +- HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | ++ HDMI_WRITE(HDMI_SCHEDULER_CONTROL, ++ HDMI_READ(HDMI_SCHEDULER_CONTROL) | + VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); + +- HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, ++ HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, + VC4_HDMI_RAM_PACKET_ENABLE); + + vc4_hdmi_set_infoframes(encoder); + +- drift = HDMI_READ(VC4_HDMI_FIFO_CTL); ++ drift = HDMI_READ(HDMI_FIFO_CTL); + drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; + +- HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ HDMI_WRITE(HDMI_FIFO_CTL, + drift & ~VC4_HDMI_FIFO_CTL_RECENTER); +- HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ HDMI_WRITE(HDMI_FIFO_CTL, + drift | VC4_HDMI_FIFO_CTL_RECENTER); + usleep_range(1000, 1100); +- HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ HDMI_WRITE(HDMI_FIFO_CTL, + drift & ~VC4_HDMI_FIFO_CTL_RECENTER); +- HDMI_WRITE(VC4_HDMI_FIFO_CTL, ++ HDMI_WRITE(HDMI_FIFO_CTL, + drift | VC4_HDMI_FIFO_CTL_RECENTER); + +- ret = wait_for(HDMI_READ(VC4_HDMI_FIFO_CTL) & ++ ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) & + VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); + WARN_ONCE(ret, "Timeout waiting for " + "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); +@@ -625,7 +580,7 @@ static void vc4_hdmi_audio_set_mai_clock + VC4_HD_MAI_SMP_M_SHIFT) + 1, + &n, &m); + +- HD_WRITE(VC4_HD_MAI_SMP, ++ HDMI_WRITE(HDMI_MAI_SMP, + VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | + VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); + } +@@ -644,7 +599,7 @@ static void vc4_hdmi_set_n_cts(struct vc + do_div(tmp, 128 * samplerate); + cts = tmp; + +- HDMI_WRITE(VC4_HDMI_CRP_CFG, ++ HDMI_WRITE(HDMI_CRP_CFG, + VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN | + VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N)); + +@@ -653,8 +608,8 @@ static void vc4_hdmi_set_n_cts(struct vc + * providing a CTS_1 value. The two CTS values are alternated + * between based on the period fields + */ +- HDMI_WRITE(VC4_HDMI_CTS_0, cts); +- HDMI_WRITE(VC4_HDMI_CTS_1, cts); ++ HDMI_WRITE(HDMI_CTS_0, cts); ++ HDMI_WRITE(HDMI_CTS_1, cts); + } + + static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) +@@ -681,7 +636,7 @@ static int vc4_hdmi_audio_startup(struct + * If the HDMI encoder hasn't probed, or the encoder is + * currently in DVI mode, treat the codec dai as missing. + */ +- if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & + VC4_HDMI_RAM_PACKET_ENABLE)) + return -ENODEV; + +@@ -707,9 +662,9 @@ static void vc4_hdmi_audio_reset(struct + if (ret) + dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); + +- HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET); +- HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); +- HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); ++ HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET); ++ HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); ++ HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); + } + + static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, +@@ -745,7 +700,7 @@ static int vc4_hdmi_audio_hw_params(stru + vc4_hdmi->audio.channels = params_channels(params); + vc4_hdmi->audio.samplerate = params_rate(params); + +- HD_WRITE(VC4_HD_MAI_CTL, ++ HDMI_WRITE(HDMI_MAI_CTL, + VC4_HD_MAI_CTL_RESET | + VC4_HD_MAI_CTL_FLUSH | + VC4_HD_MAI_CTL_DLATE | +@@ -765,22 +720,22 @@ static int vc4_hdmi_audio_hw_params(stru + + /* Set the MAI threshold. This logic mimics the firmware's. */ + if (vc4_hdmi->audio.samplerate > 96000) { +- HD_WRITE(VC4_HD_MAI_THR, ++ HDMI_WRITE(HDMI_MAI_THR, + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) | + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); + } else if (vc4_hdmi->audio.samplerate > 48000) { +- HD_WRITE(VC4_HD_MAI_THR, ++ HDMI_WRITE(HDMI_MAI_THR, + VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) | + VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); + } else { +- HD_WRITE(VC4_HD_MAI_THR, ++ HDMI_WRITE(HDMI_MAI_THR, + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) | + VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW)); + } + +- HDMI_WRITE(VC4_HDMI_MAI_CONFIG, ++ HDMI_WRITE(HDMI_MAI_CONFIG, + VC4_HDMI_MAI_CONFIG_BIT_REVERSE | + VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK)); + +@@ -790,8 +745,8 @@ static int vc4_hdmi_audio_hw_params(stru + channel_map |= i << (3 * i); + } + +- HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map); +- HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); ++ HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map); ++ HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); + vc4_hdmi_set_n_cts(vc4_hdmi); + + return 0; +@@ -806,21 +761,22 @@ static int vc4_hdmi_audio_trigger(struct + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + vc4_hdmi_set_audio_infoframe(encoder); +- HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, +- HDMI_READ(VC4_HDMI_TX_PHY_CTL0) & ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ HDMI_READ(HDMI_TX_PHY_CTL_0) & + ~VC4_HDMI_TX_PHY_RNG_PWRDN); +- HD_WRITE(VC4_HD_MAI_CTL, ++ ++ HDMI_WRITE(HDMI_MAI_CTL, + VC4_SET_FIELD(vc4_hdmi->audio.channels, + VC4_HD_MAI_CTL_CHNUM) | + VC4_HD_MAI_CTL_ENABLE); + break; + case SNDRV_PCM_TRIGGER_STOP: +- HD_WRITE(VC4_HD_MAI_CTL, ++ HDMI_WRITE(HDMI_MAI_CTL, + VC4_HD_MAI_CTL_DLATE | + VC4_HD_MAI_CTL_ERRORE | + VC4_HD_MAI_CTL_ERRORF); +- HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, +- HDMI_READ(VC4_HDMI_TX_PHY_CTL0) | ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ HDMI_READ(HDMI_TX_PHY_CTL_0) | + VC4_HDMI_TX_PHY_RNG_PWRDN); + break; + default: +@@ -954,6 +910,8 @@ static const struct snd_dmaengine_pcm_co + + static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) + { ++ const struct vc4_hdmi_register *mai_data = ++ &vc4_hdmi->variant->registers[HDMI_MAI_DATA]; + struct snd_soc_dai_link *dai_link = &vc4_hdmi->audio.link; + struct snd_soc_card *card = &vc4_hdmi->audio.card; + struct device *dev = &vc4_hdmi->pdev->dev; +@@ -968,6 +926,11 @@ static int vc4_hdmi_audio_init(struct vc + return 0; + } + ++ if (mai_data->reg != VC4_HD) { ++ WARN_ONCE(true, "MAI isn't in the HD block\n"); ++ return -EINVAL; ++ } ++ + /* + * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve + * the bus address specified in the DT, because the physical address +@@ -976,7 +939,7 @@ static int vc4_hdmi_audio_init(struct vc + * This VC/MMU should probably be exposed to avoid this kind of hacks. + */ + addr = of_get_address(dev->of_node, 1, NULL, NULL); +- vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; ++ vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset; + vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + vc4_hdmi->audio.dma_data.maxburst = 2; + +@@ -1068,7 +1031,7 @@ static void vc4_cec_read_msg(struct vc4_ + msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >> + VC4_HDMI_CEC_REC_WRD_CNT_SHIFT); + for (i = 0; i < msg->len; i += 4) { +- u32 val = HDMI_READ(VC4_HDMI_CEC_RX_DATA_1 + i); ++ u32 val = HDMI_READ(HDMI_CEC_RX_DATA_1 + i); + + msg->msg[i] = val & 0xff; + msg->msg[i + 1] = (val >> 8) & 0xff; +@@ -1080,26 +1043,26 @@ static void vc4_cec_read_msg(struct vc4_ + static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) + { + struct vc4_hdmi *vc4_hdmi = priv; +- u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS); ++ u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS); + u32 cntrl1, cntrl5; + + if (!(stat & VC4_HDMI_CPU_CEC)) + return IRQ_NONE; + vc4_hdmi->cec_rx_msg.len = 0; +- cntrl1 = HDMI_READ(VC4_HDMI_CEC_CNTRL_1); +- cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); ++ cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); ++ cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5); + vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; + if (vc4_hdmi->cec_irq_was_rx) { + vc4_cec_read_msg(vc4_hdmi, cntrl1); + cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); + cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF; + } else { + vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; + cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; + } +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1); +- HDMI_WRITE(VC4_HDMI_CPU_CLEAR, VC4_HDMI_CPU_CEC); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1); ++ HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC); + + return IRQ_WAKE_THREAD; + } +@@ -1109,7 +1072,7 @@ static int vc4_hdmi_cec_adap_enable(stru + struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + /* clock period in microseconds */ + const u32 usecs = 1000000 / CEC_CLOCK_FREQ; +- u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5); ++ u32 val = HDMI_READ(HDMI_CEC_CNTRL_5); + + val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET | + VC4_HDMI_CEC_CNT_TO_4700_US_MASK | +@@ -1118,30 +1081,30 @@ static int vc4_hdmi_cec_adap_enable(stru + ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT); + + if (enable) { +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val | ++ HDMI_WRITE(HDMI_CEC_CNTRL_5, val | + VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_2, ++ HDMI_WRITE(HDMI_CEC_CNTRL_5, val); ++ HDMI_WRITE(HDMI_CEC_CNTRL_2, + ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) | + ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) | + ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) | + ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) | + ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT)); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_3, ++ HDMI_WRITE(HDMI_CEC_CNTRL_3, + ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) | + ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) | + ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) | + ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT)); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_4, ++ HDMI_WRITE(HDMI_CEC_CNTRL_4, + ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) | + ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) | + ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) | + ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT)); + +- HDMI_WRITE(VC4_HDMI_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); ++ HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); + } else { +- HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, VC4_HDMI_CPU_CEC); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val | ++ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC); ++ HDMI_WRITE(HDMI_CEC_CNTRL_5, val | + VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET); + } + return 0; +@@ -1151,8 +1114,8 @@ static int vc4_hdmi_cec_adap_log_addr(st + { + struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, +- (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, ++ (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | + (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT); + return 0; + } +@@ -1165,20 +1128,20 @@ static int vc4_hdmi_cec_adap_transmit(st + unsigned int i; + + for (i = 0; i < msg->len; i += 4) +- HDMI_WRITE(VC4_HDMI_CEC_TX_DATA_1 + i, ++ HDMI_WRITE(HDMI_CEC_TX_DATA_1 + i, + (msg->msg[i]) | + (msg->msg[i + 1] << 8) | + (msg->msg[i + 2] << 16) | + (msg->msg[i + 3] << 24)); + +- val = HDMI_READ(VC4_HDMI_CEC_CNTRL_1); ++ val = HDMI_READ(HDMI_CEC_CNTRL_1); + val &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, val); + val &= ~VC4_HDMI_CEC_MESSAGE_LENGTH_MASK; + val |= (msg->len - 1) << VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT; + val |= VC4_HDMI_CEC_START_XMIT_BEGIN; + +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, val); + return 0; + } + +@@ -1189,26 +1152,63 @@ static const struct cec_adap_ops vc4_hdm + }; + #endif + ++static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, ++ struct debugfs_regset32 *regset, ++ enum vc4_hdmi_regs reg) ++{ ++ const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; ++ struct debugfs_reg32 *regs; ++ unsigned int count = 0; ++ unsigned int i; ++ ++ regs = kzalloc(variant->num_registers * sizeof(*regs), ++ GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; ++ ++ for (i = 0; i < variant->num_registers; i++) { ++ const struct vc4_hdmi_register *field = &variant->registers[i]; ++ ++ if (field->reg != reg) ++ continue; ++ ++ regs[count].name = field->name; ++ regs[count].offset = field->offset; ++ count++; ++ } ++ ++ regs = krealloc(regs, count * sizeof(*regs), GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; ++ ++ regset->base = __vc4_hdmi_get_field_base(vc4_hdmi, reg); ++ regset->regs = regs; ++ regset->nregs = count; ++ ++ return 0; ++} ++ + static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) + { + struct platform_device *pdev = vc4_hdmi->pdev; + struct device *dev = &pdev->dev; ++ int ret; + + vc4_hdmi->hdmicore_regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(vc4_hdmi->hdmicore_regs)) + return PTR_ERR(vc4_hdmi->hdmicore_regs); + +- vc4_hdmi->hdmi_regset.base = vc4_hdmi->hdmicore_regs; +- vc4_hdmi->hdmi_regset.regs = hdmi_regs; +- vc4_hdmi->hdmi_regset.nregs = ARRAY_SIZE(hdmi_regs); ++ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD); ++ if (ret) ++ return ret; + + vc4_hdmi->hd_regs = vc4_ioremap_regs(pdev, 1); + if (IS_ERR(vc4_hdmi->hd_regs)) + return PTR_ERR(vc4_hdmi->hd_regs); + +- vc4_hdmi->hd_regset.base = vc4_hdmi->hd_regs; +- vc4_hdmi->hd_regset.regs = hd_regs; +- vc4_hdmi->hd_regset.nregs = ARRAY_SIZE(hd_regs); ++ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI); ++ if (ret) ++ return ret; + + vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel"); + if (IS_ERR(vc4_hdmi->pixel_clock)) { +@@ -1301,12 +1301,12 @@ static int vc4_hdmi_bind(struct device * + } + + /* HDMI core must be enabled. */ +- if (!(HD_READ(VC4_HD_M_CTL) & VC4_HD_M_ENABLE)) { +- HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_SW_RST); ++ if (!(HDMI_READ(HDMI_M_CTL) & VC4_HD_M_ENABLE)) { ++ HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST); + udelay(1); +- HD_WRITE(VC4_HD_M_CTL, 0); ++ HDMI_WRITE(HDMI_M_CTL, 0); + +- HD_WRITE(VC4_HD_M_CTL, VC4_HD_M_ENABLE); ++ HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_ENABLE); + } + pm_runtime_enable(dev); + +@@ -1330,8 +1330,8 @@ static int vc4_hdmi_bind(struct device * + cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); + cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); + +- HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff); +- value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1); ++ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); ++ value = HDMI_READ(HDMI_CEC_CNTRL_1); + value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; + /* + * Set the logical address to Unregistered and set the clock +@@ -1340,7 +1340,7 @@ static int vc4_hdmi_bind(struct device * + */ + value |= VC4_HDMI_CEC_ADDR_MASK | + (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); +- HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, value); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), + vc4_cec_irq_handler, + vc4_cec_irq_handler_thread, 0, +@@ -1387,6 +1387,9 @@ static void vc4_hdmi_unbind(struct devic + struct snd_soc_card *card = dev_get_drvdata(dev); + struct vc4_hdmi *vc4_hdmi = snd_soc_card_get_drvdata(card); + ++ kfree(vc4_hdmi->hdmi_regset.regs); ++ kfree(vc4_hdmi->hd_regset.regs); ++ + cec_unregister_adapter(vc4_hdmi->cec_adap); + vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); +@@ -1414,6 +1417,9 @@ static int vc4_hdmi_dev_remove(struct pl + } + + static const struct vc4_hdmi_variant bcm2835_variant = { ++ .registers = vc4_hdmi_fields, ++ .num_registers = ARRAY_SIZE(vc4_hdmi_fields), ++ + .init_resources = vc4_hdmi_init_resources, + }; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -22,8 +22,15 @@ to_vc4_hdmi_encoder(struct drm_encoder * + } + + struct vc4_hdmi; ++struct vc4_hdmi_register; + + struct vc4_hdmi_variant { ++ /* List of the registers available on that variant */ ++ const struct vc4_hdmi_register *registers; ++ ++ /* Number of registers on that variant */ ++ unsigned int num_registers; ++ + /* Callback to get the resources (memory region, interrupts, + * clocks, etc) for that variant. + */ +@@ -85,9 +92,4 @@ encoder_to_vc4_hdmi(struct drm_encoder * + return container_of(_encoder, struct vc4_hdmi, encoder); + } + +-#define HDMI_READ(offset) readl(vc4_hdmi->hdmicore_regs + offset) +-#define HDMI_WRITE(offset, val) writel(val, vc4_hdmi->hdmicore_regs + offset) +-#define HD_READ(offset) readl(vc4_hdmi->hd_regs + offset) +-#define HD_WRITE(offset, val) writel(val, vc4_hdmi->hd_regs + offset) +- + #endif /* _VC4_HDMI_H_ */ +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -0,0 +1,250 @@ ++#ifndef _VC4_HDMI_REGS_H_ ++#define _VC4_HDMI_REGS_H_ ++ ++#include "vc4_hdmi.h" ++ ++#define VC4_MASK(high, low) ((u32)GENMASK(high, low)) ++/* Using the GNU statement expression extension */ ++#define VC4_SET_FIELD(value, field) \ ++ ({ \ ++ uint32_t fieldval = (value) << field##_SHIFT; \ ++ WARN_ON((fieldval & ~field##_MASK) != 0); \ ++ fieldval & field##_MASK; \ ++ }) ++ ++#define VC4_HDMI_PACKET_STRIDE 0x24 ++ ++enum vc4_hdmi_regs { ++ VC4_INVALID = 0, ++ VC4_HDMI, ++ VC4_HD, ++}; ++ ++enum vc4_hdmi_field { ++ HDMI_AUDIO_PACKET_CONFIG, ++ HDMI_CEC_CNTRL_1, ++ HDMI_CEC_CNTRL_2, ++ HDMI_CEC_CNTRL_3, ++ HDMI_CEC_CNTRL_4, ++ HDMI_CEC_CNTRL_5, ++ HDMI_CEC_CPU_CLEAR, ++ HDMI_CEC_CPU_MASK_CLEAR, ++ HDMI_CEC_CPU_MASK_SET, ++ HDMI_CEC_CPU_MASK_STATUS, ++ HDMI_CEC_CPU_STATUS, ++ ++ /* ++ * Transmit data, first byte is low byte of the 32-bit reg. ++ * MSB of each byte transmitted first. ++ */ ++ HDMI_CEC_RX_DATA_1, ++ HDMI_CEC_RX_DATA_2, ++ HDMI_CEC_RX_DATA_3, ++ HDMI_CEC_RX_DATA_4, ++ HDMI_CEC_TX_DATA_1, ++ HDMI_CEC_TX_DATA_2, ++ HDMI_CEC_TX_DATA_3, ++ HDMI_CEC_TX_DATA_4, ++ HDMI_CORE_REV, ++ HDMI_CRP_CFG, ++ HDMI_CSC_12_11, ++ HDMI_CSC_14_13, ++ HDMI_CSC_22_21, ++ HDMI_CSC_24_23, ++ HDMI_CSC_32_31, ++ HDMI_CSC_34_33, ++ HDMI_CSC_CTL, ++ ++ /* ++ * 20-bit fields containing CTS values to be transmitted if ++ * !EXTERNAL_CTS_EN ++ */ ++ HDMI_CTS_0, ++ HDMI_CTS_1, ++ HDMI_FIFO_CTL, ++ HDMI_FRAME_COUNT, ++ HDMI_HORZA, ++ HDMI_HORZB, ++ HDMI_HOTPLUG, ++ HDMI_HOTPLUG_INT, ++ ++ /* ++ * 3 bits per field, where each field maps from that ++ * corresponding MAI bus channel to the given HDMI channel. ++ */ ++ HDMI_MAI_CHANNEL_MAP, ++ HDMI_MAI_CONFIG, ++ HDMI_MAI_CTL, ++ ++ /* ++ * Register for DMAing in audio data to be transported over ++ * the MAI bus to the Falcon core. ++ */ ++ HDMI_MAI_DATA, ++ ++ /* Format header to be placed on the MAI data. Unused. */ ++ HDMI_MAI_FMT, ++ ++ /* Last received format word on the MAI bus. */ ++ HDMI_MAI_FORMAT, ++ HDMI_MAI_SMP, ++ HDMI_MAI_THR, ++ HDMI_M_CTL, ++ HDMI_RAM_PACKET_CONFIG, ++ HDMI_RAM_PACKET_START, ++ HDMI_RAM_PACKET_STATUS, ++ HDMI_SCHEDULER_CONTROL, ++ HDMI_SW_RESET_CONTROL, ++ HDMI_TX_PHY_CTL_0, ++ HDMI_TX_PHY_RESET_CTL, ++ HDMI_VERTA0, ++ HDMI_VERTA1, ++ HDMI_VERTB0, ++ HDMI_VERTB1, ++ HDMI_VID_CTL, ++}; ++ ++struct vc4_hdmi_register { ++ char *name; ++ enum vc4_hdmi_regs reg; ++ unsigned int offset; ++}; ++ ++#define _VC4_REG(_base, _reg, _offset) \ ++ [_reg] = { \ ++ .name = #_reg, \ ++ .reg = _base, \ ++ .offset = _offset, \ ++ } ++ ++#define VC4_HD_REG(reg, offset) _VC4_REG(VC4_HD, reg, offset) ++#define VC4_HDMI_REG(reg, offset) _VC4_REG(VC4_HDMI, reg, offset) ++ ++static const struct vc4_hdmi_register vc4_hdmi_fields[] = { ++ VC4_HD_REG(HDMI_M_CTL, 0x000c), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0014), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0018), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x001c), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x0020), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x002c), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0038), ++ VC4_HD_REG(HDMI_CSC_CTL, 0x0040), ++ VC4_HD_REG(HDMI_CSC_12_11, 0x0044), ++ VC4_HD_REG(HDMI_CSC_14_13, 0x0048), ++ VC4_HD_REG(HDMI_CSC_22_21, 0x004c), ++ VC4_HD_REG(HDMI_CSC_24_23, 0x0050), ++ VC4_HD_REG(HDMI_CSC_32_31, 0x0054), ++ VC4_HD_REG(HDMI_CSC_34_33, 0x0058), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0068), ++ ++ VC4_HDMI_REG(HDMI_CORE_REV, 0x0000), ++ VC4_HDMI_REG(HDMI_SW_RESET_CONTROL, 0x0004), ++ VC4_HDMI_REG(HDMI_HOTPLUG_INT, 0x0008), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x000c), ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x005c), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x0090), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0094), ++ VC4_HDMI_REG(HDMI_MAI_FORMAT, 0x0098), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x009c), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x00a0), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x00a4), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x00a8), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x00ac), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x00b0), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x00c0), ++ VC4_HDMI_REG(HDMI_HORZA, 0x00c4), ++ VC4_HDMI_REG(HDMI_HORZB, 0x00c8), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x00cc), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x00d0), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x00d4), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x00d8), ++ VC4_HDMI_REG(HDMI_CEC_CNTRL_1, 0x00e8), ++ VC4_HDMI_REG(HDMI_CEC_CNTRL_2, 0x00ec), ++ VC4_HDMI_REG(HDMI_CEC_CNTRL_3, 0x00f0), ++ VC4_HDMI_REG(HDMI_CEC_CNTRL_4, 0x00f4), ++ VC4_HDMI_REG(HDMI_CEC_CNTRL_5, 0x00f8), ++ VC4_HDMI_REG(HDMI_CEC_TX_DATA_1, 0x00fc), ++ VC4_HDMI_REG(HDMI_CEC_TX_DATA_2, 0x0100), ++ VC4_HDMI_REG(HDMI_CEC_TX_DATA_3, 0x0104), ++ VC4_HDMI_REG(HDMI_CEC_TX_DATA_4, 0x0108), ++ VC4_HDMI_REG(HDMI_CEC_RX_DATA_1, 0x010c), ++ VC4_HDMI_REG(HDMI_CEC_RX_DATA_2, 0x0110), ++ VC4_HDMI_REG(HDMI_CEC_RX_DATA_3, 0x0114), ++ VC4_HDMI_REG(HDMI_CEC_RX_DATA_4, 0x0118), ++ VC4_HDMI_REG(HDMI_TX_PHY_RESET_CTL, 0x02c0), ++ VC4_HDMI_REG(HDMI_TX_PHY_CTL_0, 0x02c4), ++ VC4_HDMI_REG(HDMI_CEC_CPU_STATUS, 0x0340), ++ VC4_HDMI_REG(HDMI_CEC_CPU_CLEAR, 0x0348), ++ VC4_HDMI_REG(HDMI_CEC_CPU_MASK_STATUS, 0x034c), ++ VC4_HDMI_REG(HDMI_CEC_CPU_MASK_SET, 0x034c), ++ VC4_HDMI_REG(HDMI_CEC_CPU_MASK_CLEAR, 0x0354), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400), ++}; ++ ++static inline ++void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi, ++ enum vc4_hdmi_regs reg) ++{ ++ switch (reg) { ++ case VC4_HD: ++ return hdmi->hd_regs; ++ ++ case VC4_HDMI: ++ return hdmi->hdmicore_regs; ++ ++ default: ++ return NULL; ++ } ++ ++ return NULL; ++} ++ ++static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi, ++ enum vc4_hdmi_regs reg) ++{ ++ const struct vc4_hdmi_register *field; ++ const struct vc4_hdmi_variant *variant = hdmi->variant; ++ void __iomem *base; ++ ++ if (reg > variant->num_registers) { ++ dev_warn(&hdmi->pdev->dev, ++ "Invalid register ID %u\n", reg); ++ return 0; ++ } ++ ++ field = &variant->registers[reg]; ++ base = __vc4_hdmi_get_field_base(hdmi, field->reg); ++ if (!base) { ++ dev_warn(&hdmi->pdev->dev, ++ "Unknown register ID %u\n", reg); ++ return 0; ++ } ++ ++ return readl(base + field->offset); ++} ++#define HDMI_READ(reg) vc4_hdmi_read(vc4_hdmi, reg) ++ ++static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi, ++ enum vc4_hdmi_regs reg, ++ u32 value) ++{ ++ const struct vc4_hdmi_register *field; ++ const struct vc4_hdmi_variant *variant = hdmi->variant; ++ void __iomem *base; ++ ++ if (reg > variant->num_registers) { ++ dev_warn(&hdmi->pdev->dev, ++ "Invalid register ID %u\n", reg); ++ return; ++ } ++ ++ field = &variant->registers[reg]; ++ base = __vc4_hdmi_get_field_base(hdmi, field->reg); ++ if (!base) ++ return; ++ ++ writel(value, base + field->offset); ++} ++#define HDMI_WRITE(reg, val) vc4_hdmi_write(vc4_hdmi, reg, val) ++ ++#endif /* _VC4_HDMI_REGS_H_ */ +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -493,32 +493,16 @@ + + #define SCALER5_DLIST_START 0x00004000 + +-#define VC4_HDMI_CORE_REV 0x000 +- +-#define VC4_HDMI_SW_RESET_CONTROL 0x004 + # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) + # define VC4_HDMI_SW_RESET_HDMI BIT(0) + +-#define VC4_HDMI_HOTPLUG_INT 0x008 +- +-#define VC4_HDMI_HOTPLUG 0x00c + # define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) + +-/* 3 bits per field, where each field maps from that corresponding MAI +- * bus channel to the given HDMI channel. +- */ +-#define VC4_HDMI_MAI_CHANNEL_MAP 0x090 +- +-#define VC4_HDMI_MAI_CONFIG 0x094 + # define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE BIT(27) + # define VC4_HDMI_MAI_CONFIG_BIT_REVERSE BIT(26) + # define VC4_HDMI_MAI_CHANNEL_MASK_MASK VC4_MASK(15, 0) + # define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT 0 + +-/* Last received format word on the MAI bus. */ +-#define VC4_HDMI_MAI_FORMAT 0x098 +- +-#define VC4_HDMI_AUDIO_PACKET_CONFIG 0x09c + # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT BIT(29) + # define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS BIT(24) + # define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT BIT(19) +@@ -532,12 +516,8 @@ + # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK VC4_MASK(7, 0) + # define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT 0 + +-#define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 + # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) + +-#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 +- +-#define VC4_HDMI_CRP_CFG 0x0a8 + /* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead + * of pixel clock. + */ +@@ -551,23 +531,12 @@ + # define VC4_HDMI_CRP_CFG_N_MASK VC4_MASK(19, 0) + # define VC4_HDMI_CRP_CFG_N_SHIFT 0 + +-/* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */ +-#define VC4_HDMI_CTS_0 0x0ac +-#define VC4_HDMI_CTS_1 0x0b0 +-/* 20-bit fields containing number of clocks to send CTS0/1 before +- * switching to the other one. +- */ +-#define VC4_HDMI_CTS_PERIOD_0 0x0b4 +-#define VC4_HDMI_CTS_PERIOD_1 0x0b8 +- +-#define VC4_HDMI_HORZA 0x0c4 + # define VC4_HDMI_HORZA_VPOS BIT(14) + # define VC4_HDMI_HORZA_HPOS BIT(13) + /* Horizontal active pixels (hdisplay). */ + # define VC4_HDMI_HORZA_HAP_MASK VC4_MASK(12, 0) + # define VC4_HDMI_HORZA_HAP_SHIFT 0 + +-#define VC4_HDMI_HORZB 0x0c8 + /* Horizontal pack porch (htotal - hsync_end). */ + # define VC4_HDMI_HORZB_HBP_MASK VC4_MASK(29, 20) + # define VC4_HDMI_HORZB_HBP_SHIFT 20 +@@ -578,7 +547,6 @@ + # define VC4_HDMI_HORZB_HFP_MASK VC4_MASK(9, 0) + # define VC4_HDMI_HORZB_HFP_SHIFT 0 + +-#define VC4_HDMI_FIFO_CTL 0x05c + # define VC4_HDMI_FIFO_CTL_RECENTER_DONE BIT(14) + # define VC4_HDMI_FIFO_CTL_USE_EMPTY BIT(13) + # define VC4_HDMI_FIFO_CTL_ON_VB BIT(7) +@@ -591,15 +559,12 @@ + # define VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N BIT(0) + # define VC4_HDMI_FIFO_VALID_WRITE_MASK 0xefff + +-#define VC4_HDMI_SCHEDULER_CONTROL 0x0c0 + # define VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT BIT(15) + # define VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS BIT(5) + # define VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT BIT(3) + # define VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE BIT(1) + # define VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI BIT(0) + +-#define VC4_HDMI_VERTA0 0x0cc +-#define VC4_HDMI_VERTA1 0x0d4 + /* Vertical sync pulse (vsync_end - vsync_start). */ + # define VC4_HDMI_VERTA_VSP_MASK VC4_MASK(24, 20) + # define VC4_HDMI_VERTA_VSP_SHIFT 20 +@@ -610,8 +575,6 @@ + # define VC4_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) + # define VC4_HDMI_VERTA_VAL_SHIFT 0 + +-#define VC4_HDMI_VERTB0 0x0d0 +-#define VC4_HDMI_VERTB1 0x0d8 + /* Vertical sync pulse offset (for interlaced) */ + # define VC4_HDMI_VERTB_VSPO_MASK VC4_MASK(21, 9) + # define VC4_HDMI_VERTB_VSPO_SHIFT 9 +@@ -619,7 +582,6 @@ + # define VC4_HDMI_VERTB_VBP_MASK VC4_MASK(8, 0) + # define VC4_HDMI_VERTB_VBP_SHIFT 0 + +-#define VC4_HDMI_CEC_CNTRL_1 0x0e8 + /* Set when the transmission has ended. */ + # define VC4_HDMI_CEC_TX_EOM BIT(31) + /* If set, transmission was acked on the 1st or 2nd attempt (only one +@@ -660,7 +622,6 @@ + /* Set these fields to how many bit clock cycles get to that many + * microseconds. + */ +-#define VC4_HDMI_CEC_CNTRL_2 0x0ec + # define VC4_HDMI_CEC_CNT_TO_1500_US_MASK VC4_MASK(30, 24) + # define VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT 24 + # define VC4_HDMI_CEC_CNT_TO_1300_US_MASK VC4_MASK(23, 17) +@@ -672,7 +633,6 @@ + # define VC4_HDMI_CEC_CNT_TO_400_US_MASK VC4_MASK(4, 0) + # define VC4_HDMI_CEC_CNT_TO_400_US_SHIFT 0 + +-#define VC4_HDMI_CEC_CNTRL_3 0x0f0 + # define VC4_HDMI_CEC_CNT_TO_2750_US_MASK VC4_MASK(31, 24) + # define VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT 24 + # define VC4_HDMI_CEC_CNT_TO_2400_US_MASK VC4_MASK(23, 16) +@@ -682,7 +642,6 @@ + # define VC4_HDMI_CEC_CNT_TO_1700_US_MASK VC4_MASK(7, 0) + # define VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT 0 + +-#define VC4_HDMI_CEC_CNTRL_4 0x0f4 + # define VC4_HDMI_CEC_CNT_TO_4300_US_MASK VC4_MASK(31, 24) + # define VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT 24 + # define VC4_HDMI_CEC_CNT_TO_3900_US_MASK VC4_MASK(23, 16) +@@ -692,7 +651,6 @@ + # define VC4_HDMI_CEC_CNT_TO_3500_US_MASK VC4_MASK(7, 0) + # define VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT 0 + +-#define VC4_HDMI_CEC_CNTRL_5 0x0f8 + # define VC4_HDMI_CEC_TX_SW_RESET BIT(27) + # define VC4_HDMI_CEC_RX_SW_RESET BIT(26) + # define VC4_HDMI_CEC_PAD_SW_RESET BIT(25) +@@ -705,39 +663,11 @@ + # define VC4_HDMI_CEC_CNT_TO_4500_US_MASK VC4_MASK(7, 0) + # define VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT 0 + +-/* Transmit data, first byte is low byte of the 32-bit reg. MSB of +- * each byte transmitted first. +- */ +-#define VC4_HDMI_CEC_TX_DATA_1 0x0fc +-#define VC4_HDMI_CEC_TX_DATA_2 0x100 +-#define VC4_HDMI_CEC_TX_DATA_3 0x104 +-#define VC4_HDMI_CEC_TX_DATA_4 0x108 +-#define VC4_HDMI_CEC_RX_DATA_1 0x10c +-#define VC4_HDMI_CEC_RX_DATA_2 0x110 +-#define VC4_HDMI_CEC_RX_DATA_3 0x114 +-#define VC4_HDMI_CEC_RX_DATA_4 0x118 +- +-#define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 +- +-#define VC4_HDMI_TX_PHY_CTL0 0x2c4 + # define VC4_HDMI_TX_PHY_RNG_PWRDN BIT(25) + +-/* Interrupt status bits */ +-#define VC4_HDMI_CPU_STATUS 0x340 +-#define VC4_HDMI_CPU_SET 0x344 +-#define VC4_HDMI_CPU_CLEAR 0x348 + # define VC4_HDMI_CPU_CEC BIT(6) + # define VC4_HDMI_CPU_HOTPLUG BIT(0) + +-#define VC4_HDMI_CPU_MASK_STATUS 0x34c +-#define VC4_HDMI_CPU_MASK_SET 0x350 +-#define VC4_HDMI_CPU_MASK_CLEAR 0x354 +- +-#define VC4_HDMI_GCP(x) (0x400 + ((x) * 0x4)) +-#define VC4_HDMI_RAM_PACKET(x) (0x400 + ((x) * 0x24)) +-#define VC4_HDMI_PACKET_STRIDE 0x24 +- +-#define VC4_HD_M_CTL 0x00c + /* Debug: Current receive value on the CEC pad. */ + # define VC4_HD_CECRXD BIT(9) + /* Debug: Override CEC output to 0. */ +@@ -747,7 +677,6 @@ + # define VC4_HD_M_SW_RST BIT(2) + # define VC4_HD_M_ENABLE BIT(0) + +-#define VC4_HD_MAI_CTL 0x014 + /* Set when audio stream is received at a slower rate than the + * sampling period, so MAI fifo goes empty. Write 1 to clear. + */ +@@ -772,7 +701,6 @@ + /* Single-shot reset bit. Read value is undefined. */ + # define VC4_HD_MAI_CTL_RESET BIT(0) + +-#define VC4_HD_MAI_THR 0x018 + # define VC4_HD_MAI_THR_PANICHIGH_MASK VC4_MASK(29, 24) + # define VC4_HD_MAI_THR_PANICHIGH_SHIFT 24 + # define VC4_HD_MAI_THR_PANICLOW_MASK VC4_MASK(21, 16) +@@ -782,31 +710,20 @@ + # define VC4_HD_MAI_THR_DREQLOW_MASK VC4_MASK(5, 0) + # define VC4_HD_MAI_THR_DREQLOW_SHIFT 0 + +-/* Format header to be placed on the MAI data. Unused. */ +-#define VC4_HD_MAI_FMT 0x01c +- +-/* Register for DMAing in audio data to be transported over the MAI +- * bus to the Falcon core. +- */ +-#define VC4_HD_MAI_DATA 0x020 +- + /* Divider from HDMI HSM clock to MAI serial clock. Sampling period + * converges to N / (M + 1) cycles. + */ +-#define VC4_HD_MAI_SMP 0x02c + # define VC4_HD_MAI_SMP_N_MASK VC4_MASK(31, 8) + # define VC4_HD_MAI_SMP_N_SHIFT 8 + # define VC4_HD_MAI_SMP_M_MASK VC4_MASK(7, 0) + # define VC4_HD_MAI_SMP_M_SHIFT 0 + +-#define VC4_HD_VID_CTL 0x038 + # define VC4_HD_VID_CTL_ENABLE BIT(31) + # define VC4_HD_VID_CTL_UNDERFLOW_ENABLE BIT(30) + # define VC4_HD_VID_CTL_FRAME_COUNTER_RESET BIT(29) + # define VC4_HD_VID_CTL_VSYNC_LOW BIT(28) + # define VC4_HD_VID_CTL_HSYNC_LOW BIT(27) + +-#define VC4_HD_CSC_CTL 0x040 + # define VC4_HD_CSC_CTL_ORDER_MASK VC4_MASK(7, 5) + # define VC4_HD_CSC_CTL_ORDER_SHIFT 5 + # define VC4_HD_CSC_CTL_ORDER_RGB 0 +@@ -824,15 +741,6 @@ + # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) + # define VC4_HD_CSC_CTL_ENABLE BIT(0) + +-#define VC4_HD_CSC_12_11 0x044 +-#define VC4_HD_CSC_14_13 0x048 +-#define VC4_HD_CSC_22_21 0x04c +-#define VC4_HD_CSC_24_23 0x050 +-#define VC4_HD_CSC_32_31 0x054 +-#define VC4_HD_CSC_34_33 0x058 +- +-#define VC4_HD_FRAME_COUNT 0x068 +- + /* HVS display list information. */ + #define HVS_BOOTLOADER_DLIST_END 32 + diff --git a/target/linux/bcm27xx/patches-5.4/950-0584-drm-vc4-hdmi-Add-reset-callback.patch b/target/linux/bcm27xx/patches-5.4/950-0584-drm-vc4-hdmi-Add-reset-callback.patch new file mode 100644 index 00000000000..53dd3e44053 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0584-drm-vc4-hdmi-Add-reset-callback.patch @@ -0,0 +1,66 @@ +From 3cf4a365b833d7a2e7622ad5569b9d54aebbe593 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 19 Dec 2019 16:25:26 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add reset callback + +The BCM2711 and BCM283x HDMI controllers use a slightly different reset +sequence, so let's add a callback to reset the controller. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++++++----- + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +++ + 2 files changed, 15 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -68,6 +68,15 @@ static int vc4_hdmi_debugfs_regs(struct + return 0; + } + ++static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_SW_RESET_CONTROL, ++ VC4_HDMI_SW_RESET_HDMI | ++ VC4_HDMI_SW_RESET_FORMAT_DETECT); ++ ++ HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); ++} ++ + static enum drm_connector_status + vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +@@ -372,11 +381,8 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + +- HDMI_WRITE(HDMI_SW_RESET_CONTROL, +- VC4_HDMI_SW_RESET_HDMI | +- VC4_HDMI_SW_RESET_FORMAT_DETECT); +- +- HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); ++ if (vc4_hdmi->variant->reset) ++ vc4_hdmi->variant->reset(vc4_hdmi); + + /* PHY should be in reset, like + * vc4_hdmi_encoder_disable() does. +@@ -1421,6 +1427,7 @@ static const struct vc4_hdmi_variant bcm + .num_registers = ARRAY_SIZE(vc4_hdmi_fields), + + .init_resources = vc4_hdmi_init_resources, ++ .reset = vc4_hdmi_reset, + }; + + static const struct of_device_id vc4_hdmi_dt_match[] = { +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -35,6 +35,9 @@ struct vc4_hdmi_variant { + * clocks, etc) for that variant. + */ + int (*init_resources)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to reset the HDMI block */ ++ void (*reset)(struct vc4_hdmi *vc4_hdmi); + }; + + /* HDMI audio information */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0585-drm-vc4-hdmi-Add-PHY-init-and-disable-function.patch b/target/linux/bcm27xx/patches-5.4/950-0585-drm-vc4-hdmi-Add-PHY-init-and-disable-function.patch new file mode 100644 index 00000000000..6db26d40aad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0585-drm-vc4-hdmi-Add-PHY-init-and-disable-function.patch @@ -0,0 +1,128 @@ +From 9fe77147d40e0dc58e7297e79ba8b50e13b8269d Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 19 Dec 2019 16:53:33 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add PHY init and disable function + +The HDMI PHY in the BCM2711 HDMI controller is significantly more +complicated to setup than in the older BCM283x SoCs. + +Let's add hooks to enable and disable the PHY. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/Makefile | 1 + + drivers/gpu/drm/vc4/vc4_hdmi.c | 14 +++++++------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 13 +++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 25 +++++++++++++++++++++++++ + 4 files changed, 46 insertions(+), 7 deletions(-) + create mode 100644 drivers/gpu/drm/vc4/vc4_hdmi_phy.c + +--- a/drivers/gpu/drm/vc4/Makefile ++++ b/drivers/gpu/drm/vc4/Makefile +@@ -13,6 +13,7 @@ vc4-y := \ + vc4_kms.o \ + vc4_gem.o \ + vc4_hdmi.o \ ++ vc4_hdmi_phy.o \ + vc4_vec.o \ + vc4_hvs.o \ + vc4_irq.o \ +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -324,7 +324,9 @@ static void vc4_hdmi_encoder_disable(str + + HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); + +- HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ if (vc4_hdmi->variant->phy_disable) ++ vc4_hdmi->variant->phy_disable(vc4_hdmi); ++ + HDMI_WRITE(HDMI_VID_CTL, + HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + +@@ -384,12 +386,8 @@ static void vc4_hdmi_encoder_enable(stru + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + +- /* PHY should be in reset, like +- * vc4_hdmi_encoder_disable() does. +- */ +- HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); +- +- HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); ++ if (vc4_hdmi->variant->phy_init) ++ vc4_hdmi->variant->phy_init(vc4_hdmi, mode); + + if (debug_dump_regs) { + struct drm_printer p = drm_info_printer(&vc4_hdmi->pdev->dev); +@@ -1428,6 +1426,8 @@ static const struct vc4_hdmi_variant bcm + + .init_resources = vc4_hdmi_init_resources, + .reset = vc4_hdmi_reset, ++ .phy_init = vc4_hdmi_phy_init, ++ .phy_disable = vc4_hdmi_phy_disable, + }; + + static const struct of_device_id vc4_hdmi_dt_match[] = { +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -21,6 +21,8 @@ to_vc4_hdmi_encoder(struct drm_encoder * + return container_of(encoder, struct vc4_hdmi_encoder, base.base); + } + ++struct drm_display_mode; ++ + struct vc4_hdmi; + struct vc4_hdmi_register; + +@@ -38,6 +40,13 @@ struct vc4_hdmi_variant { + + /* Callback to reset the HDMI block */ + void (*reset)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to initialize the PHY according to the mode */ ++ void (*phy_init)(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode); ++ ++ /* Callback to disable the PHY */ ++ void (*phy_disable)(struct vc4_hdmi *vc4_hdmi); + }; + + /* HDMI audio information */ +@@ -95,4 +104,8 @@ encoder_to_vc4_hdmi(struct drm_encoder * + return container_of(_encoder, struct vc4_hdmi, encoder); + } + ++void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode); ++void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); ++ + #endif /* _VC4_HDMI_H_ */ +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015 Broadcom ++ * Copyright (c) 2014 The Linux Foundation. All rights reserved. ++ * Copyright (C) 2013 Red Hat ++ * Author: Rob Clark ++ */ ++ ++#include "vc4_hdmi.h" ++#include "vc4_hdmi_regs.h" ++ ++void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) ++{ ++ /* PHY should be in reset, like ++ * vc4_hdmi_encoder_disable() does. ++ */ ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); ++} ++ ++void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); ++} diff --git a/target/linux/bcm27xx/patches-5.4/950-0586-drm-vc4-hdmi-Add-PHY-RNG-enable-disable-function.patch b/target/linux/bcm27xx/patches-5.4/950-0586-drm-vc4-hdmi-Add-PHY-RNG-enable-disable-function.patch new file mode 100644 index 00000000000..cea17a621e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0586-drm-vc4-hdmi-Add-PHY-RNG-enable-disable-function.patch @@ -0,0 +1,104 @@ +From ddf78df1db8752247e89a68231338a194e5dc52b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 19 Dec 2019 17:22:24 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add PHY RNG enable / disable function + +Let's continue the implementation of hooks for the parts that change in the +BCM2711 SoC with the PHY RNG setup. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 15 +++++++++------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 8 ++++++++ + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 15 +++++++++++++++ + 3 files changed, 32 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -765,9 +765,9 @@ static int vc4_hdmi_audio_trigger(struct + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + vc4_hdmi_set_audio_infoframe(encoder); +- HDMI_WRITE(HDMI_TX_PHY_CTL_0, +- HDMI_READ(HDMI_TX_PHY_CTL_0) & +- ~VC4_HDMI_TX_PHY_RNG_PWRDN); ++ ++ if (vc4_hdmi->variant->phy_rng_enable) ++ vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); + + HDMI_WRITE(HDMI_MAI_CTL, + VC4_SET_FIELD(vc4_hdmi->audio.channels, +@@ -779,9 +779,10 @@ static int vc4_hdmi_audio_trigger(struct + VC4_HD_MAI_CTL_DLATE | + VC4_HD_MAI_CTL_ERRORE | + VC4_HD_MAI_CTL_ERRORF); +- HDMI_WRITE(HDMI_TX_PHY_CTL_0, +- HDMI_READ(HDMI_TX_PHY_CTL_0) | +- VC4_HDMI_TX_PHY_RNG_PWRDN); ++ ++ if (vc4_hdmi->variant->phy_rng_disable) ++ vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); ++ + break; + default: + break; +@@ -1428,6 +1429,8 @@ static const struct vc4_hdmi_variant bcm + .reset = vc4_hdmi_reset, + .phy_init = vc4_hdmi_phy_init, + .phy_disable = vc4_hdmi_phy_disable, ++ .phy_rng_enable = vc4_hdmi_phy_rng_enable, ++ .phy_rng_disable = vc4_hdmi_phy_rng_disable, + }; + + static const struct of_device_id vc4_hdmi_dt_match[] = { +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -47,6 +47,12 @@ struct vc4_hdmi_variant { + + /* Callback to disable the PHY */ + void (*phy_disable)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to enable the RNG in the PHY */ ++ void (*phy_rng_enable)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to disable the RNG in the PHY */ ++ void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi); + }; + + /* HDMI audio information */ +@@ -107,5 +113,7 @@ encoder_to_vc4_hdmi(struct drm_encoder * + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, + struct drm_display_mode *mode); + void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi); ++void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); ++void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); + + #endif /* _VC4_HDMI_H_ */ +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -7,6 +7,7 @@ + */ + + #include "vc4_hdmi.h" ++#include "vc4_regs.h" + #include "vc4_hdmi_regs.h" + + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) +@@ -23,3 +24,17 @@ void vc4_hdmi_phy_disable(struct vc4_hdm + { + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); + } ++ ++void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ HDMI_READ(HDMI_TX_PHY_CTL_0) & ++ ~VC4_HDMI_TX_PHY_RNG_PWRDN); ++} ++ ++void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ HDMI_READ(HDMI_TX_PHY_CTL_0) | ++ VC4_HDMI_TX_PHY_RNG_PWRDN); ++} diff --git a/target/linux/bcm27xx/patches-5.4/950-0587-drm-vc4-hdmi-Add-a-CSC-setup-callback.patch b/target/linux/bcm27xx/patches-5.4/950-0587-drm-vc4-hdmi-Add-a-CSC-setup-callback.patch new file mode 100644 index 00000000000..c9650bca080 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0587-drm-vc4-hdmi-Add-a-CSC-setup-callback.patch @@ -0,0 +1,134 @@ +From 110cf6bdc1d79f2ee7a435bc9d1ec900aba11ed5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 26 Dec 2019 18:41:53 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add a CSC setup callback + +Similarly to the previous patches, the CSC setup is slightly different in +the BCM2711 than in the previous generations. Let's add a callback for it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 71 ++++++++++++++++++++-------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ++ + 2 files changed, 45 insertions(+), 29 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -337,6 +337,41 @@ static void vc4_hdmi_encoder_disable(str + DRM_ERROR("Failed to release power domain: %d\n", ret); + } + ++static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) ++{ ++ u32 csc_ctl; ++ ++ csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, ++ VC4_HD_CSC_CTL_ORDER); ++ ++ if (enable) { ++ /* CEA VICs other than #1 requre limited range RGB ++ * output unless overridden by an AVI infoframe. ++ * Apply a colorspace conversion to squash 0-255 down ++ * to 16-235. The matrix here is: ++ * ++ * [ 0 0 0.8594 16] ++ * [ 0 0.8594 0 16] ++ * [ 0.8594 0 0 16] ++ * [ 0 0 0 1] ++ */ ++ csc_ctl |= VC4_HD_CSC_CTL_ENABLE; ++ csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC; ++ csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, ++ VC4_HD_CSC_CTL_MODE); ++ ++ HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000); ++ } ++ ++ /* The RGB order applies even when CSC is disabled. */ ++ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); ++} ++ + static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) + { + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; +@@ -360,7 +395,6 @@ static void vc4_hdmi_encoder_enable(stru + mode->crtc_vsync_end - + interlaced, + VC4_HDMI_VERTB_VBP)); +- u32 csc_ctl; + int ret; + + ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); +@@ -431,41 +465,19 @@ static void vc4_hdmi_encoder_enable(stru + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + +- csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, +- VC4_HD_CSC_CTL_ORDER); +- + if (vc4_encoder->hdmi_monitor && +- drm_default_rgb_quant_range(mode) == +- HDMI_QUANTIZATION_RANGE_LIMITED) { +- /* CEA VICs other than #1 requre limited range RGB +- * output unless overridden by an AVI infoframe. +- * Apply a colorspace conversion to squash 0-255 down +- * to 16-235. The matrix here is: +- * +- * [ 0 0 0.8594 16] +- * [ 0 0.8594 0 16] +- * [ 0.8594 0 0 16] +- * [ 0 0 0 1] +- */ +- csc_ctl |= VC4_HD_CSC_CTL_ENABLE; +- csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC; +- csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, +- VC4_HD_CSC_CTL_MODE); ++ drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { ++ if (vc4_hdmi->variant->csc_setup) ++ vc4_hdmi->variant->csc_setup(vc4_hdmi, true); + +- HDMI_WRITE(HDMI_CSC_12_11, (0x000 << 16) | 0x000); +- HDMI_WRITE(HDMI_CSC_14_13, (0x100 << 16) | 0x6e0); +- HDMI_WRITE(HDMI_CSC_22_21, (0x6e0 << 16) | 0x000); +- HDMI_WRITE(HDMI_CSC_24_23, (0x100 << 16) | 0x000); +- HDMI_WRITE(HDMI_CSC_32_31, (0x000 << 16) | 0x6e0); +- HDMI_WRITE(HDMI_CSC_34_33, (0x100 << 16) | 0x000); + vc4_encoder->limited_rgb_range = true; + } else { ++ if (vc4_hdmi->variant->csc_setup) ++ vc4_hdmi->variant->csc_setup(vc4_hdmi, false); ++ + vc4_encoder->limited_rgb_range = false; + } + +- /* The RGB order applies even when CSC is disabled. */ +- HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); +- + HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); + + if (debug_dump_regs) { +@@ -1426,6 +1438,7 @@ static const struct vc4_hdmi_variant bcm + .num_registers = ARRAY_SIZE(vc4_hdmi_fields), + + .init_resources = vc4_hdmi_init_resources, ++ .csc_setup = vc4_hdmi_csc_setup, + .reset = vc4_hdmi_reset, + .phy_init = vc4_hdmi_phy_init, + .phy_disable = vc4_hdmi_phy_disable, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -41,6 +41,9 @@ struct vc4_hdmi_variant { + /* Callback to reset the HDMI block */ + void (*reset)(struct vc4_hdmi *vc4_hdmi); + ++ /* Callback to enable / disable the CSC */ ++ void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); ++ + /* Callback to initialize the PHY according to the mode */ + void (*phy_init)(struct vc4_hdmi *vc4_hdmi, + struct drm_display_mode *mode); diff --git a/target/linux/bcm27xx/patches-5.4/950-0588-drm-vc4-hdmi-Add-a-set_timings-callback.patch b/target/linux/bcm27xx/patches-5.4/950-0588-drm-vc4-hdmi-Add-a-set_timings-callback.patch new file mode 100644 index 00000000000..a39a8ac1095 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0588-drm-vc4-hdmi-Add-a-set_timings-callback.patch @@ -0,0 +1,133 @@ +From b9c57901c600e09b100942b637c6bb01e52b7326 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 6 Jan 2020 13:43:27 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add a set_timings callback + +Similarly to the previous patches, the timings setup in the HDMI controller +of the BCM2711 is slightly different, mostly because it supports higher +resolutions and thus needed more spaces for the various timings, resulting +in the register layout changing. + +Let's add a callback for that as well. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 71 +++++++++++++++++++--------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 4 ++ + 2 files changed, 44 insertions(+), 31 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -372,12 +372,9 @@ static void vc4_hdmi_csc_setup(struct vc + HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + } + +-static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) ++static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode) + { +- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; +- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); +- struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; +- bool debug_dump_regs = false; + bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; + bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; + bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; +@@ -395,6 +392,41 @@ static void vc4_hdmi_encoder_enable(stru + mode->crtc_vsync_end - + interlaced, + VC4_HDMI_VERTB_VBP)); ++ ++ HDMI_WRITE(HDMI_HORZA, ++ (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | ++ (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | ++ VC4_SET_FIELD(mode->hdisplay * pixel_rep, ++ VC4_HDMI_HORZA_HAP)); ++ ++ HDMI_WRITE(HDMI_HORZB, ++ VC4_SET_FIELD((mode->htotal - ++ mode->hsync_end) * pixel_rep, ++ VC4_HDMI_HORZB_HBP) | ++ VC4_SET_FIELD((mode->hsync_end - ++ mode->hsync_start) * pixel_rep, ++ VC4_HDMI_HORZB_HSP) | ++ VC4_SET_FIELD((mode->hsync_start - ++ mode->hdisplay) * pixel_rep, ++ VC4_HDMI_HORZB_HFP)); ++ ++ HDMI_WRITE(HDMI_VERTA0, verta); ++ HDMI_WRITE(HDMI_VERTA1, verta); ++ ++ HDMI_WRITE(HDMI_VERTB0, vertb_even); ++ HDMI_WRITE(HDMI_VERTB1, vertb); ++ ++ HDMI_WRITE(HDMI_VID_CTL, ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++} ++ ++static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); ++ bool debug_dump_regs = false; + int ret; + + ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); +@@ -438,32 +470,8 @@ static void vc4_hdmi_encoder_enable(stru + VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | + VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); + +- HDMI_WRITE(HDMI_HORZA, +- (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | +- (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | +- VC4_SET_FIELD(mode->hdisplay * pixel_rep, +- VC4_HDMI_HORZA_HAP)); +- +- HDMI_WRITE(HDMI_HORZB, +- VC4_SET_FIELD((mode->htotal - +- mode->hsync_end) * pixel_rep, +- VC4_HDMI_HORZB_HBP) | +- VC4_SET_FIELD((mode->hsync_end - +- mode->hsync_start) * pixel_rep, +- VC4_HDMI_HORZB_HSP) | +- VC4_SET_FIELD((mode->hsync_start - +- mode->hdisplay) * pixel_rep, +- VC4_HDMI_HORZB_HFP)); +- +- HDMI_WRITE(HDMI_VERTA0, verta); +- HDMI_WRITE(HDMI_VERTA1, verta); +- +- HDMI_WRITE(HDMI_VERTB0, vertb_even); +- HDMI_WRITE(HDMI_VERTB1, vertb); +- +- HDMI_WRITE(HDMI_VID_CTL, +- (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | +- (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ if (vc4_hdmi->variant->set_timings) ++ vc4_hdmi->variant->set_timings(vc4_hdmi, mode); + + if (vc4_encoder->hdmi_monitor && + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { +@@ -1440,6 +1448,7 @@ static const struct vc4_hdmi_variant bcm + .init_resources = vc4_hdmi_init_resources, + .csc_setup = vc4_hdmi_csc_setup, + .reset = vc4_hdmi_reset, ++ .set_timings = vc4_hdmi_set_timings, + .phy_init = vc4_hdmi_phy_init, + .phy_disable = vc4_hdmi_phy_disable, + .phy_rng_enable = vc4_hdmi_phy_rng_enable, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -44,6 +44,10 @@ struct vc4_hdmi_variant { + /* Callback to enable / disable the CSC */ + void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); + ++ /* Callback to configure the video timings in the HDMI block */ ++ void (*set_timings)(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode); ++ + /* Callback to initialize the PHY according to the mode */ + void (*phy_init)(struct vc4_hdmi *vc4_hdmi, + struct drm_display_mode *mode); diff --git a/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Add-HDMI-ID.patch b/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Add-HDMI-ID.patch new file mode 100644 index 00000000000..b6de732379d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Add-HDMI-ID.patch @@ -0,0 +1,46 @@ +From 84c1a6034e361078d540c9b3bc672ccae623dc03 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 7 Jan 2020 13:14:07 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add HDMI ID + +Some operations will need us to have the raw ID of the HDMI controller +in the BCM2711, such as the encoder type to register, the name of the +debugfs files, etc. + +Let's add it to our variant structure. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +-- + drivers/gpu/drm/vc4/vc4_hdmi.h | 5 +++++ + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1267,11 +1267,10 @@ static int vc4_hdmi_bind(struct device * + vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); + if (!vc4_hdmi) + return -ENOMEM; +- + vc4_hdmi->pdev = pdev; + variant = of_device_get_match_data(dev); + vc4_hdmi->variant = variant; +- vc4_hdmi->encoder.base.type = VC4_ENCODER_TYPE_HDMI0; ++ vc4_hdmi->encoder.base.type = variant->id ? VC4_ENCODER_TYPE_HDMI1 : VC4_ENCODER_TYPE_HDMI0; + encoder = &vc4_hdmi->encoder.base.base; + + ret = variant->init_resources(vc4_hdmi); +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -27,6 +27,11 @@ struct vc4_hdmi; + struct vc4_hdmi_register; + + struct vc4_hdmi_variant { ++ /* On devices that have multiple, different instances (like ++ * the BCM2711), which instance is that variant useful for. ++ */ ++ unsigned int id; ++ + /* List of the registers available on that variant */ + const struct vc4_hdmi_register *registers; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0590-drm-vc4-hdmi-Deal-with-multiple-debugfs-files.patch b/target/linux/bcm27xx/patches-5.4/950-0590-drm-vc4-hdmi-Deal-with-multiple-debugfs-files.patch new file mode 100644 index 00000000000..746eff91d51 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0590-drm-vc4-hdmi-Deal-with-multiple-debugfs-files.patch @@ -0,0 +1,33 @@ +From a1f24e24c065b91f833e3f546c1507f69fb04bc7 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 16 Jan 2020 14:27:56 +0100 +Subject: [PATCH] drm/vc4: hdmi: Deal with multiple debugfs files + +The HDMI driver was registering a single debugfs file so far with the name +hdmi_regs. + +Obviously, this is not going to work anymore when will have multiple HDMI +controllers since we will end up trying to register two files with the same +name. + +Let's use the ID to avoid that name conflict. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1380,7 +1380,10 @@ static int vc4_hdmi_bind(struct device * + if (ret) + goto err_destroy_encoder; + +- vc4_debugfs_add_file(drm, "hdmi_regs", vc4_hdmi_debugfs_regs, vc4_hdmi); ++ vc4_debugfs_add_file(drm, ++ variant->id ? "hdmi1_regs" : "hdmi_regs", ++ vc4_hdmi_debugfs_regs, ++ vc4_hdmi); + + return 0; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0591-drm-vc4-hdmi-Add-an-audio-support-flag.patch b/target/linux/bcm27xx/patches-5.4/950-0591-drm-vc4-hdmi-Add-an-audio-support-flag.patch new file mode 100644 index 00000000000..cc6cd868876 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0591-drm-vc4-hdmi-Add-an-audio-support-flag.patch @@ -0,0 +1,47 @@ +From 6154f7383e2defe48eea7fddb6ce646a0069828b Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 16:21:45 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add an audio support flag + +The BCM2711 audio support doesn't work yet, so let's add a boolean to +indicate whether or not it's supported, and only register a sound card if +that boolean is set. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++ + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +++ + 2 files changed, 7 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -944,6 +944,9 @@ static int vc4_hdmi_audio_init(struct vc + int ret; + int len; + ++ if (!vc4_hdmi->variant->audio_available) ++ return 0; ++ + if (!of_find_property(dev->of_node, "dmas", &len) || + len == 0) { + dev_warn(dev, +@@ -1444,6 +1447,7 @@ static int vc4_hdmi_dev_remove(struct pl + } + + static const struct vc4_hdmi_variant bcm2835_variant = { ++ .audio_available = true, + .registers = vc4_hdmi_fields, + .num_registers = ARRAY_SIZE(vc4_hdmi_fields), + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -32,6 +32,9 @@ struct vc4_hdmi_variant { + */ + unsigned int id; + ++ /* Set to true when the audio support is available */ ++ bool audio_available; ++ + /* List of the registers available on that variant */ + const struct vc4_hdmi_register *registers; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0592-drm-vc4-hdmi-Move-CEC-init-to-its-own-function.patch b/target/linux/bcm27xx/patches-5.4/950-0592-drm-vc4-hdmi-Move-CEC-init-to-its-own-function.patch new file mode 100644 index 00000000000..533eb89e7a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0592-drm-vc4-hdmi-Move-CEC-init-to-its-own-function.patch @@ -0,0 +1,165 @@ +From 9efd6edc4c7d01c74a92f2011ba285329ba956e4 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 16:22:13 +0100 +Subject: [PATCH] drm/vc4: hdmi: Move CEC init to its own function + +The CEC init code was put directly into the bind function, which was quite +inconsistent with how the audio support was done, and would prevent us from +further changes to skip that initialisation entirely. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 108 ++++++++++++++++++++------------- + 1 file changed, 67 insertions(+), 41 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1178,6 +1178,67 @@ static const struct cec_adap_ops vc4_hdm + .adap_log_addr = vc4_hdmi_cec_adap_log_addr, + .adap_transmit = vc4_hdmi_cec_adap_transmit, + }; ++ ++static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) ++{ ++ struct cec_connector_info conn_info; ++ struct platform_device *pdev = vc4_hdmi->pdev; ++ u32 value; ++ int ret; ++ ++ vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, ++ vc4_hdmi, "vc4", ++ CEC_CAP_DEFAULTS | ++ CEC_CAP_CONNECTOR_INFO, 1); ++ ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap); ++ if (ret < 0) ++ return ret; ++ ++ cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); ++ cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); ++ ++ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); ++ value = HDMI_READ(HDMI_CEC_CNTRL_1); ++ value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; ++ /* ++ * Set the logical address to Unregistered and set the clock ++ * divider: the hsm_clock rate and this divider setting will ++ * give a 40 kHz CEC clock. ++ */ ++ value |= VC4_HDMI_CEC_ADDR_MASK | ++ (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); ++ HDMI_WRITE(HDMI_CEC_CNTRL_1, value); ++ ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0), ++ vc4_cec_irq_handler, ++ vc4_cec_irq_handler_thread, 0, ++ "vc4 hdmi cec", vc4_hdmi); ++ if (ret) ++ goto err_delete_cec_adap; ++ ++ ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev); ++ if (ret < 0) ++ goto err_delete_cec_adap; ++ ++ return 0; ++ ++err_delete_cec_adap: ++ cec_delete_adapter(vc4_hdmi->cec_adap); ++ ++ return ret; ++} ++ ++static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) ++{ ++ cec_unregister_adapter(vc4_hdmi->cec_adap); ++} ++#else ++static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) ++{ ++ return 0; ++} ++ ++static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {}; ++ + #endif + + static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, +@@ -1255,9 +1316,6 @@ static int vc4_hdmi_init_resources(struc + + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + { +-#ifdef CONFIG_DRM_VC4_HDMI_CEC +- struct cec_connector_info conn_info; +-#endif + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + const struct vc4_hdmi_variant *variant; +@@ -1345,43 +1403,13 @@ static int vc4_hdmi_bind(struct device * + if (ret) + goto err_destroy_encoder; + +-#ifdef CONFIG_DRM_VC4_HDMI_CEC +- vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, +- vc4_hdmi, "vc4", +- CEC_CAP_DEFAULTS | +- CEC_CAP_CONNECTOR_INFO, 1); +- ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap); +- if (ret < 0) +- goto err_destroy_conn; +- +- cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); +- cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); +- +- HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); +- value = HDMI_READ(HDMI_CEC_CNTRL_1); +- value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; +- /* +- * Set the logical address to Unregistered and set the clock +- * divider: the hsm_clock rate and this divider setting will +- * give a 40 kHz CEC clock. +- */ +- value |= VC4_HDMI_CEC_ADDR_MASK | +- (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); +- HDMI_WRITE(HDMI_CEC_CNTRL_1, value); +- ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), +- vc4_cec_irq_handler, +- vc4_cec_irq_handler_thread, 0, +- "vc4 hdmi cec", vc4_hdmi); ++ ret = vc4_hdmi_cec_init(vc4_hdmi); + if (ret) +- goto err_delete_cec_adap; +- ret = cec_register_adapter(vc4_hdmi->cec_adap, dev); +- if (ret < 0) +- goto err_delete_cec_adap; +-#endif ++ goto err_destroy_conn; + + ret = vc4_hdmi_audio_init(vc4_hdmi); + if (ret) +- goto err_destroy_encoder; ++ goto err_free_cec; + + vc4_debugfs_add_file(drm, + variant->id ? "hdmi1_regs" : "hdmi_regs", +@@ -1390,12 +1418,10 @@ static int vc4_hdmi_bind(struct device * + + return 0; + +-#ifdef CONFIG_DRM_VC4_HDMI_CEC +-err_delete_cec_adap: +- cec_delete_adapter(vc4_hdmi->cec_adap); ++err_free_cec: ++ vc4_hdmi_cec_exit(vc4_hdmi); + err_destroy_conn: + vc4_hdmi_connector_destroy(&vc4_hdmi->connector); +-#endif + err_destroy_encoder: + vc4_hdmi_encoder_destroy(encoder); + err_unprepare_hsm: +@@ -1420,7 +1446,7 @@ static void vc4_hdmi_unbind(struct devic + kfree(vc4_hdmi->hdmi_regset.regs); + kfree(vc4_hdmi->hd_regset.regs); + +- cec_unregister_adapter(vc4_hdmi->cec_adap); ++ vc4_hdmi_cec_exit(vc4_hdmi); + vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0593-drm-vc4-hdmi-Add-CEC-support-flag.patch b/target/linux/bcm27xx/patches-5.4/950-0593-drm-vc4-hdmi-Add-CEC-support-flag.patch new file mode 100644 index 00000000000..33ecf44a27c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0593-drm-vc4-hdmi-Add-CEC-support-flag.patch @@ -0,0 +1,47 @@ +From 0f626dc8443a93138806b4a3f351bac346036358 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 6 Feb 2020 16:22:50 +0100 +Subject: [PATCH] drm/vc4: hdmi: Add CEC support flag + +Similarly to the audio support, CEC support is not there yet for the +BCM2711, so let's skip entirely the CEC initialization through a variant +flag. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++ + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +++ + 2 files changed, 7 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1186,6 +1186,9 @@ static int vc4_hdmi_cec_init(struct vc4_ + u32 value; + int ret; + ++ if (!vc4_hdmi->variant->cec_available) ++ return 0; ++ + vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops, + vc4_hdmi, "vc4", + CEC_CAP_DEFAULTS | +@@ -1474,6 +1477,7 @@ static int vc4_hdmi_dev_remove(struct pl + + static const struct vc4_hdmi_variant bcm2835_variant = { + .audio_available = true, ++ .cec_available = true, + .registers = vc4_hdmi_fields, + .num_registers = ARRAY_SIZE(vc4_hdmi_fields), + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -35,6 +35,9 @@ struct vc4_hdmi_variant { + /* Set to true when the audio support is available */ + bool audio_available; + ++ /* Set to true when the CEC support is available */ ++ bool cec_available; ++ + /* List of the registers available on that variant */ + const struct vc4_hdmi_register *registers; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Remove-unused-CEC_CLOCK_DIV-define.patch b/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Remove-unused-CEC_CLOCK_DIV-define.patch new file mode 100644 index 00000000000..4befec6c050 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Remove-unused-CEC_CLOCK_DIV-define.patch @@ -0,0 +1,23 @@ +From a1a87ba39e7fad93cbbb5ea178a12d0c669a9812 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 10 Feb 2020 15:15:47 +0100 +Subject: [PATCH] drm/vc4: hdmi: Remove unused CEC_CLOCK_DIV define + +The CEC_CLOCK_DIV define is not used anywhere in the driver, let's remove +it. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -54,7 +54,6 @@ + + #define HSM_CLOCK_FREQ 163682864 + #define CEC_CLOCK_FREQ 40000 +-#define CEC_CLOCK_DIV (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ) + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) + { diff --git a/target/linux/bcm27xx/patches-5.4/950-0595-drm-vc4-hdmi-Rename-drm_encoder-pointer-in-mode_vali.patch b/target/linux/bcm27xx/patches-5.4/950-0595-drm-vc4-hdmi-Rename-drm_encoder-pointer-in-mode_vali.patch new file mode 100644 index 00000000000..5c0ab9768b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0595-drm-vc4-hdmi-Rename-drm_encoder-pointer-in-mode_vali.patch @@ -0,0 +1,26 @@ +From dfc6e670144207251dc0902d1756bc89ef6cd1dc Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 12:31:09 +0100 +Subject: [PATCH] drm/vc4: hdmi: Rename drm_encoder pointer in + mode_valid + +The mode_valid hook on the encoder uses a pointer to a drm_encoder called +crtc, which is pretty confusing. Let's rename it to encoder to make it +clear what it is. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -559,7 +559,7 @@ static void vc4_hdmi_encoder_enable(stru + } + + static enum drm_mode_status +-vc4_hdmi_encoder_mode_valid(struct drm_encoder *crtc, ++vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, + const struct drm_display_mode *mode) + { + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0596-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch b/target/linux/bcm27xx/patches-5.4/950-0596-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch new file mode 100644 index 00000000000..4dba81b0353 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0596-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch @@ -0,0 +1,163 @@ +From 3c33724058852d7c58d77d03e11ca545fb04256a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Mon, 10 Feb 2020 15:23:06 +0100 +Subject: [PATCH] drm/vc4: hdmi: Adjust HSM clock rate depending on + pixel rate + +The HSM clock needs to be setup at around 110% of the pixel rate. This +was done previously by setting the clock rate to 148.5MHz * 108% at +probe time and only check in mode_valid whether the mode pixel clock was +under 148.5MHz or not. + +However, with 4k we need to change that frequency to a higher frequency +than 148.5MHz. + +Let's change that logic a bit by setting the clock rate of the HSM clock +to the pixel rate at encoder_enable time. This would work for the +BCM2711 that support 4k resolutions and has a clock that can provide it, +but we still have to take care of a 4k panel plugged on a BCM283x SoCs +that wouldn't be able to use those modes, so let's define the limit in +the variant. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 51 +++++++++++++++++----------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ++ + 2 files changed, 29 insertions(+), 25 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -52,7 +52,6 @@ + #include "vc4_hdmi_regs.h" + #include "vc4_regs.h" + +-#define HSM_CLOCK_FREQ 163682864 + #define CEC_CLOCK_FREQ 40000 + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) +@@ -329,6 +328,7 @@ static void vc4_hdmi_encoder_disable(str + HDMI_WRITE(HDMI_VID_CTL, + HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + ++ clk_disable_unprepare(vc4_hdmi->hsm_clock); + clk_disable_unprepare(vc4_hdmi->pixel_clock); + + ret = pm_runtime_put(&vc4_hdmi->pdev->dev); +@@ -426,6 +426,7 @@ static void vc4_hdmi_encoder_enable(stru + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + bool debug_dump_regs = false; ++ unsigned long pixel_rate, hsm_rate; + int ret; + + ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); +@@ -434,9 +435,8 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + +- ret = clk_set_rate(vc4_hdmi->pixel_clock, +- mode->clock * 1000 * +- ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); ++ pixel_rate = mode->clock * 1000 * ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1); ++ ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate); + if (ret) { + DRM_ERROR("Failed to set pixel clock rate: %d\n", ret); + return; +@@ -448,6 +448,24 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + ++ /* ++ * The HSM rate needs to be at 108% of the pixel clock, with a ++ * minimum of 108MHz. ++ */ ++ hsm_rate = max_t(unsigned long, 108000000, (pixel_rate / 100) * 108); ++ ret = clk_set_rate(vc4_hdmi->hsm_clock, hsm_rate); ++ if (ret) { ++ DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(vc4_hdmi->hsm_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on HSM clock: %d\n", ret); ++ clk_disable_unprepare(vc4_hdmi->pixel_clock); ++ return; ++ } ++ + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + +@@ -578,7 +596,9 @@ vc4_hdmi_encoder_mode_valid(struct drm_e + * Additionally, the AXI clock needs to be at least 25% of + * pixel clock, but HSM ends up being the limiting factor. + */ +- if (mode->clock > HSM_CLOCK_FREQ / (1000 * 101 / 100)) ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ ++ if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; +@@ -1353,23 +1373,6 @@ static int vc4_hdmi_bind(struct device * + return -EPROBE_DEFER; + } + +- /* This is the rate that is set by the firmware. The number +- * needs to be a bit higher than the pixel clock rate +- * (generally 148.5Mhz). +- */ +- ret = clk_set_rate(vc4_hdmi->hsm_clock, HSM_CLOCK_FREQ); +- if (ret) { +- DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); +- goto err_put_i2c; +- } +- +- ret = clk_prepare_enable(vc4_hdmi->hsm_clock); +- if (ret) { +- DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", +- ret); +- goto err_put_i2c; +- } +- + /* Only use the GPIO HPD pin if present in the DT, otherwise + * we'll use the HDMI core's register. + */ +@@ -1427,9 +1430,7 @@ err_destroy_conn: + err_destroy_encoder: + vc4_hdmi_encoder_destroy(encoder); + err_unprepare_hsm: +- clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); +-err_put_i2c: + put_device(&vc4_hdmi->ddc->dev); + + return ret; +@@ -1452,7 +1453,6 @@ static void vc4_hdmi_unbind(struct devic + vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); + +- clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); + + put_device(&vc4_hdmi->ddc->dev); +@@ -1475,6 +1475,7 @@ static int vc4_hdmi_dev_remove(struct pl + } + + static const struct vc4_hdmi_variant bcm2835_variant = { ++ .max_pixel_clock = 148500000, + .audio_available = true, + .cec_available = true, + .registers = vc4_hdmi_fields, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -38,6 +38,9 @@ struct vc4_hdmi_variant { + /* Set to true when the CEC support is available */ + bool cec_available; + ++ /* Maximum pixel clock supported by the controller (in Hz) */ ++ unsigned long long max_pixel_clock; ++ + /* List of the registers available on that variant */ + const struct vc4_hdmi_register *registers; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0597-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch b/target/linux/bcm27xx/patches-5.4/950-0597-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch new file mode 100644 index 00000000000..d511f1e212a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0597-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch @@ -0,0 +1,1131 @@ +From d0931317c51f14bf65af65e7c3f2df6bb26d7c97 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Tue, 17 Dec 2019 11:48:37 +0100 +Subject: [PATCH] drm/vc4: hdmi: Support the BCM2711 HDMI controllers + +Now that the driver is ready for it, let's bring in the HDMI controllers +variants for the BCM2711. + +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 254 +++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi.h | 35 +++ + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 469 ++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 201 ++++++++++++ + 4 files changed, 959 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -52,6 +53,31 @@ + #include "vc4_hdmi_regs.h" + #include "vc4_regs.h" + ++#define VC5_HDMI_HORZA_HFP_SHIFT 16 ++#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16) ++#define VC5_HDMI_HORZA_VPOS BIT(15) ++#define VC5_HDMI_HORZA_HPOS BIT(14) ++#define VC5_HDMI_HORZA_HAP_SHIFT 0 ++#define VC5_HDMI_HORZA_HAP_MASK VC4_MASK(13, 0) ++ ++#define VC5_HDMI_HORZB_HBP_SHIFT 16 ++#define VC5_HDMI_HORZB_HBP_MASK VC4_MASK(26, 16) ++#define VC5_HDMI_HORZB_HSP_SHIFT 0 ++#define VC5_HDMI_HORZB_HSP_MASK VC4_MASK(10, 0) ++ ++#define VC5_HDMI_VERTA_VSP_SHIFT 24 ++#define VC5_HDMI_VERTA_VSP_MASK VC4_MASK(28, 24) ++#define VC5_HDMI_VERTA_VFP_SHIFT 16 ++#define VC5_HDMI_VERTA_VFP_MASK VC4_MASK(22, 16) ++#define VC5_HDMI_VERTA_VAL_SHIFT 0 ++#define VC5_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) ++ ++#define VC5_HDMI_VERTB_VSPO_SHIFT 16 ++#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) ++ ++# define VC4_HD_M_SW_RST BIT(2) ++# define VC4_HD_M_ENABLE BIT(0) ++ + #define CEC_CLOCK_FREQ 40000 + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) +@@ -75,6 +101,13 @@ static void vc4_hdmi_reset(struct vc4_hd + HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); + } + ++static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) ++{ ++ reset_control_reset(vc4_hdmi->reset); ++ ++ HDMI_WRITE(HDMI_DVP_CTL, 0); ++} ++ + static enum drm_connector_status + vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +@@ -371,6 +404,45 @@ static void vc4_hdmi_csc_setup(struct vc + HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + } + ++static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) ++{ ++ u32 csc_ctl; ++ ++ csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ ++ ++ if (enable) { ++ /* CEA VICs other than #1 requre limited range RGB ++ * output unless overridden by an AVI infoframe. ++ * Apply a colorspace conversion to squash 0-255 down ++ * to 16-235. The matrix here is: ++ * ++ * [ 0.8594 0 0 16] ++ * [ 0 0.8594 0 16] ++ * [ 0 0 0.8594 16] ++ * [ 0 0 0 1] ++ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets ++ */ ++ HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); ++ } else { ++ /* Still use the matrix for full range, but make it unity. ++ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets ++ */ ++ HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); ++ } ++ ++ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); ++} ++ + static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, + struct drm_display_mode *mode) + { +@@ -420,6 +492,58 @@ static void vc4_hdmi_set_timings(struct + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + } + ++static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode) ++{ ++ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; ++ bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; ++ bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; ++ u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; ++ u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, ++ VC5_HDMI_VERTA_VSP) | ++ VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, ++ VC5_HDMI_VERTA_VFP) | ++ VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL)); ++ u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, ++ VC4_HDMI_VERTB_VBP)); ++ u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->crtc_vtotal - ++ mode->crtc_vsync_end - ++ interlaced, ++ VC4_HDMI_VERTB_VBP)); ++ ++ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); ++ HDMI_WRITE(HDMI_HORZA, ++ (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | ++ (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | ++ VC4_SET_FIELD(mode->hdisplay * pixel_rep, ++ VC5_HDMI_HORZA_HAP) | ++ VC4_SET_FIELD((mode->hsync_start - ++ mode->hdisplay) * pixel_rep, ++ VC5_HDMI_HORZA_HFP)); ++ ++ HDMI_WRITE(HDMI_HORZB, ++ VC4_SET_FIELD((mode->htotal - ++ mode->hsync_end) * pixel_rep, ++ VC5_HDMI_HORZB_HBP) | ++ VC4_SET_FIELD((mode->hsync_end - ++ mode->hsync_start) * pixel_rep, ++ VC5_HDMI_HORZB_HSP)); ++ ++ HDMI_WRITE(HDMI_VERTA0, verta); ++ HDMI_WRITE(HDMI_VERTA1, verta); ++ ++ HDMI_WRITE(HDMI_VERTB0, vertb_even); ++ HDMI_WRITE(HDMI_VERTB1, vertb); ++ ++ HDMI_WRITE(HDMI_VID_CTL, ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ ++ HDMI_WRITE(HDMI_CLOCK_STOP, 0); ++} ++ + static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) + { + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; +@@ -1336,6 +1460,92 @@ static int vc4_hdmi_init_resources(struc + return 0; + } + ++static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) ++{ ++ struct platform_device *pdev = vc4_hdmi->pdev; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start, ++ resource_size(res)); ++ if (IS_ERR(vc4_hdmi->hdmicore_regs)) ++ return PTR_ERR(vc4_hdmi->hdmicore_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->hd_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->hd_regs)) ++ return PTR_ERR(vc4_hdmi->hd_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->cec_regs)) ++ return PTR_ERR(vc4_hdmi->cec_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->csc_regs)) ++ return PTR_ERR(vc4_hdmi->csc_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->dvp_regs)) ++ return PTR_ERR(vc4_hdmi->dvp_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->phy_regs)) ++ return PTR_ERR(vc4_hdmi->phy_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->ram_regs)) ++ return PTR_ERR(vc4_hdmi->ram_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->rm_regs)) ++ return PTR_ERR(vc4_hdmi->rm_regs); ++ ++ vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); ++ if (IS_ERR(vc4_hdmi->hsm_clock)) { ++ DRM_ERROR("Failed to get HDMI state machine clock\n"); ++ return PTR_ERR(vc4_hdmi->hsm_clock); ++ } ++ ++ vc4_hdmi->reset = devm_reset_control_get(dev, NULL); ++ if (IS_ERR(vc4_hdmi->reset)) { ++ DRM_ERROR("Failed to get HDMI reset line\n"); ++ return PTR_ERR(vc4_hdmi->reset); ++ } ++ ++ return 0; ++} ++ + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -1491,8 +1701,52 @@ static const struct vc4_hdmi_variant bcm + .phy_rng_disable = vc4_hdmi_phy_rng_disable, + }; + ++static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { ++ .id = 0, ++ .max_pixel_clock = 297000000, ++ .registers = vc5_hdmi_hdmi0_fields, ++ .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc5_hdmi_phy_init, ++ .phy_rng_enable = vc5_hdmi_phy_rng_enable, ++ .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++}; ++ ++static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { ++ .id = 1, ++ .max_pixel_clock = 297000000, ++ .registers = vc5_hdmi_hdmi1_fields, ++ .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_1, ++ PHY_LANE_0, ++ PHY_LANE_CK, ++ PHY_LANE_2, ++ }, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc5_hdmi_phy_init, ++ .phy_rng_enable = vc5_hdmi_phy_rng_enable, ++ .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++}; ++ + static const struct of_device_id vc4_hdmi_dt_match[] = { + { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant }, ++ { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant }, ++ { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -26,6 +26,13 @@ struct drm_display_mode; + struct vc4_hdmi; + struct vc4_hdmi_register; + ++enum vc4_hdmi_phy_channel { ++ PHY_LANE_0 = 0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++}; ++ + struct vc4_hdmi_variant { + /* On devices that have multiple, different instances (like + * the BCM2711), which instance is that variant useful for. +@@ -47,6 +54,13 @@ struct vc4_hdmi_variant { + /* Number of registers on that variant */ + unsigned int num_registers; + ++ /* BCM2711 Only. ++ * The variants don't map the lane in the same order in the ++ * PHY, so this is an array mapping the HDMI channel (index) ++ * to the PHY lane (value). ++ */ ++ enum vc4_hdmi_phy_channel phy_lane_mapping[4]; ++ + /* Callback to get the resources (memory region, interrupts, + * clocks, etc) for that variant. + */ +@@ -102,6 +116,20 @@ struct vc4_hdmi { + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; + void __iomem *hd_regs; ++ ++ /* VC5 Only */ ++ void __iomem *cec_regs; ++ /* VC5 Only */ ++ void __iomem *csc_regs; ++ /* VC5 Only */ ++ void __iomem *dvp_regs; ++ /* VC5 Only */ ++ void __iomem *phy_regs; ++ /* VC5 Only */ ++ void __iomem *ram_regs; ++ /* VC5 Only */ ++ void __iomem *rm_regs; ++ + int hpd_gpio; + bool hpd_active_low; + +@@ -113,6 +141,8 @@ struct vc4_hdmi { + struct clk *pixel_clock; + struct clk *hsm_clock; + ++ struct reset_control *reset; ++ + struct debugfs_regset32 hdmi_regset; + struct debugfs_regset32 hd_regset; + }; +@@ -137,4 +167,9 @@ void vc4_hdmi_phy_disable(struct vc4_hdm + void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); + void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); + ++void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode); ++void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); ++void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); ++ + #endif /* _VC4_HDMI_H_ */ +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -10,6 +10,123 @@ + #include "vc4_regs.h" + #include "vc4_hdmi_regs.h" + ++#define VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB BIT(5) ++#define VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB BIT(4) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET BIT(3) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET BIT(2) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET BIT(1) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET BIT(0) ++ ++#define VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN BIT(4) ++ ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_SHIFT 29 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_MASK VC4_MASK(31, 29) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_SHIFT 24 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_MASK VC4_MASK(28, 24) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_SHIFT 21 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_MASK VC4_MASK(23, 21) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_SHIFT 16 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_MASK VC4_MASK(20, 16) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_SHIFT 13 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_MASK VC4_MASK(15, 13) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_MASK VC4_MASK(12, 8) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_SHIFT 5 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_MASK VC4_MASK(7, 5) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_MASK VC4_MASK(4, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_SHIFT 15 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_MASK VC4_MASK(19, 15) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_SHIFT 10 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_MASK VC4_MASK(14, 10) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_SHIFT 5 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_MASK VC4_MASK(9, 5) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_MASK VC4_MASK(4, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_SHIFT 16 ++#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_MASK VC4_MASK(19, 16) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_MASK VC4_MASK(15, 12) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_MASK VC4_MASK(11, 8) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_SHIFT 4 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_MASK VC4_MASK(7, 4) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_MASK VC4_MASK(3, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_3_RP_SHIFT 17 ++#define VC4_HDMI_TX_PHY_CTL_3_RP_MASK VC4_MASK(19, 17) ++#define VC4_HDMI_TX_PHY_CTL_3_RZ_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CTL_3_RZ_MASK VC4_MASK(16, 12) ++#define VC4_HDMI_TX_PHY_CTL_3_CP1_SHIFT 10 ++#define VC4_HDMI_TX_PHY_CTL_3_CP1_MASK VC4_MASK(11, 10) ++#define VC4_HDMI_TX_PHY_CTL_3_CP_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_3_CP_MASK VC4_MASK(9, 8) ++#define VC4_HDMI_TX_PHY_CTL_3_CZ_SHIFT 6 ++#define VC4_HDMI_TX_PHY_CTL_3_CZ_MASK VC4_MASK(7, 6) ++#define VC4_HDMI_TX_PHY_CTL_3_ICP_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_3_ICP_MASK VC4_MASK(5, 0) ++ ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE BIT(13) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VC_RANGE_EN BIT(12) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_LOW BIT(11) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_HIGH BIT(10) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_SHIFT 9 ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_MASK VC4_MASK(9, 9) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_FB_DIV2 BIT(8) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_POST_DIV2 BIT(7) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN BIT(6) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK BIT(5) ++ ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_SHIFT 16 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_MASK VC4_MASK(27, 16) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_SHIFT 14 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_MASK VC4_MASK(15, 14) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE BIT(13) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_SHIFT 11 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_MASK VC4_MASK(12, 11) ++ ++#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_MASK VC4_MASK(15, 8) ++ ++#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_SHIFT 0 ++#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_MASK VC4_MASK(3, 0) ++ ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_MASK VC4_MASK(13, 12) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_MASK VC4_MASK(9, 8) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_MASK VC4_MASK(5, 4) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_SHIFT 4 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_MASK VC4_MASK(1, 0) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK VC4_MASK(27, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK VC4_MASK(27, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_MASK VC4_MASK(31, 16) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_SHIFT 16 ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_MASK VC4_MASK(15, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_SHIFT 0 ++ ++#define VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS BIT(19) ++#define VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR BIT(17) ++#define VC4_HDMI_RM_CONTROL_FREE_RUN BIT(4) ++ ++#define VC4_HDMI_RM_OFFSET_ONLY BIT(31) ++#define VC4_HDMI_RM_OFFSET_OFFSET_SHIFT 0 ++#define VC4_HDMI_RM_OFFSET_OFFSET_MASK VC4_MASK(30, 0) ++ ++#define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 ++#define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) ++ ++#define OSCILLATOR_FREQUENCY 54000000 ++ + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) + { + /* PHY should be in reset, like +@@ -38,3 +155,355 @@ void vc4_hdmi_phy_rng_disable(struct vc4 + HDMI_READ(HDMI_TX_PHY_CTL_0) | + VC4_HDMI_TX_PHY_RNG_PWRDN); + } ++ ++static unsigned long long ++phy_get_vco_freq(unsigned long long clock, u8 *vco_sel, u8 *vco_div) ++{ ++ unsigned long long vco_freq = clock; ++ unsigned int _vco_div = 0; ++ unsigned int _vco_sel = 0; ++ ++ while (vco_freq < 3000000000ULL) { ++ _vco_div++; ++ vco_freq = clock * _vco_div * 10; ++ } ++ ++ if (vco_freq > 4500000000ULL) ++ _vco_sel = 1; ++ ++ *vco_sel = _vco_sel; ++ *vco_div = _vco_div; ++ ++ return vco_freq; ++} ++ ++static u8 phy_get_cp_current(unsigned long vco_freq) ++{ ++ if (vco_freq < 3700000000ULL) ++ return 0x1c; ++ ++ return 0xc8; ++} ++ ++static u32 phy_get_rm_offset(unsigned long long vco_freq) ++{ ++ unsigned long long fref = OSCILLATOR_FREQUENCY; ++ uint64_t offset = 0; ++ ++ /* RM offset is stored as 9.22 format */ ++ offset = vco_freq * 2; ++ do_div(offset, fref); ++ offset = offset << 22; ++ offset >>= 2; ++ ++ return offset; ++} ++ ++static u8 phy_get_vco_gain(unsigned long long vco_freq) ++{ ++ if (vco_freq < 3350000000ULL) ++ return 0xf; ++ ++ if (vco_freq < 3700000000ULL) ++ return 0xc; ++ ++ if (vco_freq < 4050000000ULL) ++ return 0x6; ++ ++ if (vco_freq < 4800000000ULL) ++ return 0x5; ++ ++ if (vco_freq < 5200000000ULL) ++ return 0x7; ++ ++ return 0x2; ++} ++ ++struct phy_lane_settings { ++ struct { ++ u8 preemphasis; ++ u8 main_driver; ++ } amplitude; ++ ++ u8 res_sel_data; ++ u8 term_res_sel_data; ++}; ++ ++struct phy_settings { ++ unsigned long long min_rate; ++ unsigned long long max_rate; ++ struct phy_lane_settings channel[3]; ++ struct phy_lane_settings clock; ++}; ++ ++static const struct phy_settings vc5_hdmi_phy_settings[] = ++{ ++ { ++ 0, 50000000, ++ { ++ {{0x0, 0x0A}, 0x12, 0x0}, ++ {{0x0, 0x0A}, 0x12, 0x0}, ++ {{0x0, 0x0A}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0A}, 0x18, 0x0}, ++ }, ++ { ++ 50000001, 75000000, ++ { ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 75000001, 165000000, ++ { ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 165000001, 250000000, ++ { ++ {{0x0, 0x0F}, 0x12, 0x1}, ++ {{0x0, 0x0F}, 0x12, 0x1}, ++ {{0x0, 0x0F}, 0x12, 0x1} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 250000001, 340000000, ++ { ++ {{0x2, 0x0D}, 0x12, 0x1}, ++ {{0x2, 0x0D}, 0x12, 0x1}, ++ {{0x2, 0x0D}, 0x12, 0x1} ++ }, ++ {{0x0, 0x0C}, 0x18, 0xF}, ++ }, ++ { ++ 340000001, 450000000, ++ { ++ {{0x0, 0x1B}, 0x12, 0xF}, ++ {{0x0, 0x1B}, 0x12, 0xF}, ++ {{0x0, 0x1B}, 0x12, 0xF} ++ }, ++ {{0x0, 0x0A}, 0x12, 0xF}, ++ }, ++ { ++ 450000001, 600000000, ++ { ++ {{0x0, 0x1C}, 0x12, 0xF}, ++ {{0x0, 0x1C}, 0x12, 0xF}, ++ {{0x0, 0x1C}, 0x12, 0xF} ++ }, ++ {{0x0, 0x0B}, 0x13, 0xF}, ++ }, ++}; ++ ++static const struct phy_settings *phy_get_settings(unsigned long long tmds_rate) ++{ ++ unsigned int count = ARRAY_SIZE(vc5_hdmi_phy_settings); ++ unsigned int i; ++ ++ for (i = 0; i < count; i++) { ++ const struct phy_settings *s = &vc5_hdmi_phy_settings[i]; ++ ++ if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate) ++ return s; ++ } ++ ++ /* ++ * If the pixel clock exceeds our max setting, try the max ++ * setting anyway. ++ */ ++ return &vc5_hdmi_phy_settings[count - 1]; ++} ++ ++static const struct phy_lane_settings * ++phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, ++ unsigned long long tmds_rate) ++{ ++ const struct phy_settings *settings = phy_get_settings(tmds_rate); ++ ++ if (chan == PHY_LANE_CK) ++ return &settings->clock; ++ ++ return &settings->channel[chan]; ++} ++ ++void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) ++{ ++ const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings; ++ const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; ++ unsigned long long pixel_freq = mode->clock * 1000; ++ unsigned long long vco_freq; ++ unsigned char word_sel; ++ u8 vco_sel, vco_div; ++ ++ vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div); ++ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET); ++ ++ HDMI_WRITE(HDMI_RM_CONTROL, ++ HDMI_READ(HDMI_RM_CONTROL) | ++ VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS | ++ VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR | ++ VC4_HDMI_RM_CONTROL_FREE_RUN); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, ++ (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1) & ++ ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK) | ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, ++ (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2) & ++ ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK) | ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT)); ++ ++ HDMI_WRITE(HDMI_RM_OFFSET, ++ VC4_SET_FIELD(phy_get_rm_offset(vco_freq), ++ VC4_HDMI_RM_OFFSET_OFFSET) | ++ VC4_HDMI_RM_OFFSET_ONLY); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CLK_DIV, ++ VC4_SET_FIELD(vco_div, VC4_HDMI_TX_PHY_CLK_DIV_VCO)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, ++ VC4_SET_FIELD(0xe147, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD) | ++ VC4_SET_FIELD(0xe14, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_0, ++ VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK | ++ VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN | ++ VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE | ++ VC4_SET_FIELD(vco_sel, VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_READ(HDMI_TX_PHY_PLL_CTL_1) | ++ VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE | ++ VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY) | ++ VC4_SET_FIELD(0x8a, VC4_HDMI_TX_PHY_PLL_CTL_1_CPP)); ++ ++ HDMI_WRITE(HDMI_RM_FORMAT, ++ HDMI_READ(HDMI_RM_FORMAT) | ++ VC4_SET_FIELD(2, VC4_HDMI_RM_FORMAT_SHIFT)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CFG, ++ HDMI_READ(HDMI_TX_PHY_PLL_CFG) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CFG_PDIV)); ++ ++ if (pixel_freq >= 340000000) ++ word_sel = 3; ++ else ++ word_sel = 0; ++ HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_3, ++ VC4_SET_FIELD(phy_get_cp_current(vco_freq), ++ VC4_HDMI_TX_PHY_CTL_3_ICP) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP1) | ++ VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_CTL_3_CZ) | ++ VC4_SET_FIELD(4, VC4_HDMI_TX_PHY_CTL_3_RP) | ++ VC4_SET_FIELD(6, VC4_HDMI_TX_PHY_CTL_3_RZ)); ++ ++ chan0_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_0], ++ pixel_freq); ++ chan1_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_1], ++ pixel_freq); ++ chan2_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_2], ++ pixel_freq); ++ clock_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_CK], ++ pixel_freq); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ VC4_SET_FIELD(chan0_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP) | ++ VC4_SET_FIELD(chan0_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV) | ++ VC4_SET_FIELD(chan1_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP) | ++ VC4_SET_FIELD(chan1_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV) | ++ VC4_SET_FIELD(chan2_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP) | ++ VC4_SET_FIELD(chan2_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV) | ++ VC4_SET_FIELD(clock_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP) | ++ VC4_SET_FIELD(clock_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_1, ++ HDMI_READ(HDMI_TX_PHY_CTL_1) | ++ VC4_SET_FIELD(chan0_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0) | ++ VC4_SET_FIELD(chan1_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1) | ++ VC4_SET_FIELD(chan2_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2) | ++ VC4_SET_FIELD(clock_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_2, ++ VC4_SET_FIELD(chan0_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0) | ++ VC4_SET_FIELD(chan1_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1) | ++ VC4_SET_FIELD(chan2_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2) | ++ VC4_SET_FIELD(clock_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK) | ++ VC4_SET_FIELD(phy_get_vco_gain(vco_freq), ++ VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CHANNEL_SWAP, ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_0], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_1], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_2], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_CK], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) & ++ ~(VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB); ++} ++ ++void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) & ++ ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++} ++ ++void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) | ++ VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++} +--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -18,6 +18,12 @@ enum vc4_hdmi_regs { + VC4_INVALID = 0, + VC4_HDMI, + VC4_HD, ++ VC5_CEC, ++ VC5_CSC, ++ VC5_DVP, ++ VC5_PHY, ++ VC5_RAM, ++ VC5_RM, + }; + + enum vc4_hdmi_field { +@@ -45,6 +51,7 @@ enum vc4_hdmi_field { + HDMI_CEC_TX_DATA_2, + HDMI_CEC_TX_DATA_3, + HDMI_CEC_TX_DATA_4, ++ HDMI_CLOCK_STOP, + HDMI_CORE_REV, + HDMI_CRP_CFG, + HDMI_CSC_12_11, +@@ -61,6 +68,7 @@ enum vc4_hdmi_field { + */ + HDMI_CTS_0, + HDMI_CTS_1, ++ HDMI_DVP_CTL, + HDMI_FIFO_CTL, + HDMI_FRAME_COUNT, + HDMI_HORZA, +@@ -93,10 +101,27 @@ enum vc4_hdmi_field { + HDMI_RAM_PACKET_CONFIG, + HDMI_RAM_PACKET_START, + HDMI_RAM_PACKET_STATUS, ++ HDMI_RM_CONTROL, ++ HDMI_RM_FORMAT, ++ HDMI_RM_OFFSET, + HDMI_SCHEDULER_CONTROL, + HDMI_SW_RESET_CONTROL, ++ HDMI_TX_PHY_CHANNEL_SWAP, ++ HDMI_TX_PHY_CLK_DIV, + HDMI_TX_PHY_CTL_0, ++ HDMI_TX_PHY_CTL_1, ++ HDMI_TX_PHY_CTL_2, ++ HDMI_TX_PHY_CTL_3, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, ++ HDMI_TX_PHY_PLL_CFG, ++ HDMI_TX_PHY_PLL_CTL_0, ++ HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_TX_PHY_POWERDOWN_CTL, + HDMI_TX_PHY_RESET_CTL, ++ HDMI_TX_PHY_TMDS_CLK_WORD_SEL, ++ HDMI_VEC_INTERFACE_XBAR, + HDMI_VERTA0, + HDMI_VERTA1, + HDMI_VERTB0, +@@ -119,6 +144,12 @@ struct vc4_hdmi_register { + + #define VC4_HD_REG(reg, offset) _VC4_REG(VC4_HD, reg, offset) + #define VC4_HDMI_REG(reg, offset) _VC4_REG(VC4_HDMI, reg, offset) ++#define VC5_CEC_REG(reg, offset) _VC4_REG(VC5_CEC, reg, offset) ++#define VC5_CSC_REG(reg, offset) _VC4_REG(VC5_CSC, reg, offset) ++#define VC5_DVP_REG(reg, offset) _VC4_REG(VC5_DVP, reg, offset) ++#define VC5_PHY_REG(reg, offset) _VC4_REG(VC5_PHY, reg, offset) ++#define VC5_RAM_REG(reg, offset) _VC4_REG(VC5_RAM, reg, offset) ++#define VC5_RM_REG(reg, offset) _VC4_REG(VC5_RM, reg, offset) + + static const struct vc4_hdmi_register vc4_hdmi_fields[] = { + VC4_HD_REG(HDMI_M_CTL, 0x000c), +@@ -181,6 +212,158 @@ static const struct vc4_hdmi_register vc + VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400), + }; + ++static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0010), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0014), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0018), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x001c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0020), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0044), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0cc), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d0), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0e4), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0e8), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0ec), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020), ++ VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++}; ++ ++static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0030), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0034), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0038), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x003c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0040), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0048), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0cc), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d0), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0e4), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0e8), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0ec), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020), ++ VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034), ++ VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++}; ++ + static inline + void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi, + enum vc4_hdmi_regs reg) +@@ -192,6 +375,24 @@ void __iomem *__vc4_hdmi_get_field_base( + case VC4_HDMI: + return hdmi->hdmicore_regs; + ++ case VC5_CSC: ++ return hdmi->csc_regs; ++ ++ case VC5_CEC: ++ return hdmi->cec_regs; ++ ++ case VC5_DVP: ++ return hdmi->dvp_regs; ++ ++ case VC5_PHY: ++ return hdmi->phy_regs; ++ ++ case VC5_RAM: ++ return hdmi->ram_regs; ++ ++ case VC5_RM: ++ return hdmi->rm_regs; ++ + default: + return NULL; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0598-dt-bindings-display-vc4-hdmi-Add-BCM2711-HDMI-contro.patch b/target/linux/bcm27xx/patches-5.4/950-0598-dt-bindings-display-vc4-hdmi-Add-BCM2711-HDMI-contro.patch new file mode 100644 index 00000000000..c41e063fde9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0598-dt-bindings-display-vc4-hdmi-Add-BCM2711-HDMI-contro.patch @@ -0,0 +1,174 @@ +From 965351ba5a271c0a4a7776193b7af78871370f7a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Thu, 13 Feb 2020 16:45:24 +0100 +Subject: [PATCH] dt-bindings: display: vc4: hdmi: Add BCM2711 HDMI + controllers bindings + +The HDMI controllers found in the BCM2711 SoC need some adjustments to the +bindings, especially since the registers have been shuffled around in more +register ranges. + +Cc: Rob Herring +Cc: devicetree@vger.kernel.org +Signed-off-by: Maxime Ripard +--- + .../bindings/display/brcm,bcm2835-hdmi.yaml | 118 ++++++++++++++++-- + 1 file changed, 109 insertions(+), 9 deletions(-) + +--- a/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml ++++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml +@@ -11,24 +11,58 @@ maintainers: + + properties: + compatible: +- const: brcm,bcm2835-hdmi ++ enum: ++ - brcm,bcm2835-hdmi ++ - brcm,bcm2711-hdmi0 ++ - brcm,bcm2711-hdmi1 + + reg: ++ oneOf: ++ - items: ++ - description: HDMI register range ++ - description: HD register range ++ ++ - items: ++ - description: HDMI controller register range ++ - description: DVP register range ++ - description: HDMI PHY register range ++ - description: Rate Manager register range ++ - description: Packet RAM register range ++ - description: Metadata RAM register range ++ - description: CSC register range ++ - description: CEC register range ++ - description: HD register range ++ ++ reg-names: + items: +- - description: HDMI register range +- - description: HD register range ++ - const: hdmi ++ - const: dvp ++ - const: phy ++ - const: rm ++ - const: packet ++ - const: metadata ++ - const: csc ++ - const: cec ++ - const: hd + + interrupts: + minItems: 2 + + clocks: +- items: +- - description: The pixel clock +- - description: The HDMI state machine clock ++ oneOf: ++ - items: ++ - description: The pixel clock ++ - description: The HDMI state machine clock ++ ++ - items: ++ - description: The HDMI state machine clock + + clock-names: +- items: +- - const: pixel ++ oneOf: ++ - items: ++ - const: pixel ++ - const: hdmi ++ + - const: hdmi + + ddc: +@@ -51,15 +85,54 @@ properties: + dma-names: + const: audio-rx + ++ resets: ++ maxItems: 1 ++ + required: + - compatible + - reg +- - interrupts + - clocks + - ddc + + additionalProperties: false + ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - brcm,bcm2711-hdmi0 ++ - brcm,bcm2711-hdmi1 ++ ++then: ++ properties: ++ reg: ++ minItems: 9 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ maxItems: 1 ++ ++ required: ++ - reg-names ++ - resets ++ ++else: ++ properties: ++ reg: ++ maxItems: 2 ++ ++ clocks: ++ minItems: 2 ++ ++ clock-names: ++ minItems: 2 ++ ++ required: ++ - interrupts ++ + examples: + - | + #include +@@ -77,4 +150,31 @@ examples: + clock-names = "pixel", "hdmi"; + }; + ++ - | ++ hdmi0: hdmi@7ef00700 { ++ compatible = "brcm,bcm2711-hdmi0"; ++ reg = <0x7ef00700 0x300>, ++ <0x7ef00300 0x200>, ++ <0x7ef00f00 0x80>, ++ <0x7ef00f80 0x80>, ++ <0x7ef01b00 0x200>, ++ <0x7ef01f00 0x400>, ++ <0x7ef00200 0x80>, ++ <0x7ef04300 0x100>, ++ <0x7ef20000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ clocks = <&firmware_clocks 13>; ++ clock-names = "hdmi"; ++ resets = <&dvp 0>; ++ ddc = <&ddc0>; ++ }; ++ + ... diff --git a/target/linux/bcm27xx/patches-5.4/950-0599-ARM-dts-bcm2711-Enable-the-display-pipeline.patch b/target/linux/bcm27xx/patches-5.4/950-0599-ARM-dts-bcm2711-Enable-the-display-pipeline.patch new file mode 100644 index 00000000000..aae9b9e00d2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0599-ARM-dts-bcm2711-Enable-the-display-pipeline.patch @@ -0,0 +1,210 @@ +From 661edd663841d94bded4e95acfd0a4947cb079b5 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Wed, 12 Feb 2020 12:26:40 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Enable the display pipeline + +Now that all the drivers have been adjusted for it, let's bring in the +necessary device tree changes. + +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 40 ++++++++++ + arch/arm/boot/dts/bcm2711.dtsi | 110 ++++++++++++++++++++++++++ + 2 files changed, 150 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -138,6 +138,46 @@ + interrupts = ; + }; + ++&vc4 { ++ status = "okay"; ++}; ++ ++&pixelvalve0 { ++ status = "okay"; ++}; ++ ++&pixelvalve1 { ++ status = "okay"; ++}; ++ ++&pixelvalve2 { ++ status = "okay"; ++}; ++ ++&pixelvalve3 { ++ status = "okay"; ++}; ++ ++&pixelvalve4 { ++ status = "okay"; ++}; ++ ++&hdmi0 { ++ status = "okay"; ++}; ++ ++&ddc0 { ++ status = "okay"; ++}; ++ ++&hdmi1 { ++ status = "okay"; ++}; ++ ++&ddc1 { ++ status = "okay"; ++}; ++ + // ============================================= + // Downstream rpi- changes + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -31,6 +31,11 @@ + }; + }; + ++ vc4: gpu { ++ compatible = "brcm,bcm2711-vc5"; ++ status = "disabled"; ++ }; ++ + clk_108MHz: clk-108M { + #clock-cells = <0>; + compatible = "fixed-clock"; +@@ -254,6 +259,27 @@ + status = "disabled"; + }; + ++ pixelvalve0: pixelvalve@7e206000 { ++ compatible = "brcm,bcm2711-pixelvalve0"; ++ reg = <0x7e206000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pixelvalve1: pixelvalve@7e207000 { ++ compatible = "brcm,bcm2711-pixelvalve1"; ++ reg = <0x7e207000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ pixelvalve2: pixelvalve@7e20a000 { ++ compatible = "brcm,bcm2711-pixelvalve2"; ++ reg = <0x7e20a000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ + pwm1: pwm@7e20c800 { + compatible = "brcm,bcm2835-pwm"; + reg = <0x7e20c800 0x28>; +@@ -264,6 +290,13 @@ + status = "disabled"; + }; + ++ pixelvalve4: pixelvalve@7e216000 { ++ compatible = "brcm,bcm2711-pixelvalve4"; ++ reg = <0x7e216000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ + emmc2: emmc2@7e340000 { + compatible = "brcm,bcm2711-emmc2"; + reg = <0x7e340000 0x100>; +@@ -276,6 +309,13 @@ + interrupts = ; + }; + ++ pixelvalve3: pixelvalve@7ec12000 { ++ compatible = "brcm,bcm2711-pixelvalve3"; ++ reg = <0x7ec12000 0x100>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ + dvp: clock@7ef00000 { + compatible = "brcm,brcm2711-dvp"; + reg = <0x7ef00000 0x10>; +@@ -283,6 +323,76 @@ + #clock-cells = <1>; + #reset-cells = <1>; + }; ++ ++ hdmi0: hdmi@7ef00700 { ++ compatible = "brcm,bcm2711-hdmi0"; ++ reg = <0x7ef00700 0x300>, ++ <0x7ef00300 0x200>, ++ <0x7ef00f00 0x80>, ++ <0x7ef00f80 0x80>, ++ <0x7ef01b00 0x200>, ++ <0x7ef01f00 0x400>, ++ <0x7ef00200 0x80>, ++ <0x7ef04300 0x100>, ++ <0x7ef20000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ clocks = <&firmware_clocks 13>; ++ clock-names = "hdmi"; ++ resets = <&dvp 0>; ++ ddc = <&ddc0>; ++ status = "disabled"; ++ }; ++ ++ ddc0: i2c@7ef04500 { ++ compatible = "brcm,bcm2711-hdmi-i2c"; ++ reg = <0x7ef04500 0x100>, <0x7ef00b00 0x300>; ++ reg-names = "bsc", "auto-i2c"; ++ clock-frequency = <390000>; ++ status = "disabled"; ++ }; ++ ++ hdmi1: hdmi@7ef05700 { ++ compatible = "brcm,bcm2711-hdmi1"; ++ reg = <0x7ef05700 0x300>, ++ <0x7ef05300 0x200>, ++ <0x7ef05f00 0x80>, ++ <0x7ef05f80 0x80>, ++ <0x7ef06b00 0x200>, ++ <0x7ef06f00 0x400>, ++ <0x7ef00280 0x80>, ++ <0x7ef09300 0x100>, ++ <0x7ef20000 0x100>; ++ reg-names = "hdmi", ++ "dvp", ++ "phy", ++ "rm", ++ "packet", ++ "metadata", ++ "csc", ++ "cec", ++ "hd"; ++ ddc = <&ddc1>; ++ clocks = <&firmware_clocks 13>; ++ clock-names = "hdmi"; ++ resets = <&dvp 1>; ++ status = "disabled"; ++ }; ++ ++ ddc1: i2c@7ef09500 { ++ compatible = "brcm,bcm2711-hdmi-i2c"; ++ reg = <0x7ef09500 0x100>, <0x7ef05b00 0x300>; ++ reg-names = "bsc", "auto-i2c"; ++ clock-frequency = <390000>; ++ status = "disabled"; ++ }; + }; + + arm-pmu { diff --git a/target/linux/bcm27xx/patches-5.4/950-0600-DOWNSTREAM-ARM-dts-rpi4-Disable-KMS-driver-by-defaul.patch b/target/linux/bcm27xx/patches-5.4/950-0600-DOWNSTREAM-ARM-dts-rpi4-Disable-KMS-driver-by-defaul.patch new file mode 100644 index 00000000000..b27d3553405 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0600-DOWNSTREAM-ARM-dts-rpi4-Disable-KMS-driver-by-defaul.patch @@ -0,0 +1,90 @@ +From 46369abfb7dd4c33637da4340fa47a5f76f7f1c2 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard +Date: Fri, 21 Feb 2020 17:10:45 +0100 +Subject: [PATCH] ARM: dts: rpi4: Disable KMS driver by + default + +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 48 +++++++++++++++++++++++++++ + arch/arm/boot/dts/bcm2711-rpi.dtsi | 5 --- + 2 files changed, 48 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -182,6 +182,14 @@ + // Downstream rpi- changes + + #include "bcm270x.dtsi" ++ ++/ { ++ soc { ++ /delete-node/ pixelvalve@7e807000; ++ /delete-node/ hdmi@7e902000; ++ }; ++}; ++ + #include "bcm2711-rpi.dtsi" + #include "bcm283x-rpi-csi1-2lane.dtsi" + +@@ -476,6 +484,46 @@ + pinctrl-0 = <&audio_pins>; + }; + ++&vc4 { ++ status = "disabled"; ++}; ++ ++&pixelvalve0 { ++ status = "disabled"; ++}; ++ ++&pixelvalve1 { ++ status = "disabled"; ++}; ++ ++&pixelvalve2 { ++ status = "disabled"; ++}; ++ ++&pixelvalve3 { ++ status = "disabled"; ++}; ++ ++&pixelvalve4 { ++ status = "disabled"; ++}; ++ ++&hdmi0 { ++ status = "disabled"; ++}; ++ ++&ddc0 { ++ status = "disabled"; ++}; ++ ++&hdmi1 { ++ status = "disabled"; ++}; ++ ++&ddc1 { ++ status = "disabled"; ++}; ++ + / { + __overrides__ { + act_led_gpio = <&act_led>,"gpios:4"; +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -55,11 +55,6 @@ + status = "okay"; + }; + +- vc4: gpu { +- compatible = "brcm,bcm2835-vc4"; +- status = "disabled"; +- }; +- + /delete-node/ audio; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0601-dtoverlays-Add-Pi4-version-of-vc4-kms-v3d.patch b/target/linux/bcm27xx/patches-5.4/950-0601-dtoverlays-Add-Pi4-version-of-vc4-kms-v3d.patch new file mode 100644 index 00000000000..1c46fa44850 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0601-dtoverlays-Add-Pi4-version-of-vc4-kms-v3d.patch @@ -0,0 +1,241 @@ +From 7f9f7a113e9c5d6efd997de7de93af31ec286174 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 20 Sep 2019 17:20:01 +0100 +Subject: [PATCH] dtoverlays: Add Pi4 version of vc4-kms-v3d + +The Pi4 version of the KMS drivers is a work in progress, some +blocks need alternate configuration, and some blocks currently +need to remain disabled (eg the VEC). + +Add a new overlay (vc4-kms-v3d-pi4) that loads the parts of +vc4-kms that do work on Pi4. +This has been tested with DPI and HDMI (not 100% reliable on mode +switching) + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 14 ++ + .../dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 183 ++++++++++++++++++ + 3 files changed, 198 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -191,6 +191,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + vc4-fkms-v3d.dtbo \ + vc4-kms-kippah-7inch.dtbo \ + vc4-kms-v3d.dtbo \ ++ vc4-kms-v3d-pi4.dtbo \ + vga666.dtbo \ + w1-gpio.dtbo \ + w1-gpio-pullup.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2684,6 +2684,20 @@ Params: cma-256 CMA is 2 + audio Enable or disable audio over HDMI (default "on") + + ++Name: vc4-kms-v3d-pi4 ++Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver for Pi4. ++Load: dtoverlay=vc4-kms-v3d-pi4, ++Params: cma-256 CMA is 256MB ++ cma-192 CMA is 192MB ++ cma-128 CMA is 128MB ++ cma-96 CMA is 96MB ++ cma-64 CMA is 64MB ++ audio Enable or disable audio over HDMI0 (default ++ "on") ++ audio1 Enable or disable audio over HDMI1 (default ++ "on") ++ ++ + Name: vga666 + Info: Overlay for the Fen Logic VGA666 board + This uses GPIOs 2-21 (so no I2C), and activates the output 2-3 seconds +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts +@@ -0,0 +1,183 @@ ++/* ++ * vc4-kms-v3d-pi4-overlay.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "cma=256M"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=192M"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=128M"; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=96M"; ++ }; ++ }; ++ ++ fragment@4 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=64M"; ++ }; ++ }; ++ ++ fragment@5 { ++ target = <&ddc0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@6 { ++ target = <&ddc1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@7 { ++ target = <&hdmi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&hdmi1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@9 { ++ target = <&hvs>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&pixelvalve0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&pixelvalve1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&pixelvalve2>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&pixelvalve3>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@14 { ++ target = <&pixelvalve4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@15 { ++ target = <&v3d>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@16 { ++ target = <&vc4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@17 { ++ target = <&txp>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@18 { ++ target = <&fb>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@19 { ++ target = <&firmwarekms>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@20 { ++ target = <&vec>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@21 { ++ target = <&hdmi0>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ fragment@22 { ++ target = <&hdmi1>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ ++ __overrides__ { ++ cma-256 = <0>,"+0-1-2-3-4"; ++ cma-192 = <0>,"-0+1-2-3-4"; ++ cma-128 = <0>,"-0-1+2-3-4"; ++ cma-96 = <0>,"-0-1-2+3-4"; ++ cma-64 = <0>,"-0-1-2-3+4"; ++ audio = <0>,"!21"; ++ audio1 = <0>,"!22"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0602-drm-Checking-of-the-pitch-is-only-valid-for-linear-f.patch b/target/linux/bcm27xx/patches-5.4/950-0602-drm-Checking-of-the-pitch-is-only-valid-for-linear-f.patch new file mode 100644 index 00000000000..3f0aa4aa02d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0602-drm-Checking-of-the-pitch-is-only-valid-for-linear-f.patch @@ -0,0 +1,39 @@ +From 60ef8af4bc2d5f8643adbcb69bb1f52e491a96ae Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 27 Jan 2020 10:22:44 +0000 +Subject: [PATCH] drm: Checking of the pitch is only valid for linear + formats + +framebuffer_check was computing a minimum pitch value and ensuring +that the provided value was greater than this. +That check is only valid if the format is linear. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/drm_framebuffer.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/gpu/drm/drm_framebuffer.c ++++ b/drivers/gpu/drm/drm_framebuffer.c +@@ -217,12 +217,16 @@ static int framebuffer_check(struct drm_ + if (min_pitch > UINT_MAX) + return -ERANGE; + +- if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) +- return -ERANGE; ++ if (r->modifier[i] == DRM_FORMAT_MOD_LINEAR) { ++ if ((uint64_t)height * r->pitches[i] + r->offsets[i] > ++ UINT_MAX) ++ return -ERANGE; + +- if (block_size && r->pitches[i] < min_pitch) { +- DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); +- return -EINVAL; ++ if (block_size && r->pitches[i] < min_pitch) { ++ DRM_DEBUG_KMS("bad pitch %u for plane %d\n", ++ r->pitches[i], i); ++ return -EINVAL; ++ } + } + + if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0603-drm-vc4-Add-support-for-DRM_FORMAT_P030-to-vc4-plane.patch b/target/linux/bcm27xx/patches-5.4/950-0603-drm-vc4-Add-support-for-DRM_FORMAT_P030-to-vc4-plane.patch new file mode 100644 index 00000000000..9d83d8a3dde --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0603-drm-vc4-Add-support-for-DRM_FORMAT_P030-to-vc4-plane.patch @@ -0,0 +1,174 @@ +From 87c4b03b9d1180c2f878b19363ec0609b5f24c75 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 24 Jan 2020 14:25:41 +0000 +Subject: [PATCH] drm/vc4: Add support for DRM_FORMAT_P030 to vc4 + planes + +This currently doesn't handle non-zero source rectangles correctly, +but add support for DRM_FORMAT_P030 with DRM_FORMAT_MOD_BROADCOM_SAND128 +modifier to planes when running on HVS5. + +WIP still for source cropping SAND/P030 formats + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 83 +++++++++++++++++++++++---------- + 1 file changed, 59 insertions(+), 24 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -33,6 +33,7 @@ static const struct hvs_format { + u32 hvs; /* HVS_FORMAT_* */ + u32 pixel_order; + u32 pixel_order_hvs5; ++ bool hvs5_only; + } hvs_formats[] = { + { + .drm = DRM_FORMAT_XRGB8888, +@@ -128,6 +129,12 @@ static const struct hvs_format { + .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, + .pixel_order = HVS_PIXEL_ORDER_XYCRCB, + }, ++ { ++ .drm = DRM_FORMAT_P030, ++ .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT, ++ .pixel_order = HVS_PIXEL_ORDER_XYCBCR, ++ .hvs5_only = true, ++ }, + }; + + static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) +@@ -801,27 +808,33 @@ static int vc4_plane_mode_set(struct drm + uint32_t param = fourcc_mod_broadcom_param(fb->modifier); + u32 tile_w, tile, x_off, pix_per_tile; + +- hvs_format = HVS_PIXEL_FORMAT_H264; +- +- switch (base_format_mod) { +- case DRM_FORMAT_MOD_BROADCOM_SAND64: +- tiling = SCALER_CTL0_TILING_64B; +- tile_w = 64; +- break; +- case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ if (fb->format->format == DRM_FORMAT_P030) { ++ hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; + tiling = SCALER_CTL0_TILING_128B; +- tile_w = 128; +- break; +- case DRM_FORMAT_MOD_BROADCOM_SAND256: +- tiling = SCALER_CTL0_TILING_256B_OR_T; +- tile_w = 256; +- break; +- default: +- break; +- } ++ tile_w = 96; ++ } else { ++ hvs_format = HVS_PIXEL_FORMAT_H264; + ++ switch (base_format_mod) { ++ case DRM_FORMAT_MOD_BROADCOM_SAND64: ++ tiling = SCALER_CTL0_TILING_64B; ++ tile_w = 64; ++ break; ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ tiling = SCALER_CTL0_TILING_128B; ++ tile_w = 128; ++ break; ++ case DRM_FORMAT_MOD_BROADCOM_SAND256: ++ tiling = SCALER_CTL0_TILING_256B_OR_T; ++ tile_w = 256; ++ break; ++ default: ++ break; ++ } ++ } + if (param > SCALER_TILE_HEIGHT_MASK) { +- DRM_DEBUG_KMS("SAND height too large (%d)\n", param); ++ DRM_DEBUG_KMS("SAND height too large (%d)\n", ++ param); + return -EINVAL; + } + +@@ -831,6 +844,13 @@ static int vc4_plane_mode_set(struct drm + + /* Adjust the base pointer to the first pixel to be scanned + * out. ++ * ++ * For P030, y_ptr [31:4] is the 128bit word for the start pixel ++ * y_ptr [3:0] is the pixel (0-11) contained within that 128bit ++ * word that should be taken as the first pixel. ++ * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the ++ * element within the 128bit word, eg for pixel 3 the value ++ * should be 6. + */ + for (i = 0; i < num_planes; i++) { + vc4_state->offsets[i] += param * tile_w * tile; +@@ -943,8 +963,8 @@ static int vc4_plane_mode_set(struct drm + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(state->alpha >> 4, + SCALER5_CTL2_ALPHA) | +- fb->format->has_alpha ? +- SCALER5_CTL2_ALPHA_PREMULT : 0 | ++ (fb->format->has_alpha ? ++ SCALER5_CTL2_ALPHA_PREMULT : 0) | + (mix_plane_alpha ? + SCALER5_CTL2_ALPHA_MIX : 0) | + VC4_SET_FIELD(fb->format->has_alpha ? +@@ -992,7 +1012,8 @@ static int vc4_plane_mode_set(struct drm + + /* Pitch word 1/2 */ + for (i = 1; i < num_planes; i++) { +- if (hvs_format != HVS_PIXEL_FORMAT_H264) { ++ if (hvs_format != HVS_PIXEL_FORMAT_H264 && ++ hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) { + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(fb->pitches[i], + SCALER_SRC_PITCH)); +@@ -1361,6 +1382,13 @@ static bool vc4_format_mod_supported(str + default: + return false; + } ++ case DRM_FORMAT_P030: ++ switch (fourcc_mod_broadcom_mod(modifier)) { ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ return true; ++ default: ++ return false; ++ } + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_RGBA1010102: +@@ -1393,8 +1421,11 @@ struct drm_plane *vc4_plane_init(struct + struct drm_plane *plane = NULL; + struct vc4_plane *vc4_plane; + u32 formats[ARRAY_SIZE(hvs_formats)]; ++ int num_formats = 0; + int ret = 0; + unsigned i; ++ bool hvs5 = of_device_is_compatible(dev->dev->of_node, ++ "brcm,bcm2711-vc5"); + static const uint64_t modifiers[] = { + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, + DRM_FORMAT_MOD_BROADCOM_SAND128, +@@ -1409,13 +1440,17 @@ struct drm_plane *vc4_plane_init(struct + if (!vc4_plane) + return ERR_PTR(-ENOMEM); + +- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) +- formats[i] = hvs_formats[i].drm; ++ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { ++ if (hvs_formats[i].hvs5_only || hvs5) { ++ formats[num_formats] = hvs_formats[i].drm; ++ num_formats++; ++ } ++ } + + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0, + &vc4_plane_funcs, +- formats, ARRAY_SIZE(formats), ++ formats, num_formats, + modifiers, type, NULL); + + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); diff --git a/target/linux/bcm27xx/patches-5.4/950-0604-Fixup-P030-support.patch b/target/linux/bcm27xx/patches-5.4/950-0604-Fixup-P030-support.patch new file mode 100644 index 00000000000..a24127e6f28 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0604-Fixup-P030-support.patch @@ -0,0 +1,26 @@ +From 63423f4f48afc96949a63c53203faa904a85670b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 25 Feb 2020 17:35:10 +0000 +Subject: [PATCH] Fixup P030 support + +I got the logic wrong for enabling pixel formats, resulting in +Pi0-3 only getting a single, invalid, format (P030 SAND). + +Fixes: e07ef1d drm/vc4: Add support for DRM_FORMAT_P030 to vc4 planes + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -1441,7 +1441,7 @@ struct drm_plane *vc4_plane_init(struct + return ERR_PTR(-ENOMEM); + + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { +- if (hvs_formats[i].hvs5_only || hvs5) { ++ if (!hvs_formats[i].hvs5_only || hvs5) { + formats[num_formats] = hvs_formats[i].drm; + num_formats++; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0605-drm-vc4-The-check-for-assigned-HVS-channels-is-not-a.patch b/target/linux/bcm27xx/patches-5.4/950-0605-drm-vc4-The-check-for-assigned-HVS-channels-is-not-a.patch new file mode 100644 index 00000000000..00a65a9b111 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0605-drm-vc4-The-check-for-assigned-HVS-channels-is-not-a.patch @@ -0,0 +1,33 @@ +From 76534156ad6e835ad89135210d565dd5f58e91ab Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 11 Feb 2020 15:36:59 +0000 +Subject: [PATCH] drm/vc4: The check for assigned HVS channels is not + applicable firmware_kms + +Channel assignments is only in full KMS, so skip the check +if in firmware kms mode. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -579,6 +579,7 @@ static int + vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) + { + unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0); ++ struct vc4_dev *vc4 = to_vc4_dev(state->dev); + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i, ret; +@@ -590,7 +591,7 @@ vc4_atomic_check(struct drm_device *dev, + bool is_assigned = false; + unsigned int channel; + +- if (!crtc_state->active) ++ if (!crtc_state->active || vc4->firmware_kms) + continue; + + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0606-dt-Update-v3d-to-use-firmware_clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0606-dt-Update-v3d-to-use-firmware_clocks.patch new file mode 100644 index 00000000000..b67f38782fe --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0606-dt-Update-v3d-to-use-firmware_clocks.patch @@ -0,0 +1,23 @@ +From 310d91d120b672d13d83fd4ab7cfb9cff485a1de Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 17 Feb 2020 11:37:21 +0000 +Subject: [PATCH] dt: Update v3d to use firmware_clocks. + +Use the updated DT clock-names property to map the v3d clock +to the firmware_clocks driver, instead of the older clkdev API. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -34,6 +34,7 @@ + power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; + resets = <&pm BCM2835_RESET_V3D>; + clocks = <&firmware_clocks 5>; ++ clocks-names = "v3d"; + interrupts = ; + status = "disabled"; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0607-drm-vc4-Reset-audio-infoframe-on-encoder_enable-if-p.patch b/target/linux/bcm27xx/patches-5.4/950-0607-drm-vc4-Reset-audio-infoframe-on-encoder_enable-if-p.patch new file mode 100644 index 00000000000..56106a42743 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0607-drm-vc4-Reset-audio-infoframe-on-encoder_enable-if-p.patch @@ -0,0 +1,72 @@ +From 3e45488069e20b07b83d8cbba88c7fa2b205e559 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:01:04 +0000 +Subject: [PATCH] drm/vc4: Reset audio infoframe on encoder_enable if + previously streaming + +If the encoder is disabled and re-enabled (eg mode change) all infoframes +are reset, whilst the audio subsystem know nothing about this change. +The driver therefore needs to reinstate the audio infoframe for +itself. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi.h | 2 ++ + 2 files changed, 14 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -344,8 +344,16 @@ static void vc4_hdmi_set_audio_infoframe + + static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) + { ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ + vc4_hdmi_set_avi_infoframe(encoder); + vc4_hdmi_set_spd_infoframe(encoder); ++ /* ++ * If audio was streaming, then we need to reenabled the audio ++ * infoframe here during encoder_enable. ++ */ ++ if (vc4_hdmi->audio.streaming) ++ vc4_hdmi_set_audio_infoframe(encoder); + } + + static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) +@@ -825,6 +833,7 @@ static void vc4_hdmi_audio_reset(struct + struct device *dev = &vc4_hdmi->pdev->dev; + int ret; + ++ vc4_hdmi->audio.streaming = false; + ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); + if (ret) + dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); +@@ -928,6 +937,7 @@ static int vc4_hdmi_audio_trigger(struct + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + vc4_hdmi_set_audio_infoframe(encoder); ++ vc4_hdmi->audio.streaming = true; + + if (vc4_hdmi->variant->phy_rng_enable) + vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); +@@ -946,6 +956,8 @@ static int vc4_hdmi_audio_trigger(struct + if (vc4_hdmi->variant->phy_rng_disable) + vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); + ++ vc4_hdmi->audio.streaming = false; ++ + break; + default: + break; +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -101,6 +101,8 @@ struct vc4_hdmi_audio { + int channels; + struct snd_dmaengine_dai_dma_data dma_data; + struct snd_pcm_substream *substream; ++ ++ bool streaming; + }; + + /* General HDMI hardware state. */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0608-drm-vc4-Set-the-b-frame-marker-to-the-match-ALSA-s-d.patch b/target/linux/bcm27xx/patches-5.4/950-0608-drm-vc4-Set-the-b-frame-marker-to-the-match-ALSA-s-d.patch new file mode 100644 index 00000000000..4827f960231 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0608-drm-vc4-Set-the-b-frame-marker-to-the-match-ALSA-s-d.patch @@ -0,0 +1,31 @@ +From 1cf3e20f13378430cd1fc929548bca9f5e517afe Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:03:42 +0000 +Subject: [PATCH] drm/vc4: Set the b-frame marker to the match ALSA's + default. + +ALSA's iec958 plugin by default sets the block start preamble +to 8, whilst this driver was programming the hardware to expect +0xF. +Amend the hardware config to match ALSA. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -885,10 +885,11 @@ static int vc4_hdmi_audio_hw_params(stru + + vc4_hdmi_audio_set_mai_clock(vc4_hdmi); + ++ /* The B frame identifier should match the value used by alsa-lib (8) */ + audio_packet_config = + VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT | + VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | +- VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); ++ VC4_SET_FIELD(0x8, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); + + channel_mask = GENMASK(vc4_hdmi->audio.channels - 1, 0); + audio_packet_config |= VC4_SET_FIELD(channel_mask, diff --git a/target/linux/bcm27xx/patches-5.4/950-0609-dts-Add-reg-names-for-the-HDMI-registers-on-bcm2835.patch b/target/linux/bcm27xx/patches-5.4/950-0609-dts-Add-reg-names-for-the-HDMI-registers-on-bcm2835.patch new file mode 100644 index 00000000000..65e206c1813 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0609-dts-Add-reg-names-for-the-HDMI-registers-on-bcm2835.patch @@ -0,0 +1,27 @@ +From 9f7718ae7edcf5feab81d3c8561e6c5112e0b462 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:07:19 +0000 +Subject: [PATCH] dts: Add reg-names for the HDMI registers on bcm2835 + +Pi4 is requiring many more register configs in the HDMI +block, and has switched to using reg-names instead of fixed index +values. + +Switch bc2835-common to match. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2835-common.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm/boot/dts/bcm2835-common.dtsi ++++ b/arch/arm/boot/dts/bcm2835-common.dtsi +@@ -110,6 +110,8 @@ + compatible = "brcm,bcm2835-hdmi"; + reg = <0x7e902000 0x600>, + <0x7e808000 0x100>; ++ reg-names = "hdmi", ++ "hd"; + interrupts = <2 8>, <2 9>; + ddc = <&i2c2>; + clocks = <&clocks BCM2835_PLLH_PIX>, diff --git a/target/linux/bcm27xx/patches-5.4/950-0610-dt-Add-HDMI-audio-dma-values-to-bcm2711.dtsi.patch b/target/linux/bcm27xx/patches-5.4/950-0610-dt-Add-HDMI-audio-dma-values-to-bcm2711.dtsi.patch new file mode 100644 index 00000000000..9a9fd06eebc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0610-dt-Add-HDMI-audio-dma-values-to-bcm2711.dtsi.patch @@ -0,0 +1,32 @@ +From 4a3b5d7018f3b0d66f412b0b1500b76ab089a2c9 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:08:39 +0000 +Subject: [PATCH] dt: Add HDMI audio dma values to bcm2711.dtsi + +Adds the relevant DMA settings for HDMI audio to work. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2711.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -348,6 +348,8 @@ + clock-names = "hdmi"; + resets = <&dvp 0>; + ddc = <&ddc0>; ++ dmas = <&dma 10>; ++ dma-names = "audio-rx"; + status = "disabled"; + }; + +@@ -383,6 +385,8 @@ + clocks = <&firmware_clocks 13>; + clock-names = "hdmi"; + resets = <&dvp 1>; ++ dmas = <&dma 17>; ++ dma-names = "audio-rx"; + status = "disabled"; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0611-drm-vc4-Use-reg-names-to-configure-HDMI-audio.patch b/target/linux/bcm27xx/patches-5.4/950-0611-drm-vc4-Use-reg-names-to-configure-HDMI-audio.patch new file mode 100644 index 00000000000..2504a07083e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0611-drm-vc4-Use-reg-names-to-configure-HDMI-audio.patch @@ -0,0 +1,35 @@ +From 7a463d59a0539cdf79ee6f1fe6c52f0a487ee63e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:11:41 +0000 +Subject: [PATCH] drm/vc4: Use reg-names to configure HDMI audio. + +HDMI audio configuration was using fixed index numbers to +load in DT register settings. +Switch to using reg-names for flexibility and to match Pi4. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1097,6 +1097,7 @@ static int vc4_hdmi_audio_init(struct vc + struct snd_soc_card *card = &vc4_hdmi->audio.card; + struct device *dev = &vc4_hdmi->pdev->dev; + const __be32 *addr; ++ int index; + int ret; + int len; + +@@ -1122,7 +1123,9 @@ static int vc4_hdmi_audio_init(struct vc + * for DMA transfers. + * This VC/MMU should probably be exposed to avoid this kind of hacks. + */ +- addr = of_get_address(dev->of_node, 1, NULL, NULL); ++ index = of_property_match_string(dev->of_node, "reg-names", "hd"); ++ addr = of_get_address(dev->of_node, index, NULL, NULL); ++ + vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset; + vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + vc4_hdmi->audio.dma_data.maxburst = 2; diff --git a/target/linux/bcm27xx/patches-5.4/950-0612-drm-vc4-Add-audio-initialisation-for-Pi4.patch b/target/linux/bcm27xx/patches-5.4/950-0612-drm-vc4-Add-audio-initialisation-for-Pi4.patch new file mode 100644 index 00000000000..6ec6850866d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0612-drm-vc4-Add-audio-initialisation-for-Pi4.patch @@ -0,0 +1,127 @@ +From 727b5180ec09faab313d7e2517e225001c967bb0 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:16:14 +0000 +Subject: [PATCH] drm/vc4: Add audio initialisation for Pi4. + +The audio configuration has changed for Pi4, so support the +configuration functions via the variant tables. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 51 ++++++++++++++++++++++++++++------ + drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++ + 2 files changed, 49 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -742,10 +742,44 @@ static const struct drm_encoder_helper_f + .enable = vc4_hdmi_encoder_enable, + }; + ++static u32 vc4_hdmi_get_hsm_clock(struct vc4_hdmi *vc4_hdmi) ++{ ++ return clk_get_rate(vc4_hdmi->hsm_clock); ++} ++ ++static u32 vc5_hdmi_get_hsm_clock(struct vc4_hdmi *vc4_hdmi) ++{ ++ return 108000000; ++} ++ ++static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) ++{ ++ int i; ++ u32 channel_map = 0; ++ ++ for (i = 0; i < 8; i++) { ++ if (channel_mask & BIT(i)) ++ channel_map |= i << (3 * i); ++ } ++ return channel_map; ++} ++ ++static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) ++{ ++ int i; ++ u32 channel_map = 0; ++ ++ for (i = 0; i < 8; i++) { ++ if (channel_mask & BIT(i)) ++ channel_map |= i << (4 * i); ++ } ++ return channel_map; ++} ++ + /* HDMI audio codec callbacks */ + static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi) + { +- u32 hsm_clock = clk_get_rate(vc4_hdmi->hsm_clock); ++ u32 hsm_clock = vc4_hdmi->variant->get_hsm_clock(vc4_hdmi); + unsigned long n, m; + + rational_best_approximation(hsm_clock, vc4_hdmi->audio.samplerate, +@@ -864,7 +898,7 @@ static int vc4_hdmi_audio_hw_params(stru + struct vc4_hdmi *vc4_hdmi = dai_to_hdmi(dai); + struct device *dev = &vc4_hdmi->pdev->dev; + u32 audio_packet_config, channel_mask; +- u32 channel_map, i; ++ u32 channel_map; + + if (substream != vc4_hdmi->audio.substream) + return -EINVAL; +@@ -916,12 +950,7 @@ static int vc4_hdmi_audio_hw_params(stru + VC4_HDMI_MAI_CONFIG_BIT_REVERSE | + VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK)); + +- channel_map = 0; +- for (i = 0; i < 8; i++) { +- if (channel_mask & BIT(i)) +- channel_map |= i << (3 * i); +- } +- ++ channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask); + HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map); + HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); + vc4_hdmi_set_n_cts(vc4_hdmi); +@@ -1715,6 +1744,8 @@ static const struct vc4_hdmi_variant bcm + .phy_disable = vc4_hdmi_phy_disable, + .phy_rng_enable = vc4_hdmi_phy_rng_enable, + .phy_rng_disable = vc4_hdmi_phy_rng_disable, ++ .get_hsm_clock = vc4_hdmi_get_hsm_clock, ++ .channel_map = vc4_hdmi_channel_map, + }; + + static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { +@@ -1736,6 +1767,8 @@ static const struct vc4_hdmi_variant bcm + .phy_init = vc5_hdmi_phy_init, + .phy_rng_enable = vc5_hdmi_phy_rng_enable, + .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++ .get_hsm_clock = vc5_hdmi_get_hsm_clock, ++ .channel_map = vc5_hdmi_channel_map, + }; + + static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { +@@ -1757,6 +1790,8 @@ static const struct vc4_hdmi_variant bcm + .phy_init = vc5_hdmi_phy_init, + .phy_rng_enable = vc5_hdmi_phy_rng_enable, + .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++ .get_hsm_clock = vc5_hdmi_get_hsm_clock, ++ .channel_map = vc5_hdmi_channel_map, + }; + + static const struct of_device_id vc4_hdmi_dt_match[] = { +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -88,6 +88,12 @@ struct vc4_hdmi_variant { + + /* Callback to disable the RNG in the PHY */ + void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to get hsm clock */ ++ u32 (*get_hsm_clock)(struct vc4_hdmi *vc4_hdmi); ++ ++ /* Callback to get channel map */ ++ u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask); + }; + + /* HDMI audio information */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0613-drm-vc4-Enable-audio-on-Pi4.patch b/target/linux/bcm27xx/patches-5.4/950-0613-drm-vc4-Enable-audio-on-Pi4.patch new file mode 100644 index 00000000000..78340ced705 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0613-drm-vc4-Enable-audio-on-Pi4.patch @@ -0,0 +1,31 @@ +From 446b19807781d73f214f959a8f4dab7662eed337 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:18:45 +0000 +Subject: [PATCH] drm/vc4: Enable audio on Pi4. + +This could be a revert of "drm/vc4: hdmi: Add an audio support flag" +as it is no longer needed. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1750,6 +1750,7 @@ static const struct vc4_hdmi_variant bcm + + static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { + .id = 0, ++ .audio_available = true, + .max_pixel_clock = 297000000, + .registers = vc5_hdmi_hdmi0_fields, + .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields), +@@ -1773,6 +1774,7 @@ static const struct vc4_hdmi_variant bcm + + static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { + .id = 1, ++ .audio_available = true, + .max_pixel_clock = 297000000, + .registers = vc5_hdmi_hdmi1_fields, + .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields), diff --git a/target/linux/bcm27xx/patches-5.4/950-0614-drm-vc4-Alter-the-HDMI-state-machine-clock-calc-to-a.patch b/target/linux/bcm27xx/patches-5.4/950-0614-drm-vc4-Alter-the-HDMI-state-machine-clock-calc-to-a.patch new file mode 100644 index 00000000000..f576b8624e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0614-drm-vc4-Alter-the-HDMI-state-machine-clock-calc-to-a.patch @@ -0,0 +1,46 @@ +From 37b204f22778f51cad7bdf678d7574ff6d7508a6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 25 Mar 2020 18:22:40 +0000 +Subject: [PATCH] drm/vc4: Alter the HDMI state machine clock calc to + allow for 1920x1200 + +Whilst the documentation for BCM2835 states that the HDMI state machine +clock needs to be 108% of the pixel clock, other documentation says +that it only has to be greater than the pixel clock. The firmware +uses 101%, and that allows 1920x1200@60Hz to work within the +constraint of the HSM clock being < 163.68MHz. + +Adopt 101%, and increase the maximum pixel clock for vc4 to 162MHz +so that it too supports 1920x1200@60. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -581,10 +581,11 @@ static void vc4_hdmi_encoder_enable(stru + } + + /* +- * The HSM rate needs to be at 108% of the pixel clock, with a +- * minimum of 108MHz. ++ * The HSM rate needs to be slightly greater than the pixel clock, with ++ * a minimum of 108MHz. ++ * Use 101% as this is what the firmware uses. + */ +- hsm_rate = max_t(unsigned long, 108000000, (pixel_rate / 100) * 108); ++ hsm_rate = max_t(unsigned long, 108000000, (pixel_rate / 100) * 101); + ret = clk_set_rate(vc4_hdmi->hsm_clock, hsm_rate); + if (ret) { + DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); +@@ -1730,7 +1731,7 @@ static int vc4_hdmi_dev_remove(struct pl + } + + static const struct vc4_hdmi_variant bcm2835_variant = { +- .max_pixel_clock = 148500000, ++ .max_pixel_clock = 162000000, + .audio_available = true, + .cec_available = true, + .registers = vc4_hdmi_fields, diff --git a/target/linux/bcm27xx/patches-5.4/950-0615-dtoverlays-Remove-comment-about-vc4-kms-v3d-locking-.patch b/target/linux/bcm27xx/patches-5.4/950-0615-dtoverlays-Remove-comment-about-vc4-kms-v3d-locking-.patch new file mode 100644 index 00000000000..a05bf055ff4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0615-dtoverlays-Remove-comment-about-vc4-kms-v3d-locking-.patch @@ -0,0 +1,28 @@ +From 11d932df7f39124645cd017eb00853b4a70c28b4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 26 Mar 2020 11:51:55 +0000 +Subject: [PATCH] dtoverlays: Remove comment about vc4-kms-v3d locking + up X from README + +Using vc4-kms-v3d with X has worked for quite a while, and essentially +required not using fbturbo and having an up to date MESA library. +Remove the comment that says otherwise. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/overlays/README | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2672,9 +2672,7 @@ Params: + + + Name: vc4-kms-v3d +-Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. Running startx or +- booting to GUI while this overlay is in use will cause interesting +- lockups. ++Info: Enable Eric Anholt's DRM VC4 HDMI/HVS/V3D driver. + Load: dtoverlay=vc4-kms-v3d, + Params: cma-256 CMA is 256MB (needs 1GB) + cma-192 CMA is 192MB (needs 1GB) diff --git a/target/linux/bcm27xx/patches-5.4/950-0616-drm-vc4-Kick-the-core-clock-up-during-a-mode-change.patch b/target/linux/bcm27xx/patches-5.4/950-0616-drm-vc4-Kick-the-core-clock-up-during-a-mode-change.patch new file mode 100644 index 00000000000..871d86a7a98 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0616-drm-vc4-Kick-the-core-clock-up-during-a-mode-change.patch @@ -0,0 +1,97 @@ +From 289c29b96fcc6cbe5c966fb0cc9e1bb8efbdd9dc Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 26 Mar 2020 15:32:19 +0000 +Subject: [PATCH] drm/vc4: Kick the core clock up during a mode change + +Experimental commit to kick the core clock up during mode +switching. This makes mode switching far more reliable, and +mimics what the firmware does. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2711.dtsi | 1 + + drivers/gpu/drm/vc4/vc4_drv.h | 2 ++ + drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++++++ + drivers/gpu/drm/vc4/vc4_kms.c | 6 ++++++ + 4 files changed, 16 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -306,6 +306,7 @@ + }; + + hvs@7e400000 { ++ clocks = <&firmware_clocks 4>; + interrupts = ; + }; + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -326,6 +326,8 @@ struct vc4_hvs { + void __iomem *regs; + u32 __iomem *dlist; + ++ struct clk *core_clk; ++ + /* Memory manager for CRTCs to allocate space in the display + * list. Units are dwords. + */ +--- a/drivers/gpu/drm/vc4/vc4_hvs.c ++++ b/drivers/gpu/drm/vc4/vc4_hvs.c +@@ -19,6 +19,7 @@ + * each CRTC. + */ + ++#include + #include + #include + +@@ -239,6 +240,12 @@ static int vc4_hvs_bind(struct device *d + hvs->regset.regs = hvs_regs; + hvs->regset.nregs = ARRAY_SIZE(hvs_regs); + ++ hvs->core_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(hvs->core_clk)) { ++ dev_err(&pdev->dev, "Couldn't get core clock\n"); ++ return PTR_ERR(hvs->regs); ++ } ++ + hvs_version = readl(hvs->regs + SCALER_DISPLSTAT) >> 24; + if (hvs_version >= 0x40) + hvs->hvs5 = true; +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + + #include + #include +@@ -222,6 +223,7 @@ vc4_atomic_complete_commit(struct drm_at + { + struct drm_device *dev = state->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_hvs *hvs = vc4->hvs; + struct vc4_crtc *vc4_crtc; + int i; + +@@ -237,6 +239,8 @@ vc4_atomic_complete_commit(struct drm_at + vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel); + } + ++ clk_set_rate(hvs->core_clk, 500000000); ++ + drm_atomic_helper_wait_for_fences(dev, state, false); + + drm_atomic_helper_wait_for_dependencies(state); +@@ -262,6 +266,8 @@ vc4_atomic_complete_commit(struct drm_at + + drm_atomic_helper_commit_cleanup_done(state); + ++ clk_set_rate(hvs->core_clk, 200000000); ++ + drm_atomic_state_put(state); + + up(&vc4->async_modeset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0617-drm-vc4-Fixup-for-firmware-KMS.patch b/target/linux/bcm27xx/patches-5.4/950-0617-drm-vc4-Fixup-for-firmware-KMS.patch new file mode 100644 index 00000000000..62080bffec5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0617-drm-vc4-Fixup-for-firmware-KMS.patch @@ -0,0 +1,36 @@ +From 3c10a82ae5ce60ee8b4dbd1d1f8436efaa4593c3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 30 Mar 2020 12:52:26 +0100 +Subject: [PATCH] drm/vc4: Fixup for firmware KMS + +Fix up "drm/vc4: Kick the core clock up during a mode change" for +firmware KMS mode where we don't have the HVS or core clock +configured. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -239,7 +239,8 @@ vc4_atomic_complete_commit(struct drm_at + vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel); + } + +- clk_set_rate(hvs->core_clk, 500000000); ++ if (!vc4->firmware_kms) ++ clk_set_rate(hvs->core_clk, 500000000); + + drm_atomic_helper_wait_for_fences(dev, state, false); + +@@ -266,7 +267,8 @@ vc4_atomic_complete_commit(struct drm_at + + drm_atomic_helper_commit_cleanup_done(state); + +- clk_set_rate(hvs->core_clk, 200000000); ++ if (!vc4->firmware_kms) ++ clk_set_rate(hvs->core_clk, 200000000); + + drm_atomic_state_put(state); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0618-drm-vc4-Fixup-plane-init-within-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0618-drm-vc4-Fixup-plane-init-within-firmware-kms.patch new file mode 100644 index 00000000000..8edba988f2b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0618-drm-vc4-Fixup-plane-init-within-firmware-kms.patch @@ -0,0 +1,31 @@ +From d39fee7763d49f3b0bfd57e6cdc014467415d56a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 30 Mar 2020 18:25:10 +0100 +Subject: [PATCH] drm/vc4: Fixup plane init within firmware-kms + +"drm/vc4: plane: Move additional planes creation to driver" moved +overlay and cursor plane creation to a global function thata was +unconditionally run, when it is not wanted in firmware KMS mode. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.c ++++ b/drivers/gpu/drm/vc4/vc4_drv.c +@@ -291,9 +291,11 @@ static int vc4_drm_bind(struct device *d + if (ret) + goto gem_destroy; + +- ret = vc4_plane_create_additional_planes(drm); +- if (ret) +- goto unbind_all; ++ if (!vc4->firmware_kms) { ++ ret = vc4_plane_create_additional_planes(drm); ++ if (ret) ++ goto unbind_all; ++ } + + drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0619-drm-vc4-hdmi-Give-the-HDMI-audio-instances-different.patch b/target/linux/bcm27xx/patches-5.4/950-0619-drm-vc4-hdmi-Give-the-HDMI-audio-instances-different.patch new file mode 100644 index 00000000000..a7b5b5fad3c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0619-drm-vc4-hdmi-Give-the-HDMI-audio-instances-different.patch @@ -0,0 +1,26 @@ +From 992513ac2ec9245cb8f0fdd9c0e2ce4add07beb2 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 31 Mar 2020 16:21:45 +0100 +Subject: [PATCH] drm/vc4-hdmi: Give the HDMI audio instances different + names + +The debugfs usage within asoc gets confused if multiple interfaces +have the same card name, therefore use unique names when +initialising them. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1198,7 +1198,7 @@ static int vc4_hdmi_audio_init(struct vc + + card->dai_link = dai_link; + card->num_links = 1; +- card->name = "vc4-hdmi"; ++ card->name = vc4_hdmi->variant->id ? "vc4-hdmi1" : "vc4-hdmi"; + card->dev = dev; + + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0620-i2c-brcmstb-The-interrupt-line-is-optional-so-use-pl.patch b/target/linux/bcm27xx/patches-5.4/950-0620-i2c-brcmstb-The-interrupt-line-is-optional-so-use-pl.patch new file mode 100644 index 00000000000..89285ad25c1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0620-i2c-brcmstb-The-interrupt-line-is-optional-so-use-pl.patch @@ -0,0 +1,49 @@ +From 8aa48c2a3fa470d348104e8f8aa558a661b724e5 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 31 Mar 2020 16:23:11 +0100 +Subject: [PATCH] i2c: brcmstb: The interrupt line is optional, so use + platform_get_irq_optional + +If there is no interrupt defined then an error is logged due +to the use of platform_get_irq. The driver handles not having +the interrupt by falling back to polling, therefore make +the appropriate call when claiming it. + +Signed-off-by: Dave Stevenson +--- + drivers/i2c/busses/i2c-brcmstb.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/i2c/busses/i2c-brcmstb.c ++++ b/drivers/i2c/busses/i2c-brcmstb.c +@@ -647,20 +647,22 @@ static int brcmstb_i2c_probe(struct plat + int_name = NULL; + + /* Get the interrupt number */ +- dev->irq = platform_get_irq(pdev, 0); ++ dev->irq = platform_get_irq_optional(pdev, 0); + + /* disable the bsc interrupt line */ + brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); + + /* register the ISR handler */ +- rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr, +- IRQF_SHARED, +- int_name ? int_name : pdev->name, +- dev); ++ if (dev->irq >= 0) { ++ rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr, ++ IRQF_SHARED, ++ int_name ? int_name : pdev->name, ++ dev); + +- if (rc) { +- dev_dbg(dev->device, "falling back to polling mode"); +- dev->irq = -1; ++ if (rc) { ++ dev_dbg(dev->device, "falling back to polling mode"); ++ dev->irq = -1; ++ } + } + + if (of_property_read_u32(dev->device->of_node, diff --git a/target/linux/bcm27xx/patches-5.4/950-0621-dt-Drop-I2C-for-Pi4-HDMI-interfaces-to-97.5kHz.patch b/target/linux/bcm27xx/patches-5.4/950-0621-dt-Drop-I2C-for-Pi4-HDMI-interfaces-to-97.5kHz.patch new file mode 100644 index 00000000000..cd18cd1309a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0621-dt-Drop-I2C-for-Pi4-HDMI-interfaces-to-97.5kHz.patch @@ -0,0 +1,35 @@ +From 460ddd2729f0dbb2723e48f3a22ffccbb78b42c7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 31 Mar 2020 17:54:08 +0100 +Subject: [PATCH] dt: Drop I2C for Pi4 HDMI interfaces to 97.5kHz. + +It was set to 390kHz, which is outside of the required spec for +reading HDMI (max 100kHz). The i2c-brcmstb driver only supports +a number of fixed bus speeds, of which 97.5kHz is the closest to +100kHz without exceeding it. + +Signed-off-by: Dave Stevenson +--- + arch/arm/boot/dts/bcm2711.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -358,7 +358,7 @@ + compatible = "brcm,bcm2711-hdmi-i2c"; + reg = <0x7ef04500 0x100>, <0x7ef00b00 0x300>; + reg-names = "bsc", "auto-i2c"; +- clock-frequency = <390000>; ++ clock-frequency = <97500>; + status = "disabled"; + }; + +@@ -395,7 +395,7 @@ + compatible = "brcm,bcm2711-hdmi-i2c"; + reg = <0x7ef09500 0x100>, <0x7ef05b00 0x300>; + reg-names = "bsc", "auto-i2c"; +- clock-frequency = <390000>; ++ clock-frequency = <97500>; + status = "disabled"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0622-overlays-Add-missing-rpi-poe-parameters.patch b/target/linux/bcm27xx/patches-5.4/950-0622-overlays-Add-missing-rpi-poe-parameters.patch new file mode 100644 index 00000000000..716678f078e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0622-overlays-Add-missing-rpi-poe-parameters.patch @@ -0,0 +1,39 @@ +From bb766b0401a49f4a824dd116b9befe8542fe3cd6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 27 Mar 2020 13:49:25 +0000 +Subject: [PATCH] overlays: Add missing rpi-poe parameters + +The rpi-poe fan overlay has gained two more fan speeds and adjusted +the thresholds and hystereses. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2037,12 +2037,20 @@ Name: rpi-poe + Info: Raspberry Pi PoE HAT fan + Load: dtoverlay=rpi-poe,[=] + Params: poe_fan_temp0 Temperature (in millicelcius) at which the fan +- turns on (default 50000) ++ turns on (default 40000) + poe_fan_temp0_hyst Temperature delta (in millicelcius) at which +- the fan turns off (default 5000) ++ the fan turns off (default 2000) + poe_fan_temp1 Temperature (in millicelcius) at which the fan +- speeds up (default 55000) ++ speeds up (default 45000) + poe_fan_temp1_hyst Temperature delta (in millicelcius) at which ++ the fan slows down (default 2000) ++ poe_fan_temp2 Temperature (in millicelcius) at which the fan ++ speeds up (default 50000) ++ poe_fan_temp2_hyst Temperature delta (in millicelcius) at which ++ the fan slows down (default 2000) ++ poe_fan_temp3 Temperature (in millicelcius) at which the fan ++ speeds up (default 55000) ++ poe_fan_temp3_hyst Temperature delta (in millicelcius) at which + the fan slows down (default 5000) + + diff --git a/target/linux/bcm27xx/patches-5.4/950-0623-vc4_hdmi_phy-Fix-offset-calculation.patch b/target/linux/bcm27xx/patches-5.4/950-0623-vc4_hdmi_phy-Fix-offset-calculation.patch new file mode 100644 index 00000000000..83d8d25e29f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0623-vc4_hdmi_phy-Fix-offset-calculation.patch @@ -0,0 +1,30 @@ +From 9da2d153eb010d3e92083c322e87de9ae066d93e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 2 Apr 2020 16:46:31 +0100 +Subject: [PATCH] vc4_hdmi_phy: Fix offset calculation + +The original firmware code worked with float and did + offset = ((vco_freq / fref * 2) * (1 << 22)); + offset >>= 2; + +In this code it's all integer so doing the integer divide before the shift loses lots of precision + +This fixes the issue of 1080p59.94 mode having 59.64 fps + +Signed-off-by: popcornmix +--- + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -192,8 +192,8 @@ static u32 phy_get_rm_offset(unsigned lo + + /* RM offset is stored as 9.22 format */ + offset = vco_freq * 2; +- do_div(offset, fref); + offset = offset << 22; ++ do_div(offset, fref); + offset >>= 2; + + return offset; diff --git a/target/linux/bcm27xx/patches-5.4/950-0624-overlays-Add-overlay_map.patch b/target/linux/bcm27xx/patches-5.4/950-0624-overlays-Add-overlay_map.patch new file mode 100644 index 00000000000..20f548328c4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0624-overlays-Add-overlay_map.patch @@ -0,0 +1,101 @@ +From b9b7a84463d95fd912406e377a58af8b1fb81d21 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 1 Apr 2020 15:09:42 +0100 +Subject: [PATCH] overlays: Add overlay_map + +The overlay map permits platform-specific overlays, with deprecation +and renaming. + +See: https://github.com/raspberrypi/linux/issues/3520 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/Makefile | 2 + + arch/arm/boot/dts/overlays/overlay_map.dts | 71 ++++++++++++++++++++++ + 2 files changed, 73 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/overlay_map.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -1,5 +1,7 @@ + # Overlays for the Raspberry Pi platform + ++dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb ++ + dtbo-$(CONFIG_ARCH_BCM2835) += \ + act-led.dtbo \ + adau1977-adc.dtbo \ +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -0,0 +1,71 @@ ++/dts-v1/; ++ ++/ { ++ i2c3 { ++ bcm2711; ++ }; ++ ++ i2c4 { ++ bcm2711; ++ }; ++ ++ i2c5 { ++ bcm2711; ++ }; ++ ++ i2c6 { ++ bcm2711; ++ }; ++ ++ rpivid-v4l2 { ++ bcm2711; ++ }; ++ ++ spi3-1cs { ++ bcm2711; ++ }; ++ ++ spi3-2cs { ++ bcm2711; ++ }; ++ ++ spi4-1cs { ++ bcm2711; ++ }; ++ ++ spi4-2cs { ++ bcm2711; ++ }; ++ ++ spi5-1cs { ++ bcm2711; ++ }; ++ ++ spi5-2cs { ++ bcm2711; ++ }; ++ ++ spi6-1cs { ++ bcm2711; ++ }; ++ ++ spi6-2cs { ++ bcm2711; ++ }; ++ ++ uart2 { ++ bcm2711; ++ }; ++ ++ uart3 { ++ bcm2711; ++ }; ++ ++ uart4 { ++ bcm2711; ++ }; ++ ++ uart5 { ++ bcm2711; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0625-overlays-Formally-rename-deprecate-old-overlays.patch b/target/linux/bcm27xx/patches-5.4/950-0625-overlays-Formally-rename-deprecate-old-overlays.patch new file mode 100644 index 00000000000..edcb3792afc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0625-overlays-Formally-rename-deprecate-old-overlays.patch @@ -0,0 +1,226 @@ +From c9d7d2eb73f2c6024e3f94765fc830bce0203f2b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 1 Apr 2020 17:24:15 +0100 +Subject: [PATCH] overlays: Formally rename/deprecate old overlays + +Take advantage of the overlay_map to rename or deprecate some obsolete +overlays. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/Makefile | 7 ---- + arch/arm/boot/dts/overlays/README | 12 +----- + .../overlays/bmp085_i2c-sensor-overlay.dts | 23 ----------- + .../dts/overlays/i2c0-bcm2708-overlay.dts | 14 ------- + .../dts/overlays/i2c1-bcm2708-overlay.dts | 9 ----- + arch/arm/boot/dts/overlays/overlay_map.dts | 40 +++++++++++++++++++ + .../boot/dts/overlays/pi3-act-led-overlay.dts | 1 - + .../dts/overlays/pi3-disable-bt-overlay.dts | 1 - + .../dts/overlays/pi3-disable-wifi-overlay.dts | 1 - + .../dts/overlays/pi3-miniuart-bt-overlay.dts | 1 - + 10 files changed, 42 insertions(+), 67 deletions(-) + delete mode 100644 arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts + delete mode 100644 arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -27,7 +27,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + audiosense-pi.dtbo \ + audremap.dtbo \ + balena-fin.dtbo \ +- bmp085_i2c-sensor.dtbo \ + dht11.dtbo \ + dionaudio-loco.dtbo \ + dionaudio-loco-v2.dtbo \ +@@ -75,9 +74,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + i2c-rtc-gpio.dtbo \ + i2c-sensor.dtbo \ + i2c0.dtbo \ +- i2c0-bcm2708.dtbo \ + i2c1.dtbo \ +- i2c1-bcm2708.dtbo \ + i2c3.dtbo \ + i2c4.dtbo \ + i2c5.dtbo \ +@@ -114,10 +111,6 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + mz61581.dtbo \ + ov5647.dtbo \ + papirus.dtbo \ +- pi3-act-led.dtbo \ +- pi3-disable-bt.dtbo \ +- pi3-disable-wifi.dtbo \ +- pi3-miniuart-bt.dtbo \ + pibell.dtbo \ + piglow.dtbo \ + piscreen.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1288,11 +1288,8 @@ Params: pins_0_1 Use pins + + + Name: i2c0-bcm2708 +-Info: Deprecated, legacy version of i2c0, from which it inherits its +- parameters, just adding the explicit individual pin specifiers. ++Info: Deprecated, legacy version of i2c0. + Load: +-Params: sda0_pin GPIO pin for SDA0 (deprecated - use pins_*) +- scl0_pin GPIO pin for SCL0 (deprecated - use pins_*) + + + Name: i2c1 +@@ -1307,13 +1304,8 @@ Params: pins_2_3 Use pins + + + Name: i2c1-bcm2708 +-Info: Deprecated, legacy version of i2c1, from which it inherits its +- parameters, just adding the explicit individual pin specifiers. ++Info: Deprecated, legacy version of i2c1. + Load: +-Params: sda1_pin GPIO pin for SDA1 (2 or 44 - default 2) +- scl1_pin GPIO pin for SCL1 (3 or 45 - default 3) +- pin_func Alternative pin function (4 (alt0), 6 (alt2) - +- default 4) + + + Name: i2c3 +--- a/arch/arm/boot/dts/overlays/bmp085_i2c-sensor-overlay.dts ++++ /dev/null +@@ -1,23 +0,0 @@ +-// Definitions for BMP085/BMP180 digital barometric pressure and temperature sensors from Bosch Sensortec +-/dts-v1/; +-/plugin/; +- +-/ { +- compatible = "brcm,bcm2835"; +- +- fragment@0 { +- target = <&i2c_arm>; +- __overlay__ { +- #address-cells = <1>; +- #size-cells = <0>; +- status = "okay"; +- +- bmp085@77 { +- compatible = "bosch,bmp085"; +- reg = <0x77>; +- default-oversampling = <3>; +- status = "okay"; +- }; +- }; +- }; +-}; +--- a/arch/arm/boot/dts/overlays/i2c0-bcm2708-overlay.dts ++++ /dev/null +@@ -1,14 +0,0 @@ +-#include "i2c0-overlay.dts" +- +-/{ +- __overrides__ { +- sda0_pin = <&pins1>,"brcm,pins:0", +- <&pins2>,"brcm,pins:0", +- <&pins3>,"brcm,pins:0", +- <&pins4>,"brcm,pins:0"; +- scl0_pin = <&pins1>,"brcm,pins:4", +- <&pins2>,"brcm,pins:4", +- <&pins3>,"brcm,pins:4", +- <&pins4>,"brcm,pins:4"; +- }; +-}; +--- a/arch/arm/boot/dts/overlays/i2c1-bcm2708-overlay.dts ++++ /dev/null +@@ -1,9 +0,0 @@ +-#include "i2c1-overlay.dts" +- +-/{ +- __overrides__ { +- sda1_pin = <&pins1>,"brcm,pins:0", <&pins2>,"brcm,pins:0"; +- scl1_pin = <&pins1>,"brcm,pins:4", <&pins1>,"brcm,pins:4"; +- pin_func = <&pins1>,"brcm,function:0", <&pins2>,"brcm,function:0"; +- }; +-}; +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -1,6 +1,18 @@ + /dts-v1/; + + / { ++ bmp085_i2c-sensor { ++ deprecated = "use i2c-sensor,bmp085"; ++ }; ++ ++ i2c0-bcm2708 { ++ deprecated = "use i2c0"; ++ }; ++ ++ i2c1-bcm2708 { ++ deprecated = "use i2c1"; ++ }; ++ + i2c3 { + bcm2711; + }; +@@ -17,10 +29,34 @@ + bcm2711; + }; + ++ lirc-rpi { ++ deprecated = "use gpio-ir"; ++ }; ++ ++ pi3-act-led { ++ renamed = "act-led"; ++ }; ++ ++ pi3-disable-bt { ++ renamed = "disable-bt"; ++ }; ++ ++ pi3-disable-wifi { ++ renamed = "disable-wifi"; ++ }; ++ ++ pi3-miniuart-bt { ++ renamed = "miniuart-bt"; ++ }; ++ + rpivid-v4l2 { + bcm2711; + }; + ++ sdio-1bit { ++ deprecated = "use sdio,bus_width=1,gpios_22_25"; ++ }; ++ + spi3-1cs { + bcm2711; + }; +@@ -68,4 +104,8 @@ + uart5 { + bcm2711; + }; ++ ++ upstream-aux-interrupt { ++ deprecated = "no longer necessary"; ++ }; + }; +--- a/arch/arm/boot/dts/overlays/pi3-act-led-overlay.dts ++++ /dev/null +@@ -1 +0,0 @@ +-#include "act-led-overlay.dts" +--- a/arch/arm/boot/dts/overlays/pi3-disable-bt-overlay.dts ++++ /dev/null +@@ -1 +0,0 @@ +-#include "disable-bt-overlay.dts" +--- a/arch/arm/boot/dts/overlays/pi3-disable-wifi-overlay.dts ++++ /dev/null +@@ -1 +0,0 @@ +-#include "disable-wifi-overlay.dts" +--- a/arch/arm/boot/dts/overlays/pi3-miniuart-bt-overlay.dts ++++ /dev/null +@@ -1 +0,0 @@ +-#include "miniuart-bt-overlay.dts" diff --git a/target/linux/bcm27xx/patches-5.4/950-0626-overlays-Add-vc4-kms-v3d-pi4-to-overlay_map.patch b/target/linux/bcm27xx/patches-5.4/950-0626-overlays-Add-vc4-kms-v3d-pi4-to-overlay_map.patch new file mode 100644 index 00000000000..4fd5879ec8b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0626-overlays-Add-vc4-kms-v3d-pi4-to-overlay_map.patch @@ -0,0 +1,26 @@ +From ed5f6f5d1077e849c0762595069e79a7749951bf Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 1 Apr 2020 15:51:56 +0100 +Subject: [PATCH] overlays: Add vc4-kms-v3d-pi4 to overlay_map + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/overlay_map.dts | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -108,4 +108,13 @@ + upstream-aux-interrupt { + deprecated = "no longer necessary"; + }; ++ ++ vc4-kms-v3d { ++ bcm2835; ++ bcm2711 = "vc4-kms-v3d-pi4"; ++ }; ++ ++ vc4-kms-v3d-pi4 { ++ bcm2711; ++ }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0627-Add-upstream-and-upstream-pi4-to-overlay_map.patch b/target/linux/bcm27xx/patches-5.4/950-0627-Add-upstream-and-upstream-pi4-to-overlay_map.patch new file mode 100644 index 00000000000..e76367b9da7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0627-Add-upstream-and-upstream-pi4-to-overlay_map.patch @@ -0,0 +1,229 @@ +From 0a65f76d99bce7685e57ae506eedc499c551ac83 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 6 Apr 2020 09:47:42 +0100 +Subject: [PATCH] Add upstream and upstream-pi4 to overlay_map + +Because the upstream overlay applies vc4-kms-v3d, of which Pi 4 has its +own version, there also needs to be a Pi 4 version - vc4-kms-v3d-pi4. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 7 + + arch/arm/boot/dts/overlays/overlay_map.dts | 9 + + .../dts/overlays/upstream-pi4-overlay.dts | 161 ++++++++++++++++++ + 4 files changed, 178 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -183,6 +183,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + uart5.dtbo \ + udrc.dtbo \ + upstream.dtbo \ ++ upstream-pi4.dtbo \ + vc4-fkms-v3d.dtbo \ + vc4-kms-kippah-7inch.dtbo \ + vc4-kms-v3d.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2653,6 +2653,13 @@ Info: This overlay has been deprecated + Load: + + ++Name: upstream-pi4 ++Info: Allow usage of downstream .dtb with upstream kernel on Pi 4. Comprises ++ the vc4-kms-v3d-pi4 and dwc2 overlays. ++Load: dtoverlay=upstream-pi4 ++Params: ++ ++ + Name: vc4-fkms-v3d + Info: Enable Eric Anholt's DRM VC4 V3D driver on top of the dispmanx + display stack. +--- a/arch/arm/boot/dts/overlays/overlay_map.dts ++++ b/arch/arm/boot/dts/overlays/overlay_map.dts +@@ -105,10 +105,19 @@ + bcm2711; + }; + ++ upstream { ++ bcm2835; ++ bcm2711 = "upstream-pi4"; ++ }; ++ + upstream-aux-interrupt { + deprecated = "no longer necessary"; + }; + ++ upstream-pi4 { ++ bcm2711; ++ }; ++ + vc4-kms-v3d { + bcm2835; + bcm2711 = "vc4-kms-v3d-pi4"; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts +@@ -0,0 +1,161 @@ ++// redo: ovmerge -c vc4-kms-v3d-pi4-overlay.dts,cma-96 dwc2-overlay.dts,dr_mode=otg ++ ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ fragment@0 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=256M"; ++ }; ++ }; ++ fragment@1 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=192M"; ++ }; ++ }; ++ fragment@2 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=128M"; ++ }; ++ }; ++ fragment@3 { ++ target-path = "/chosen"; ++ __overlay__ { ++ bootargs = "cma=96M"; ++ }; ++ }; ++ fragment@4 { ++ target-path = "/chosen"; ++ __dormant__ { ++ bootargs = "cma=64M"; ++ }; ++ }; ++ fragment@5 { ++ target = <&ddc0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@6 { ++ target = <&ddc1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@7 { ++ target = <&hdmi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@8 { ++ target = <&hdmi1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@9 { ++ target = <&hvs>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@10 { ++ target = <&pixelvalve0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@11 { ++ target = <&pixelvalve1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@12 { ++ target = <&pixelvalve2>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@13 { ++ target = <&pixelvalve3>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@14 { ++ target = <&pixelvalve4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@15 { ++ target = <&v3d>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@16 { ++ target = <&vc4>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@17 { ++ target = <&txp>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ fragment@18 { ++ target = <&fb>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ fragment@19 { ++ target = <&firmwarekms>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ fragment@20 { ++ target = <&vec>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ fragment@21 { ++ target = <&hdmi0>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ fragment@22 { ++ target = <&hdmi1>; ++ __dormant__ { ++ dmas; ++ }; ++ }; ++ fragment@23 { ++ target = <&usb>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ __overlay__ { ++ compatible = "brcm,bcm2835-usb"; ++ dr_mode = "otg"; ++ g-np-tx-fifo-size = <32>; ++ g-rx-fifo-size = <558>; ++ g-tx-fifo-size = <512 512 512 512 512 256 256>; ++ status = "okay"; ++ }; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0353-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch b/target/linux/bcm27xx/patches-5.4/950-0628-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch similarity index 81% rename from target/linux/bcm27xx/patches-5.4/950-0353-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch rename to target/linux/bcm27xx/patches-5.4/950-0628-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch index 31978c761a0..c0422f4ed3b 100644 --- a/target/linux/bcm27xx/patches-5.4/950-0353-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch +++ b/target/linux/bcm27xx/patches-5.4/950-0628-clk-raspberrypi-Allow-cpufreq-driver-to-also-adjust-.patch @@ -1,4 +1,4 @@ -From 3e2eb77ba8d0c6913138382512309e7892907a1c Mon Sep 17 00:00:00 2001 +From a2e39f36678626f5d7883c5a1dc8c476134c5e0b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 9 Sep 2019 15:49:56 +0100 Subject: [PATCH] clk-raspberrypi: Allow cpufreq driver to also adjust @@ -14,9 +14,9 @@ Signed-off-by: popcornmix --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c -@@ -70,7 +70,7 @@ static int raspberrypi_clock_property(st +@@ -76,7 +76,7 @@ static int raspberrypi_clock_property(st struct raspberrypi_firmware_prop msg = { - .id = cpu_to_le32(clk), + .id = cpu_to_le32(data->id), .val = cpu_to_le32(*val), - .disable_turbo = cpu_to_le32(1), + .disable_turbo = cpu_to_le32(0), diff --git a/target/linux/bcm27xx/patches-5.4/950-0629-Add-support-for-the-AudioInjector.net-Isolated-sound.patch b/target/linux/bcm27xx/patches-5.4/950-0629-Add-support-for-the-AudioInjector.net-Isolated-sound.patch new file mode 100644 index 00000000000..e35806962eb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0629-Add-support-for-the-AudioInjector.net-Isolated-sound.patch @@ -0,0 +1,323 @@ +From 5b37b08ff1c29e7386eb8a29b168e94e33cf82c3 Mon Sep 17 00:00:00 2001 +From: Matt Flax +Date: Wed, 8 Apr 2020 20:00:30 +1000 +Subject: [PATCH] Add support for the AudioInjector.net Isolated sound + card + +This patch adds support for the Audio Injector Isolated sound card. + +Signed-off-by: Matt Flax +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 + + ...dioinjector-isolated-soundcard-overlay.dts | 55 ++++++ + sound/soc/bcm/Kconfig | 7 + + sound/soc/bcm/Makefile | 2 + + .../bcm/audioinjector-isolated-soundcard.c | 183 ++++++++++++++++++ + 11 files changed, 259 insertions(+), 5 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts + create mode 100644 sound/soc/bcm/audioinjector-isolated-soundcard.c + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -22,6 +22,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + applepi-dac.dtbo \ + at86rf233.dtbo \ + audioinjector-addons.dtbo \ ++ audioinjector-isolated-soundcard.dtbo \ + audioinjector-ultra.dtbo \ + audioinjector-wm8731-audio.dtbo \ + audiosense-pi.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -505,6 +505,12 @@ Params: non-stop-clocks Keeps th + is paused or stopped (default off) + + ++Name: audioinjector-isolated-soundcard ++Info: Configures the audioinjector.net isolated soundcard ++Load: dtoverlay=audioinjector-isolated-soundcard ++Params: ++ ++ + Name: audioinjector-ultra + Info: Configures the audioinjector.net ultra soundcard + Load: dtoverlay=audioinjector-ultra +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts +@@ -0,0 +1,55 @@ ++// Definitions for audioinjector.net audio isolated soundcard ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target-path = "/"; ++ __overlay__ { ++ cs4272_mclk: codec-mclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ cs4272: cs4271@10 { ++ #sound-dai-cells = <0>; ++ compatible = "cirrus,cs4271"; ++ reg = <0x10>; ++ reset-gpio = <&gpio 5 0>; ++ clocks = <&cs4272_mclk>; ++ clock-names = "mclk"; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ snd: __overlay__ { ++ compatible = "ai,audioinjector-isolated-soundcard"; ++ mute-gpios = <&gpio 17 0>; ++ i2s-controller = <&i2s>; ++ codec = <&cs4272>; ++ status = "okay"; ++ }; ++ }; ++}; +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -192,6 +192,13 @@ config SND_AUDIOINJECTOR_OCTO_SOUNDCARD + help + Say Y or M if you want to add support for audioinjector.net octo add on + ++config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD ++ tristate "Support for audioinjector.net isolated DAC and ADC soundcard" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_CS4271_I2C ++ help ++ Say Y or M if you want to add support for audioinjector.net isolated soundcard ++ + config SND_AUDIOSENSE_PI + tristate "Support for AudioSense Add-On Soundcard" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -27,6 +27,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac. + snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o + snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o + snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o ++snd-soc-audioinjector-isolated-soundcard-objs := audioinjector-isolated-soundcard.o + snd-soc-audiosense-pi-objs := audiosense-pi.o + snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o + snd-soc-dionaudio-loco-objs := dionaudio_loco.o +@@ -55,6 +56,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC + obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o + obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o + obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o ++obj-$(CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD) += snd-soc-audioinjector-isolated-soundcard.o + obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o + obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o + obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o +--- /dev/null ++++ b/sound/soc/bcm/audioinjector-isolated-soundcard.c +@@ -0,0 +1,183 @@ ++/* ++ * ASoC Driver for AudioInjector.net isolated soundcard ++ * ++ * Created on: 20-February-2020 ++ * Author: flatmax@flatmax.org ++ * based on audioinjector-octo-soundcard.c ++ * ++ * Copyright (C) 2020 Flatmax Pty. Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static struct gpio_desc *mute_gpio; ++ ++static const unsigned int audioinjector_isolated_rates[] = { ++ 192000, 96000, 48000, 32000, 24000, 16000, 8000 ++}; ++ ++static struct snd_pcm_hw_constraint_list audioinjector_isolated_constraints = { ++ .list = audioinjector_isolated_rates, ++ .count = ARRAY_SIZE(audioinjector_isolated_rates), ++}; ++ ++static int audioinjector_isolated_dai_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ int ret=snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 24576000, 0); ++ if (ret) ++ return ret; ++ ++ return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, 64); ++} ++ ++static int audioinjector_isolated_startup(struct snd_pcm_substream *substream) ++{ ++ snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, &audioinjector_isolated_constraints); ++ ++ return 0; ++} ++ ++static int audioinjector_isolated_trigger(struct snd_pcm_substream *substream, ++ int cmd){ ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ gpiod_set_value(mute_gpio, 0); ++ break; ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ gpiod_set_value(mute_gpio, 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static struct snd_soc_ops audioinjector_isolated_ops = { ++ .startup = audioinjector_isolated_startup, ++ .trigger = audioinjector_isolated_trigger, ++}; ++ ++SND_SOC_DAILINK_DEFS(audioinjector_isolated, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("cs4271.1-0010", "cs4271-hifi")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link audioinjector_isolated_dai[] = { ++ { ++ .name = "AudioInjector ISO", ++ .stream_name = "AI-HIFI", ++ .ops = &audioinjector_isolated_ops, ++ .init = audioinjector_isolated_dai_init, ++ .symmetric_rates = 1, ++ .symmetric_channels = 1, ++ .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF, ++ SND_SOC_DAILINK_REG(audioinjector_isolated), ++ } ++}; ++ ++static const struct snd_soc_dapm_widget audioinjector_isolated_widgets[] = { ++ SND_SOC_DAPM_OUTPUT("OUTPUTS"), ++ SND_SOC_DAPM_INPUT("INPUTS"), ++}; ++ ++static const struct snd_soc_dapm_route audioinjector_isolated_route[] = { ++ /* Balanced outputs */ ++ {"OUTPUTS", NULL, "AOUTA+"}, ++ {"OUTPUTS", NULL, "AOUTA-"}, ++ {"OUTPUTS", NULL, "AOUTB+"}, ++ {"OUTPUTS", NULL, "AOUTB-"}, ++ ++ /* Balanced inputs */ ++ {"AINA", NULL, "INPUTS"}, ++ {"AINB", NULL, "INPUTS"}, ++}; ++ ++static struct snd_soc_card snd_soc_audioinjector_isolated = { ++ .name = "audioinjector-isolated-soundcard", ++ .dai_link = audioinjector_isolated_dai, ++ .num_links = ARRAY_SIZE(audioinjector_isolated_dai), ++ ++ .dapm_widgets = audioinjector_isolated_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(audioinjector_isolated_widgets), ++ .dapm_routes = audioinjector_isolated_route, ++ .num_dapm_routes = ARRAY_SIZE(audioinjector_isolated_route), ++}; ++ ++static int audioinjector_isolated_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_card *card = &snd_soc_audioinjector_isolated; ++ int ret; ++ ++ card->dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct snd_soc_dai_link *dai = &audioinjector_isolated_dai[0]; ++ struct device_node *i2s_node = ++ of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0); ++ ++ if (i2s_node) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } else { ++ dev_err(&pdev->dev, ++ "i2s-controller missing or invalid in DT\n"); ++ return -EINVAL; ++ } ++ ++ mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_LOW); ++ if (IS_ERR(mute_gpio)){ ++ dev_err(&pdev->dev, "mute gpio not found in dt overlay\n"); ++ return PTR_ERR(mute_gpio); ++ } ++ } ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, card); ++ if (ret && ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); ++ return ret; ++} ++ ++static const struct of_device_id audioinjector_isolated_of_match[] = { ++ { .compatible = "ai,audioinjector-isolated-soundcard", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, audioinjector_isolated_of_match); ++ ++static struct platform_driver audioinjector_isolated_driver = { ++ .driver = { ++ .name = "audioinjector-isolated", ++ .owner = THIS_MODULE, ++ .of_match_table = audioinjector_isolated_of_match, ++ }, ++ .probe = audioinjector_isolated_probe, ++}; ++ ++module_platform_driver(audioinjector_isolated_driver); ++MODULE_AUTHOR("Matt Flax "); ++MODULE_DESCRIPTION("AudioInjector.net isolated Soundcard"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:audioinjector-isolated-soundcard"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0630-overlays-Fix-dtc-warnings-in-i2c-gpio.patch b/target/linux/bcm27xx/patches-5.4/950-0630-overlays-Fix-dtc-warnings-in-i2c-gpio.patch new file mode 100644 index 00000000000..2da57b81de0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0630-overlays-Fix-dtc-warnings-in-i2c-gpio.patch @@ -0,0 +1,24 @@ +From 1231481bdb45114abe7b0348c78a943642fde717 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Apr 2020 11:59:39 +0100 +Subject: [PATCH] overlays: Fix dtc warnings in i2c-gpio + +Better late than never. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts +@@ -9,6 +9,9 @@ + target-path = "/"; + + __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ + i2c_gpio: i2c@0 { + reg = <0xffffffff>; + compatible = "i2c-gpio"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0631-kbuild-Disable-gcc-plugins.patch b/target/linux/bcm27xx/patches-5.4/950-0631-kbuild-Disable-gcc-plugins.patch new file mode 100644 index 00000000000..66091ca591d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0631-kbuild-Disable-gcc-plugins.patch @@ -0,0 +1,28 @@ +From 31b68a380e7649f0cbc7209c465bf747c072a7ce Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 8 Apr 2020 15:23:56 +0100 +Subject: [PATCH] kbuild: Disable gcc plugins + +The GCC plugin feature leads to different kernel configurations on what +ought to be equivalent build systems because they depend on the build +hosts native compilers rather than the cross compilers needed for the +target. This causes problems with module symbol version mismatches. + +Disable GCC plugins for all build hosts. + +Advanced build script hackery borrowed from a patch by milhouse. + +Signed-off-by: Phil Elwell +--- + scripts/gcc-plugin.sh | 1 + + 1 file changed, 1 insertion(+) + +--- a/scripts/gcc-plugin.sh ++++ b/scripts/gcc-plugin.sh +@@ -1,5 +1,6 @@ + #!/bin/sh + # SPDX-License-Identifier: GPL-2.0 ++exit 0 # Disable plugins + srctree=$(dirname "$0") + + SHOW_ERROR= diff --git a/target/linux/bcm27xx/patches-5.4/950-0632-ASoC-ma120x0p-Add-96KHz-rate-support.patch b/target/linux/bcm27xx/patches-5.4/950-0632-ASoC-ma120x0p-Add-96KHz-rate-support.patch new file mode 100644 index 00000000000..a5aee43aef3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0632-ASoC-ma120x0p-Add-96KHz-rate-support.patch @@ -0,0 +1,42 @@ +From 9554903fc8c15828d8f6cc9bd8c5444433c56cae Mon Sep 17 00:00:00 2001 +From: AMuszkat +Date: Wed, 8 Apr 2020 10:04:49 +0200 +Subject: [PATCH] ASoC: ma120x0p: Add 96KHz rate support + +Add 96KHz rate support to MA120X0P codec and make enable and mute gpio +pins optional. + +Signed-off-by: AMuszkat +--- + sound/soc/codecs/ma120x0p.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/sound/soc/codecs/ma120x0p.c ++++ b/sound/soc/codecs/ma120x0p.c +@@ -1002,7 +1002,7 @@ static struct snd_soc_dai_driver ma120x0 + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 44100, +- .rate_max = 48000, ++ .rate_max = 96000, + .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &ma120x0p_dai_ops, +@@ -1235,7 +1235,7 @@ static int ma120x0p_i2c_probe(struct i2c + //Startup sequence + + //Make sure the device is muted +- priv_data->mute_gpio = devm_gpiod_get(&i2c->dev, "mute_gp", ++ priv_data->mute_gpio = devm_gpiod_get_optional(&i2c->dev, "mute_gp", + GPIOD_OUT_LOW); + if (IS_ERR(priv_data->mute_gpio)) { + ret = PTR_ERR(priv_data->mute_gpio); +@@ -1262,7 +1262,7 @@ static int ma120x0p_i2c_probe(struct i2c + msleep(200); + + //Enable ma120x0pp +- priv_data->enable_gpio = devm_gpiod_get(&i2c->dev, ++ priv_data->enable_gpio = devm_gpiod_get_optional(&i2c->dev, + "enable_gp", GPIOD_OUT_LOW); + if (IS_ERR(priv_data->enable_gpio)) { + ret = PTR_ERR(priv_data->enable_gpio); diff --git a/target/linux/bcm27xx/patches-5.4/950-0633-arm64-mm-reserve-CMA-and-crashkernel-in-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0633-arm64-mm-reserve-CMA-and-crashkernel-in-ZONE_DMA32.patch new file mode 100644 index 00000000000..137a2fa4a02 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0633-arm64-mm-reserve-CMA-and-crashkernel-in-ZONE_DMA32.patch @@ -0,0 +1,44 @@ +From d4cf092a0e923361f521e1bc7d1fbfb1907958b3 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 7 Nov 2019 10:56:11 +0100 +Subject: [PATCH] arm64: mm: reserve CMA and crashkernel in ZONE_DMA32 + +commit bff3b04460a80f425442fe8e5c6ee8c3ebef611f upstream. + +With the introduction of ZONE_DMA in arm64 we moved the default CMA and +crashkernel reservation into that area. This caused a regression on big +machines that need big CMA and crashkernel reservations. Note that +ZONE_DMA is only 1GB big. + +Restore the previous behavior as the wide majority of devices are OK +with reserving these in ZONE_DMA32. The ones that need them in ZONE_DMA +will configure it explicitly. + +Fixes: 1a8e1cef7603 ("arm64: use both ZONE_DMA and ZONE_DMA32") +Reported-by: Qian Cai +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -91,7 +91,7 @@ static void __init reserve_crashkernel(v + + if (crash_base == 0) { + /* Current arm64 boot protocol requires 2MB alignment */ +- crash_base = memblock_find_in_range(0, ARCH_LOW_ADDRESS_LIMIT, ++ crash_base = memblock_find_in_range(0, arm64_dma32_phys_limit, + crash_size, SZ_2M); + if (crash_base == 0) { + pr_warn("cannot allocate crashkernel (size:0x%llx)\n", +@@ -459,7 +459,7 @@ void __init arm64_memblock_init(void) + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + +- dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit); ++ dma_contiguous_reserve(arm64_dma32_phys_limit); + } + + void __init bootmem_init(void) diff --git a/target/linux/bcm27xx/patches-5.4/950-0634-arm64-mm-Fix-initialisation-of-DMA-zones-on-non-NUMA.patch b/target/linux/bcm27xx/patches-5.4/950-0634-arm64-mm-Fix-initialisation-of-DMA-zones-on-non-NUMA.patch new file mode 100644 index 00000000000..654864d52da --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0634-arm64-mm-Fix-initialisation-of-DMA-zones-on-non-NUMA.patch @@ -0,0 +1,105 @@ +From cd2d09e995bc72711b48b5c271b72e3ea3e99cdf Mon Sep 17 00:00:00 2001 +From: Will Deacon +Date: Tue, 3 Dec 2019 12:10:13 +0000 +Subject: [PATCH] arm64: mm: Fix initialisation of DMA zones on + non-NUMA systems + +commit 93b90414c33f59b7960bc8d607da0ce83377e021 upstream. + +John reports that the recently merged commit 1a8e1cef7603 ("arm64: use +both ZONE_DMA and ZONE_DMA32") breaks the boot on his DB845C board: + + | Booting Linux on physical CPU 0x0000000000 [0x517f803c] + | Linux version 5.4.0-mainline-10675-g957a03b9e38f + | Machine model: Thundercomm Dragonboard 845c + | [...] + | Built 1 zonelists, mobility grouping on. Total pages: -188245 + | Kernel command line: earlycon + | firmware_class.path=/vendor/firmware/ androidboot.hardware=db845c + | init=/init androidboot.boot_devices=soc/1d84000.ufshc + | printk.devkmsg=on buildvariant=userdebug root=/dev/sda2 + | androidboot.bootdevice=1d84000.ufshc androidboot.serialno=c4e1189c + | androidboot.baseband=sda + | msm_drm.dsi_display0=dsi_lt9611_1080_video_display: + | androidboot.slot_suffix=_a skip_initramfs rootwait ro init=/init + | + | + +This is because, when CONFIG_NUMA=n, zone_sizes_init() fails to handle +memblocks that fall entirely within the ZONE_DMA region and erroneously ends up +trying to add a negatively-sized region into the following ZONE_DMA32, which is +later interpreted as a large unsigned region by the core MM code. + +Rework the non-NUMA implementation of zone_sizes_init() so that the start +address of the memblock being processed is adjusted according to the end of the +previous zone, which is then range-checked before updating the hole information +of subsequent zones. + +Cc: Nicolas Saenz Julienne +Cc: Christoph Hellwig +Cc: Bjorn Andersson +Link: https://lore.kernel.org/lkml/CALAqxLVVcsmFrDKLRGRq7GewcW405yTOxG=KR3csVzQ6bXutkA@mail.gmail.com +Fixes: 1a8e1cef7603 ("arm64: use both ZONE_DMA and ZONE_DMA32") +Reported-by: John Stultz +Tested-by: John Stultz +Signed-off-by: Will Deacon +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -214,15 +214,14 @@ static void __init zone_sizes_init(unsig + { + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; +- unsigned long max_dma32 = min; +- unsigned long max_dma = min; ++ unsigned long __maybe_unused max_dma, max_dma32; + + memset(zone_size, 0, sizeof(zone_size)); + ++ max_dma = max_dma32 = min; + #ifdef CONFIG_ZONE_DMA +- max_dma = PFN_DOWN(arm64_dma_phys_limit); ++ max_dma = max_dma32 = PFN_DOWN(arm64_dma_phys_limit); + zone_size[ZONE_DMA] = max_dma - min; +- max_dma32 = max_dma; + #endif + #ifdef CONFIG_ZONE_DMA32 + max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); +@@ -236,25 +235,23 @@ static void __init zone_sizes_init(unsig + unsigned long start = memblock_region_memory_base_pfn(reg); + unsigned long end = memblock_region_memory_end_pfn(reg); + +- if (start >= max) +- continue; + #ifdef CONFIG_ZONE_DMA +- if (start < max_dma) { +- unsigned long dma_end = min_not_zero(end, max_dma); ++ if (start >= min && start < max_dma) { ++ unsigned long dma_end = min(end, max_dma); + zhole_size[ZONE_DMA] -= dma_end - start; ++ start = dma_end; + } + #endif + #ifdef CONFIG_ZONE_DMA32 +- if (start < max_dma32) { ++ if (start >= max_dma && start < max_dma32) { + unsigned long dma32_end = min(end, max_dma32); +- unsigned long dma32_start = max(start, max_dma); +- zhole_size[ZONE_DMA32] -= dma32_end - dma32_start; ++ zhole_size[ZONE_DMA32] -= dma32_end - start; ++ start = dma32_end; + } + #endif +- if (end > max_dma32) { ++ if (start >= max_dma32 && start < max) { + unsigned long normal_end = min(end, max); +- unsigned long normal_start = max(start, max_dma32); +- zhole_size[ZONE_NORMAL] -= normal_end - normal_start; ++ zhole_size[ZONE_NORMAL] -= normal_end - start; + } + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0635-ARM-dts-bcm283x-Unify-CMA-configuration.patch b/target/linux/bcm27xx/patches-5.4/950-0635-ARM-dts-bcm283x-Unify-CMA-configuration.patch new file mode 100644 index 00000000000..a0dfcb33251 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0635-ARM-dts-bcm283x-Unify-CMA-configuration.patch @@ -0,0 +1,95 @@ +From a2e6d1c03908eccf76b9305c4a493230a36035c0 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Fri, 10 Jan 2020 18:29:35 +0100 +Subject: [PATCH] ARM: dts: bcm283x: Unify CMA configuration + +commit c5a1e5375d19bd4001c59dc5d482ac5b1ba51cbf upstream. + +With the introduction of the Raspberry Pi 4 we were forced to explicitly +configure CMA's location, since arm64 defaults it into the ZONE_DMA32 +memory area, which is not good enough to perform DMA operations on that +device. To bypass this limitation a dedicated CMA DT node was created, +explicitly indicating the acceptable memory range and size. + +That said, compatibility between boards is a must on the Raspberry Pi +ecosystem so this creates a common CMA DT node so as for DT overlays to +be able to update CMA's properties regardless of the board being used. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Phil Elwell +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711.dtsi | 32 +++++++++++++------------------- + arch/arm/boot/dts/bcm283x.dtsi | 13 +++++++++++++ + 2 files changed, 26 insertions(+), 19 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -12,25 +12,6 @@ + + interrupt-parent = <&gicv2>; + +- reserved-memory { +- #address-cells = <2>; +- #size-cells = <1>; +- ranges; +- +- /* +- * arm64 reserves the CMA by default somewhere in ZONE_DMA32, +- * that's not good enough for the BCM2711 as some devices can +- * only address the lower 1G of memory (ZONE_DMA). +- */ +- linux,cma { +- compatible = "shared-dma-pool"; +- size = <0x2000000>; /* 32MB */ +- alloc-ranges = <0x0 0x00000000 0x40000000>; +- reusable; +- linux,cma-default; +- }; +- }; +- + vc4: gpu { + compatible = "brcm,bcm2711-vc5"; + status = "disabled"; +@@ -992,6 +973,19 @@ + }; + }; + ++&rmem { ++ #address-cells = <2>; ++}; ++ ++&cma { ++ /* ++ * arm64 reserves the CMA by default somewhere in ZONE_DMA32, ++ * that's not good enough for the BCM2711 as some devices can ++ * only address the lower 1G of memory (ZONE_DMA). ++ */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++}; ++ + &i2c0 { + compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; + interrupts = ; +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -30,6 +30,19 @@ + stdout-path = "serial0:115200n8"; + }; + ++ rmem: reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ cma: linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x4000000>; /* 64MB */ ++ reusable; ++ linux,cma-default; ++ }; ++ }; ++ + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0636-dma-contiguous-CMA-give-precedence-to-cmdline.patch b/target/linux/bcm27xx/patches-5.4/950-0636-dma-contiguous-CMA-give-precedence-to-cmdline.patch new file mode 100644 index 00000000000..d3354bb9e10 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0636-dma-contiguous-CMA-give-precedence-to-cmdline.patch @@ -0,0 +1,49 @@ +From cf40e83d2b6fb6857b13df4c8d69cc4c45395ea2 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Fri, 10 Jan 2020 18:19:33 +0100 +Subject: [PATCH] dma-contiguous: CMA: give precedence to cmdline + +commit 8c8c5a4994a306c217fd061cbfc5903399fd4c1c upstream. + +Although the device tree might contain a reserved-memory DT node +dedicated as the default CMA pool, users might want to change CMA's +parameters using the kernel command line for debugging purposes and +whatnot. Honor this by bypassing the reserved memory CMA setup, which +will ultimately end up freeing the memblock and allow the command line +CMA configuration routine to run. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Phil Elwell +Signed-off-by: Christoph Hellwig +--- + kernel/dma/contiguous.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/kernel/dma/contiguous.c ++++ b/kernel/dma/contiguous.c +@@ -301,9 +301,16 @@ static int __init rmem_cma_setup(struct + phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); + phys_addr_t mask = align - 1; + unsigned long node = rmem->fdt_node; ++ bool default_cma = of_get_flat_dt_prop(node, "linux,cma-default", NULL); + struct cma *cma; + int err; + ++ if (size_cmdline != -1 && default_cma) { ++ pr_info("Reserved memory: bypass %s node, using cmdline CMA params instead\n", ++ rmem->name); ++ return -EBUSY; ++ } ++ + if (!of_get_flat_dt_prop(node, "reusable", NULL) || + of_get_flat_dt_prop(node, "no-map", NULL)) + return -EINVAL; +@@ -321,7 +328,7 @@ static int __init rmem_cma_setup(struct + /* Architecture specific contiguous memory fixup. */ + dma_contiguous_early_fixup(rmem->base, rmem->size); + +- if (of_get_flat_dt_prop(node, "linux,cma-default", NULL)) ++ if (default_cma) + dma_contiguous_set_default(cma); + + rmem->ops = &rmem_cma_ops; diff --git a/target/linux/bcm27xx/patches-5.4/950-0637-ARM-dts-Use-upstream-CMA-configuration.patch b/target/linux/bcm27xx/patches-5.4/950-0637-ARM-dts-Use-upstream-CMA-configuration.patch new file mode 100644 index 00000000000..fb4fe893c00 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0637-ARM-dts-Use-upstream-CMA-configuration.patch @@ -0,0 +1,36 @@ +From 4d0f0dfc57f6a8652c624575ea34f04bddea629b Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 2 Apr 2020 19:22:46 +0200 +Subject: [PATCH] ARM: dts: Use upstream CMA configuration + +Now that the kernel command line has precedence over the device tree, +we can use the upstream CMA setup without breaking backward +compatibility. + +Signed-off-by: Nicolas Saenz Julienne +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -195,7 +195,7 @@ + + / { + chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M"; ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1"; + }; + + aliases { +@@ -215,10 +215,6 @@ + }; + + /delete-node/ wifi-pwrseq; +- +- reserved-memory { +- /delete-node/ linux,cma; +- }; + }; + + &mmcnr { diff --git a/target/linux/bcm27xx/patches-5.4/950-0638-ARM-dts-overlays-Unify-overlay-CMA-handling.patch b/target/linux/bcm27xx/patches-5.4/950-0638-ARM-dts-overlays-Unify-overlay-CMA-handling.patch new file mode 100644 index 00000000000..3c0f1e4388c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0638-ARM-dts-overlays-Unify-overlay-CMA-handling.patch @@ -0,0 +1,871 @@ +From 3cd31a44e61e2219d730d6b1a4a13c8e15d6e395 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 2 Apr 2020 19:54:33 +0200 +Subject: [PATCH] ARM: dts: overlays: Unify overlay CMA handling + +Now that we don't have to abuse the kernel command line to change CMA's +size we can clean-up and centralize CMA usage in overlays. + +A new file, cma-overlay.dts is created to be used as a standalone +overlay or included on other overlays. All CMA users are converted to +this scheme. Ultimately upstream-overlay.dts is also updated to use the +default CMA size provided by upstream. + +Signed-off-by: Nicolas Saenz Julienne +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 19 +++++ + arch/arm/boot/dts/overlays/cma-overlay.dts | 32 ++++++++ + .../boot/dts/overlays/upstream-overlay.dts | 56 ++++--------- + .../dts/overlays/upstream-pi4-overlay.dts | 66 +++++---------- + .../dts/overlays/vc4-fkms-v3d-overlay.dts | 51 ++---------- + .../boot/dts/overlays/vc4-kms-v3d-overlay.dts | 66 ++++----------- + .../dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 80 +++++-------------- + 8 files changed, 129 insertions(+), 242 deletions(-) + create mode 100644 arch/arm/boot/dts/overlays/cma-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -28,6 +28,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + audiosense-pi.dtbo \ + audremap.dtbo \ + balena-fin.dtbo \ ++ cma.dtbo \ + dht11.dtbo \ + dionaudio-loco.dtbo \ + dionaudio-loco-v2.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -554,6 +554,19 @@ Info: This overlay is now deprecated - + Load: + + ++Name: cma ++Info: Set custom CMA sizes, only use if you know what you are doing, might ++ clash with other overlays like vc4-fkms-v3d and vc4-kms-v3d. ++Load: dtoverlay=cma,= ++Params: cma-256 CMA is 256MB (needs 1GB) ++ cma-192 CMA is 192MB (needs 1GB) ++ cma-128 CMA is 128MB ++ cma-96 CMA is 96MB ++ cma-64 CMA is 64MB ++ cma-size CMA size in bytes, 4MB aligned ++ cma-default Use upstream's default value ++ ++ + Name: dht11 + Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors + Also sometimes found with the part number(s) AM230x. +@@ -2675,6 +2688,8 @@ Params: cma-256 CMA is 2 + cma-128 CMA is 128MB + cma-96 CMA is 96MB + cma-64 CMA is 64MB ++ cma-size CMA size in bytes, 4MB aligned ++ cma-default Use upstream's default value + + + Name: vc4-kms-kippah-7inch +@@ -2692,6 +2707,8 @@ Params: cma-256 CMA is 2 + cma-128 CMA is 128MB + cma-96 CMA is 96MB + cma-64 CMA is 64MB ++ cma-size CMA size in bytes, 4MB aligned ++ cma-default Use upstream's default value + audio Enable or disable audio over HDMI (default "on") + + +@@ -2703,6 +2720,8 @@ Params: cma-256 CMA is 2 + cma-128 CMA is 128MB + cma-96 CMA is 96MB + cma-64 CMA is 64MB ++ cma-size CMA size in bytes, 4MB aligned ++ cma-default Use upstream's default value + audio Enable or disable audio over HDMI0 (default + "on") + audio1 Enable or disable audio over HDMI1 (default +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/cma-overlay.dts +@@ -0,0 +1,32 @@ ++/* ++ * cma.dts ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&cma>; ++ frag0: __overlay__ { ++ /* ++ * The default size when using this overlay is 256 MB ++ * and should be kept as is for backwards ++ * compatibility. ++ */ ++ size = <0x10000000>; ++ }; ++ }; ++ ++ __overrides__ { ++ cma-256 = <&frag0>,"size:0=",<0x10000000>; ++ cma-192 = <&frag0>,"size:0=",<0xC000000>; ++ cma-128 = <&frag0>,"size:0=",<0x8000000>; ++ cma-96 = <&frag0>,"size:0=",<0x6000000>; ++ cma-64 = <&frag0>,"size:0=",<0x4000000>; ++ cma-size = <&frag0>,"size:0"; /* in bytes, 4MB aligned */ ++ cma-default = <0>,"-0"; ++ }; ++}; +--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts ++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts +@@ -1,4 +1,4 @@ +-// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-96 dwc2-overlay.dts,dr_mode=otg ++// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg + + /dts-v1/; + /plugin/; +@@ -8,114 +8,90 @@ + / { + compatible = "brcm,bcm2835"; + fragment@0 { +- target-path = "/chosen"; ++ target = <&cma>; + __dormant__ { +- bootargs = "cma=256M"; ++ size = <0x10000000>; + }; + }; + fragment@1 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=192M"; +- }; +- }; +- fragment@2 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=128M"; +- }; +- }; +- fragment@3 { +- target-path = "/chosen"; +- __overlay__ { +- bootargs = "cma=96M"; +- }; +- }; +- fragment@4 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=64M"; +- }; +- }; +- fragment@5 { + target = <&i2c2>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@6 { ++ fragment@2 { + target = <&fb>; + __overlay__ { + status = "disabled"; + }; + }; +- fragment@7 { ++ fragment@3 { + target = <&pixelvalve0>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@8 { ++ fragment@4 { + target = <&pixelvalve1>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@9 { ++ fragment@5 { + target = <&pixelvalve2>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@10 { ++ fragment@6 { + target = <&hvs>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@11 { ++ fragment@7 { + target = <&hdmi>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@12 { ++ fragment@8 { + target = <&v3d>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@13 { ++ fragment@9 { + target = <&vc4>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@14 { ++ fragment@10 { + target = <&clocks>; + __overlay__ { + claim-clocks = ; + }; + }; +- fragment@15 { ++ fragment@11 { + target = <&vec>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@16 { ++ fragment@12 { + target = <&txp>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@17 { ++ fragment@13 { + target = <&hdmi>; + __dormant__ { + dmas; + }; + }; +- fragment@18 { ++ fragment@14 { + target = <&usb>; + #address-cells = <1>; + #size-cells = <1>; +--- a/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts ++++ b/arch/arm/boot/dts/overlays/upstream-pi4-overlay.dts +@@ -8,144 +8,120 @@ + / { + compatible = "brcm,bcm2835"; + fragment@0 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=256M"; +- }; +- }; +- fragment@1 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=192M"; +- }; +- }; +- fragment@2 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=128M"; +- }; +- }; +- fragment@3 { +- target-path = "/chosen"; ++ target = <&cma>; + __overlay__ { +- bootargs = "cma=96M"; ++ size = <100663296>; + }; + }; +- fragment@4 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=64M"; +- }; +- }; +- fragment@5 { ++ fragment@1 { + target = <&ddc0>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@6 { ++ fragment@2 { + target = <&ddc1>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@7 { ++ fragment@3 { + target = <&hdmi0>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@8 { ++ fragment@4 { + target = <&hdmi1>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@9 { ++ fragment@5 { + target = <&hvs>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@10 { ++ fragment@6 { + target = <&pixelvalve0>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@11 { ++ fragment@7 { + target = <&pixelvalve1>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@12 { ++ fragment@8 { + target = <&pixelvalve2>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@13 { ++ fragment@9 { + target = <&pixelvalve3>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@14 { ++ fragment@10 { + target = <&pixelvalve4>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@15 { ++ fragment@11 { + target = <&v3d>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@16 { ++ fragment@12 { + target = <&vc4>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@17 { ++ fragment@13 { + target = <&txp>; + __overlay__ { + status = "okay"; + }; + }; +- fragment@18 { ++ fragment@14 { + target = <&fb>; + __overlay__ { + status = "disabled"; + }; + }; +- fragment@19 { ++ fragment@15 { + target = <&firmwarekms>; + __overlay__ { + status = "disabled"; + }; + }; +- fragment@20 { ++ fragment@16 { + target = <&vec>; + __overlay__ { + status = "disabled"; + }; + }; +- fragment@21 { ++ fragment@17 { + target = <&hdmi0>; + __dormant__ { + dmas; + }; + }; +- fragment@22 { ++ fragment@18 { + target = <&hdmi1>; + __dormant__ { + dmas; + }; + }; +- fragment@23 { ++ fragment@19 { + target = <&usb>; + #address-cells = <1>; + #size-cells = <1>; +--- a/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-fkms-v3d-overlay.dts +@@ -5,77 +5,36 @@ + /dts-v1/; + /plugin/; + ++#include "cma-overlay.dts" ++ + / { + compatible = "brcm,bcm2835"; + +- fragment@0 { +- target-path = "/chosen"; +- __overlay__ { +- bootargs = "cma=256M"; +- }; +- }; +- + fragment@1 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=192M"; +- }; +- }; +- +- fragment@2 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=128M"; +- }; +- }; +- +- fragment@3 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=96M"; +- }; +- }; +- +- fragment@4 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=64M"; +- }; +- }; +- +- fragment@5 { + target = <&fb>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@6 { ++ fragment@2 { + target = <&firmwarekms>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@7 { ++ fragment@3 { + target = <&v3d>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@8 { ++ fragment@4 { + target = <&vc4>; + __overlay__ { + status = "okay"; + }; + }; +- +- __overrides__ { +- cma-256 = <0>,"+0-1-2-3-4"; +- cma-192 = <0>,"-0+1-2-3-4"; +- cma-128 = <0>,"-0-1+2-3-4"; +- cma-96 = <0>,"-0-1-2+3-4"; +- cma-64 = <0>,"-0-1-2-3+4"; +- }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +@@ -7,108 +7,75 @@ + + #include + ++#include "cma-overlay.dts" ++ + / { + compatible = "brcm,bcm2835"; + +- fragment@0 { +- target-path = "/chosen"; +- __overlay__ { +- bootargs = "cma=256M"; +- }; +- }; +- + fragment@1 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=192M"; +- }; +- }; +- +- fragment@2 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=128M"; +- }; +- }; +- +- fragment@3 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=96M"; +- }; +- }; +- +- fragment@4 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=64M"; +- }; +- }; +- +- fragment@5 { + target = <&i2c2>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@6 { ++ fragment@2 { + target = <&fb>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@7 { ++ fragment@3 { + target = <&pixelvalve0>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@8 { ++ fragment@4 { + target = <&pixelvalve1>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@9 { ++ fragment@5 { + target = <&pixelvalve2>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@10 { ++ fragment@6 { + target = <&hvs>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@11 { ++ fragment@7 { + target = <&hdmi>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@12 { ++ fragment@8 { + target = <&v3d>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@13 { ++ fragment@9 { + target = <&vc4>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@14 { ++ fragment@10 { + target = <&clocks>; + __overlay__ { + claim-clocks = < +@@ -120,21 +87,21 @@ + }; + }; + +- fragment@15 { ++ fragment@11 { + target = <&vec>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@16 { ++ fragment@12 { + target = <&txp>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@17 { ++ fragment@13 { + target = <&hdmi>; + __dormant__ { + dmas; +@@ -142,11 +109,6 @@ + }; + + __overrides__ { +- cma-256 = <0>,"+0-1-2-3-4"; +- cma-192 = <0>,"-0+1-2-3-4"; +- cma-128 = <0>,"-0-1+2-3-4"; +- cma-96 = <0>,"-0-1-2+3-4"; +- cma-64 = <0>,"-0-1-2-3+4"; + audio = <0>,"!17"; + }; + }; +--- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts ++++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts +@@ -7,164 +7,131 @@ + + #include + ++#include "cma-overlay.dts" ++ + / { + compatible = "brcm,bcm2835"; + +- fragment@0 { +- target-path = "/chosen"; +- __overlay__ { +- bootargs = "cma=256M"; +- }; +- }; +- + fragment@1 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=192M"; +- }; +- }; +- +- fragment@2 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=128M"; +- }; +- }; +- +- fragment@3 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=96M"; +- }; +- }; +- +- fragment@4 { +- target-path = "/chosen"; +- __dormant__ { +- bootargs = "cma=64M"; +- }; +- }; +- +- fragment@5 { + target = <&ddc0>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@6 { ++ fragment@2 { + target = <&ddc1>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@7 { ++ fragment@3 { + target = <&hdmi0>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@8 { ++ fragment@4 { + target = <&hdmi1>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@9 { ++ fragment@5 { + target = <&hvs>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@10 { ++ fragment@6 { + target = <&pixelvalve0>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@11 { ++ fragment@7 { + target = <&pixelvalve1>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@12 { ++ fragment@8 { + target = <&pixelvalve2>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@13 { ++ fragment@9 { + target = <&pixelvalve3>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@14 { ++ fragment@10 { + target = <&pixelvalve4>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@15 { ++ fragment@11 { + target = <&v3d>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@16 { ++ fragment@12 { + target = <&vc4>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@17 { ++ fragment@13 { + target = <&txp>; + __overlay__ { + status = "okay"; + }; + }; + +- fragment@18 { ++ fragment@14 { + target = <&fb>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@19 { ++ fragment@15 { + target = <&firmwarekms>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@20 { ++ fragment@16 { + target = <&vec>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@21 { ++ fragment@17 { + target = <&hdmi0>; + __dormant__ { + dmas; + }; + }; + +- fragment@22 { ++ fragment@18 { + target = <&hdmi1>; + __dormant__ { + dmas; +@@ -172,12 +139,7 @@ + }; + + __overrides__ { +- cma-256 = <0>,"+0-1-2-3-4"; +- cma-192 = <0>,"-0+1-2-3-4"; +- cma-128 = <0>,"-0-1+2-3-4"; +- cma-96 = <0>,"-0-1-2+3-4"; +- cma-64 = <0>,"-0-1-2-3+4"; +- audio = <0>,"!21"; +- audio1 = <0>,"!22"; ++ audio = <0>,"!17"; ++ audio1 = <0>,"!18"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0639-ARM-dts-bcm283x-Fix-vc4-s-firmware-bus-DMA-limitatio.patch b/target/linux/bcm27xx/patches-5.4/950-0639-ARM-dts-bcm283x-Fix-vc4-s-firmware-bus-DMA-limitatio.patch new file mode 100644 index 00000000000..31840e5437d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0639-ARM-dts-bcm283x-Fix-vc4-s-firmware-bus-DMA-limitatio.patch @@ -0,0 +1,28 @@ +From 142ad0b8433d6beb87070bd39a6b2d23ca9cae30 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 19 Mar 2020 20:00:13 +0100 +Subject: [PATCH] ARM: dts: bcm283x: Fix vc4's firmware bus DMA + limitations + +The bus is virtual and devices have to inherit their DMA constraints +from the underlying interconnect. So add an empty dma-ranges property to +the bus node, implying the firmware bus' DMA constraints are identical to +its parent's. + +Fixes: 7dbe8c62ceeb ("ARM: dts: Add minimal Raspberry Pi 4 support") +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2835-rpi.dtsi | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -15,6 +15,7 @@ + firmware: firmware { + compatible = "raspberrypi,bcm2835-firmware", "simple-bus"; + mboxes = <&mailbox>; ++ dma-ranges; + }; + + power: power { diff --git a/target/linux/bcm27xx/patches-5.4/950-0640-ARM-dts-bcm2711-Restrict-CMA-to-first-768MB.patch b/target/linux/bcm27xx/patches-5.4/950-0640-ARM-dts-bcm2711-Restrict-CMA-to-first-768MB.patch new file mode 100644 index 00000000000..9a1e29e7d19 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0640-ARM-dts-bcm2711-Restrict-CMA-to-first-768MB.patch @@ -0,0 +1,33 @@ +From 7b307016ed13cbb65e08b6a704912e5c9e5b81ac Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 14 Apr 2020 15:25:02 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Restrict CMA to first 768MB + +The downstream 32-bit 2711 kernel configuration enables HIGHMEM for +access to more physical RAM. The HIGHMEM zone starts at 0x30000000 +(768MB), and allowing the CMA zone to overlap that area causes a +failure during CMA activation. + +Avoid the overlap by limiting CMA to the first 768MB. This is overly +restrictive on a 64-bit kernel, but shouldn't cause any practical +problems. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -45,6 +45,11 @@ + }; + }; + ++&cma { ++ /* Limit cma to the lower 768MB to allow room for HIGHMEM on 32-bit */ ++ alloc-ranges = <0x0 0x00000000 0x30000000>; ++}; ++ + &soc { + thermal: thermal@7d5d2200 { + compatible = "brcm,avs-tmon-bcm2711"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0641-ARM-dts-Extend-SCB-bus-address-range.patch b/target/linux/bcm27xx/patches-5.4/950-0641-ARM-dts-Extend-SCB-bus-address-range.patch new file mode 100644 index 00000000000..8eb2b16b102 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0641-ARM-dts-Extend-SCB-bus-address-range.patch @@ -0,0 +1,23 @@ +From 9773c8c521f45f34631bcb147d638ba0252bbdd4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2020 12:51:56 +0000 +Subject: [PATCH] ARM: dts: Extend SCB bus address range + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -69,7 +69,9 @@ + <0x0 0x40000000 0x0 0xff800000 0x00800000>, + <0x6 0x00000000 0x6 0x00000000 0x40000000>, + <0x0 0x00000000 0x0 0x00000000 0xfc000000>; +- dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; ++ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>, ++ <0x1 0x00000000 0x1 0x00000000 0x80000000>, ++ <0x1 0x80000000 0x1 0x80000000 0x80000000>; + + dma40: dma@7e007b00 { + compatible = "brcm,bcm2711-dma"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0642-dts-bcm2711-Move-emmc2-to-its-own-bus.patch b/target/linux/bcm27xx/patches-5.4/950-0642-dts-bcm2711-Move-emmc2-to-its-own-bus.patch new file mode 100644 index 00000000000..52cf03a3828 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0642-dts-bcm2711-Move-emmc2-to-its-own-bus.patch @@ -0,0 +1,52 @@ +From f97ba33547711d727fbbcb10eb046f8ac605a966 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 5 Dec 2019 18:02:08 +0000 +Subject: [PATCH] dts: bcm2711: Move emmc2 to its own "bus" + +Moving the EMMC2 controller under a dedicated bus allows the firmware +to patch the dma-ranges property for different memory sizes without +affecting anything else. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -193,6 +193,8 @@ + #include "bcm2711-rpi.dtsi" + #include "bcm283x-rpi-csi1-2lane.dtsi" + ++/delete-node/ &emmc2; ++ + / { + chosen { + bootargs = "coherent_pool=1M 8250.nr_uarts=1"; +@@ -212,6 +214,26 @@ + /delete-property/ ethernet; + /delete-property/ intc; + pcie0 = &pcie0; ++ emmc2bus = &emmc2bus; ++ }; ++ ++ emmc2bus: emmc2bus { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ ranges = <0x0 0x7e000000 0x0 0xfe000000 0x01800000>; ++ dma-ranges = <0x0 0xc0000000 0x0 0x00000000 0x3c000000>; ++ ++ emmc2: emmc2@7e340000 { ++ compatible = "brcm,bcm2711-emmc2"; ++ status = "okay"; ++ interrupts = ; ++ clocks = <&clocks BCM2711_CLOCK_EMMC2>; ++ reg = <0x0 0x7e340000 0x100>; ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ broken-cd; ++ }; + }; + + /delete-node/ wifi-pwrseq; diff --git a/target/linux/bcm27xx/patches-5.4/950-0643-drm-vc4-hdmi-Silence-pixel-clock-error-on-EPROBE_DEF.patch b/target/linux/bcm27xx/patches-5.4/950-0643-drm-vc4-hdmi-Silence-pixel-clock-error-on-EPROBE_DEF.patch new file mode 100644 index 00000000000..1b1cb143ae0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0643-drm-vc4-hdmi-Silence-pixel-clock-error-on-EPROBE_DEF.patch @@ -0,0 +1,29 @@ +From ba875ce27cd407bc61502517671623df07bb6c1a Mon Sep 17 00:00:00 2001 +From: James Hilliard +Date: Fri, 10 Apr 2020 19:24:40 -0600 +Subject: [PATCH] drm/vc4: hdmi: Silence pixel clock error on + -EPROBE_DEFER + +If the vc4 hdmi driver loads before the pixel clock is available we +see a spurious "*ERROR* Failed to get pixel clock" error. + +Signed-off-by: James Hilliard +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1493,8 +1493,10 @@ static int vc4_hdmi_init_resources(struc + + vc4_hdmi->pixel_clock = devm_clk_get(dev, "pixel"); + if (IS_ERR(vc4_hdmi->pixel_clock)) { +- DRM_ERROR("Failed to get pixel clock\n"); +- return PTR_ERR(vc4_hdmi->pixel_clock); ++ ret = PTR_ERR(vc4_hdmi->pixel_clock); ++ if (ret != -EPROBE_DEFER) ++ DRM_ERROR("Failed to get pixel clock\n"); ++ return ret; + } + + vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0644-component-Silence-bind-error-on-EPROBE_DEFER.patch b/target/linux/bcm27xx/patches-5.4/950-0644-component-Silence-bind-error-on-EPROBE_DEFER.patch new file mode 100644 index 00000000000..f7b1217527e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0644-component-Silence-bind-error-on-EPROBE_DEFER.patch @@ -0,0 +1,41 @@ +From 8695764265eb6e749c9fdc901e98c2e7b4d2adfc Mon Sep 17 00:00:00 2001 +From: James Hilliard +Date: Fri, 10 Apr 2020 20:23:13 -0600 +Subject: [PATCH] component: Silence bind error on -EPROBE_DEFER + +If a component fails to bind due to -EPROBE_DEFER we should not log an +error as this is not a real failure. + +Fixes: +vc4-drm soc:gpu: failed to bind 3f902000.hdmi (ops vc4_hdmi_ops): -517 +vc4-drm soc:gpu: master bind failed: -517 + +Signed-off-by: James Hilliard +--- + drivers/base/component.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/base/component.c ++++ b/drivers/base/component.c +@@ -257,7 +257,8 @@ static int try_to_bring_up_master(struct + ret = master->ops->bind(master->dev); + if (ret < 0) { + devres_release_group(master->dev, NULL); +- dev_info(master->dev, "master bind failed: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_info(master->dev, "master bind failed: %d\n", ret); + return ret; + } + +@@ -611,8 +612,9 @@ static int component_bind(struct compone + devres_release_group(component->dev, NULL); + devres_release_group(master->dev, NULL); + +- dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", +- dev_name(component->dev), component->ops, ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", ++ dev_name(component->dev), component->ops, ret); + } + + return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0645-Fixes-a-problem-with-clock-settings-of-HiFiBerry-DAC.patch b/target/linux/bcm27xx/patches-5.4/950-0645-Fixes-a-problem-with-clock-settings-of-HiFiBerry-DAC.patch new file mode 100644 index 00000000000..f1427ae71fd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0645-Fixes-a-problem-with-clock-settings-of-HiFiBerry-DAC.patch @@ -0,0 +1,42 @@ +From f303194bc24925d3efd965ccfae40974ea437240 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= + +Date: Wed, 15 Apr 2020 11:48:29 +0200 +Subject: [PATCH] Fixes a problem with clock settings of HiFiBerry + DAC+ADC PRO (#3545) + +This patch fixes a problem of the re-calculation of +i2s-clock and -parameter settings when only the ADC is activated. + +Signed-off-by: Joerg Schambacher +--- + sound/soc/bcm/hifiberry_dacplusadcpro.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -390,9 +390,11 @@ static int snd_rpi_hifiberry_dacplusadcp + int channels = params_channels(params); + int width = 32; + struct snd_soc_component *dac = rtd->codec_dais[0]->component; ++ struct snd_soc_dai *dai = rtd->codec_dais[0]; ++ struct snd_soc_dai_driver *drv = dai->driver; ++ const struct snd_soc_dai_ops *ops = drv->ops; + + if (snd_rpi_hifiberry_is_dacpro) { +- + width = snd_pcm_format_physical_width(params_format(params)); + + snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac, +@@ -414,6 +416,11 @@ static int snd_rpi_hifiberry_dacplusadcp + return ret; + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03, + channels, width); ++ if (ret) ++ return ret; ++ ++ if (snd_rpi_hifiberry_is_dacpro && ops->hw_params) ++ ret = ops->hw_params(substream, params, dai); + return ret; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0646-Documentation-media-Update-sub-device-API-intro.patch b/target/linux/bcm27xx/patches-5.4/950-0646-Documentation-media-Update-sub-device-API-intro.patch new file mode 100644 index 00000000000..f843a83a7d8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0646-Documentation-media-Update-sub-device-API-intro.patch @@ -0,0 +1,34 @@ +From afd6952c4dfb0d4945b496ef08b2f478d6f40097 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Tue, 7 Apr 2020 17:21:55 +0200 +Subject: [PATCH] Documentation: media: Update sub-device API intro + +Update the V4L2 sub-device userspace API introduction to provide more +details on why complex devices might want to register devnodes for the +connected subdevices. + +Acked-by: Sakari Ailus +Suggested-by: Laurent Pinchart +Signed-off-by: Jacopo Mondi +--- + Documentation/media/kapi/v4l2-subdev.rst | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/Documentation/media/kapi/v4l2-subdev.rst ++++ b/Documentation/media/kapi/v4l2-subdev.rst +@@ -275,8 +275,13 @@ system the .unbind() method is called. A + V4L2 sub-device userspace API + ----------------------------- + +-Beside exposing a kernel API through the :c:type:`v4l2_subdev_ops` structure, +-V4L2 sub-devices can also be controlled directly by userspace applications. ++Bridge drivers traditionally expose one or multiple video nodes to userspace, ++and control subdevices through the :c:type:`v4l2_subdev_ops` operations in ++response to video node operations. This hides the complexity of the underlying ++hardware from applications. For complex devices, finer-grained control of the ++device than what the video nodes offer may be required. In those cases, bridge ++drivers that implement :ref:`the media controller API ` may ++opt for making the subdevice operations directly accessible from userpace. + + Device nodes named ``v4l-subdev``\ *X* can be created in ``/dev`` to access + sub-devices directly. If a sub-device supports direct userspace configuration diff --git a/target/linux/bcm27xx/patches-5.4/950-0647-Documentation-media-Document-read-only-subdevice.patch b/target/linux/bcm27xx/patches-5.4/950-0647-Documentation-media-Document-read-only-subdevice.patch new file mode 100644 index 00000000000..1983334ae15 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0647-Documentation-media-Document-read-only-subdevice.patch @@ -0,0 +1,217 @@ +From c1a630e792140b4791bad84974e31b4a1cf09b1b Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Tue, 7 Apr 2020 17:21:56 +0200 +Subject: [PATCH] Documentation: media: Document read-only subdevice + +Document a new kAPI function to register subdev device nodes in read only +mode and for each affected ioctl report how access is restricted. + +Acked-by: Sakari Ailus +Signed-off-by: Jacopo Mondi +--- + Documentation/media/kapi/v4l2-subdev.rst | 44 +++++++++++++++++++ + Documentation/media/uapi/v4l/dev-subdev.rst | 5 +++ + .../media/uapi/v4l/vidioc-g-dv-timings.rst | 6 +++ + Documentation/media/uapi/v4l/vidioc-g-std.rst | 6 +++ + .../media/uapi/v4l/vidioc-subdev-g-crop.rst | 9 ++++ + .../media/uapi/v4l/vidioc-subdev-g-fmt.rst | 8 ++++ + .../v4l/vidioc-subdev-g-frame-interval.rst | 8 ++++ + .../uapi/v4l/vidioc-subdev-g-selection.rst | 8 ++++ + 8 files changed, 94 insertions(+) + +--- a/Documentation/media/kapi/v4l2-subdev.rst ++++ b/Documentation/media/kapi/v4l2-subdev.rst +@@ -332,6 +332,50 @@ Private ioctls + All ioctls not in the above list are passed directly to the sub-device + driver through the core::ioctl operation. + ++Read-only sub-device userspace API ++---------------------------------- ++ ++Bridge drivers that control their connected subdevices through direct calls to ++the kernel API realized by :c:type:`v4l2_subdev_ops` structure do not usually ++want userspace to be able to change the same parameters through the subdevice ++device node and thus do not usually register any. ++ ++It is sometimes useful to report to userspace the current subdevice ++configuration through a read-only API, that does not permit applications to ++change to the device parameters but allows interfacing to the subdevice device ++node to inspect them. ++ ++For instance, to implement cameras based on computational photography, userspace ++needs to know the detailed camera sensor configuration (in terms of skipping, ++binning, cropping and scaling) for each supported output resolution. To support ++such use cases, bridge drivers may expose the subdevice operations to userspace ++through a read-only API. ++ ++To create a read-only device node for all the subdevices registered with the ++``V4L2_SUBDEV_FL_HAS_DEVNODE`` set, the :c:type:`v4l2_device` driver should call ++:c:func:`v4l2_device_register_ro_subdev_nodes`. ++ ++Access to the following ioctls for userspace applications is restricted on ++sub-device device nodes registered with ++:c:func:`v4l2_device_register_ro_subdev_nodes`. ++ ++``VIDIOC_SUBDEV_S_FMT``, ++``VIDIOC_SUBDEV_S_CROP``, ++``VIDIOC_SUBDEV_S_SELECTION``: ++ ++ These ioctls are only allowed on a read-only subdevice device node ++ for the :ref:`V4L2_SUBDEV_FORMAT_TRY ` ++ formats and selection rectangles. ++ ++``VIDIOC_SUBDEV_S_FRAME_INTERVAL``, ++``VIDIOC_SUBDEV_S_DV_TIMINGS``, ++``VIDIOC_SUBDEV_S_STD``: ++ ++ These ioctls are not allowed on a read-only subdevice node. ++ ++In case the ioctl is not allowed, or the format to modify is set to ++``V4L2_SUBDEV_FORMAT_ACTIVE``, the core returns a negative error code and ++the errno variable is set to ``-EPERM``. + + I2C sub-device drivers + ---------------------- +--- a/Documentation/media/uapi/v4l/dev-subdev.rst ++++ b/Documentation/media/uapi/v4l/dev-subdev.rst +@@ -39,6 +39,11 @@ will feature a character device node on + Sub-device character device nodes, conventionally named + ``/dev/v4l-subdev*``, use major number 81. + ++Drivers may opt to limit the sub-device character devices to only expose ++operations that do not modify the device state. In such a case the sub-devices ++are referred to as ``read-only`` in the rest of this documentation, and the ++related restrictions are documented in individual ioctls. ++ + + Controls + ======== +--- a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst ++++ b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst +@@ -57,6 +57,10 @@ pointer to the struct :c:type:`v4l2_dv_t + structure as argument. If the ioctl is not supported or the timing + values are not correct, the driver returns ``EINVAL`` error code. + ++Calling ``VIDIOC_SUBDEV_S_DV_TIMINGS`` on a subdev device node that has been ++registered in read-only mode is not allowed. An error is returned and the errno ++variable is set to ``-EPERM``. ++ + The ``linux/v4l2-dv-timings.h`` header can be used to get the timings of + the formats in the :ref:`cea861` and :ref:`vesadmt` standards. If + the current input or output does not support DV timings (e.g. if +@@ -81,6 +85,8 @@ ENODATA + EBUSY + The device is busy and therefore can not change the timings. + ++EPERM ++ ``VIDIOC_SUBDEV_S_DV_TIMINGS`` has been called on a read-only subdevice. + + .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| + +--- a/Documentation/media/uapi/v4l/vidioc-g-std.rst ++++ b/Documentation/media/uapi/v4l/vidioc-g-std.rst +@@ -66,6 +66,9 @@ video timings (e.g. if :ref:`VIDIOC_ENUM + does not set the ``V4L2_IN_CAP_STD`` flag), then ``ENODATA`` error code is + returned. + ++Calling ``VIDIOC_SUBDEV_S_STD`` on a subdev device node that has been registered ++in read-only mode is not allowed. An error is returned and the errno variable is ++set to ``-EPERM``. + + Return Value + ============ +@@ -79,3 +82,6 @@ EINVAL + + ENODATA + Standard video timings are not supported for this input or output. ++ ++EPERM ++ ``VIDIOC_SUBDEV_S_STD`` has been called on a read-only subdevice. +--- a/Documentation/media/uapi/v4l/vidioc-subdev-g-crop.rst ++++ b/Documentation/media/uapi/v4l/vidioc-subdev-g-crop.rst +@@ -73,6 +73,11 @@ crop rectangles and stored in the sub-de + applications querying the same sub-device would thus not interact with + each other. + ++If the subdev device node has been registered in read-only mode, calls to ++``VIDIOC_SUBDEV_S_CROP`` are only valid if the ``which`` field is set to ++``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno ++variable is set to ``-EPERM``. ++ + Drivers must not return an error solely because the requested crop + rectangle doesn't match the device capabilities. They must instead + modify the rectangle to match what the hardware can provide. The +@@ -123,3 +128,7 @@ EINVAL + references a non-existing pad, the ``which`` field references a + non-existing format, or cropping is not supported on the given + subdev pad. ++ ++EPERM ++ The ``VIDIOC_SUBDEV_S_CROP`` ioctl has been called on a read-only subdevice ++ and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``. +--- a/Documentation/media/uapi/v4l/vidioc-subdev-g-fmt.rst ++++ b/Documentation/media/uapi/v4l/vidioc-subdev-g-fmt.rst +@@ -78,6 +78,11 @@ current links configuration or sub-devic + a low-pass noise filter might crop pixels at the frame boundaries, + modifying its output frame size. + ++If the subdev device node has been registered in read-only mode, calls to ++``VIDIOC_SUBDEV_S_FMT`` are only valid if the ``which`` field is set to ++``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno ++variable is set to ``-EPERM``. ++ + Drivers must not return an error solely because the requested format + doesn't match the device capabilities. They must instead modify the + format to match what the hardware can provide. The modified format +@@ -146,6 +151,9 @@ EINVAL + ``pad`` references a non-existing pad, or the ``which`` field + references a non-existing format. + ++EPERM ++ The ``VIDIOC_SUBDEV_S_FMT`` ioctl has been called on a read-only subdevice ++ and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``. + + ============ + +--- a/Documentation/media/uapi/v4l/vidioc-subdev-g-frame-interval.rst ++++ b/Documentation/media/uapi/v4l/vidioc-subdev-g-frame-interval.rst +@@ -65,6 +65,10 @@ struct + contains the current frame interval as would be returned by a + ``VIDIOC_SUBDEV_G_FRAME_INTERVAL`` call. + ++Calling ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` on a subdev device node that has been ++registered in read-only mode is not allowed. An error is returned and the errno ++variable is set to ``-EPERM``. ++ + Drivers must not return an error solely because the requested interval + doesn't match the device capabilities. They must instead modify the + interval to match what the hardware can provide. The modified interval +@@ -118,3 +122,7 @@ EINVAL + :c:type:`v4l2_subdev_frame_interval` + ``pad`` references a non-existing pad, or the pad doesn't support + frame intervals. ++ ++EPERM ++ The ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` ioctl has been called on a read-only ++ subdevice. +--- a/Documentation/media/uapi/v4l/vidioc-subdev-g-selection.rst ++++ b/Documentation/media/uapi/v4l/vidioc-subdev-g-selection.rst +@@ -53,6 +53,10 @@ function of the crop API, and more, are + See :ref:`subdev` for more information on how each selection target + affects the image processing pipeline inside the subdevice. + ++If the subdev device node has been registered in read-only mode, calls to ++``VIDIOC_SUBDEV_S_SELECTION`` are only valid if the ``which`` field is set to ++``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno ++variable is set to ``-EPERM``. + + Types of selection targets + -------------------------- +@@ -123,3 +127,7 @@ EINVAL + ``pad`` references a non-existing pad, the ``which`` field + references a non-existing format, or the selection target is not + supported on the given subdev pad. ++ ++EPERM ++ The ``VIDIOC_SUBDEV_S_SELECTION`` ioctl has been called on a read-only ++ subdevice and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``. diff --git a/target/linux/bcm27xx/patches-5.4/950-0648-media-v4l2-dev-Add-v4l2_device_register_ro_subdev_no.patch b/target/linux/bcm27xx/patches-5.4/950-0648-media-v4l2-dev-Add-v4l2_device_register_ro_subdev_no.patch new file mode 100644 index 00000000000..47f2551ec78 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0648-media-v4l2-dev-Add-v4l2_device_register_ro_subdev_no.patch @@ -0,0 +1,206 @@ +From 90712c1a495c2aa4b10dd8127fdd7f1a0cd9ef00 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Tue, 7 Apr 2020 17:21:57 +0200 +Subject: [PATCH] media: v4l2-dev: Add + v4l2_device_register_ro_subdev_node() + +Add to the V4L2 core a function to register device nodes for video +subdevices in read-only mode. + +Registering a device node in read-only mode is useful to expose to +userspace the current sub-device configuration, without allowing +application to change it by using the V4L2 subdevice ioctls. + +Acked-by: Sakari Ailus +Signed-off-by: Jacopo Mondi +--- + drivers/media/v4l2-core/v4l2-device.c | 7 ++-- + drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++ + include/media/v4l2-dev.h | 7 ++++ + include/media/v4l2-device.h | 50 ++++++++++++++++++++++++--- + 4 files changed, 77 insertions(+), 6 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-device.c ++++ b/drivers/media/v4l2-core/v4l2-device.c +@@ -189,7 +189,8 @@ static void v4l2_device_release_subdev_n + kfree(vdev); + } + +-int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) ++int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, ++ bool read_only) + { + struct video_device *vdev; + struct v4l2_subdev *sd; +@@ -218,6 +219,8 @@ int v4l2_device_register_subdev_nodes(st + vdev->fops = &v4l2_subdev_fops; + vdev->release = v4l2_device_release_subdev_node; + vdev->ctrl_handler = sd->ctrl_handler; ++ if (read_only) ++ set_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); + err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, + sd->owner); + if (err < 0) { +@@ -255,7 +258,7 @@ clean_up: + + return err; + } +-EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); ++EXPORT_SYMBOL_GPL(__v4l2_device_register_subdev_nodes); + + void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) + { +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -331,6 +331,7 @@ static long subdev_do_ioctl(struct file + struct v4l2_fh *vfh = file->private_data; + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); ++ bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); + int rval; + #endif + +@@ -453,6 +454,9 @@ static long subdev_do_ioctl(struct file + case VIDIOC_SUBDEV_S_FMT: { + struct v4l2_subdev_format *format = arg; + ++ if (format->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) ++ return -EPERM; ++ + memset(format->reserved, 0, sizeof(format->reserved)); + memset(format->format.reserved, 0, sizeof(format->format.reserved)); + return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); +@@ -480,6 +484,9 @@ static long subdev_do_ioctl(struct file + struct v4l2_subdev_crop *crop = arg; + struct v4l2_subdev_selection sel; + ++ if (crop->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) ++ return -EPERM; ++ + memset(crop->reserved, 0, sizeof(crop->reserved)); + memset(&sel, 0, sizeof(sel)); + sel.which = crop->which; +@@ -521,6 +528,9 @@ static long subdev_do_ioctl(struct file + case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { + struct v4l2_subdev_frame_interval *fi = arg; + ++ if (ro_subdev) ++ return -EPERM; ++ + memset(fi->reserved, 0, sizeof(fi->reserved)); + return v4l2_subdev_call(sd, video, s_frame_interval, arg); + } +@@ -544,6 +554,9 @@ static long subdev_do_ioctl(struct file + case VIDIOC_SUBDEV_S_SELECTION: { + struct v4l2_subdev_selection *sel = arg; + ++ if (sel->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) ++ return -EPERM; ++ + memset(sel->reserved, 0, sizeof(sel->reserved)); + return v4l2_subdev_call( + sd, pad, set_selection, subdev_fh->pad, sel); +@@ -580,6 +593,9 @@ static long subdev_do_ioctl(struct file + return v4l2_subdev_call(sd, video, g_dv_timings, arg); + + case VIDIOC_SUBDEV_S_DV_TIMINGS: ++ if (ro_subdev) ++ return -EPERM; ++ + return v4l2_subdev_call(sd, video, s_dv_timings, arg); + + case VIDIOC_SUBDEV_G_STD: +@@ -588,6 +604,9 @@ static long subdev_do_ioctl(struct file + case VIDIOC_SUBDEV_S_STD: { + v4l2_std_id *std = arg; + ++ if (ro_subdev) ++ return -EPERM; ++ + return v4l2_subdev_call(sd, video, s_std, *std); + } + +--- a/include/media/v4l2-dev.h ++++ b/include/media/v4l2-dev.h +@@ -82,11 +82,18 @@ struct v4l2_ctrl_handler; + * but the old crop API will still work as expected in order to preserve + * backwards compatibility. + * Never set this flag for new drivers. ++ * @V4L2_FL_SUBDEV_RO_DEVNODE: ++ * indicates that the video device node is registered in read-only mode. ++ * The flag only applies to device nodes registered for sub-devices, it is ++ * set by the core when the sub-devices device nodes are registered with ++ * v4l2_device_register_ro_subdev_nodes() and used by the sub-device ioctl ++ * handler to restrict access to some ioctl calls. + */ + enum v4l2_video_device_flags { + V4L2_FL_REGISTERED = 0, + V4L2_FL_USES_V4L2_FH = 1, + V4L2_FL_QUIRK_INVERTED_CROP = 2, ++ V4L2_FL_SUBDEV_RO_DEVNODE = 3, + }; + + /* Priority helper functions */ +--- a/include/media/v4l2-device.h ++++ b/include/media/v4l2-device.h +@@ -174,14 +174,56 @@ int __must_check v4l2_device_register_su + void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); + + /** +- * v4l2_device_register_subdev_nodes - Registers device nodes for all subdevs +- * of the v4l2 device that are marked with +- * the %V4L2_SUBDEV_FL_HAS_DEVNODE flag. ++ * __v4l2_device_register_ro_subdev_nodes - Registers device nodes for ++ * all subdevs of the v4l2 device that are marked with the ++ * %V4L2_SUBDEV_FL_HAS_DEVNODE flag. + * + * @v4l2_dev: pointer to struct v4l2_device ++ * @read_only: subdevices read-only flag. True to register the subdevices ++ * device nodes in read-only mode, false to allow full access to the ++ * subdevice userspace API. + */ + int __must_check +-v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); ++__v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, ++ bool read_only); ++ ++/** ++ * v4l2_device_register_subdev_nodes - Registers subdevices device nodes with ++ * unrestricted access to the subdevice userspace operations ++ * ++ * Internally calls __v4l2_device_register_subdev_nodes(). See its documentation ++ * for more details. ++ * ++ * @v4l2_dev: pointer to struct v4l2_device ++ */ ++static inline int __must_check ++v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) ++{ ++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) ++ return __v4l2_device_register_subdev_nodes(v4l2_dev, false); ++#else ++ return 0; ++#endif ++} ++ ++/** ++ * v4l2_device_register_ro_subdev_nodes - Registers subdevices device nodes ++ * in read-only mode ++ * ++ * Internally calls __v4l2_device_register_subdev_nodes(). See its documentation ++ * for more details. ++ * ++ * @v4l2_dev: pointer to struct v4l2_device ++ */ ++static inline int __must_check ++v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev) ++{ ++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) ++ return __v4l2_device_register_subdev_nodes(v4l2_dev, true); ++#else ++ return 0; ++#endif ++} + + /** + * v4l2_subdev_notify - Sends a notification to v4l2_device. diff --git a/target/linux/bcm27xx/patches-5.4/950-0649-media-bcm2835-unicam-Driver-for-CCP2-CSI2-camera-int.patch b/target/linux/bcm27xx/patches-5.4/950-0649-media-bcm2835-unicam-Driver-for-CCP2-CSI2-camera-int.patch new file mode 100644 index 00000000000..e142f598ad6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0649-media-bcm2835-unicam-Driver-for-CCP2-CSI2-camera-int.patch @@ -0,0 +1,2709 @@ +From 33a897162230dfc35b854aae2bec1ce8c2996642 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 1 Apr 2020 08:39:49 +0100 +Subject: [PATCH] media: bcm2835-unicam: Driver for CCP2/CSI2 camera + interface + +Add driver for the Unicam camera receiver block on +BCM283x processors. + +This commit is made up of a series of changes cherry-picked from the +rpi-4.19.y branch. + +Signed-off-by: Dave Stevenson +Signed-off-by: Naushir Patuck +--- + MAINTAINERS | 2 +- + drivers/media/platform/Kconfig | 1 + + drivers/media/platform/Makefile | 2 + + drivers/media/platform/bcm2835/Kconfig | 14 + + drivers/media/platform/bcm2835/Makefile | 3 + + .../media/platform/bcm2835/bcm2835-unicam.c | 2369 +++++++++++++++++ + .../media/platform/bcm2835/vc4-regs-unicam.h | 253 ++ + 7 files changed, 2643 insertions(+), 1 deletion(-) + create mode 100644 drivers/media/platform/bcm2835/Kconfig + create mode 100644 drivers/media/platform/bcm2835/Makefile + create mode 100644 drivers/media/platform/bcm2835/bcm2835-unicam.c + create mode 100644 drivers/media/platform/bcm2835/vc4-regs-unicam.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3206,7 +3206,7 @@ F: Documentation/devicetree/bindings/med + F: drivers/staging/media/rpivid + + BROADCOM BCM2835 CAMERA DRIVER +-M: Dave Stevenson ++M: Raspberry Pi Kernel Maintenance + L: linux-media@vger.kernel.org + S: Maintained + F: drivers/media/platform/bcm2835/ +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -146,6 +146,7 @@ source "drivers/media/platform/am437x/Kc + source "drivers/media/platform/xilinx/Kconfig" + source "drivers/media/platform/rcar-vin/Kconfig" + source "drivers/media/platform/atmel/Kconfig" ++source "drivers/media/platform/bcm2835/Kconfig" + source "drivers/media/platform/sunxi/Kconfig" + + config VIDEO_TI_CAL +--- a/drivers/media/platform/Makefile ++++ b/drivers/media/platform/Makefile +@@ -100,4 +100,6 @@ obj-y += meson/ + + obj-y += cros-ec-cec/ + ++obj-y += bcm2835/ ++ + obj-y += sunxi/ +--- /dev/null ++++ b/drivers/media/platform/bcm2835/Kconfig +@@ -0,0 +1,14 @@ ++# Broadcom VideoCore4 V4L2 camera support ++ ++config VIDEO_BCM2835_UNICAM ++ tristate "Broadcom BCM2835 Unicam video capture driver" ++ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER ++ depends on ARCH_BCM2835 || COMPILE_TEST ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_FWNODE ++ help ++ Say Y here to enable V4L2 subdevice for CSI2 receiver. ++ This is a V4L2 subdevice that interfaces directly to the VC4 peripheral. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called bcm2835-unicam. +--- /dev/null ++++ b/drivers/media/platform/bcm2835/Makefile +@@ -0,0 +1,3 @@ ++# Makefile for BCM2835 Unicam driver ++ ++obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o +--- /dev/null ++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c +@@ -0,0 +1,2369 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * BCM2835 Unicam Capture Driver ++ * ++ * Copyright (C) 2017-2020 - Raspberry Pi (Trading) Ltd. ++ * ++ * Dave Stevenson ++ * ++ * Based on TI am437x driver by ++ * Benoit Parrot ++ * Lad, Prabhakar ++ * ++ * and TI CAL camera interface driver by ++ * Benoit Parrot ++ * ++ * ++ * There are two camera drivers in the kernel for BCM283x - this one ++ * and bcm2835-camera (currently in staging). ++ * ++ * This driver directly controls the Unicam peripheral - there is no ++ * involvement with the VideoCore firmware. Unicam receives CSI-2 or ++ * CCP2 data and writes it into SDRAM. ++ * The only potential processing options are to repack Bayer data into an ++ * alternate format, and applying windowing. ++ * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P ++ * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12, ++ * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both ++ * formats where the relevant formats are defined, and will automatically ++ * configure the repacking as required. ++ * Support for windowing may be added later. ++ * ++ * It should be possible to connect this driver to any sensor with a ++ * suitable output interface and V4L2 subdevice driver. ++ * ++ * bcm2835-camera uses the VideoCore firmware to control the sensor, ++ * Unicam, ISP, and all tuner control loops. Fully processed frames are ++ * delivered to the driver by the firmware. It only has sensor drivers ++ * for Omnivision OV5647, and Sony IMX219 sensors. ++ * ++ * The two drivers are mutually exclusive for the same Unicam instance. ++ * The VideoCore firmware checks the device tree configuration during boot. ++ * If it finds device tree nodes called csi0 or csi1 it will block the ++ * firmware from accessing the peripheral, and bcm2835-camera will ++ * not be able to stream data. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc4-regs-unicam.h" ++ ++#define UNICAM_MODULE_NAME "unicam" ++#define UNICAM_VERSION "0.1.0" ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Debug level 0-3"); ++ ++#define unicam_dbg(level, dev, fmt, arg...) \ ++ v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ##arg) ++#define unicam_info(dev, fmt, arg...) \ ++ v4l2_info(&(dev)->v4l2_dev, fmt, ##arg) ++#define unicam_err(dev, fmt, arg...) \ ++ v4l2_err(&(dev)->v4l2_dev, fmt, ##arg) ++ ++/* To protect against a dodgy sensor driver never returning an error from ++ * enum_mbus_code, set a maximum index value to be used. ++ */ ++#define MAX_ENUM_MBUS_CODE 128 ++ ++/* ++ * Stride is a 16 bit register, but also has to be a multiple of 32. ++ */ ++#define BPL_ALIGNMENT 32 ++#define MAX_BYTESPERLINE ((1 << 16) - BPL_ALIGNMENT) ++/* ++ * Max width is therefore determined by the max stride divided by ++ * the number of bits per pixel. Take 32bpp as a ++ * worst case. ++ * No imposed limit on the height, so adopt a square image for want ++ * of anything better. ++ */ ++#define MAX_WIDTH (MAX_BYTESPERLINE / 4) ++#define MAX_HEIGHT MAX_WIDTH ++/* Define a nominal minimum image size */ ++#define MIN_WIDTH 16 ++#define MIN_HEIGHT 16 ++ ++/* ++ * struct unicam_fmt - Unicam media bus format information ++ * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a. ++ * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded ++ * out to 16bpp. 0 if n/a. ++ * @code: V4L2 media bus format code. ++ * @depth: Bits per pixel as delivered from the source. ++ * @csi_dt: CSI data type. ++ * @check_variants: Flag to denote that there are multiple mediabus formats ++ * still in the list that could match this V4L2 format. ++ */ ++struct unicam_fmt { ++ u32 fourcc; ++ u32 repacked_fourcc; ++ u32 code; ++ u8 depth; ++ u8 csi_dt; ++ u8 check_variants; ++}; ++ ++static const struct unicam_fmt formats[] = { ++ /* YUV Formats */ ++ { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ .check_variants = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .code = MEDIA_BUS_FMT_UYVY8_2X8, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ .check_variants = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ .check_variants = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .code = MEDIA_BUS_FMT_VYUY8_2X8, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ .check_variants = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .code = MEDIA_BUS_FMT_YUYV8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .code = MEDIA_BUS_FMT_UYVY8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .code = MEDIA_BUS_FMT_YVYU8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .code = MEDIA_BUS_FMT_VYUY8_1X16, ++ .depth = 16, ++ .csi_dt = 0x1e, ++ }, { ++ /* RGB Formats */ ++ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .depth = 16, ++ .csi_dt = 0x22, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB565_2X8_BE, ++ .depth = 16, ++ .csi_dt = 0x22 ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, ++ .depth = 16, ++ .csi_dt = 0x21, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ ++ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, ++ .depth = 16, ++ .csi_dt = 0x21, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ ++ .code = MEDIA_BUS_FMT_RGB888_1X24, ++ .depth = 24, ++ .csi_dt = 0x24, ++ }, { ++ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ ++ .code = MEDIA_BUS_FMT_BGR888_1X24, ++ .depth = 24, ++ .csi_dt = 0x24, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ ++ .code = MEDIA_BUS_FMT_ARGB8888_1X32, ++ .depth = 32, ++ .csi_dt = 0x0, ++ }, { ++ /* Bayer Formats */ ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR10P, ++ .repacked_fourcc = V4L2_PIX_FMT_SBGGR10, ++ .code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG10P, ++ .repacked_fourcc = V4L2_PIX_FMT_SGBRG10, ++ .code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG10P, ++ .repacked_fourcc = V4L2_PIX_FMT_SGRBG10, ++ .code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB10P, ++ .repacked_fourcc = V4L2_PIX_FMT_SRGGB10, ++ .code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR12P, ++ .repacked_fourcc = V4L2_PIX_FMT_SBGGR12, ++ .code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG12P, ++ .repacked_fourcc = V4L2_PIX_FMT_SGBRG12, ++ .code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG12P, ++ .repacked_fourcc = V4L2_PIX_FMT_SGRBG12, ++ .code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB12P, ++ .repacked_fourcc = V4L2_PIX_FMT_SRGGB12, ++ .code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR14P, ++ .code = MEDIA_BUS_FMT_SBGGR14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG14P, ++ .code = MEDIA_BUS_FMT_SGBRG14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG14P, ++ .code = MEDIA_BUS_FMT_SGRBG14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB14P, ++ .code = MEDIA_BUS_FMT_SRGGB14_1X14, ++ .depth = 14, ++ .csi_dt = 0x2d, ++ }, { ++ /* ++ * 16 bit Bayer formats could be supported, but there is no CSI2 ++ * data_type defined for raw 16, and no sensors that produce it at ++ * present. ++ */ ++ ++ /* Greyscale formats */ ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .code = MEDIA_BUS_FMT_Y8_1X8, ++ .depth = 8, ++ .csi_dt = 0x2a, ++ }, { ++ .fourcc = V4L2_PIX_FMT_Y10P, ++ .repacked_fourcc = V4L2_PIX_FMT_Y10, ++ .code = MEDIA_BUS_FMT_Y10_1X10, ++ .depth = 10, ++ .csi_dt = 0x2b, ++ }, { ++ /* NB There is no packed V4L2 fourcc for this format. */ ++ .repacked_fourcc = V4L2_PIX_FMT_Y12, ++ .code = MEDIA_BUS_FMT_Y12_1X12, ++ .depth = 12, ++ .csi_dt = 0x2c, ++ }, ++}; ++ ++struct unicam_dmaqueue { ++ struct list_head active; ++}; ++ ++struct unicam_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++struct unicam_cfg { ++ /* peripheral base address */ ++ void __iomem *base; ++ /* clock gating base address */ ++ void __iomem *clk_gate_base; ++}; ++ ++#define MAX_POSSIBLE_PIX_FMTS (ARRAY_SIZE(formats)) ++ ++struct unicam_device { ++ /* V4l2 specific parameters */ ++ /* Identifies video device for this channel */ ++ struct video_device video_dev; ++ struct v4l2_ctrl_handler ctrl_handler; ++ ++ struct v4l2_fwnode_endpoint endpoint; ++ ++ struct v4l2_async_subdev asd; ++ ++ /* unicam cfg */ ++ struct unicam_cfg cfg; ++ /* clock handle */ ++ struct clk *clock; ++ /* V4l2 device */ ++ struct v4l2_device v4l2_dev; ++ struct media_device mdev; ++ struct media_pad pad; ++ ++ /* parent device */ ++ struct platform_device *pdev; ++ /* subdevice async Notifier */ ++ struct v4l2_async_notifier notifier; ++ unsigned int sequence; ++ ++ /* ptr to sub device */ ++ struct v4l2_subdev *sensor; ++ /* Pad config for the sensor */ ++ struct v4l2_subdev_pad_config *sensor_config; ++ /* current input at the sub device */ ++ int current_input; ++ ++ /* Pointer pointing to current v4l2_buffer */ ++ struct unicam_buffer *cur_frm; ++ /* Pointer pointing to next v4l2_buffer */ ++ struct unicam_buffer *next_frm; ++ ++ /* video capture */ ++ const struct unicam_fmt *fmt; ++ /* Used to store current pixel format */ ++ struct v4l2_format v_fmt; ++ /* Used to store current mbus frame format */ ++ struct v4l2_mbus_framefmt m_fmt; ++ ++ unsigned int virtual_channel; ++ enum v4l2_mbus_type bus_type; ++ /* ++ * Stores bus.mipi_csi2.flags for CSI2 sensors, or ++ * bus.mipi_csi1.strobe for CCP2. ++ */ ++ unsigned int bus_flags; ++ unsigned int max_data_lanes; ++ unsigned int active_data_lanes; ++ ++ struct v4l2_rect crop; ++ ++ /* Currently selected input on subdev */ ++ int input; ++ ++ /* Buffer queue used in video-buf */ ++ struct vb2_queue buffer_queue; ++ /* Queue of filled frames */ ++ struct unicam_dmaqueue dma_queue; ++ /* IRQ lock for DMA queue */ ++ spinlock_t dma_queue_lock; ++ /* lock used to access this structure */ ++ struct mutex lock; ++ /* Flag to denote that we are processing buffers */ ++ int streaming; ++}; ++ ++/* Hardware access */ ++#define clk_write(dev, val) writel((val) | 0x5a000000, (dev)->clk_gate_base) ++#define clk_read(dev) readl((dev)->clk_gate_base) ++ ++#define reg_read(dev, offset) readl((dev)->base + (offset)) ++#define reg_write(dev, offset, val) writel(val, (dev)->base + (offset)) ++ ++#define reg_read_field(dev, offset, mask) get_field(reg_read((dev), (offset), \ ++ mask)) ++ ++static inline int get_field(u32 value, u32 mask) ++{ ++ return (value & mask) >> __ffs(mask); ++} ++ ++static inline void set_field(u32 *valp, u32 field, u32 mask) ++{ ++ u32 val = *valp; ++ ++ val &= ~mask; ++ val |= (field << __ffs(mask)) & mask; ++ *valp = val; ++} ++ ++static inline void reg_write_field(struct unicam_cfg *dev, u32 offset, ++ u32 field, u32 mask) ++{ ++ u32 val = reg_read((dev), (offset)); ++ ++ set_field(&val, field, mask); ++ reg_write((dev), (offset), val); ++} ++ ++/* Power management functions */ ++static inline int unicam_runtime_get(struct unicam_device *dev) ++{ ++ return pm_runtime_get_sync(&dev->pdev->dev); ++} ++ ++static inline void unicam_runtime_put(struct unicam_device *dev) ++{ ++ pm_runtime_put_sync(&dev->pdev->dev); ++} ++ ++/* Format setup functions */ ++static const struct unicam_fmt *find_format_by_code(u32 code) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formats[i].code == code) ++ return &formats[i]; ++ } ++ ++ return NULL; ++} ++ ++static int check_mbus_format(struct unicam_device *dev, ++ const struct unicam_fmt *format) ++{ ++ struct v4l2_subdev_mbus_code_enum mbus_code; ++ int ret = 0; ++ int i; ++ ++ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) { ++ memset(&mbus_code, 0, sizeof(mbus_code)); ++ mbus_code.index = i; ++ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, ++ NULL, &mbus_code); ++ ++ if (!ret && mbus_code.code == format->code) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static const struct unicam_fmt *find_format_by_pix(struct unicam_device *dev, ++ u32 pixelformat) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(formats); i++) { ++ if (formats[i].fourcc == pixelformat || ++ formats[i].repacked_fourcc == pixelformat) { ++ if (formats[i].check_variants && ++ !check_mbus_format(dev, &formats[i])) ++ continue; ++ return &formats[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static inline unsigned int bytes_per_line(u32 width, ++ const struct unicam_fmt *fmt, ++ u32 v4l2_fourcc) ++{ ++ if (v4l2_fourcc == fmt->repacked_fourcc) ++ /* Repacking always goes to 16bpp */ ++ return ALIGN(width << 1, BPL_ALIGNMENT); ++ else ++ return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT); ++} ++ ++static int __subdev_get_format(struct unicam_device *dev, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_subdev_format sd_fmt = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ int ret; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, get_fmt, dev->sensor_config, ++ &sd_fmt); ++ if (ret < 0) ++ return ret; ++ ++ *fmt = sd_fmt.format; ++ ++ unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, ++ fmt->width, fmt->height, fmt->code); ++ ++ return 0; ++} ++ ++static int __subdev_set_format(struct unicam_device *dev, ++ struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_subdev_format sd_fmt = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ int ret; ++ ++ sd_fmt.format = *fmt; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, ++ &sd_fmt); ++ if (ret < 0) ++ return ret; ++ ++ unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, ++ fmt->width, fmt->height, fmt->code); ++ ++ return 0; ++} ++ ++static int unicam_calc_format_size_bpl(struct unicam_device *dev, ++ const struct unicam_fmt *fmt, ++ struct v4l2_format *f) ++{ ++ unsigned int min_bytesperline; ++ ++ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, ++ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, ++ 0); ++ ++ min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt, ++ f->fmt.pix.pixelformat); ++ ++ if (f->fmt.pix.bytesperline > min_bytesperline && ++ f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) ++ f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, ++ BPL_ALIGNMENT); ++ else ++ f->fmt.pix.bytesperline = min_bytesperline; ++ ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ ++ unicam_dbg(3, dev, "%s: fourcc: %08X size: %dx%d bpl:%d img_size:%d\n", ++ __func__, ++ f->fmt.pix.pixelformat, ++ f->fmt.pix.width, f->fmt.pix.height, ++ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); ++ ++ return 0; ++} ++ ++static int unicam_reset_format(struct unicam_device *dev) ++{ ++ struct v4l2_mbus_framefmt mbus_fmt; ++ int ret; ++ ++ ret = __subdev_get_format(dev, &mbus_fmt); ++ if (ret) { ++ unicam_err(dev, "Failed to get_format - ret %d\n", ret); ++ return ret; ++ } ++ ++ if (mbus_fmt.code != dev->fmt->code) { ++ unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n", ++ dev->fmt->code, mbus_fmt.code); ++ return ret; ++ } ++ ++ v4l2_fill_pix_format(&dev->v_fmt.fmt.pix, &mbus_fmt); ++ dev->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ unicam_calc_format_size_bpl(dev, dev->fmt, &dev->v_fmt); ++ ++ dev->m_fmt = mbus_fmt; ++ ++ return 0; ++} ++ ++static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr) ++{ ++ /* ++ * dmaaddr should be a 32-bit address with the top two bits set to 0x3 ++ * to signify uncached access through the Videocore memory controller. ++ */ ++ BUG_ON((dmaaddr >> 30) != 0x3); ++ ++ reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); ++ reg_write(&dev->cfg, UNICAM_IBEA0, ++ dmaaddr + dev->v_fmt.fmt.pix.sizeimage); ++} ++ ++static inline unsigned int unicam_get_lines_done(struct unicam_device *dev) ++{ ++ dma_addr_t start_addr, cur_addr; ++ unsigned int stride = dev->v_fmt.fmt.pix.bytesperline; ++ struct unicam_buffer *frm = dev->cur_frm; ++ ++ if (!frm) ++ return 0; ++ ++ start_addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0); ++ cur_addr = reg_read(&dev->cfg, UNICAM_IBWP); ++ return (unsigned int)(cur_addr - start_addr) / stride; ++} ++ ++static inline void unicam_schedule_next_buffer(struct unicam_device *dev) ++{ ++ struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_buffer *buf; ++ dma_addr_t addr; ++ ++ buf = list_entry(dma_q->active.next, struct unicam_buffer, list); ++ dev->next_frm = buf; ++ list_del(&buf->list); ++ ++ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ unicam_wr_dma_addr(dev, addr); ++} ++ ++static inline void unicam_process_buffer_complete(struct unicam_device *dev) ++{ ++ dev->cur_frm->vb.field = dev->m_fmt.field; ++ dev->cur_frm->vb.sequence = dev->sequence++; ++ ++ vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); ++ dev->cur_frm = dev->next_frm; ++} ++ ++/* ++ * unicam_isr : ISR handler for unicam capture ++ * @irq: irq number ++ * @dev_id: dev_id ptr ++ * ++ * It changes status of the captured buffer, takes next buffer from the queue ++ * and sets its address in unicam registers ++ */ ++static irqreturn_t unicam_isr(int irq, void *dev) ++{ ++ struct unicam_device *unicam = (struct unicam_device *)dev; ++ struct unicam_cfg *cfg = &unicam->cfg; ++ struct unicam_dmaqueue *dma_q = &unicam->dma_queue; ++ unsigned int lines_done = unicam_get_lines_done(dev); ++ unsigned int sequence = unicam->sequence; ++ int ista, sta; ++ ++ /* ++ * Don't service interrupts if not streaming. ++ * Avoids issues if the VPU should enable the ++ * peripheral without the kernel knowing (that ++ * shouldn't happen, but causes issues if it does). ++ */ ++ if (!unicam->streaming) ++ return IRQ_HANDLED; ++ ++ sta = reg_read(cfg, UNICAM_STA); ++ /* Write value back to clear the interrupts */ ++ reg_write(cfg, UNICAM_STA, sta); ++ ++ ista = reg_read(cfg, UNICAM_ISTA); ++ /* Write value back to clear the interrupts */ ++ reg_write(cfg, UNICAM_ISTA, ista); ++ ++ unicam_dbg(3, unicam, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d", ++ ista, sta, sequence, lines_done); ++ ++ if (!(sta && (UNICAM_IS | UNICAM_PI0))) ++ return IRQ_HANDLED; ++ ++ if (ista & UNICAM_FSI) { ++ /* ++ * Timestamp is to be when the first data byte was captured, ++ * aka frame start. ++ */ ++ if (unicam->cur_frm) ++ unicam->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); ++ } ++ if (ista & UNICAM_FEI || sta & UNICAM_PI0) { ++ /* ++ * Ensure we have swapped buffers already as we can't ++ * stop the peripheral. Overwrite the frame we've just ++ * captured instead. ++ */ ++ if (unicam->cur_frm && unicam->cur_frm != unicam->next_frm) ++ unicam_process_buffer_complete(unicam); ++ } ++ ++ /* Cannot swap buffer at frame end, there may be a race condition ++ * where the HW does not actually swap it if the new frame has ++ * already started. ++ */ ++ if (ista & (UNICAM_FSI | UNICAM_LCI) && !(ista & UNICAM_FEI)) { ++ spin_lock(&unicam->dma_queue_lock); ++ if (!list_empty(&dma_q->active) && ++ unicam->cur_frm == unicam->next_frm) ++ unicam_schedule_next_buffer(unicam); ++ spin_unlock(&unicam->dma_queue_lock); ++ } ++ ++ if (reg_read(&unicam->cfg, UNICAM_ICTL) & UNICAM_FCM) { ++ /* Switch out of trigger mode if selected */ ++ reg_write_field(&unicam->cfg, UNICAM_ICTL, 1, UNICAM_TFC); ++ reg_write_field(&unicam->cfg, UNICAM_ICTL, 0, UNICAM_FCM); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int unicam_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ strlcpy(cap->driver, UNICAM_MODULE_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, UNICAM_MODULE_NAME, sizeof(cap->card)); ++ ++ snprintf(cap->bus_info, sizeof(cap->bus_info), ++ "platform:%s", dev->v4l2_dev.name); ++ ++ return 0; ++} ++ ++static int unicam_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct v4l2_subdev_mbus_code_enum mbus_code; ++ const struct unicam_fmt *fmt = NULL; ++ int index = 0; ++ int ret = 0; ++ int i; ++ ++ for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) { ++ memset(&mbus_code, 0, sizeof(mbus_code)); ++ mbus_code.index = i; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, ++ NULL, &mbus_code); ++ if (ret < 0) { ++ unicam_dbg(2, dev, ++ "subdev->enum_mbus_code idx %d returned %d - index invalid\n", ++ i, ret); ++ return -EINVAL; ++ } ++ ++ fmt = find_format_by_code(mbus_code.code); ++ if (fmt) { ++ if (fmt->fourcc) { ++ if (index == f->index) { ++ f->pixelformat = fmt->fourcc; ++ break; ++ } ++ index++; ++ } ++ if (fmt->repacked_fourcc) { ++ if (index == f->index) { ++ f->pixelformat = fmt->repacked_fourcc; ++ break; ++ } ++ index++; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int unicam_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ *f = dev->v_fmt; ++ ++ return 0; ++} ++ ++static ++const struct unicam_fmt *get_first_supported_format(struct unicam_device *dev) ++{ ++ struct v4l2_subdev_mbus_code_enum mbus_code; ++ const struct unicam_fmt *fmt = NULL; ++ int ret; ++ int j; ++ ++ for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) { ++ memset(&mbus_code, 0, sizeof(mbus_code)); ++ mbus_code.index = j; ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL, ++ &mbus_code); ++ if (ret < 0) { ++ unicam_dbg(2, dev, ++ "subdev->enum_mbus_code idx %d returned %d - continue\n", ++ j, ret); ++ continue; ++ } ++ ++ unicam_dbg(2, dev, "subdev %s: code: 0x%08x idx: %d\n", ++ dev->sensor->name, mbus_code.code, j); ++ ++ fmt = find_format_by_code(mbus_code.code); ++ unicam_dbg(2, dev, "fmt 0x%08x returned as %p, V4L2 FOURCC 0x%08x, csi_dt 0x%02x\n", ++ mbus_code.code, fmt, fmt ? fmt->fourcc : 0, ++ fmt ? fmt->csi_dt : 0); ++ if (fmt) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static int unicam_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct v4l2_subdev_format sd_fmt = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; ++ const struct unicam_fmt *fmt; ++ int ret; ++ ++ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat); ++ if (!fmt) { ++ /* Pixel format not supported by unicam. Choose the first ++ * supported format, and let the sensor choose something else. ++ */ ++ unicam_dbg(3, dev, "Fourcc format (0x%08x) not found. Use first format.\n", ++ f->fmt.pix.pixelformat); ++ ++ fmt = &formats[0]; ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ } ++ ++ v4l2_fill_mbus_format(mbus_fmt, &f->fmt.pix, fmt->code); ++ /* ++ * No support for receiving interlaced video, so never ++ * request it from the sensor subdev. ++ */ ++ mbus_fmt->field = V4L2_FIELD_NONE; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, dev->sensor_config, ++ &sd_fmt); ++ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) ++ return ret; ++ ++ if (mbus_fmt->field != V4L2_FIELD_NONE) ++ unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n"); ++ ++ v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format); ++ if (mbus_fmt->code != fmt->code) { ++ /* Sensor has returned an alternate format */ ++ fmt = find_format_by_code(mbus_fmt->code); ++ if (!fmt) { ++ /* The alternate format is one unicam can't support. ++ * Find the first format that is supported by both, and ++ * then set that. ++ */ ++ fmt = get_first_supported_format(dev); ++ mbus_fmt->code = fmt->code; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, set_fmt, ++ dev->sensor_config, &sd_fmt); ++ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) ++ return ret; ++ ++ if (mbus_fmt->field != V4L2_FIELD_NONE) ++ unicam_info(dev, "Sensor trying to send interlaced video - results may be unpredictable\n"); ++ ++ v4l2_fill_pix_format(&f->fmt.pix, &sd_fmt.format); ++ ++ if (mbus_fmt->code != fmt->code) { ++ /* We've set a format that the sensor reports ++ * as being supported, but it refuses to set it. ++ * Not much else we can do. ++ * Assume that the sensor driver may accept the ++ * format when it is set (rather than tried). ++ */ ++ unicam_err(dev, "Sensor won't accept default format, and Unicam can't support sensor default\n"); ++ } ++ } ++ ++ if (fmt->fourcc) ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ else ++ f->fmt.pix.pixelformat = fmt->repacked_fourcc; ++ } ++ ++ return unicam_calc_format_size_bpl(dev, fmt, f); ++} ++ ++static int unicam_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct vb2_queue *q = &dev->buffer_queue; ++ struct v4l2_mbus_framefmt mbus_fmt = {0}; ++ const struct unicam_fmt *fmt; ++ int ret; ++ ++ if (vb2_is_busy(q)) ++ return -EBUSY; ++ ++ ret = unicam_try_fmt_vid_cap(file, priv, f); ++ if (ret < 0) ++ return ret; ++ ++ fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat); ++ if (!fmt) { ++ /* Unknown pixel format - adopt a default. ++ * This shouldn't happen as try_fmt should have resolved any ++ * issues first. ++ */ ++ fmt = get_first_supported_format(dev); ++ if (!fmt) ++ /* It shouldn't be possible to get here with no ++ * supported formats ++ */ ++ return -EINVAL; ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ return -EINVAL; ++ } ++ ++ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code); ++ ++ ret = __subdev_set_format(dev, &mbus_fmt); ++ if (ret) { ++ unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ /* Just double check nothing has gone wrong */ ++ if (mbus_fmt.code != fmt->code) { ++ unicam_dbg(3, dev, ++ "%s subdev changed format on us, this should not happen\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ dev->fmt = fmt; ++ dev->v_fmt.fmt.pix.pixelformat = f->fmt.pix.pixelformat; ++ dev->v_fmt.fmt.pix.bytesperline = f->fmt.pix.bytesperline; ++ unicam_reset_format(dev); ++ ++ unicam_dbg(3, dev, "%s %dx%d, mbus_fmt 0x%08X, V4L2 pix 0x%08X.\n", ++ __func__, dev->v_fmt.fmt.pix.width, ++ dev->v_fmt.fmt.pix.height, mbus_fmt.code, ++ dev->v_fmt.fmt.pix.pixelformat); ++ ++ *f = dev->v_fmt; ++ ++ return 0; ++} ++ ++static int unicam_queue_setup(struct vb2_queue *vq, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ struct device *alloc_devs[]) ++{ ++ struct unicam_device *dev = vb2_get_drv_priv(vq); ++ unsigned int size = dev->v_fmt.fmt.pix.sizeimage; ++ ++ if (vq->num_buffers + *nbuffers < 3) ++ *nbuffers = 3 - vq->num_buffers; ++ ++ if (*nplanes) { ++ if (sizes[0] < size) { ++ unicam_err(dev, "sizes[0] %i < size %u\n", sizes[0], ++ size); ++ return -EINVAL; ++ } ++ size = sizes[0]; ++ } ++ ++ *nplanes = 1; ++ sizes[0] = size; ++ ++ return 0; ++} ++ ++static int unicam_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, ++ vb.vb2_buf); ++ unsigned long size; ++ ++ if (WARN_ON(!dev->fmt)) ++ return -EINVAL; ++ ++ size = dev->v_fmt.fmt.pix.sizeimage; ++ if (vb2_plane_size(vb, 0) < size) { ++ unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", ++ vb2_plane_size(vb, 0), size); ++ return -EINVAL; ++ } ++ ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); ++ return 0; ++} ++ ++static void unicam_buffer_queue(struct vb2_buffer *vb) ++{ ++ struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, ++ vb.vb2_buf); ++ struct unicam_dmaqueue *dma_queue = &dev->dma_queue; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ list_add_tail(&buf->list, &dma_queue->active); ++ spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++} ++ ++static void unicam_set_packing_config(struct unicam_device *dev) ++{ ++ int pack, unpack; ++ u32 val; ++ ++ if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) { ++ unpack = UNICAM_PUM_NONE; ++ pack = UNICAM_PPM_NONE; ++ } else { ++ switch (dev->fmt->depth) { ++ case 8: ++ unpack = UNICAM_PUM_UNPACK8; ++ break; ++ case 10: ++ unpack = UNICAM_PUM_UNPACK10; ++ break; ++ case 12: ++ unpack = UNICAM_PUM_UNPACK12; ++ break; ++ case 14: ++ unpack = UNICAM_PUM_UNPACK14; ++ break; ++ case 16: ++ unpack = UNICAM_PUM_UNPACK16; ++ break; ++ default: ++ unpack = UNICAM_PUM_NONE; ++ break; ++ } ++ ++ /* Repacking is always to 16bpp */ ++ pack = UNICAM_PPM_PACK16; ++ } ++ ++ val = 0; ++ set_field(&val, unpack, UNICAM_PUM_MASK); ++ set_field(&val, pack, UNICAM_PPM_MASK); ++ reg_write(&dev->cfg, UNICAM_IPIPE, val); ++} ++ ++static void unicam_cfg_image_id(struct unicam_device *dev) ++{ ++ struct unicam_cfg *cfg = &dev->cfg; ++ ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ /* CSI2 mode */ ++ reg_write(cfg, UNICAM_IDI0, ++ (dev->virtual_channel << 6) | dev->fmt->csi_dt); ++ } else { ++ /* CCP2 mode */ ++ reg_write(cfg, UNICAM_IDI0, (0x80 | dev->fmt->csi_dt)); ++ } ++} ++ ++static void unicam_start_rx(struct unicam_device *dev, unsigned long addr) ++{ ++ struct unicam_cfg *cfg = &dev->cfg; ++ int line_int_freq = dev->v_fmt.fmt.pix.height >> 2; ++ unsigned int i; ++ u32 val; ++ ++ if (line_int_freq < 128) ++ line_int_freq = 128; ++ ++ /* Enable lane clocks */ ++ val = 1; ++ for (i = 0; i < dev->active_data_lanes; i++) ++ val = val << 2 | 1; ++ clk_write(cfg, val); ++ ++ /* Basic init */ ++ reg_write(cfg, UNICAM_CTRL, UNICAM_MEM); ++ ++ /* Enable analogue control, and leave in reset. */ ++ val = UNICAM_AR; ++ set_field(&val, 7, UNICAM_CTATADJ_MASK); ++ set_field(&val, 7, UNICAM_PTATADJ_MASK); ++ reg_write(cfg, UNICAM_ANA, val); ++ usleep_range(1000, 2000); ++ ++ /* Come out of reset */ ++ reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_AR); ++ ++ /* Peripheral reset */ ++ reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPR); ++ reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPR); ++ ++ reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE); ++ ++ /* Enable Rx control. */ ++ val = reg_read(cfg, UNICAM_CTRL); ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK); ++ set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK); ++ } else { ++ set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK); ++ set_field(&val, dev->bus_flags, UNICAM_DCM_MASK); ++ } ++ /* Packet framer timeout */ ++ set_field(&val, 0xf, UNICAM_PFT_MASK); ++ set_field(&val, 128, UNICAM_OET_MASK); ++ reg_write(cfg, UNICAM_CTRL, val); ++ ++ reg_write(cfg, UNICAM_IHWIN, 0); ++ reg_write(cfg, UNICAM_IVWIN, 0); ++ ++ /* AXI bus access QoS setup */ ++ val = reg_read(&dev->cfg, UNICAM_PRI); ++ set_field(&val, 0, UNICAM_BL_MASK); ++ set_field(&val, 0, UNICAM_BS_MASK); ++ set_field(&val, 0xe, UNICAM_PP_MASK); ++ set_field(&val, 8, UNICAM_NP_MASK); ++ set_field(&val, 2, UNICAM_PT_MASK); ++ set_field(&val, 1, UNICAM_PE); ++ reg_write(cfg, UNICAM_PRI, val); ++ ++ reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_DDL); ++ ++ /* Always start in trigger frame capture mode (UNICAM_FCM set) */ ++ val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM; ++ set_field(&val, line_int_freq, UNICAM_LCIE_MASK); ++ reg_write(cfg, UNICAM_ICTL, val); ++ reg_write(cfg, UNICAM_STA, UNICAM_STA_MASK_ALL); ++ reg_write(cfg, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL); ++ ++ /* tclk_term_en */ ++ reg_write_field(cfg, UNICAM_CLT, 2, UNICAM_CLT1_MASK); ++ /* tclk_settle */ ++ reg_write_field(cfg, UNICAM_CLT, 6, UNICAM_CLT2_MASK); ++ /* td_term_en */ ++ reg_write_field(cfg, UNICAM_DLT, 2, UNICAM_DLT1_MASK); ++ /* ths_settle */ ++ reg_write_field(cfg, UNICAM_DLT, 6, UNICAM_DLT2_MASK); ++ /* trx_enable */ ++ reg_write_field(cfg, UNICAM_DLT, 0, UNICAM_DLT3_MASK); ++ ++ reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_SOE); ++ ++ /* Packet compare setup - required to avoid missing frame ends */ ++ val = 0; ++ set_field(&val, 1, UNICAM_PCE); ++ set_field(&val, 1, UNICAM_GI); ++ set_field(&val, 1, UNICAM_CPH); ++ set_field(&val, 0, UNICAM_PCVC_MASK); ++ set_field(&val, 1, UNICAM_PCDT_MASK); ++ reg_write(cfg, UNICAM_CMP0, val); ++ ++ /* Enable clock lane and set up terminations */ ++ val = 0; ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ /* CSI2 */ ++ set_field(&val, 1, UNICAM_CLE); ++ set_field(&val, 1, UNICAM_CLLPE); ++ if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { ++ set_field(&val, 1, UNICAM_CLTRE); ++ set_field(&val, 1, UNICAM_CLHSE); ++ } ++ } else { ++ /* CCP2 */ ++ set_field(&val, 1, UNICAM_CLE); ++ set_field(&val, 1, UNICAM_CLHSE); ++ set_field(&val, 1, UNICAM_CLTRE); ++ } ++ reg_write(cfg, UNICAM_CLK, val); ++ ++ /* ++ * Enable required data lanes with appropriate terminations. ++ * The same value needs to be written to UNICAM_DATn registers for ++ * the active lanes, and 0 for inactive ones. ++ */ ++ val = 0; ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ /* CSI2 */ ++ set_field(&val, 1, UNICAM_DLE); ++ set_field(&val, 1, UNICAM_DLLPE); ++ if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { ++ set_field(&val, 1, UNICAM_DLTRE); ++ set_field(&val, 1, UNICAM_DLHSE); ++ } ++ } else { ++ /* CCP2 */ ++ set_field(&val, 1, UNICAM_DLE); ++ set_field(&val, 1, UNICAM_DLHSE); ++ set_field(&val, 1, UNICAM_DLTRE); ++ } ++ reg_write(cfg, UNICAM_DAT0, val); ++ ++ if (dev->active_data_lanes == 1) ++ val = 0; ++ reg_write(cfg, UNICAM_DAT1, val); ++ ++ if (dev->max_data_lanes > 2) { ++ /* ++ * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the ++ * instance supports more than 2 data lanes. ++ */ ++ if (dev->active_data_lanes == 2) ++ val = 0; ++ reg_write(cfg, UNICAM_DAT2, val); ++ ++ if (dev->active_data_lanes == 3) ++ val = 0; ++ reg_write(cfg, UNICAM_DAT3, val); ++ } ++ ++ reg_write(&dev->cfg, UNICAM_IBLS, dev->v_fmt.fmt.pix.bytesperline); ++ unicam_wr_dma_addr(dev, addr); ++ unicam_set_packing_config(dev); ++ unicam_cfg_image_id(dev); ++ ++ /* Disabled embedded data */ ++ val = 0; ++ set_field(&val, 0, UNICAM_EDL_MASK); ++ reg_write(cfg, UNICAM_DCS, val); ++ ++ val = reg_read(cfg, UNICAM_MISC); ++ set_field(&val, 1, UNICAM_FL0); ++ set_field(&val, 1, UNICAM_FL1); ++ reg_write(cfg, UNICAM_MISC, val); ++ ++ /* Enable peripheral */ ++ reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPE); ++ ++ /* Load image pointers */ ++ reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_LIP_MASK); ++ ++ /* ++ * Enable trigger only for the first frame to ++ * sync correctly to the FS from the source. ++ */ ++ reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_TFC); ++} ++ ++static void unicam_disable(struct unicam_device *dev) ++{ ++ struct unicam_cfg *cfg = &dev->cfg; ++ ++ /* Analogue lane control disable */ ++ reg_write_field(cfg, UNICAM_ANA, 1, UNICAM_DDL); ++ ++ /* Stop the output engine */ ++ reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_SOE); ++ ++ /* Disable the data lanes. */ ++ reg_write(cfg, UNICAM_DAT0, 0); ++ reg_write(cfg, UNICAM_DAT1, 0); ++ ++ if (dev->max_data_lanes > 2) { ++ reg_write(cfg, UNICAM_DAT2, 0); ++ reg_write(cfg, UNICAM_DAT3, 0); ++ } ++ ++ /* Peripheral reset */ ++ reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPR); ++ usleep_range(50, 100); ++ reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPR); ++ ++ /* Disable peripheral */ ++ reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE); ++ ++ /* Disable all lane clocks */ ++ clk_write(cfg, 0); ++} ++ ++static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) ++{ ++ struct unicam_device *dev = vb2_get_drv_priv(vq); ++ struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_buffer *buf, *tmp; ++ unsigned long addr = 0; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ buf = list_entry(dma_q->active.next, struct unicam_buffer, list); ++ dev->cur_frm = buf; ++ dev->next_frm = buf; ++ list_del(&buf->list); ++ spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++ ++ addr = vb2_dma_contig_plane_dma_addr(&dev->cur_frm->vb.vb2_buf, 0); ++ dev->sequence = 0; ++ ++ ret = unicam_runtime_get(dev); ++ if (ret < 0) { ++ unicam_dbg(3, dev, "unicam_runtime_get failed\n"); ++ goto err_release_buffers; ++ } ++ ++ dev->active_data_lanes = dev->max_data_lanes; ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY && ++ v4l2_subdev_has_op(dev->sensor, video, g_mbus_config)) { ++ struct v4l2_mbus_config mbus_config; ++ ++ ret = v4l2_subdev_call(dev->sensor, video, g_mbus_config, ++ &mbus_config); ++ if (ret < 0) { ++ unicam_dbg(3, dev, "g_mbus_config failed\n"); ++ goto err_pm_put; ++ } ++ ++ dev->active_data_lanes = ++ (mbus_config.flags & V4L2_MBUS_CSI2_LANE_MASK) >> ++ __ffs(V4L2_MBUS_CSI2_LANE_MASK); ++ if (!dev->active_data_lanes) ++ dev->active_data_lanes = dev->max_data_lanes; ++ } ++ if (dev->active_data_lanes > dev->max_data_lanes) { ++ unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", ++ dev->active_data_lanes, dev->max_data_lanes); ++ ret = -EINVAL; ++ goto err_pm_put; ++ } ++ ++ unicam_dbg(1, dev, "Running with %u data lanes\n", ++ dev->active_data_lanes); ++ ++ ret = clk_set_rate(dev->clock, 100 * 1000 * 1000); ++ if (ret) { ++ unicam_err(dev, "failed to set up clock\n"); ++ goto err_pm_put; ++ } ++ ++ ret = clk_prepare_enable(dev->clock); ++ if (ret) { ++ unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); ++ goto err_pm_put; ++ } ++ dev->streaming = 1; ++ ++ unicam_start_rx(dev, addr); ++ ++ ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); ++ if (ret < 0) { ++ unicam_err(dev, "stream on failed in subdev\n"); ++ goto err_disable_unicam; ++ } ++ ++ return 0; ++ ++err_disable_unicam: ++ unicam_disable(dev); ++ clk_disable_unprepare(dev->clock); ++err_pm_put: ++ unicam_runtime_put(dev); ++err_release_buffers: ++ list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { ++ list_del(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); ++ } ++ if (dev->cur_frm != dev->next_frm) ++ vb2_buffer_done(&dev->next_frm->vb.vb2_buf, ++ VB2_BUF_STATE_QUEUED); ++ vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); ++ dev->next_frm = NULL; ++ dev->cur_frm = NULL; ++ ++ return ret; ++} ++ ++static void unicam_stop_streaming(struct vb2_queue *vq) ++{ ++ struct unicam_device *dev = vb2_get_drv_priv(vq); ++ struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_buffer *buf, *tmp; ++ unsigned long flags; ++ ++ if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) ++ unicam_err(dev, "stream off failed in subdev\n"); ++ ++ unicam_disable(dev); ++ ++ /* Release all active buffers */ ++ spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { ++ list_del(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ ++ if (dev->cur_frm == dev->next_frm) { ++ vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } else { ++ vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ vb2_buffer_done(&dev->next_frm->vb.vb2_buf, ++ VB2_BUF_STATE_ERROR); ++ } ++ dev->cur_frm = NULL; ++ dev->next_frm = NULL; ++ spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++ ++ clk_disable_unprepare(dev->clock); ++ unicam_runtime_put(dev); ++} ++ ++static int unicam_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) { ++ inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; ++ inp->std = 0; ++ } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) { ++ inp->capabilities = V4L2_IN_CAP_STD; ++ if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) ++ < 0) ++ inp->std = V4L2_STD_ALL; ++ } else { ++ inp->capabilities = 0; ++ inp->std = 0; ++ } ++ sprintf(inp->name, "Camera 0"); ++ return 0; ++} ++ ++static int unicam_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int unicam_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ /* ++ * FIXME: Ideally we would like to be able to query the source ++ * subdevice for information over the input connectors it supports, ++ * and map that through in to a call to video_ops->s_routing. ++ * There is no infrastructure support for defining that within ++ * devicetree at present. Until that is implemented we can't ++ * map a user physical connector number to s_routing input number. ++ */ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int unicam_querystd(struct file *file, void *priv, ++ v4l2_std_id *std) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, video, querystd, std); ++} ++ ++static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, video, g_std, std); ++} ++ ++static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ int ret; ++ v4l2_std_id current_std; ++ ++ ret = v4l2_subdev_call(dev->sensor, video, g_std, ¤t_std); ++ if (ret) ++ return ret; ++ ++ if (std == current_std) ++ return 0; ++ ++ if (vb2_is_busy(&dev->buffer_queue)) ++ return -EBUSY; ++ ++ ret = v4l2_subdev_call(dev->sensor, video, s_std, std); ++ ++ /* Force recomputation of bytesperline */ ++ dev->v_fmt.fmt.pix.bytesperline = 0; ++ ++ unicam_reset_format(dev); ++ ++ return ret; ++} ++ ++static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, pad, set_edid, edid); ++} ++ ++static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, pad, get_edid, edid); ++} ++ ++static int unicam_enum_framesizes(struct file *file, void *priv, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ const struct unicam_fmt *fmt; ++ struct v4l2_subdev_frame_size_enum fse; ++ int ret; ++ ++ /* check for valid format */ ++ fmt = find_format_by_pix(dev, fsize->pixel_format); ++ if (!fmt) { ++ unicam_dbg(3, dev, "Invalid pixel code: %x\n", ++ fsize->pixel_format); ++ return -EINVAL; ++ } ++ ++ fse.index = fsize->index; ++ fse.pad = 0; ++ fse.code = fmt->code; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse); ++ if (ret) ++ return ret; ++ ++ unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", ++ __func__, fse.index, fse.code, fse.min_width, fse.max_width, ++ fse.min_height, fse.max_height); ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = fse.max_width; ++ fsize->discrete.height = fse.max_height; ++ ++ return 0; ++} ++ ++static int unicam_enum_frameintervals(struct file *file, void *priv, ++ struct v4l2_frmivalenum *fival) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ const struct unicam_fmt *fmt; ++ struct v4l2_subdev_frame_interval_enum fie = { ++ .index = fival->index, ++ .width = fival->width, ++ .height = fival->height, ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ int ret; ++ ++ fmt = find_format_by_pix(dev, fival->pixel_format); ++ if (!fmt) ++ return -EINVAL; ++ ++ fie.code = fmt->code; ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval, ++ NULL, &fie); ++ if (ret) ++ return ret; ++ ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete = fie.interval; ++ ++ return 0; ++} ++ ++static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a); ++} ++ ++static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a); ++} ++ ++static int unicam_g_dv_timings(struct file *file, void *priv, ++ struct v4l2_dv_timings *timings) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings); ++} ++ ++static int unicam_s_dv_timings(struct file *file, void *priv, ++ struct v4l2_dv_timings *timings) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct v4l2_dv_timings current_timings; ++ int ret; ++ ++ ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings, ++ ¤t_timings); ++ ++ if (v4l2_match_dv_timings(timings, ¤t_timings, 0, false)) ++ return 0; ++ ++ if (vb2_is_busy(&dev->buffer_queue)) ++ return -EBUSY; ++ ++ ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings); ++ ++ /* Force recomputation of bytesperline */ ++ dev->v_fmt.fmt.pix.bytesperline = 0; ++ ++ unicam_reset_format(dev); ++ ++ return ret; ++} ++ ++static int unicam_query_dv_timings(struct file *file, void *priv, ++ struct v4l2_dv_timings *timings) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings); ++} ++ ++static int unicam_enum_dv_timings(struct file *file, void *priv, ++ struct v4l2_enum_dv_timings *timings) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); ++} ++ ++static int unicam_dv_timings_cap(struct file *file, void *priv, ++ struct v4l2_dv_timings_cap *cap) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ ++ return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); ++} ++ ++static int unicam_subscribe_event(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_SOURCE_CHANGE: ++ return v4l2_event_subscribe(fh, sub, 4, NULL); ++ } ++ ++ return v4l2_ctrl_subscribe_event(fh, sub); ++} ++ ++static int unicam_log_status(struct file *file, void *fh) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct unicam_cfg *cfg = &dev->cfg; ++ u32 reg; ++ ++ /* status for sub devices */ ++ v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status); ++ ++ unicam_info(dev, "-----Receiver status-----\n"); ++ unicam_info(dev, "V4L2 width/height: %ux%u\n", ++ dev->v_fmt.fmt.pix.width, dev->v_fmt.fmt.pix.height); ++ unicam_info(dev, "Mediabus format: %08x\n", dev->fmt->code); ++ unicam_info(dev, "V4L2 format: %08x\n", ++ dev->v_fmt.fmt.pix.pixelformat); ++ reg = reg_read(&dev->cfg, UNICAM_IPIPE); ++ unicam_info(dev, "Unpacking/packing: %u / %u\n", ++ get_field(reg, UNICAM_PUM_MASK), ++ get_field(reg, UNICAM_PPM_MASK)); ++ unicam_info(dev, "----Live data----\n"); ++ unicam_info(dev, "Programmed stride: %4u\n", ++ reg_read(cfg, UNICAM_IBLS)); ++ unicam_info(dev, "Detected resolution: %ux%u\n", ++ reg_read(cfg, UNICAM_IHSTA), ++ reg_read(cfg, UNICAM_IVSTA)); ++ unicam_info(dev, "Write pointer: %08x\n", ++ reg_read(cfg, UNICAM_IBWP)); ++ ++ return 0; ++} ++ ++static void unicam_notify(struct v4l2_subdev *sd, ++ unsigned int notification, void *arg) ++{ ++ struct unicam_device *dev = ++ container_of(sd->v4l2_dev, struct unicam_device, v4l2_dev); ++ ++ switch (notification) { ++ case V4L2_DEVICE_NOTIFY_EVENT: ++ v4l2_event_queue(&dev->video_dev, arg); ++ break; ++ default: ++ break; ++ } ++} ++ ++static const struct vb2_ops unicam_video_qops = { ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .queue_setup = unicam_queue_setup, ++ .buf_prepare = unicam_buffer_prepare, ++ .buf_queue = unicam_buffer_queue, ++ .start_streaming = unicam_start_streaming, ++ .stop_streaming = unicam_stop_streaming, ++}; ++ ++/* ++ * unicam_open : This function is based on the v4l2_fh_open helper function. ++ * It has been augmented to handle sensor subdevice power management, ++ */ ++static int unicam_open(struct file *file) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ int ret; ++ ++ mutex_lock(&dev->lock); ++ ++ ret = v4l2_fh_open(file); ++ if (ret) { ++ unicam_err(dev, "v4l2_fh_open failed\n"); ++ goto unlock; ++ } ++ ++ if (!v4l2_fh_is_singular_file(file)) ++ goto unlock; ++ ++ ret = v4l2_subdev_call(dev->sensor, core, s_power, 1); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ v4l2_fh_release(file); ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&dev->lock); ++ return ret; ++} ++ ++static int unicam_release(struct file *file) ++{ ++ struct unicam_device *dev = video_drvdata(file); ++ struct v4l2_subdev *sd = dev->sensor; ++ bool fh_singular; ++ int ret; ++ ++ mutex_lock(&dev->lock); ++ ++ fh_singular = v4l2_fh_is_singular_file(file); ++ ++ ret = _vb2_fop_release(file, NULL); ++ ++ if (fh_singular) ++ v4l2_subdev_call(sd, core, s_power, 0); ++ ++ mutex_unlock(&dev->lock); ++ ++ return ret; ++} ++ ++/* unicam capture driver file operations */ ++static const struct v4l2_file_operations unicam_fops = { ++ .owner = THIS_MODULE, ++ .open = unicam_open, ++ .release = unicam_release, ++ .read = vb2_fop_read, ++ .poll = vb2_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = vb2_fop_mmap, ++}; ++ ++/* unicam capture ioctl operations */ ++static const struct v4l2_ioctl_ops unicam_ioctl_ops = { ++ .vidioc_querycap = unicam_querycap, ++ .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap, ++ ++ .vidioc_enum_input = unicam_enum_input, ++ .vidioc_g_input = unicam_g_input, ++ .vidioc_s_input = unicam_s_input, ++ ++ .vidioc_querystd = unicam_querystd, ++ .vidioc_s_std = unicam_s_std, ++ .vidioc_g_std = unicam_g_std, ++ ++ .vidioc_g_edid = unicam_g_edid, ++ .vidioc_s_edid = unicam_s_edid, ++ ++ .vidioc_enum_framesizes = unicam_enum_framesizes, ++ .vidioc_enum_frameintervals = unicam_enum_frameintervals, ++ ++ .vidioc_g_parm = unicam_g_parm, ++ .vidioc_s_parm = unicam_s_parm, ++ ++ .vidioc_s_dv_timings = unicam_s_dv_timings, ++ .vidioc_g_dv_timings = unicam_g_dv_timings, ++ .vidioc_query_dv_timings = unicam_query_dv_timings, ++ .vidioc_enum_dv_timings = unicam_enum_dv_timings, ++ .vidioc_dv_timings_cap = unicam_dv_timings_cap, ++ ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_create_bufs = vb2_ioctl_create_bufs, ++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ ++ .vidioc_log_status = unicam_log_status, ++ .vidioc_subscribe_event = unicam_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++}; ++ ++static int ++unicam_async_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct unicam_device *unicam = container_of(notifier->v4l2_dev, ++ struct unicam_device, v4l2_dev); ++ ++ if (unicam->sensor) { ++ unicam_info(unicam, "Rejecting subdev %s (Already set!!)", ++ subdev->name); ++ return 0; ++ } ++ ++ unicam->sensor = subdev; ++ unicam_dbg(1, unicam, "Using sensor %s for capture\n", subdev->name); ++ ++ return 0; ++} ++ ++static int unicam_probe_complete(struct unicam_device *unicam) ++{ ++ struct video_device *vdev; ++ struct vb2_queue *q; ++ struct v4l2_mbus_framefmt mbus_fmt = {0}; ++ const struct unicam_fmt *fmt; ++ int ret; ++ ++ v4l2_set_subdev_hostdata(unicam->sensor, unicam); ++ ++ unicam->v4l2_dev.notify = unicam_notify; ++ ++ unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor); ++ if (!unicam->sensor_config) ++ return -ENOMEM; ++ ++ ret = __subdev_get_format(unicam, &mbus_fmt); ++ if (ret) { ++ unicam_err(unicam, "Failed to get_format - ret %d\n", ret); ++ return ret; ++ } ++ ++ fmt = find_format_by_code(mbus_fmt.code); ++ if (!fmt) { ++ /* Find the first format that the sensor and unicam both ++ * support ++ */ ++ fmt = get_first_supported_format(unicam); ++ ++ if (!fmt) ++ /* No compatible formats */ ++ return -EINVAL; ++ ++ mbus_fmt.code = fmt->code; ++ ret = __subdev_set_format(unicam, &mbus_fmt); ++ if (ret) ++ return -EINVAL; ++ } ++ if (mbus_fmt.field != V4L2_FIELD_NONE) { ++ /* Interlaced not supported - disable it now. */ ++ mbus_fmt.field = V4L2_FIELD_NONE; ++ ret = __subdev_set_format(unicam, &mbus_fmt); ++ if (ret) ++ return -EINVAL; ++ } ++ ++ unicam->fmt = fmt; ++ if (fmt->fourcc) ++ unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc; ++ else ++ unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc; ++ ++ /* Read current subdev format */ ++ unicam_reset_format(unicam); ++ ++ if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) { ++ v4l2_std_id tvnorms; ++ ++ if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video, ++ g_tvnorms))) ++ /* ++ * Subdevice should not advertise s_std but not ++ * g_tvnorms ++ */ ++ return -EINVAL; ++ ++ ret = v4l2_subdev_call(unicam->sensor, video, ++ g_tvnorms, &tvnorms); ++ if (WARN_ON(ret)) ++ return -EINVAL; ++ unicam->video_dev.tvnorms |= tvnorms; ++ } ++ ++ spin_lock_init(&unicam->dma_queue_lock); ++ mutex_init(&unicam->lock); ++ ++ /* Add controls from the subdevice */ ++ ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, ++ unicam->sensor->ctrl_handler, NULL, true); ++ if (ret < 0) ++ return ret; ++ ++ q = &unicam->buffer_queue; ++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; ++ q->drv_priv = unicam; ++ q->ops = &unicam_video_qops; ++ q->mem_ops = &vb2_dma_contig_memops; ++ q->buf_struct_size = sizeof(struct unicam_buffer); ++ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ q->lock = &unicam->lock; ++ q->min_buffers_needed = 2; ++ q->dev = &unicam->pdev->dev; ++ ++ ret = vb2_queue_init(q); ++ if (ret) { ++ unicam_err(unicam, "vb2_queue_init() failed\n"); ++ return ret; ++ } ++ ++ INIT_LIST_HEAD(&unicam->dma_queue.active); ++ ++ vdev = &unicam->video_dev; ++ strlcpy(vdev->name, UNICAM_MODULE_NAME, sizeof(vdev->name)); ++ vdev->release = video_device_release_empty; ++ vdev->fops = &unicam_fops; ++ vdev->ioctl_ops = &unicam_ioctl_ops; ++ vdev->v4l2_dev = &unicam->v4l2_dev; ++ vdev->vfl_dir = VFL_DIR_RX; ++ vdev->queue = q; ++ vdev->lock = &unicam->lock; ++ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | ++ V4L2_CAP_READWRITE; ++ ++ /* If the source has no controls then remove our ctrl handler. */ ++ if (list_empty(&unicam->ctrl_handler.ctrls)) ++ unicam->v4l2_dev.ctrl_handler = NULL; ++ ++ video_set_drvdata(vdev, unicam); ++ vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; ++ ++ if (!v4l2_subdev_has_op(unicam->sensor, video, s_std)) { ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_STD); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_STD); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUMSTD); ++ } ++ if (!v4l2_subdev_has_op(unicam->sensor, video, querystd)) ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERYSTD); ++ if (!v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_EDID); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_EDID); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_DV_TIMINGS_CAP); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_DV_TIMINGS); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_DV_TIMINGS); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS); ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS); ++ } ++ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval)) ++ v4l2_disable_ioctl(&unicam->video_dev, ++ VIDIOC_ENUM_FRAMEINTERVALS); ++ if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval)) ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_PARM); ++ if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval)) ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_PARM); ++ ++ if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size)) ++ v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_FRAMESIZES); ++ ++ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ unicam_err(unicam, "Unable to register video device.\n"); ++ return ret; ++ } ++ ++ ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); ++ if (ret) { ++ unicam_err(unicam, ++ "Unable to register subdev nodes.\n"); ++ video_unregister_device(&unicam->video_dev); ++ return ret; ++ } ++ ++ ret = media_create_pad_link(&unicam->sensor->entity, 0, ++ &unicam->video_dev.entity, 0, ++ MEDIA_LNK_FL_ENABLED | ++ MEDIA_LNK_FL_IMMUTABLE); ++ if (ret) { ++ unicam_err(unicam, "Unable to create pad links.\n"); ++ video_unregister_device(&unicam->video_dev); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int unicam_async_complete(struct v4l2_async_notifier *notifier) ++{ ++ struct unicam_device *unicam = container_of(notifier->v4l2_dev, ++ struct unicam_device, v4l2_dev); ++ ++ return unicam_probe_complete(unicam); ++} ++ ++static const struct v4l2_async_notifier_operations unicam_async_ops = { ++ .bound = unicam_async_bound, ++ .complete = unicam_async_complete, ++}; ++ ++static int of_unicam_connect_subdevs(struct unicam_device *dev) ++{ ++ struct platform_device *pdev = dev->pdev; ++ struct device_node *parent, *ep_node = NULL, *remote_ep = NULL, ++ *sensor_node = NULL; ++ struct v4l2_fwnode_endpoint *ep; ++ struct v4l2_async_subdev *asd; ++ unsigned int peripheral_data_lanes; ++ int ret = -EINVAL; ++ unsigned int lane; ++ ++ parent = pdev->dev.of_node; ++ ++ asd = &dev->asd; ++ ep = &dev->endpoint; ++ ++ ep_node = of_graph_get_next_endpoint(parent, NULL); ++ if (!ep_node) { ++ unicam_dbg(3, dev, "can't get next endpoint\n"); ++ goto cleanup_exit; ++ } ++ ++ unicam_dbg(3, dev, "ep_node is %s\n", ep_node->name); ++ ++ v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), ep); ++ ++ for (lane = 0; lane < ep->bus.mipi_csi2.num_data_lanes; lane++) { ++ if (ep->bus.mipi_csi2.data_lanes[lane] != lane + 1) { ++ unicam_err(dev, "Local endpoint - data lane reordering not supported\n"); ++ goto cleanup_exit; ++ } ++ } ++ ++ peripheral_data_lanes = ep->bus.mipi_csi2.num_data_lanes; ++ ++ sensor_node = of_graph_get_remote_port_parent(ep_node); ++ if (!sensor_node) { ++ unicam_dbg(3, dev, "can't get remote parent\n"); ++ goto cleanup_exit; ++ } ++ unicam_dbg(3, dev, "sensor_node is %s\n", sensor_node->name); ++ asd->match_type = V4L2_ASYNC_MATCH_FWNODE; ++ asd->match.fwnode = of_fwnode_handle(sensor_node); ++ ++ remote_ep = of_graph_get_remote_endpoint(ep_node); ++ if (!remote_ep) { ++ unicam_dbg(3, dev, "can't get remote-endpoint\n"); ++ goto cleanup_exit; ++ } ++ unicam_dbg(3, dev, "remote_ep is %s\n", remote_ep->name); ++ v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), ep); ++ unicam_dbg(3, dev, "parsed remote_ep to endpoint. nr_of_link_frequencies %u, bus_type %u\n", ++ ep->nr_of_link_frequencies, ep->bus_type); ++ ++ switch (ep->bus_type) { ++ case V4L2_MBUS_CSI2_DPHY: ++ if (ep->bus.mipi_csi2.num_data_lanes > ++ peripheral_data_lanes) { ++ unicam_err(dev, "Subdevice %s wants too many data lanes (%u > %u)\n", ++ sensor_node->name, ++ ep->bus.mipi_csi2.num_data_lanes, ++ peripheral_data_lanes); ++ goto cleanup_exit; ++ } ++ for (lane = 0; ++ lane < ep->bus.mipi_csi2.num_data_lanes; ++ lane++) { ++ if (ep->bus.mipi_csi2.data_lanes[lane] != lane + 1) { ++ unicam_err(dev, "Subdevice %s - incompatible data lane config\n", ++ sensor_node->name); ++ goto cleanup_exit; ++ } ++ } ++ dev->max_data_lanes = ep->bus.mipi_csi2.num_data_lanes; ++ dev->bus_flags = ep->bus.mipi_csi2.flags; ++ break; ++ case V4L2_MBUS_CCP2: ++ if (ep->bus.mipi_csi1.clock_lane != 0 || ++ ep->bus.mipi_csi1.data_lane != 1) { ++ unicam_err(dev, "Subdevice %s incompatible lane config\n", ++ sensor_node->name); ++ goto cleanup_exit; ++ } ++ dev->max_data_lanes = 1; ++ dev->bus_flags = ep->bus.mipi_csi1.strobe; ++ break; ++ default: ++ /* Unsupported bus type */ ++ unicam_err(dev, "sub-device %s is not a CSI2 or CCP2 device %d\n", ++ sensor_node->name, ep->bus_type); ++ goto cleanup_exit; ++ } ++ ++ /* Store bus type - CSI2 or CCP2 */ ++ dev->bus_type = ep->bus_type; ++ unicam_dbg(3, dev, "bus_type is %d\n", dev->bus_type); ++ ++ /* Store Virtual Channel number */ ++ dev->virtual_channel = ep->base.id; ++ ++ unicam_dbg(3, dev, "v4l2-endpoint: %s\n", ++ dev->bus_type == V4L2_MBUS_CSI2_DPHY ? "CSI2" : "CCP2"); ++ unicam_dbg(3, dev, "Virtual Channel=%d\n", dev->virtual_channel); ++ if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) ++ unicam_dbg(3, dev, "flags=0x%08x\n", ep->bus.mipi_csi2.flags); ++ unicam_dbg(3, dev, "num_data_lanes=%d\n", dev->max_data_lanes); ++ ++ unicam_dbg(1, dev, "found sub-device %s\n", sensor_node->name); ++ ++ v4l2_async_notifier_init(&dev->notifier); ++ ++ ret = v4l2_async_notifier_add_subdev(&dev->notifier, asd); ++ if (ret) { ++ unicam_err(dev, "Error adding subdevice - ret %d\n", ret); ++ goto cleanup_exit; ++ } ++ ++ dev->notifier.ops = &unicam_async_ops; ++ ret = v4l2_async_notifier_register(&dev->v4l2_dev, ++ &dev->notifier); ++ if (ret) { ++ unicam_err(dev, "Error registering async notifier - ret %d\n", ++ ret); ++ ret = -EINVAL; ++ } ++ ++cleanup_exit: ++ if (remote_ep) ++ of_node_put(remote_ep); ++ if (sensor_node) ++ of_node_put(sensor_node); ++ if (ep_node) ++ of_node_put(ep_node); ++ ++ return ret; ++} ++ ++static int unicam_probe(struct platform_device *pdev) ++{ ++ struct unicam_cfg *unicam_cfg; ++ struct unicam_device *unicam; ++ struct v4l2_ctrl_handler *hdl; ++ struct resource *res; ++ int ret; ++ ++ unicam = devm_kzalloc(&pdev->dev, sizeof(*unicam), GFP_KERNEL); ++ if (!unicam) ++ return -ENOMEM; ++ ++ unicam->pdev = pdev; ++ unicam_cfg = &unicam->cfg; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ unicam_cfg->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(unicam_cfg->base)) { ++ unicam_err(unicam, "Failed to get main io block\n"); ++ return PTR_ERR(unicam_cfg->base); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ unicam_cfg->clk_gate_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(unicam_cfg->clk_gate_base)) { ++ unicam_err(unicam, "Failed to get 2nd io block\n"); ++ return PTR_ERR(unicam_cfg->clk_gate_base); ++ } ++ ++ unicam->clock = devm_clk_get(&pdev->dev, "lp"); ++ if (IS_ERR(unicam->clock)) { ++ unicam_err(unicam, "Failed to get clock\n"); ++ return PTR_ERR(unicam->clock); ++ } ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(&pdev->dev, "No IRQ resource\n"); ++ return -ENODEV; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, ret, unicam_isr, 0, ++ "unicam_capture0", unicam); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to request interrupt\n"); ++ return -EINVAL; ++ } ++ ++ unicam->mdev.dev = &pdev->dev; ++ strscpy(unicam->mdev.model, UNICAM_MODULE_NAME, ++ sizeof(unicam->mdev.model)); ++ strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial)); ++ snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info), ++ "platform:%s %s", ++ pdev->dev.driver->name, dev_name(&pdev->dev)); ++ unicam->mdev.hw_revision = 1; ++ ++ media_entity_pads_init(&unicam->video_dev.entity, 1, &unicam->pad); ++ media_device_init(&unicam->mdev); ++ ++ unicam->v4l2_dev.mdev = &unicam->mdev; ++ ++ ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev); ++ if (ret) { ++ unicam_err(unicam, ++ "Unable to register v4l2 device.\n"); ++ goto media_cleanup; ++ } ++ ++ ret = media_device_register(&unicam->mdev); ++ if (ret < 0) { ++ unicam_err(unicam, ++ "Unable to register media-controller device.\n"); ++ goto probe_out_v4l2_unregister; ++ } ++ ++ /* Reserve space for the controls */ ++ hdl = &unicam->ctrl_handler; ++ ret = v4l2_ctrl_handler_init(hdl, 16); ++ if (ret < 0) ++ goto media_unregister; ++ unicam->v4l2_dev.ctrl_handler = hdl; ++ ++ /* set the driver data in platform device */ ++ platform_set_drvdata(pdev, unicam); ++ ++ ret = of_unicam_connect_subdevs(unicam); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to connect subdevs\n"); ++ goto free_hdl; ++ } ++ ++ /* Enable the block power domain */ ++ pm_runtime_enable(&pdev->dev); ++ ++ return 0; ++ ++free_hdl: ++ v4l2_ctrl_handler_free(hdl); ++media_unregister: ++ media_device_unregister(&unicam->mdev); ++probe_out_v4l2_unregister: ++ v4l2_device_unregister(&unicam->v4l2_dev); ++media_cleanup: ++ media_device_cleanup(&unicam->mdev); ++ ++ return ret; ++} ++ ++static int unicam_remove(struct platform_device *pdev) ++{ ++ struct unicam_device *unicam = platform_get_drvdata(pdev); ++ ++ unicam_dbg(2, unicam, "%s\n", __func__); ++ ++ pm_runtime_disable(&pdev->dev); ++ ++ v4l2_async_notifier_unregister(&unicam->notifier); ++ v4l2_ctrl_handler_free(&unicam->ctrl_handler); ++ v4l2_device_unregister(&unicam->v4l2_dev); ++ video_unregister_device(&unicam->video_dev); ++ if (unicam->sensor_config) ++ v4l2_subdev_free_pad_config(unicam->sensor_config); ++ media_device_unregister(&unicam->mdev); ++ media_device_cleanup(&unicam->mdev); ++ ++ return 0; ++} ++ ++static const struct of_device_id unicam_of_match[] = { ++ { .compatible = "brcm,bcm2835-unicam", }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, unicam_of_match); ++ ++static struct platform_driver unicam_driver = { ++ .probe = unicam_probe, ++ .remove = unicam_remove, ++ .driver = { ++ .name = UNICAM_MODULE_NAME, ++ .of_match_table = of_match_ptr(unicam_of_match), ++ }, ++}; ++ ++module_platform_driver(unicam_driver); ++ ++MODULE_AUTHOR("Dave Stevenson "); ++MODULE_DESCRIPTION("BCM2835 Unicam driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(UNICAM_VERSION); +--- /dev/null ++++ b/drivers/media/platform/bcm2835/vc4-regs-unicam.h +@@ -0,0 +1,253 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++/* ++ * Copyright (C) 2017-2020 Raspberry Pi Trading. ++ * Dave Stevenson ++ */ ++ ++#ifndef VC4_REGS_UNICAM_H ++#define VC4_REGS_UNICAM_H ++ ++/* ++ * The following values are taken from files found within the code drop ++ * made by Broadcom for the BCM21553 Graphics Driver, predominantly in ++ * brcm_usrlib/dag/vmcsx/vcinclude/hardware_vc4.h. ++ * They have been modified to be only the register offset. ++ */ ++#define UNICAM_CTRL 0x000 ++#define UNICAM_STA 0x004 ++#define UNICAM_ANA 0x008 ++#define UNICAM_PRI 0x00c ++#define UNICAM_CLK 0x010 ++#define UNICAM_CLT 0x014 ++#define UNICAM_DAT0 0x018 ++#define UNICAM_DAT1 0x01c ++#define UNICAM_DAT2 0x020 ++#define UNICAM_DAT3 0x024 ++#define UNICAM_DLT 0x028 ++#define UNICAM_CMP0 0x02c ++#define UNICAM_CMP1 0x030 ++#define UNICAM_CAP0 0x034 ++#define UNICAM_CAP1 0x038 ++#define UNICAM_ICTL 0x100 ++#define UNICAM_ISTA 0x104 ++#define UNICAM_IDI0 0x108 ++#define UNICAM_IPIPE 0x10c ++#define UNICAM_IBSA0 0x110 ++#define UNICAM_IBEA0 0x114 ++#define UNICAM_IBLS 0x118 ++#define UNICAM_IBWP 0x11c ++#define UNICAM_IHWIN 0x120 ++#define UNICAM_IHSTA 0x124 ++#define UNICAM_IVWIN 0x128 ++#define UNICAM_IVSTA 0x12c ++#define UNICAM_ICC 0x130 ++#define UNICAM_ICS 0x134 ++#define UNICAM_IDC 0x138 ++#define UNICAM_IDPO 0x13c ++#define UNICAM_IDCA 0x140 ++#define UNICAM_IDCD 0x144 ++#define UNICAM_IDS 0x148 ++#define UNICAM_DCS 0x200 ++#define UNICAM_DBSA0 0x204 ++#define UNICAM_DBEA0 0x208 ++#define UNICAM_DBWP 0x20c ++#define UNICAM_DBCTL 0x300 ++#define UNICAM_IBSA1 0x304 ++#define UNICAM_IBEA1 0x308 ++#define UNICAM_IDI1 0x30c ++#define UNICAM_DBSA1 0x310 ++#define UNICAM_DBEA1 0x314 ++#define UNICAM_MISC 0x400 ++ ++/* ++ * The following bitmasks are from the kernel released by Broadcom ++ * for Android - https://android.googlesource.com/kernel/bcm/ ++ * The Rhea, Hawaii, and Java chips all contain the same VideoCore4 ++ * Unicam block as BCM2835, as defined in eg ++ * arch/arm/mach-rhea/include/mach/rdb_A0/brcm_rdb_cam.h and similar. ++ * Values reworked to use the kernel BIT and GENMASK macros. ++ * ++ * Some of the bit mnenomics have been amended to match the datasheet. ++ */ ++/* UNICAM_CTRL Register */ ++#define UNICAM_CPE BIT(0) ++#define UNICAM_MEM BIT(1) ++#define UNICAM_CPR BIT(2) ++#define UNICAM_CPM_MASK GENMASK(3, 3) ++#define UNICAM_CPM_CSI2 0 ++#define UNICAM_CPM_CCP2 1 ++#define UNICAM_SOE BIT(4) ++#define UNICAM_DCM_MASK GENMASK(5, 5) ++#define UNICAM_DCM_STROBE 0 ++#define UNICAM_DCM_DATA 1 ++#define UNICAM_SLS BIT(6) ++#define UNICAM_PFT_MASK GENMASK(11, 8) ++#define UNICAM_OET_MASK GENMASK(20, 12) ++ ++/* UNICAM_STA Register */ ++#define UNICAM_SYN BIT(0) ++#define UNICAM_CS BIT(1) ++#define UNICAM_SBE BIT(2) ++#define UNICAM_PBE BIT(3) ++#define UNICAM_HOE BIT(4) ++#define UNICAM_PLE BIT(5) ++#define UNICAM_SSC BIT(6) ++#define UNICAM_CRCE BIT(7) ++#define UNICAM_OES BIT(8) ++#define UNICAM_IFO BIT(9) ++#define UNICAM_OFO BIT(10) ++#define UNICAM_BFO BIT(11) ++#define UNICAM_DL BIT(12) ++#define UNICAM_PS BIT(13) ++#define UNICAM_IS BIT(14) ++#define UNICAM_PI0 BIT(15) ++#define UNICAM_PI1 BIT(16) ++#define UNICAM_FSI_S BIT(17) ++#define UNICAM_FEI_S BIT(18) ++#define UNICAM_LCI_S BIT(19) ++#define UNICAM_BUF0_RDY BIT(20) ++#define UNICAM_BUF0_NO BIT(21) ++#define UNICAM_BUF1_RDY BIT(22) ++#define UNICAM_BUF1_NO BIT(23) ++#define UNICAM_DI BIT(24) ++ ++#define UNICAM_STA_MASK_ALL \ ++ (UNICAM_DL + \ ++ UNICAM_SBE + \ ++ UNICAM_PBE + \ ++ UNICAM_HOE + \ ++ UNICAM_PLE + \ ++ UNICAM_SSC + \ ++ UNICAM_CRCE + \ ++ UNICAM_IFO + \ ++ UNICAM_OFO + \ ++ UNICAM_PS + \ ++ UNICAM_PI0 + \ ++ UNICAM_PI1) ++ ++/* UNICAM_ANA Register */ ++#define UNICAM_APD BIT(0) ++#define UNICAM_BPD BIT(1) ++#define UNICAM_AR BIT(2) ++#define UNICAM_DDL BIT(3) ++#define UNICAM_CTATADJ_MASK GENMASK(7, 4) ++#define UNICAM_PTATADJ_MASK GENMASK(11, 8) ++ ++/* UNICAM_PRI Register */ ++#define UNICAM_PE BIT(0) ++#define UNICAM_PT_MASK GENMASK(2, 1) ++#define UNICAM_NP_MASK GENMASK(7, 4) ++#define UNICAM_PP_MASK GENMASK(11, 8) ++#define UNICAM_BS_MASK GENMASK(15, 12) ++#define UNICAM_BL_MASK GENMASK(17, 16) ++ ++/* UNICAM_CLK Register */ ++#define UNICAM_CLE BIT(0) ++#define UNICAM_CLPD BIT(1) ++#define UNICAM_CLLPE BIT(2) ++#define UNICAM_CLHSE BIT(3) ++#define UNICAM_CLTRE BIT(4) ++#define UNICAM_CLAC_MASK GENMASK(8, 5) ++#define UNICAM_CLSTE BIT(29) ++ ++/* UNICAM_CLT Register */ ++#define UNICAM_CLT1_MASK GENMASK(7, 0) ++#define UNICAM_CLT2_MASK GENMASK(15, 8) ++ ++/* UNICAM_DATn Registers */ ++#define UNICAM_DLE BIT(0) ++#define UNICAM_DLPD BIT(1) ++#define UNICAM_DLLPE BIT(2) ++#define UNICAM_DLHSE BIT(3) ++#define UNICAM_DLTRE BIT(4) ++#define UNICAM_DLSM BIT(5) ++#define UNICAM_DLFO BIT(28) ++#define UNICAM_DLSTE BIT(29) ++ ++#define UNICAM_DAT_MASK_ALL (UNICAM_DLSTE + UNICAM_DLFO) ++ ++/* UNICAM_DLT Register */ ++#define UNICAM_DLT1_MASK GENMASK(7, 0) ++#define UNICAM_DLT2_MASK GENMASK(15, 8) ++#define UNICAM_DLT3_MASK GENMASK(23, 16) ++ ++/* UNICAM_ICTL Register */ ++#define UNICAM_FSIE BIT(0) ++#define UNICAM_FEIE BIT(1) ++#define UNICAM_IBOB BIT(2) ++#define UNICAM_FCM BIT(3) ++#define UNICAM_TFC BIT(4) ++#define UNICAM_LIP_MASK GENMASK(6, 5) ++#define UNICAM_LCIE_MASK GENMASK(28, 16) ++ ++/* UNICAM_IDI0/1 Register */ ++#define UNICAM_ID0_MASK GENMASK(7, 0) ++#define UNICAM_ID1_MASK GENMASK(15, 8) ++#define UNICAM_ID2_MASK GENMASK(23, 16) ++#define UNICAM_ID3_MASK GENMASK(31, 24) ++ ++/* UNICAM_ISTA Register */ ++#define UNICAM_FSI BIT(0) ++#define UNICAM_FEI BIT(1) ++#define UNICAM_LCI BIT(2) ++ ++#define UNICAM_ISTA_MASK_ALL (UNICAM_FSI + UNICAM_FEI + UNICAM_LCI) ++ ++/* UNICAM_IPIPE Register */ ++#define UNICAM_PUM_MASK GENMASK(2, 0) ++ /* Unpacking modes */ ++ #define UNICAM_PUM_NONE 0 ++ #define UNICAM_PUM_UNPACK6 1 ++ #define UNICAM_PUM_UNPACK7 2 ++ #define UNICAM_PUM_UNPACK8 3 ++ #define UNICAM_PUM_UNPACK10 4 ++ #define UNICAM_PUM_UNPACK12 5 ++ #define UNICAM_PUM_UNPACK14 6 ++ #define UNICAM_PUM_UNPACK16 7 ++#define UNICAM_DDM_MASK GENMASK(6, 3) ++#define UNICAM_PPM_MASK GENMASK(9, 7) ++ /* Packing modes */ ++ #define UNICAM_PPM_NONE 0 ++ #define UNICAM_PPM_PACK8 1 ++ #define UNICAM_PPM_PACK10 2 ++ #define UNICAM_PPM_PACK12 3 ++ #define UNICAM_PPM_PACK14 4 ++ #define UNICAM_PPM_PACK16 5 ++#define UNICAM_DEM_MASK GENMASK(11, 10) ++#define UNICAM_DEBL_MASK GENMASK(14, 12) ++#define UNICAM_ICM_MASK GENMASK(16, 15) ++#define UNICAM_IDM_MASK GENMASK(17, 17) ++ ++/* UNICAM_ICC Register */ ++#define UNICAM_ICFL_MASK GENMASK(4, 0) ++#define UNICAM_ICFH_MASK GENMASK(9, 5) ++#define UNICAM_ICST_MASK GENMASK(12, 10) ++#define UNICAM_ICLT_MASK GENMASK(15, 13) ++#define UNICAM_ICLL_MASK GENMASK(31, 16) ++ ++/* UNICAM_DCS Register */ ++#define UNICAM_DIE BIT(0) ++#define UNICAM_DIM BIT(1) ++#define UNICAM_DBOB BIT(3) ++#define UNICAM_FDE BIT(4) ++#define UNICAM_LDP BIT(5) ++#define UNICAM_EDL_MASK GENMASK(15, 8) ++ ++/* UNICAM_DBCTL Register */ ++#define UNICAM_DBEN BIT(0) ++#define UNICAM_BUF0_IE BIT(1) ++#define UNICAM_BUF1_IE BIT(2) ++ ++/* UNICAM_CMP[0,1] register */ ++#define UNICAM_PCE BIT(31) ++#define UNICAM_GI BIT(9) ++#define UNICAM_CPH BIT(8) ++#define UNICAM_PCVC_MASK GENMASK(7, 6) ++#define UNICAM_PCDT_MASK GENMASK(5, 0) ++ ++/* UNICAM_MISC register */ ++#define UNICAM_FL0 BIT(6) ++#define UNICAM_FL1 BIT(9) ++ ++#endif diff --git a/target/linux/bcm27xx/patches-5.4/950-0650-media-uapi-v4l2-core-Add-sensor-ancillary-data-V4L2-.patch b/target/linux/bcm27xx/patches-5.4/950-0650-media-uapi-v4l2-core-Add-sensor-ancillary-data-V4L2-.patch new file mode 100644 index 00000000000..de8f1d209a8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0650-media-uapi-v4l2-core-Add-sensor-ancillary-data-V4L2-.patch @@ -0,0 +1,85 @@ +From 09f5e82f292a900d17a5205e54a35e24296bd9f7 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Wed, 1 Apr 2020 08:46:29 +0100 +Subject: [PATCH] media: uapi: v4l2-core: Add sensor ancillary data + V4L2 foucc type. + +Add V4L2_META_FMT_SENSOR_DATA format 4CC. + +This new format will be used by the BCM2835 Unicam device to return +out camera sensor embedded data. + +Signed-off-by: Naushir Patuck +--- + Documentation/media/uapi/v4l/meta-formats.rst | 1 + + .../uapi/v4l/pixfmt-meta-sensor-data.rst | 32 +++++++++++++++++++ + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + + include/uapi/linux/videodev2.h | 1 + + 4 files changed, 35 insertions(+) + create mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-sensor-data.rst + +--- a/Documentation/media/uapi/v4l/meta-formats.rst ++++ b/Documentation/media/uapi/v4l/meta-formats.rst +@@ -21,6 +21,7 @@ These formats are used for the :ref:`met + + pixfmt-meta-d4xx + pixfmt-meta-intel-ipu3 ++ pixfmt-meta-sensor-data + pixfmt-meta-uvc + pixfmt-meta-vsp1-hgo + pixfmt-meta-vsp1-hgt +--- /dev/null ++++ b/Documentation/media/uapi/v4l/pixfmt-meta-sensor-data.rst +@@ -0,0 +1,32 @@ ++.. Permission is granted to copy, distribute and/or modify this ++.. document under the terms of the GNU Free Documentation License, ++.. Version 1.1 or any later version published by the Free Software ++.. Foundation, with no Invariant Sections, no Front-Cover Texts ++.. and no Back-Cover Texts. A copy of the license is included at ++.. Documentation/media/uapi/fdl-appendix.rst. ++.. ++.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections ++ ++.. _v4l2-meta-fmt-sensor-data: ++ ++*********************************** ++V4L2_META_FMT_SENSOR_DATA ('SENS') ++*********************************** ++ ++Sensor Ancillary Metadata ++ ++Description ++=========== ++ ++This format describes ancillary data generated by a camera sensor and ++transmitted over a stream on the camera bus. Sensor vendors generally have their ++own custom format for this ancillary data. Some vendors follow a generic ++CSI-2/SMIA embedded data format as described in the `CSI-2 specification. ++`_ ++ ++The size of the embedded buffer is defined as a single line with a pixel width ++width specified in bytes. This is obtained by a call to the ++:c:type:`VIDIOC_SUBDEV_G_FMT` ioctl on the sensor subdevice where the ``pad`` ++field in :c:type:`v4l2_subdev_format` is set to 1. Note that this size is fixed ++and cannot be modified with a call to :c:type:`VIDIOC_SUBDEV_S_FMT`. ++ +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1332,6 +1332,7 @@ static void v4l_fill_fmtdesc(struct v4l2 + case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; + case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; + case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; ++ case V4L2_META_FMT_SENSOR_DATA: descr = "Sensor Ancillary Metadata"; break; + + default: + /* Compressed formats */ +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -769,6 +769,7 @@ struct v4l2_pix_format { + #define V4L2_META_FMT_VSP1_HGT v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */ + #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ + #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ ++#define V4L2_META_FMT_SENSOR_DATA v4l2_fourcc('S', 'E', 'N', 'S') /* Sensor Ancillary metadata */ + + /* priv field value to indicates that subsequent fields are valid. */ + #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe diff --git a/target/linux/bcm27xx/patches-5.4/950-0651-media-uapi-Add-MEDIA_BUS_FMT_SENSOR_DATA-media-bus-f.patch b/target/linux/bcm27xx/patches-5.4/950-0651-media-uapi-Add-MEDIA_BUS_FMT_SENSOR_DATA-media-bus-f.patch new file mode 100644 index 00000000000..65162cc5d51 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0651-media-uapi-Add-MEDIA_BUS_FMT_SENSOR_DATA-media-bus-f.patch @@ -0,0 +1,64 @@ +From 65573c84d5a9115444cc5e365c94cb3ae0fb7e10 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 21 Jan 2020 14:06:47 +0000 +Subject: [PATCH] media: uapi: Add MEDIA_BUS_FMT_SENSOR_DATA media bus + format + +This patch adds MEDIA_BUS_FMT_SENSOR_DATA used by the bcm2835-unicam +driver to support CSI-2 embedded data streams from camera sensors. + +Signed-off-by: Naushir Patuck +--- + .../media/uapi/v4l/subdev-formats.rst | 33 +++++++++++++++++++ + include/uapi/linux/media-bus-format.h | 3 ++ + 2 files changed, 36 insertions(+) + +--- a/Documentation/media/uapi/v4l/subdev-formats.rst ++++ b/Documentation/media/uapi/v4l/subdev-formats.rst +@@ -7794,3 +7794,36 @@ formats. + - 0x5001 + - Interleaved raw UYVY and JPEG image format with embedded meta-data + used by Samsung S3C73MX camera sensors. ++ ++ ++ ++.. _v4l2-mbus-sensor-data: ++ ++Sensor Ancillary Metadata Formats ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++This section lists ancillary data generated by a camera sensor and ++transmitted over a stream on the camera bus. ++ ++The following table lists the existing sensor ancillary metadata formats: ++ ++ ++.. _v4l2-mbus-pixelcode-sensor-metadata: ++ ++.. tabularcolumns:: |p{8.0cm}|p{1.4cm}|p{7.7cm}| ++ ++.. flat-table:: Sensor ancillary metadata formats ++ :header-rows: 1 ++ :stub-columns: 0 ++ ++ * - Identifier ++ - Code ++ - Comments ++ * .. _MEDIA_BUS_FMT_SENSOR_DATA: ++ ++ - MEDIA_BUS_FMT_SENSOR_DATA ++ - 0x7001 ++ - Sensor vendor specific ancillary metadata. Some vendors follow a generic ++ CSI-2/SMIA embedded data format as described in the `CSI-2 specification. ++ `_ ++ +--- a/include/uapi/linux/media-bus-format.h ++++ b/include/uapi/linux/media-bus-format.h +@@ -155,4 +155,7 @@ + /* HSV - next is 0x6002 */ + #define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 + ++/* Sensor ancillary metadata formats - next is 0x7002 */ ++#define MEDIA_BUS_FMT_SENSOR_DATA 0x7001 ++ + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0652-media-bcm2835-unicam-Add-support-for-mulitple-device.patch b/target/linux/bcm27xx/patches-5.4/950-0652-media-bcm2835-unicam-Add-support-for-mulitple-device.patch new file mode 100644 index 00000000000..315feff5d3d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0652-media-bcm2835-unicam-Add-support-for-mulitple-device.patch @@ -0,0 +1,1084 @@ +From b466d74b45466b417e364c85c7fce71e9fc3fc7c Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Tue, 7 Apr 2020 10:42:14 +0100 +Subject: [PATCH] media: bcm2835-unicam: Add support for mulitple + device nodes. + +Move device node specific state out of the device state structure and +into a new node structure. This separation will be needed for future +changes where we will add an embedded data node to the driver to work +alongside the existing image data node. + +Currently only use a single image node, so this commit does not add +any functional changes. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/bcm2835/bcm2835-unicam.c | 484 ++++++++++-------- + 1 file changed, 283 insertions(+), 201 deletions(-) + +--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c ++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c +@@ -109,7 +109,8 @@ MODULE_PARM_DESC(debug, "Debug level 0-3 + /* Define a nominal minimum image size */ + #define MIN_WIDTH 16 + #define MIN_HEIGHT 16 +- ++/* Maximum number of simulataneous streams Uncaim can handle. */ ++#define MAX_NODES 2 + /* + * struct unicam_fmt - Unicam media bus format information + * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a. +@@ -346,11 +347,37 @@ struct unicam_cfg { + + #define MAX_POSSIBLE_PIX_FMTS (ARRAY_SIZE(formats)) + +-struct unicam_device { +- /* V4l2 specific parameters */ ++struct unicam_node { ++ bool registered; ++ unsigned int pad_id; ++ /* Pointer pointing to current v4l2_buffer */ ++ struct unicam_buffer *cur_frm; ++ /* Pointer pointing to next v4l2_buffer */ ++ struct unicam_buffer *next_frm; ++ /* video capture */ ++ const struct unicam_fmt *fmt; ++ /* Used to store current pixel format */ ++ struct v4l2_format v_fmt; ++ /* Used to store current mbus frame format */ ++ struct v4l2_mbus_framefmt m_fmt; ++ /* Buffer queue used in video-buf */ ++ struct vb2_queue buffer_queue; ++ /* Queue of filled frames */ ++ struct unicam_dmaqueue dma_queue; ++ /* IRQ lock for DMA queue */ ++ spinlock_t dma_queue_lock; ++ /* lock used to access this structure */ ++ struct mutex lock; + /* Identifies video device for this channel */ + struct video_device video_dev; ++ /* Pointer to the parent handle */ ++ struct unicam_device *dev; ++ struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; ++}; ++ ++struct unicam_device { ++ /* V4l2 specific parameters */ + + struct v4l2_fwnode_endpoint endpoint; + +@@ -363,7 +390,6 @@ struct unicam_device { + /* V4l2 device */ + struct v4l2_device v4l2_dev; + struct media_device mdev; +- struct media_pad pad; + + /* parent device */ + struct platform_device *pdev; +@@ -378,18 +404,6 @@ struct unicam_device { + /* current input at the sub device */ + int current_input; + +- /* Pointer pointing to current v4l2_buffer */ +- struct unicam_buffer *cur_frm; +- /* Pointer pointing to next v4l2_buffer */ +- struct unicam_buffer *next_frm; +- +- /* video capture */ +- const struct unicam_fmt *fmt; +- /* Used to store current pixel format */ +- struct v4l2_format v_fmt; +- /* Used to store current mbus frame format */ +- struct v4l2_mbus_framefmt m_fmt; +- + unsigned int virtual_channel; + enum v4l2_mbus_type bus_type; + /* +@@ -401,20 +415,10 @@ struct unicam_device { + unsigned int active_data_lanes; + + struct v4l2_rect crop; +- +- /* Currently selected input on subdev */ +- int input; +- +- /* Buffer queue used in video-buf */ +- struct vb2_queue buffer_queue; +- /* Queue of filled frames */ +- struct unicam_dmaqueue dma_queue; +- /* IRQ lock for DMA queue */ +- spinlock_t dma_queue_lock; +- /* lock used to access this structure */ +- struct mutex lock; + /* Flag to denote that we are processing buffers */ + int streaming; ++ ++ struct unicam_node node[MAX_NODES]; + }; + + /* Hardware access */ +@@ -526,10 +530,11 @@ static inline unsigned int bytes_per_lin + } + + static int __subdev_get_format(struct unicam_device *dev, +- struct v4l2_mbus_framefmt *fmt) ++ struct v4l2_mbus_framefmt *fmt, int pad_id) + { + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ .pad = pad_id + }; + int ret; + +@@ -598,29 +603,30 @@ static int unicam_calc_format_size_bpl(s + return 0; + } + +-static int unicam_reset_format(struct unicam_device *dev) ++static int unicam_reset_format(struct unicam_node *node) + { ++ struct unicam_device *dev = node->dev; + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + +- ret = __subdev_get_format(dev, &mbus_fmt); ++ ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id); + if (ret) { + unicam_err(dev, "Failed to get_format - ret %d\n", ret); + return ret; + } + +- if (mbus_fmt.code != dev->fmt->code) { ++ if (mbus_fmt.code != dev->node[0].fmt->code) { + unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n", +- dev->fmt->code, mbus_fmt.code); ++ dev->node[0].fmt->code, mbus_fmt.code); + return ret; + } + +- v4l2_fill_pix_format(&dev->v_fmt.fmt.pix, &mbus_fmt); +- dev->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ v4l2_fill_pix_format(&dev->node[0].v_fmt.fmt.pix, &mbus_fmt); ++ dev->node[0].v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + +- unicam_calc_format_size_bpl(dev, dev->fmt, &dev->v_fmt); ++ unicam_calc_format_size_bpl(dev, dev->node[0].fmt, &dev->node[0].v_fmt); + +- dev->m_fmt = mbus_fmt; ++ dev->node[0].m_fmt = mbus_fmt; + + return 0; + } +@@ -635,14 +641,14 @@ static void unicam_wr_dma_addr(struct un + + reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); + reg_write(&dev->cfg, UNICAM_IBEA0, +- dmaaddr + dev->v_fmt.fmt.pix.sizeimage); ++ dmaaddr + dev->node[0].v_fmt.fmt.pix.sizeimage); + } + + static inline unsigned int unicam_get_lines_done(struct unicam_device *dev) + { + dma_addr_t start_addr, cur_addr; +- unsigned int stride = dev->v_fmt.fmt.pix.bytesperline; +- struct unicam_buffer *frm = dev->cur_frm; ++ unsigned int stride = dev->node[0].v_fmt.fmt.pix.bytesperline; ++ struct unicam_buffer *frm = dev->node[0].cur_frm; + + if (!frm) + return 0; +@@ -654,12 +660,12 @@ static inline unsigned int unicam_get_li + + static inline void unicam_schedule_next_buffer(struct unicam_device *dev) + { +- struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_dmaqueue *dma_q = &dev->node[0].dma_queue; + struct unicam_buffer *buf; + dma_addr_t addr; + + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); +- dev->next_frm = buf; ++ dev->node[0].next_frm = buf; + list_del(&buf->list); + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +@@ -668,11 +674,11 @@ static inline void unicam_schedule_next_ + + static inline void unicam_process_buffer_complete(struct unicam_device *dev) + { +- dev->cur_frm->vb.field = dev->m_fmt.field; +- dev->cur_frm->vb.sequence = dev->sequence++; ++ dev->node[0].cur_frm->vb.field = dev->node[0].m_fmt.field; ++ dev->node[0].cur_frm->vb.sequence = dev->sequence++; + +- vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); +- dev->cur_frm = dev->next_frm; ++ vb2_buffer_done(&dev->node[0].cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); ++ dev->node[0].cur_frm = dev->node[0].next_frm; + } + + /* +@@ -687,7 +693,7 @@ static irqreturn_t unicam_isr(int irq, v + { + struct unicam_device *unicam = (struct unicam_device *)dev; + struct unicam_cfg *cfg = &unicam->cfg; +- struct unicam_dmaqueue *dma_q = &unicam->dma_queue; ++ struct unicam_dmaqueue *dma_q = &unicam->node[0].dma_queue; + unsigned int lines_done = unicam_get_lines_done(dev); + unsigned int sequence = unicam->sequence; + int ista, sta; +@@ -720,8 +726,9 @@ static irqreturn_t unicam_isr(int irq, v + * Timestamp is to be when the first data byte was captured, + * aka frame start. + */ +- if (unicam->cur_frm) +- unicam->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); ++ if (unicam->node[0].cur_frm) ++ unicam->node[0].cur_frm->vb.vb2_buf.timestamp = ++ ktime_get_ns(); + } + if (ista & UNICAM_FEI || sta & UNICAM_PI0) { + /* +@@ -729,7 +736,8 @@ static irqreturn_t unicam_isr(int irq, v + * stop the peripheral. Overwrite the frame we've just + * captured instead. + */ +- if (unicam->cur_frm && unicam->cur_frm != unicam->next_frm) ++ if (unicam->node[0].cur_frm && ++ unicam->node[0].cur_frm != unicam->node[0].next_frm) + unicam_process_buffer_complete(unicam); + } + +@@ -738,11 +746,11 @@ static irqreturn_t unicam_isr(int irq, v + * already started. + */ + if (ista & (UNICAM_FSI | UNICAM_LCI) && !(ista & UNICAM_FEI)) { +- spin_lock(&unicam->dma_queue_lock); ++ spin_lock(&unicam->node[0].dma_queue_lock); + if (!list_empty(&dma_q->active) && +- unicam->cur_frm == unicam->next_frm) ++ unicam->node[0].cur_frm == unicam->node[0].next_frm) + unicam_schedule_next_buffer(unicam); +- spin_unlock(&unicam->dma_queue_lock); ++ spin_unlock(&unicam->node[0].dma_queue_lock); + } + + if (reg_read(&unicam->cfg, UNICAM_ICTL) & UNICAM_FCM) { +@@ -756,7 +764,8 @@ static irqreturn_t unicam_isr(int irq, v + static int unicam_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + strlcpy(cap->driver, UNICAM_MODULE_NAME, sizeof(cap->driver)); + strlcpy(cap->card, UNICAM_MODULE_NAME, sizeof(cap->card)); +@@ -770,7 +779,8 @@ static int unicam_querycap(struct file * + static int unicam_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + struct v4l2_subdev_mbus_code_enum mbus_code; + const struct unicam_fmt *fmt = NULL; + int index = 0; +@@ -815,9 +825,9 @@ static int unicam_enum_fmt_vid_cap(struc + static int unicam_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); + +- *f = dev->v_fmt; ++ *f = node->v_fmt; + + return 0; + } +@@ -859,9 +869,11 @@ const struct unicam_fmt *get_first_suppo + static int unicam_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, ++ .pad = 0 + }; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + const struct unicam_fmt *fmt; +@@ -939,8 +951,9 @@ static int unicam_try_fmt_vid_cap(struct + static int unicam_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) + { +- struct unicam_device *dev = video_drvdata(file); +- struct vb2_queue *q = &dev->buffer_queue; ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; ++ struct vb2_queue *q = &node->buffer_queue; + struct v4l2_mbus_framefmt mbus_fmt = {0}; + const struct unicam_fmt *fmt; + int ret; +@@ -985,17 +998,18 @@ static int unicam_s_fmt_vid_cap(struct f + return -EINVAL; + } + +- dev->fmt = fmt; +- dev->v_fmt.fmt.pix.pixelformat = f->fmt.pix.pixelformat; +- dev->v_fmt.fmt.pix.bytesperline = f->fmt.pix.bytesperline; +- unicam_reset_format(dev); +- +- unicam_dbg(3, dev, "%s %dx%d, mbus_fmt 0x%08X, V4L2 pix 0x%08X.\n", +- __func__, dev->v_fmt.fmt.pix.width, +- dev->v_fmt.fmt.pix.height, mbus_fmt.code, +- dev->v_fmt.fmt.pix.pixelformat); ++ node->fmt = fmt; ++ node->v_fmt.fmt.pix.pixelformat = f->fmt.pix.pixelformat; ++ node->v_fmt.fmt.pix.bytesperline = f->fmt.pix.bytesperline; ++ unicam_reset_format(node); ++ ++ unicam_dbg(3, dev, ++ "%s %dx%d, mbus_fmt 0x%08X, V4L2 pix 0x%08X.\n", ++ __func__, node->v_fmt.fmt.pix.width, ++ node->v_fmt.fmt.pix.height, mbus_fmt.code, ++ node->v_fmt.fmt.pix.pixelformat); + +- *f = dev->v_fmt; ++ *f = node->v_fmt; + + return 0; + } +@@ -1006,8 +1020,9 @@ static int unicam_queue_setup(struct vb2 + unsigned int sizes[], + struct device *alloc_devs[]) + { +- struct unicam_device *dev = vb2_get_drv_priv(vq); +- unsigned int size = dev->v_fmt.fmt.pix.sizeimage; ++ struct unicam_node *node = vb2_get_drv_priv(vq); ++ struct unicam_device *dev = node->dev; ++ unsigned int size = node->v_fmt.fmt.pix.sizeimage; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; +@@ -1029,15 +1044,16 @@ static int unicam_queue_setup(struct vb2 + + static int unicam_buffer_prepare(struct vb2_buffer *vb) + { +- struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); ++ struct unicam_device *dev = node->dev; + struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, + vb.vb2_buf); + unsigned long size; + +- if (WARN_ON(!dev->fmt)) ++ if (WARN_ON(!node->fmt)) + return -EINVAL; + +- size = dev->v_fmt.fmt.pix.sizeimage; ++ size = node->v_fmt.fmt.pix.sizeimage; + if (vb2_plane_size(vb, 0) < size) { + unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); +@@ -1050,15 +1066,15 @@ static int unicam_buffer_prepare(struct + + static void unicam_buffer_queue(struct vb2_buffer *vb) + { +- struct unicam_device *dev = vb2_get_drv_priv(vb->vb2_queue); ++ struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct unicam_buffer *buf = container_of(vb, struct unicam_buffer, + vb.vb2_buf); +- struct unicam_dmaqueue *dma_queue = &dev->dma_queue; ++ struct unicam_dmaqueue *dma_queue = &node->dma_queue; + unsigned long flags = 0; + +- spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ spin_lock_irqsave(&node->dma_queue_lock, flags); + list_add_tail(&buf->list, &dma_queue->active); +- spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++ spin_unlock_irqrestore(&node->dma_queue_lock, flags); + } + + static void unicam_set_packing_config(struct unicam_device *dev) +@@ -1066,11 +1082,12 @@ static void unicam_set_packing_config(st + int pack, unpack; + u32 val; + +- if (dev->v_fmt.fmt.pix.pixelformat == dev->fmt->fourcc) { ++ if (dev->node[0].v_fmt.fmt.pix.pixelformat == ++ dev->node[0].fmt->fourcc) { + unpack = UNICAM_PUM_NONE; + pack = UNICAM_PPM_NONE; + } else { +- switch (dev->fmt->depth) { ++ switch (dev->node[0].fmt->depth) { + case 8: + unpack = UNICAM_PUM_UNPACK8; + break; +@@ -1108,17 +1125,17 @@ static void unicam_cfg_image_id(struct u + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + /* CSI2 mode */ + reg_write(cfg, UNICAM_IDI0, +- (dev->virtual_channel << 6) | dev->fmt->csi_dt); ++ (dev->virtual_channel << 6) | dev->node[0].fmt->csi_dt); + } else { + /* CCP2 mode */ +- reg_write(cfg, UNICAM_IDI0, (0x80 | dev->fmt->csi_dt)); ++ reg_write(cfg, UNICAM_IDI0, (0x80 | dev->node[0].fmt->csi_dt)); + } + } + + static void unicam_start_rx(struct unicam_device *dev, unsigned long addr) + { + struct unicam_cfg *cfg = &dev->cfg; +- int line_int_freq = dev->v_fmt.fmt.pix.height >> 2; ++ int line_int_freq = dev->node[0].v_fmt.fmt.pix.height >> 2; + unsigned int i; + u32 val; + +@@ -1266,7 +1283,8 @@ static void unicam_start_rx(struct unica + reg_write(cfg, UNICAM_DAT3, val); + } + +- reg_write(&dev->cfg, UNICAM_IBLS, dev->v_fmt.fmt.pix.bytesperline); ++ reg_write(&dev->cfg, UNICAM_IBLS, ++ dev->node[0].v_fmt.fmt.pix.bytesperline); + unicam_wr_dma_addr(dev, addr); + unicam_set_packing_config(dev); + unicam_cfg_image_id(dev); +@@ -1327,21 +1345,22 @@ static void unicam_disable(struct unicam + + static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) + { +- struct unicam_device *dev = vb2_get_drv_priv(vq); +- struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_node *node = vb2_get_drv_priv(vq); ++ struct unicam_device *dev = node->dev; ++ struct unicam_dmaqueue *dma_q = &node->dma_queue; + struct unicam_buffer *buf, *tmp; + unsigned long addr = 0; + unsigned long flags; + int ret; + +- spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ spin_lock_irqsave(&node->dma_queue_lock, flags); + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); +- dev->cur_frm = buf; +- dev->next_frm = buf; ++ node->cur_frm = buf; ++ node->next_frm = buf; + list_del(&buf->list); +- spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++ spin_unlock_irqrestore(&node->dma_queue_lock, flags); + +- addr = vb2_dma_contig_plane_dma_addr(&dev->cur_frm->vb.vb2_buf, 0); ++ addr = vb2_dma_contig_plane_dma_addr(&node->cur_frm->vb.vb2_buf, 0); + dev->sequence = 0; + + ret = unicam_runtime_get(dev); +@@ -1411,20 +1430,21 @@ err_release_buffers: + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + } +- if (dev->cur_frm != dev->next_frm) +- vb2_buffer_done(&dev->next_frm->vb.vb2_buf, ++ if (node->cur_frm != node->next_frm) ++ vb2_buffer_done(&node->next_frm->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); +- vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); +- dev->next_frm = NULL; +- dev->cur_frm = NULL; ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); ++ node->next_frm = NULL; ++ node->cur_frm = NULL; + + return ret; + } + + static void unicam_stop_streaming(struct vb2_queue *vq) + { +- struct unicam_device *dev = vb2_get_drv_priv(vq); +- struct unicam_dmaqueue *dma_q = &dev->dma_queue; ++ struct unicam_node *node = vb2_get_drv_priv(vq); ++ struct unicam_device *dev = node->dev; ++ struct unicam_dmaqueue *dma_q = &node->dma_queue; + struct unicam_buffer *buf, *tmp; + unsigned long flags; + +@@ -1434,22 +1454,24 @@ static void unicam_stop_streaming(struct + unicam_disable(dev); + + /* Release all active buffers */ +- spin_lock_irqsave(&dev->dma_queue_lock, flags); ++ spin_lock_irqsave(&node->dma_queue_lock, flags); + list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + +- if (dev->cur_frm == dev->next_frm) { +- vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ if (node->cur_frm == node->next_frm) { ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, ++ VB2_BUF_STATE_ERROR); + } else { +- vb2_buffer_done(&dev->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); +- vb2_buffer_done(&dev->next_frm->vb.vb2_buf, ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, ++ VB2_BUF_STATE_ERROR); ++ vb2_buffer_done(&node->next_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + } +- dev->cur_frm = NULL; +- dev->next_frm = NULL; +- spin_unlock_irqrestore(&dev->dma_queue_lock, flags); ++ node->cur_frm = NULL; ++ node->next_frm = NULL; ++ spin_unlock_irqrestore(&node->dma_queue_lock, flags); + + clk_disable_unprepare(dev->clock); + unicam_runtime_put(dev); +@@ -1458,7 +1480,8 @@ static void unicam_stop_streaming(struct + static int unicam_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + if (inp->index != 0) + return -EINVAL; +@@ -1506,21 +1529,24 @@ static int unicam_s_input(struct file *f + static int unicam_querystd(struct file *file, void *priv, + v4l2_std_id *std) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, video, querystd, std); + } + + static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, video, g_std, std); + } + + static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + int ret; + v4l2_std_id current_std; + +@@ -1531,29 +1557,31 @@ static int unicam_s_std(struct file *fil + if (std == current_std) + return 0; + +- if (vb2_is_busy(&dev->buffer_queue)) ++ if (vb2_is_busy(&node->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(dev->sensor, video, s_std, std); + + /* Force recomputation of bytesperline */ +- dev->v_fmt.fmt.pix.bytesperline = 0; ++ node->v_fmt.fmt.pix.bytesperline = 0; + +- unicam_reset_format(dev); ++ unicam_reset_format(node); + + return ret; + } + + static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, pad, set_edid, edid); + } + + static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, pad, get_edid, edid); + } +@@ -1561,7 +1589,8 @@ static int unicam_g_edid(struct file *fi + static int unicam_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + struct v4l2_subdev_frame_size_enum fse; + int ret; +@@ -1596,7 +1625,8 @@ static int unicam_enum_framesizes(struct + static int unicam_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, +@@ -1624,14 +1654,16 @@ static int unicam_enum_frameintervals(st + + static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a); + } + + static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a); + } +@@ -1639,7 +1671,8 @@ static int unicam_s_parm(struct file *fi + static int unicam_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings); + } +@@ -1647,7 +1680,8 @@ static int unicam_g_dv_timings(struct fi + static int unicam_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + struct v4l2_dv_timings current_timings; + int ret; + +@@ -1657,15 +1691,15 @@ static int unicam_s_dv_timings(struct fi + if (v4l2_match_dv_timings(timings, ¤t_timings, 0, false)) + return 0; + +- if (vb2_is_busy(&dev->buffer_queue)) ++ if (vb2_is_busy(&node->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings); + + /* Force recomputation of bytesperline */ +- dev->v_fmt.fmt.pix.bytesperline = 0; ++ node->v_fmt.fmt.pix.bytesperline = 0; + +- unicam_reset_format(dev); ++ unicam_reset_format(node); + + return ret; + } +@@ -1673,7 +1707,8 @@ static int unicam_s_dv_timings(struct fi + static int unicam_query_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings); + } +@@ -1681,7 +1716,8 @@ static int unicam_query_dv_timings(struc + static int unicam_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); + } +@@ -1689,7 +1725,8 @@ static int unicam_enum_dv_timings(struct + static int unicam_dv_timings_cap(struct file *file, void *priv, + struct v4l2_dv_timings_cap *cap) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); + } +@@ -1707,7 +1744,8 @@ static int unicam_subscribe_event(struct + + static int unicam_log_status(struct file *file, void *fh) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + struct unicam_cfg *cfg = &dev->cfg; + u32 reg; + +@@ -1716,10 +1754,10 @@ static int unicam_log_status(struct file + + unicam_info(dev, "-----Receiver status-----\n"); + unicam_info(dev, "V4L2 width/height: %ux%u\n", +- dev->v_fmt.fmt.pix.width, dev->v_fmt.fmt.pix.height); +- unicam_info(dev, "Mediabus format: %08x\n", dev->fmt->code); ++ node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height); ++ unicam_info(dev, "Mediabus format: %08x\n", node->fmt->code); + unicam_info(dev, "V4L2 format: %08x\n", +- dev->v_fmt.fmt.pix.pixelformat); ++ node->v_fmt.fmt.pix.pixelformat); + reg = reg_read(&dev->cfg, UNICAM_IPIPE); + unicam_info(dev, "Unpacking/packing: %u / %u\n", + get_field(reg, UNICAM_PUM_MASK), +@@ -1744,7 +1782,7 @@ static void unicam_notify(struct v4l2_su + + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: +- v4l2_event_queue(&dev->video_dev, arg); ++ v4l2_event_queue(&dev->node[0].video_dev, arg); + break; + default: + break; +@@ -1767,10 +1805,11 @@ static const struct vb2_ops unicam_video + */ + static int unicam_open(struct file *file) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + int ret; + +- mutex_lock(&dev->lock); ++ mutex_lock(&node->lock); + + ret = v4l2_fh_open(file); + if (ret) { +@@ -1790,18 +1829,19 @@ static int unicam_open(struct file *file + ret = 0; + + unlock: +- mutex_unlock(&dev->lock); ++ mutex_unlock(&node->lock); + return ret; + } + + static int unicam_release(struct file *file) + { +- struct unicam_device *dev = video_drvdata(file); ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; + struct v4l2_subdev *sd = dev->sensor; + bool fh_singular; + int ret; + +- mutex_lock(&dev->lock); ++ mutex_lock(&node->lock); + + fh_singular = v4l2_fh_is_singular_file(file); + +@@ -1810,7 +1850,7 @@ static int unicam_release(struct file *f + if (fh_singular) + v4l2_subdev_call(sd, core, s_power, 0); + +- mutex_unlock(&dev->lock); ++ mutex_unlock(&node->lock); + + return ret; + } +@@ -1892,7 +1932,8 @@ unicam_async_bound(struct v4l2_async_not + return 0; + } + +-static int unicam_probe_complete(struct unicam_device *unicam) ++static int register_node(struct unicam_device *unicam, struct unicam_node *node, ++ enum v4l2_buf_type type, int pad_id) + { + struct video_device *vdev; + struct vb2_queue *q; +@@ -1900,15 +1941,7 @@ static int unicam_probe_complete(struct + const struct unicam_fmt *fmt; + int ret; + +- v4l2_set_subdev_hostdata(unicam->sensor, unicam); +- +- unicam->v4l2_dev.notify = unicam_notify; +- +- unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor); +- if (!unicam->sensor_config) +- return -ENOMEM; +- +- ret = __subdev_get_format(unicam, &mbus_fmt); ++ ret = __subdev_get_format(unicam, &mbus_fmt, pad_id); + if (ret) { + unicam_err(unicam, "Failed to get_format - ret %d\n", ret); + return ret; +@@ -1938,14 +1971,15 @@ static int unicam_probe_complete(struct + return -EINVAL; + } + +- unicam->fmt = fmt; ++ node->pad_id = pad_id; ++ node->fmt = fmt; + if (fmt->fourcc) +- unicam->v_fmt.fmt.pix.pixelformat = fmt->fourcc; ++ node->v_fmt.fmt.pix.pixelformat = fmt->fourcc; + else +- unicam->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc; ++ node->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc; + + /* Read current subdev format */ +- unicam_reset_format(unicam); ++ unicam_reset_format(node); + + if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_std_id tvnorms; +@@ -1962,27 +1996,30 @@ static int unicam_probe_complete(struct + g_tvnorms, &tvnorms); + if (WARN_ON(ret)) + return -EINVAL; +- unicam->video_dev.tvnorms |= tvnorms; ++ node->video_dev.tvnorms |= tvnorms; + } + +- spin_lock_init(&unicam->dma_queue_lock); +- mutex_init(&unicam->lock); ++ spin_lock_init(&node->dma_queue_lock); ++ mutex_init(&node->lock); + +- /* Add controls from the subdevice */ +- ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, +- unicam->sensor->ctrl_handler, NULL, true); +- if (ret < 0) +- return ret; ++ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ /* Add controls from the subdevice */ ++ ret = v4l2_ctrl_add_handler(&node->ctrl_handler, ++ unicam->sensor->ctrl_handler, NULL, ++ true); ++ if (ret < 0) ++ return ret; ++ } + +- q = &unicam->buffer_queue; +- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ q = &node->buffer_queue; ++ q->type = type; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; +- q->drv_priv = unicam; ++ q->drv_priv = node; + q->ops = &unicam_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct unicam_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; +- q->lock = &unicam->lock; ++ q->lock = &node->lock; + q->min_buffers_needed = 2; + q->dev = &unicam->pdev->dev; + +@@ -1992,9 +2029,9 @@ static int unicam_probe_complete(struct + return ret; + } + +- INIT_LIST_HEAD(&unicam->dma_queue.active); ++ INIT_LIST_HEAD(&node->dma_queue.active); + +- vdev = &unicam->video_dev; ++ vdev = &node->video_dev; + strlcpy(vdev->name, UNICAM_MODULE_NAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &unicam_fops; +@@ -2002,69 +2039,113 @@ static int unicam_probe_complete(struct + vdev->v4l2_dev = &unicam->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; +- vdev->lock = &unicam->lock; ++ vdev->lock = &node->lock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; +- + /* If the source has no controls then remove our ctrl handler. */ +- if (list_empty(&unicam->ctrl_handler.ctrls)) ++ if (list_empty(&node->ctrl_handler.ctrls)) + unicam->v4l2_dev.ctrl_handler = NULL; + +- video_set_drvdata(vdev, unicam); ++ node->dev = unicam; ++ video_set_drvdata(vdev, node); + vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; + + if (!v4l2_subdev_has_op(unicam->sensor, video, s_std)) { +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_STD); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_STD); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUMSTD); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD); + } + if (!v4l2_subdev_has_op(unicam->sensor, video, querystd)) +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERYSTD); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD); + if (!v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_EDID); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_EDID); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_DV_TIMINGS_CAP); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_DV_TIMINGS); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_DV_TIMINGS); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_DV_TIMINGS); +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_QUERY_DV_TIMINGS); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_DV_TIMINGS); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_DV_TIMINGS); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS); + } + if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval)) +- v4l2_disable_ioctl(&unicam->video_dev, ++ v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); + if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval)) +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_G_PARM); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM); + if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval)) +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_S_PARM); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM); + + if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size)) +- v4l2_disable_ioctl(&unicam->video_dev, VIDIOC_ENUM_FRAMESIZES); ++ v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + unicam_err(unicam, "Unable to register video device.\n"); + return ret; + } ++ node->registered = true; + +- ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); ++ ret = media_create_pad_link(&unicam->sensor->entity, ++ 0, &node->video_dev.entity, 0, ++ MEDIA_LNK_FL_ENABLED | ++ MEDIA_LNK_FL_IMMUTABLE); ++ if (ret) ++ unicam_err(unicam, "Unable to create pad links.\n"); ++ ++ return ret; ++} ++ ++static void unregister_nodes(struct unicam_device *unicam) ++{ ++ if (unicam->node[0].registered) { ++ video_unregister_device(&unicam->node[0].video_dev); ++ unicam->node[0].registered = false; ++ } ++ if (unicam->node[1].registered) { ++ video_unregister_device(&unicam->node[1].video_dev); ++ unicam->node[1].registered = false; ++ } ++} ++ ++static int unicam_probe_complete(struct unicam_device *unicam) ++{ ++ int ret; ++ ++ v4l2_set_subdev_hostdata(unicam->sensor, unicam); ++ ++ unicam->v4l2_dev.notify = unicam_notify; ++ ++ unicam->sensor_config = v4l2_subdev_alloc_pad_config(unicam->sensor); ++ if (!unicam->sensor_config) ++ return -ENOMEM; ++ ++ ret = register_node(unicam, &unicam->node[0], ++ V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); + if (ret) { +- unicam_err(unicam, +- "Unable to register subdev nodes.\n"); +- video_unregister_device(&unicam->video_dev); +- return ret; ++ unicam_err(unicam, "Unable to register subdev node 0.\n"); ++ goto unregister; ++ } ++ if (unicam->sensor->entity.num_pads >= 2) { ++ ret = register_node(unicam, &unicam->node[1], ++ V4L2_BUF_TYPE_META_CAPTURE, 1); ++ if (ret) { ++ unicam_err(unicam, ++ "Unable to register subdev node 1.\n"); ++ goto unregister; ++ } + } + +- ret = media_create_pad_link(&unicam->sensor->entity, 0, +- &unicam->video_dev.entity, 0, +- MEDIA_LNK_FL_ENABLED | +- MEDIA_LNK_FL_IMMUTABLE); ++ ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); + if (ret) { +- unicam_err(unicam, "Unable to create pad links.\n"); +- video_unregister_device(&unicam->video_dev); +- return ret; ++ unicam_err(unicam, "Unable to register subdev nodes.\n"); ++ goto unregister; + } + + return 0; ++ ++unregister: ++ unregister_nodes(unicam); ++ ++ return ret; + } + + static int unicam_async_complete(struct v4l2_async_notifier *notifier) +@@ -2274,7 +2355,8 @@ static int unicam_probe(struct platform_ + pdev->dev.driver->name, dev_name(&pdev->dev)); + unicam->mdev.hw_revision = 1; + +- media_entity_pads_init(&unicam->video_dev.entity, 1, &unicam->pad); ++ media_entity_pads_init(&unicam->node[0].video_dev.entity, 1, ++ &unicam->node[0].pad); + media_device_init(&unicam->mdev); + + unicam->v4l2_dev.mdev = &unicam->mdev; +@@ -2294,7 +2376,7 @@ static int unicam_probe(struct platform_ + } + + /* Reserve space for the controls */ +- hdl = &unicam->ctrl_handler; ++ hdl = &unicam->node[0].ctrl_handler; + ret = v4l2_ctrl_handler_init(hdl, 16); + if (ret < 0) + goto media_unregister; +@@ -2335,9 +2417,9 @@ static int unicam_remove(struct platform + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&unicam->notifier); +- v4l2_ctrl_handler_free(&unicam->ctrl_handler); ++ v4l2_ctrl_handler_free(&unicam->node[0].ctrl_handler); + v4l2_device_unregister(&unicam->v4l2_dev); +- video_unregister_device(&unicam->video_dev); ++ unregister_nodes(unicam); + if (unicam->sensor_config) + v4l2_subdev_free_pad_config(unicam->sensor_config); + media_device_unregister(&unicam->mdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0653-media-bcm2835-unicam-Add-embedded-data-node.patch b/target/linux/bcm27xx/patches-5.4/950-0653-media-bcm2835-unicam-Add-embedded-data-node.patch new file mode 100644 index 00000000000..a163a6f1a5c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0653-media-bcm2835-unicam-Add-embedded-data-node.patch @@ -0,0 +1,1170 @@ +From 272ee62d6410319ab4d73997de32776cc3e274cb Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 16 Apr 2020 11:35:41 +0100 +Subject: [PATCH] media: bcm2835-unicam: Add embedded data node. + +This patch adds a new node in the bcm2835-unicam driver to support +CSI-2 embedded data streams. The subdevice is queried to see if +embedded data is available from the sensor. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/bcm2835/bcm2835-unicam.c | 667 +++++++++++++----- + 1 file changed, 474 insertions(+), 193 deletions(-) + +--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c ++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c +@@ -109,8 +109,15 @@ MODULE_PARM_DESC(debug, "Debug level 0-3 + /* Define a nominal minimum image size */ + #define MIN_WIDTH 16 + #define MIN_HEIGHT 16 +-/* Maximum number of simulataneous streams Uncaim can handle. */ +-#define MAX_NODES 2 ++/* Default size of the embedded buffer */ ++#define UNICAM_EMBEDDED_SIZE 8192 ++ ++enum pad_types { ++ IMAGE_PAD, ++ METADATA_PAD, ++ MAX_NODES ++}; ++ + /* + * struct unicam_fmt - Unicam media bus format information + * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a. +@@ -327,6 +334,12 @@ static const struct unicam_fmt formats[] + .depth = 12, + .csi_dt = 0x2c, + }, ++ /* Embedded data format */ ++ { ++ .fourcc = V4L2_META_FMT_SENSOR_DATA, ++ .code = MEDIA_BUS_FMT_SENSOR_DATA, ++ .depth = 8, ++ } + }; + + struct unicam_dmaqueue { +@@ -348,7 +361,9 @@ struct unicam_cfg { + #define MAX_POSSIBLE_PIX_FMTS (ARRAY_SIZE(formats)) + + struct unicam_node { +- bool registered; ++ int registered; ++ int open; ++ int streaming; + unsigned int pad_id; + /* Pointer pointing to current v4l2_buffer */ + struct unicam_buffer *cur_frm; +@@ -374,6 +389,7 @@ struct unicam_node { + struct unicam_device *dev; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; ++ unsigned int embedded_lines; + }; + + struct unicam_device { +@@ -401,8 +417,6 @@ struct unicam_device { + struct v4l2_subdev *sensor; + /* Pad config for the sensor */ + struct v4l2_subdev_pad_config *sensor_config; +- /* current input at the sub device */ +- int current_input; + + unsigned int virtual_channel; + enum v4l2_mbus_type bus_type; +@@ -413,10 +427,7 @@ struct unicam_device { + unsigned int bus_flags; + unsigned int max_data_lanes; + unsigned int active_data_lanes; +- +- struct v4l2_rect crop; +- /* Flag to denote that we are processing buffers */ +- int streaming; ++ bool sensor_embedded_data; + + struct unicam_node node[MAX_NODES]; + }; +@@ -488,6 +499,7 @@ static int check_mbus_format(struct unic + for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) { + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = i; ++ mbus_code.pad = IMAGE_PAD; + mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, +@@ -552,10 +564,11 @@ static int __subdev_get_format(struct un + } + + static int __subdev_set_format(struct unicam_device *dev, +- struct v4l2_mbus_framefmt *fmt) ++ struct v4l2_mbus_framefmt *fmt, int pad_id) + { + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ .pad = pad_id + }; + int ret; + +@@ -566,8 +579,12 @@ static int __subdev_set_format(struct un + if (ret < 0) + return ret; + +- unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, +- fmt->width, fmt->height, fmt->code); ++ if (pad_id == IMAGE_PAD) ++ unicam_dbg(1, dev, "%s %dx%d code:%04x\n", __func__, fmt->width, ++ fmt->height, fmt->code); ++ else ++ unicam_dbg(1, dev, "%s Embedded data code:%04x\n", __func__, ++ sd_fmt.format.code); + + return 0; + } +@@ -609,46 +626,70 @@ static int unicam_reset_format(struct un + struct v4l2_mbus_framefmt mbus_fmt; + int ret; + +- ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id); +- if (ret) { +- unicam_err(dev, "Failed to get_format - ret %d\n", ret); +- return ret; +- } ++ if (dev->sensor_embedded_data || node->pad_id != METADATA_PAD) { ++ ret = __subdev_get_format(dev, &mbus_fmt, node->pad_id); ++ if (ret) { ++ unicam_err(dev, "Failed to get_format - ret %d\n", ret); ++ return ret; ++ } + +- if (mbus_fmt.code != dev->node[0].fmt->code) { +- unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n", +- dev->node[0].fmt->code, mbus_fmt.code); +- return ret; ++ if (mbus_fmt.code != node->fmt->code) { ++ unicam_err(dev, "code mismatch - fmt->code %08x, mbus_fmt.code %08x\n", ++ node->fmt->code, mbus_fmt.code); ++ return ret; ++ } + } + +- v4l2_fill_pix_format(&dev->node[0].v_fmt.fmt.pix, &mbus_fmt); +- dev->node[0].v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +- +- unicam_calc_format_size_bpl(dev, dev->node[0].fmt, &dev->node[0].v_fmt); +- +- dev->node[0].m_fmt = mbus_fmt; ++ if (node->pad_id == IMAGE_PAD) { ++ v4l2_fill_pix_format(&node->v_fmt.fmt.pix, &mbus_fmt); ++ node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ unicam_calc_format_size_bpl(dev, node->fmt, &node->v_fmt); ++ } else { ++ node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; ++ node->v_fmt.fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA; ++ if (dev->sensor_embedded_data) { ++ node->v_fmt.fmt.meta.buffersize = ++ mbus_fmt.width * mbus_fmt.height; ++ node->embedded_lines = mbus_fmt.height; ++ } else { ++ node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE; ++ node->embedded_lines = 1; ++ } ++ } + ++ node->m_fmt = mbus_fmt; + return 0; + } + +-static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr) ++static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr, ++ int pad_id) + { ++ dma_addr_t endaddr; ++ + /* + * dmaaddr should be a 32-bit address with the top two bits set to 0x3 + * to signify uncached access through the Videocore memory controller. + */ + BUG_ON((dmaaddr >> 30) != 0x3); + +- reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); +- reg_write(&dev->cfg, UNICAM_IBEA0, +- dmaaddr + dev->node[0].v_fmt.fmt.pix.sizeimage); ++ if (pad_id == IMAGE_PAD) { ++ endaddr = dmaaddr + ++ dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage; ++ reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); ++ reg_write(&dev->cfg, UNICAM_IBEA0, endaddr); ++ } else { ++ endaddr = dmaaddr + ++ dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; ++ reg_write(&dev->cfg, UNICAM_DBSA0, dmaaddr); ++ reg_write(&dev->cfg, UNICAM_DBEA0, endaddr); ++ } + } + + static inline unsigned int unicam_get_lines_done(struct unicam_device *dev) + { + dma_addr_t start_addr, cur_addr; +- unsigned int stride = dev->node[0].v_fmt.fmt.pix.bytesperline; +- struct unicam_buffer *frm = dev->node[0].cur_frm; ++ unsigned int stride = dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline; ++ struct unicam_buffer *frm = dev->node[IMAGE_PAD].cur_frm; + + if (!frm) + return 0; +@@ -658,27 +699,51 @@ static inline unsigned int unicam_get_li + return (unsigned int)(cur_addr - start_addr) / stride; + } + +-static inline void unicam_schedule_next_buffer(struct unicam_device *dev) ++static inline void unicam_schedule_next_buffer(struct unicam_node *node) + { +- struct unicam_dmaqueue *dma_q = &dev->node[0].dma_queue; ++ struct unicam_device *dev = node->dev; ++ struct unicam_dmaqueue *dma_q = &node->dma_queue; + struct unicam_buffer *buf; + dma_addr_t addr; + + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); +- dev->node[0].next_frm = buf; ++ node->next_frm = buf; + list_del(&buf->list); + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +- unicam_wr_dma_addr(dev, addr); ++ unicam_wr_dma_addr(dev, addr, node->pad_id); + } + +-static inline void unicam_process_buffer_complete(struct unicam_device *dev) ++static inline void unicam_process_buffer_complete(struct unicam_node *node, ++ unsigned int sequence) + { +- dev->node[0].cur_frm->vb.field = dev->node[0].m_fmt.field; +- dev->node[0].cur_frm->vb.sequence = dev->sequence++; ++ node->cur_frm->vb.field = node->m_fmt.field; ++ node->cur_frm->vb.sequence = sequence; ++ ++ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); ++ node->cur_frm = node->next_frm; ++} + +- vb2_buffer_done(&dev->node[0].cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); +- dev->node[0].cur_frm = dev->node[0].next_frm; ++static int unicam_num_nodes_streaming(struct unicam_device *dev) ++{ ++ return dev->node[IMAGE_PAD].streaming + ++ dev->node[METADATA_PAD].streaming; ++} ++ ++static int unicam_all_nodes_streaming(struct unicam_device *dev) ++{ ++ int ret; ++ ++ ret = dev->node[IMAGE_PAD].open && dev->node[IMAGE_PAD].streaming; ++ ret &= !dev->node[METADATA_PAD].open || ++ dev->node[METADATA_PAD].streaming; ++ return ret; ++} ++ ++static int unicam_all_nodes_disabled(struct unicam_device *dev) ++{ ++ return !dev->node[IMAGE_PAD].streaming && ++ !dev->node[METADATA_PAD].streaming; + } + + /* +@@ -693,10 +758,12 @@ static irqreturn_t unicam_isr(int irq, v + { + struct unicam_device *unicam = (struct unicam_device *)dev; + struct unicam_cfg *cfg = &unicam->cfg; +- struct unicam_dmaqueue *dma_q = &unicam->node[0].dma_queue; + unsigned int lines_done = unicam_get_lines_done(dev); + unsigned int sequence = unicam->sequence; ++ int num_nodes_streaming = unicam_num_nodes_streaming(dev); + int ista, sta; ++ u64 ts; ++ int i; + + /* + * Don't service interrupts if not streaming. +@@ -704,7 +771,7 @@ static irqreturn_t unicam_isr(int irq, v + * peripheral without the kernel knowing (that + * shouldn't happen, but causes issues if it does). + */ +- if (!unicam->streaming) ++ if (unicam_all_nodes_disabled(unicam)) + return IRQ_HANDLED; + + sta = reg_read(cfg, UNICAM_STA); +@@ -726,9 +793,12 @@ static irqreturn_t unicam_isr(int irq, v + * Timestamp is to be when the first data byte was captured, + * aka frame start. + */ +- if (unicam->node[0].cur_frm) +- unicam->node[0].cur_frm->vb.vb2_buf.timestamp = +- ktime_get_ns(); ++ ts = ktime_get_ns(); ++ for (i = 0; i < num_nodes_streaming; i++) { ++ if (unicam->node[i].cur_frm) ++ unicam->node[i].cur_frm->vb.vb2_buf.timestamp = ++ ts; ++ } + } + if (ista & UNICAM_FEI || sta & UNICAM_PI0) { + /* +@@ -736,9 +806,13 @@ static irqreturn_t unicam_isr(int irq, v + * stop the peripheral. Overwrite the frame we've just + * captured instead. + */ +- if (unicam->node[0].cur_frm && +- unicam->node[0].cur_frm != unicam->node[0].next_frm) +- unicam_process_buffer_complete(unicam); ++ for (i = 0; i < num_nodes_streaming; i++) { ++ if (unicam->node[i].cur_frm && ++ unicam->node[i].cur_frm != unicam->node[i].next_frm) ++ unicam_process_buffer_complete(&unicam->node[i], ++ sequence); ++ } ++ unicam->sequence++; + } + + /* Cannot swap buffer at frame end, there may be a race condition +@@ -746,11 +820,13 @@ static irqreturn_t unicam_isr(int irq, v + * already started. + */ + if (ista & (UNICAM_FSI | UNICAM_LCI) && !(ista & UNICAM_FEI)) { +- spin_lock(&unicam->node[0].dma_queue_lock); +- if (!list_empty(&dma_q->active) && +- unicam->node[0].cur_frm == unicam->node[0].next_frm) +- unicam_schedule_next_buffer(unicam); +- spin_unlock(&unicam->node[0].dma_queue_lock); ++ for (i = 0; i < num_nodes_streaming; i++) { ++ spin_lock(&unicam->node[i].dma_queue_lock); ++ if (!list_empty(&unicam->node[i].dma_queue.active) && ++ unicam->node[i].cur_frm == unicam->node[i].next_frm) ++ unicam_schedule_next_buffer(&unicam->node[i]); ++ spin_unlock(&unicam->node[i].dma_queue_lock); ++ } + } + + if (reg_read(&unicam->cfg, UNICAM_ICTL) & UNICAM_FCM) { +@@ -773,6 +849,15 @@ static int unicam_querycap(struct file * + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev->v4l2_dev.name); + ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | ++ V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS | ++ V4L2_CAP_META_CAPTURE; ++ ++ if (node->pad_id == IMAGE_PAD) ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ else ++ cap->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; ++ + return 0; + } + +@@ -787,9 +872,14 @@ static int unicam_enum_fmt_vid_cap(struc + int ret = 0; + int i; + ++ if (node->pad_id == METADATA_PAD) ++ return -EINVAL; ++ + for (i = 0; !ret && i < MAX_ENUM_MBUS_CODE; i++) { + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = i; ++ mbus_code.pad = IMAGE_PAD; ++ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, + NULL, &mbus_code); +@@ -827,6 +917,9 @@ static int unicam_g_fmt_vid_cap(struct f + { + struct unicam_node *node = video_drvdata(file); + ++ if (node->pad_id == METADATA_PAD) ++ return -EINVAL; ++ + *f = node->v_fmt; + + return 0; +@@ -843,6 +936,9 @@ const struct unicam_fmt *get_first_suppo + for (j = 0; ret != -EINVAL && ret != -ENOIOCTLCMD; ++j) { + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = j; ++ mbus_code.pad = IMAGE_PAD; ++ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ + ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL, + &mbus_code); + if (ret < 0) { +@@ -873,12 +969,15 @@ static int unicam_try_fmt_vid_cap(struct + struct unicam_device *dev = node->dev; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, +- .pad = 0 ++ .pad = IMAGE_PAD + }; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; + const struct unicam_fmt *fmt; + int ret; + ++ if (node->pad_id == METADATA_PAD) ++ return -EINVAL; ++ + fmt = find_format_by_pix(dev, f->fmt.pix.pixelformat); + if (!fmt) { + /* Pixel format not supported by unicam. Choose the first +@@ -983,7 +1082,7 @@ static int unicam_s_fmt_vid_cap(struct f + + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code); + +- ret = __subdev_set_format(dev, &mbus_fmt); ++ ret = __subdev_set_format(dev, &mbus_fmt, node->pad_id); + if (ret) { + unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n", + __func__, ret); +@@ -1014,6 +1113,106 @@ static int unicam_s_fmt_vid_cap(struct f + return 0; + } + ++static int unicam_enum_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; ++ struct v4l2_subdev_mbus_code_enum mbus_code; ++ const struct unicam_fmt *fmt = NULL; ++ int ret = 0; ++ ++ if (node->pad_id != METADATA_PAD || f->index != 0) ++ return -EINVAL; ++ ++ if (dev->sensor_embedded_data) { ++ memset(&mbus_code, 0, sizeof(mbus_code)); ++ mbus_code.index = f->index; ++ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ mbus_code.pad = METADATA_PAD; ++ ++ ret = v4l2_subdev_call(dev->sensor, pad, enum_mbus_code, NULL, ++ &mbus_code); ++ if (ret < 0) { ++ unicam_dbg(2, dev, ++ "subdev->enum_mbus_code idx 0 returned %d - index invalid\n", ++ ret); ++ return -EINVAL; ++ } ++ } else { ++ mbus_code.code = MEDIA_BUS_FMT_SENSOR_DATA; ++ } ++ ++ fmt = find_format_by_code(mbus_code.code); ++ if (fmt) ++ f->pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++ ++static int unicam_g_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_node *node = video_drvdata(file); ++ ++ if (node->pad_id != METADATA_PAD) ++ return -EINVAL; ++ ++ *f = node->v_fmt; ++ ++ return 0; ++} ++ ++static int unicam_try_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_node *node = video_drvdata(file); ++ ++ if (node->pad_id != METADATA_PAD) ++ return -EINVAL; ++ ++ *f = node->v_fmt; ++ ++ return 0; ++} ++ ++static int unicam_s_fmt_meta_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct unicam_node *node = video_drvdata(file); ++ struct unicam_device *dev = node->dev; ++ struct v4l2_mbus_framefmt mbus_fmt = { 0 }; ++ const struct unicam_fmt *fmt; ++ int ret; ++ ++ if (node->pad_id == IMAGE_PAD) ++ return -EINVAL; ++ ++ if (dev->sensor_embedded_data) { ++ fmt = find_format_by_pix(dev, f->fmt.meta.dataformat); ++ if (!fmt) { ++ unicam_err(dev, "unknown format: V4L2 pix 0x%08x\n", ++ f->fmt.meta.dataformat); ++ return -EINVAL; ++ } ++ mbus_fmt.code = fmt->code; ++ ret = __subdev_set_format(dev, &mbus_fmt, node->pad_id); ++ if (ret) { ++ unicam_dbg(3, dev, "%s __subdev_set_format failed %d\n", ++ __func__, ret); ++ return ret; ++ } ++ } ++ ++ *f = node->v_fmt; ++ ++ unicam_dbg(3, dev, "%s size %d, V4L2 pix 0x%08x\n", ++ __func__, node->v_fmt.fmt.meta.buffersize, ++ node->v_fmt.fmt.meta.dataformat); ++ ++ return 0; ++} ++ + static int unicam_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, +@@ -1022,7 +1221,9 @@ static int unicam_queue_setup(struct vb2 + { + struct unicam_node *node = vb2_get_drv_priv(vq); + struct unicam_device *dev = node->dev; +- unsigned int size = node->v_fmt.fmt.pix.sizeimage; ++ unsigned int size = node->pad_id == IMAGE_PAD ? ++ node->v_fmt.fmt.pix.sizeimage : ++ node->v_fmt.fmt.meta.buffersize; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; +@@ -1053,7 +1254,8 @@ static int unicam_buffer_prepare(struct + if (WARN_ON(!node->fmt)) + return -EINVAL; + +- size = node->v_fmt.fmt.pix.sizeimage; ++ size = node->pad_id == IMAGE_PAD ? node->v_fmt.fmt.pix.sizeimage : ++ node->v_fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); +@@ -1082,12 +1284,12 @@ static void unicam_set_packing_config(st + int pack, unpack; + u32 val; + +- if (dev->node[0].v_fmt.fmt.pix.pixelformat == +- dev->node[0].fmt->fourcc) { ++ if (dev->node[IMAGE_PAD].v_fmt.fmt.pix.pixelformat == ++ dev->node[IMAGE_PAD].fmt->fourcc) { + unpack = UNICAM_PUM_NONE; + pack = UNICAM_PPM_NONE; + } else { +- switch (dev->node[0].fmt->depth) { ++ switch (dev->node[IMAGE_PAD].fmt->depth) { + case 8: + unpack = UNICAM_PUM_UNPACK8; + break; +@@ -1125,17 +1327,31 @@ static void unicam_cfg_image_id(struct u + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + /* CSI2 mode */ + reg_write(cfg, UNICAM_IDI0, +- (dev->virtual_channel << 6) | dev->node[0].fmt->csi_dt); ++ (dev->virtual_channel << 6) | ++ dev->node[IMAGE_PAD].fmt->csi_dt); + } else { + /* CCP2 mode */ +- reg_write(cfg, UNICAM_IDI0, (0x80 | dev->node[0].fmt->csi_dt)); ++ reg_write(cfg, UNICAM_IDI0, ++ 0x80 | dev->node[IMAGE_PAD].fmt->csi_dt); + } + } + +-static void unicam_start_rx(struct unicam_device *dev, unsigned long addr) ++static void unicam_enable_ed(struct unicam_device *dev) ++{ ++ struct unicam_cfg *cfg = &dev->cfg; ++ u32 val = reg_read(cfg, UNICAM_DCS); ++ ++ set_field(&val, 2, UNICAM_EDL_MASK); ++ /* Do not wrap at the end of the embedded data buffer */ ++ set_field(&val, 0, UNICAM_DBOB); ++ ++ reg_write(cfg, UNICAM_DCS, val); ++} ++ ++static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr) + { + struct unicam_cfg *cfg = &dev->cfg; +- int line_int_freq = dev->node[0].v_fmt.fmt.pix.height >> 2; ++ int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2; + unsigned int i; + u32 val; + +@@ -1284,27 +1500,31 @@ static void unicam_start_rx(struct unica + } + + reg_write(&dev->cfg, UNICAM_IBLS, +- dev->node[0].v_fmt.fmt.pix.bytesperline); +- unicam_wr_dma_addr(dev, addr); ++ dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline); ++ unicam_wr_dma_addr(dev, addr[IMAGE_PAD], IMAGE_PAD); + unicam_set_packing_config(dev); + unicam_cfg_image_id(dev); + +- /* Disabled embedded data */ +- val = 0; +- set_field(&val, 0, UNICAM_EDL_MASK); +- reg_write(cfg, UNICAM_DCS, val); +- + val = reg_read(cfg, UNICAM_MISC); + set_field(&val, 1, UNICAM_FL0); + set_field(&val, 1, UNICAM_FL1); + reg_write(cfg, UNICAM_MISC, val); + ++ if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) { ++ unicam_enable_ed(dev); ++ unicam_wr_dma_addr(dev, addr[METADATA_PAD], METADATA_PAD); ++ } ++ + /* Enable peripheral */ + reg_write_field(cfg, UNICAM_CTRL, 1, UNICAM_CPE); + + /* Load image pointers */ + reg_write_field(cfg, UNICAM_ICTL, 1, UNICAM_LIP_MASK); + ++ /* Load embedded data buffer pointers if needed */ ++ if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) ++ reg_write_field(cfg, UNICAM_DCS, 1, UNICAM_LDP); ++ + /* + * Enable trigger only for the first frame to + * sync correctly to the FS from the source. +@@ -1339,6 +1559,9 @@ static void unicam_disable(struct unicam + /* Disable peripheral */ + reg_write_field(cfg, UNICAM_CTRL, 0, UNICAM_CPE); + ++ /* Clear ED setup */ ++ reg_write(cfg, UNICAM_DCS, 0); ++ + /* Disable all lane clocks */ + clk_write(cfg, 0); + } +@@ -1347,26 +1570,23 @@ static int unicam_start_streaming(struct + { + struct unicam_node *node = vb2_get_drv_priv(vq); + struct unicam_device *dev = node->dev; +- struct unicam_dmaqueue *dma_q = &node->dma_queue; +- struct unicam_buffer *buf, *tmp; +- unsigned long addr = 0; ++ struct unicam_buffer *buf; ++ dma_addr_t buffer_addr[MAX_NODES] = { 0 }; ++ int num_nodes_streaming; + unsigned long flags; +- int ret; ++ int ret, i; + +- spin_lock_irqsave(&node->dma_queue_lock, flags); +- buf = list_entry(dma_q->active.next, struct unicam_buffer, list); +- node->cur_frm = buf; +- node->next_frm = buf; +- list_del(&buf->list); +- spin_unlock_irqrestore(&node->dma_queue_lock, flags); ++ node->streaming = 1; ++ if (!unicam_all_nodes_streaming(dev)) { ++ unicam_dbg(3, dev, "Not all nodes are streaming yet."); ++ return 0; ++ } + +- addr = vb2_dma_contig_plane_dma_addr(&node->cur_frm->vb.vb2_buf, 0); + dev->sequence = 0; +- + ret = unicam_runtime_get(dev); + if (ret < 0) { + unicam_dbg(3, dev, "unicam_runtime_get failed\n"); +- goto err_release_buffers; ++ return ret; + } + + dev->active_data_lanes = dev->max_data_lanes; +@@ -1388,7 +1608,7 @@ static int unicam_start_streaming(struct + dev->active_data_lanes = dev->max_data_lanes; + } + if (dev->active_data_lanes > dev->max_data_lanes) { +- unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", ++ unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", + dev->active_data_lanes, dev->max_data_lanes); + ret = -EINVAL; + goto err_pm_put; +@@ -1408,9 +1628,22 @@ static int unicam_start_streaming(struct + unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); + goto err_pm_put; + } +- dev->streaming = 1; + +- unicam_start_rx(dev, addr); ++ num_nodes_streaming = unicam_num_nodes_streaming(dev); ++ for (i = 0; i < num_nodes_streaming; i++) { ++ spin_lock_irqsave(&dev->node[i].dma_queue_lock, flags); ++ buf = list_entry(dev->node[i].dma_queue.active.next, ++ struct unicam_buffer, list); ++ dev->node[i].cur_frm = buf; ++ dev->node[i].next_frm = buf; ++ list_del(&buf->list); ++ spin_unlock_irqrestore(&dev->node[i].dma_queue_lock, flags); ++ buffer_addr[i] = ++ vb2_dma_contig_plane_dma_addr(&dev->node[i].cur_frm->vb.vb2_buf, ++ 0); ++ } ++ ++ unicam_start_rx(dev, buffer_addr); + + ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); + if (ret < 0) { +@@ -1421,21 +1654,11 @@ static int unicam_start_streaming(struct + return 0; + + err_disable_unicam: ++ node->streaming = 0; + unicam_disable(dev); + clk_disable_unprepare(dev->clock); + err_pm_put: + unicam_runtime_put(dev); +-err_release_buffers: +- list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { +- list_del(&buf->list); +- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); +- } +- if (node->cur_frm != node->next_frm) +- vb2_buffer_done(&node->next_frm->vb.vb2_buf, +- VB2_BUF_STATE_QUEUED); +- vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); +- node->next_frm = NULL; +- node->cur_frm = NULL; + + return ret; + } +@@ -1448,33 +1671,47 @@ static void unicam_stop_streaming(struct + struct unicam_buffer *buf, *tmp; + unsigned long flags; + +- if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) +- unicam_err(dev, "stream off failed in subdev\n"); ++ node->streaming = 0; + +- unicam_disable(dev); ++ if (node->pad_id == IMAGE_PAD) { ++ /* Stop streaming the sensor and disable the peripheral. ++ * We cannot continue streaming embedded data with the ++ * image pad disabled. ++ */ ++ if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) ++ unicam_err(dev, "stream off failed in subdev\n"); + +- /* Release all active buffers */ ++ unicam_disable(dev); ++ clk_disable_unprepare(dev->clock); ++ unicam_runtime_put(dev); ++ ++ } else if (node->pad_id == METADATA_PAD) { ++ /* Null out the embedded data buffer address so the HW does ++ * not use it. This is only really needed if the embedded data ++ * pad is disabled before the image pad. The 0x3 in the top two ++ * bits signifies uncached accesses through the Videocore ++ * memory controller. ++ */ ++ unicam_wr_dma_addr(dev, 0xc0000000, METADATA_PAD); ++ } ++ ++ /* Clear all queued buffers for the node */ + spin_lock_irqsave(&node->dma_queue_lock, flags); + list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + +- if (node->cur_frm == node->next_frm) { +- vb2_buffer_done(&node->cur_frm->vb.vb2_buf, +- VB2_BUF_STATE_ERROR); +- } else { ++ if (node->cur_frm) + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); ++ if (node->next_frm && node->cur_frm != node->next_frm) + vb2_buffer_done(&node->next_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); +- } ++ + node->cur_frm = NULL; + node->next_frm = NULL; + spin_unlock_irqrestore(&node->dma_queue_lock, flags); +- +- clk_disable_unprepare(dev->clock); +- unicam_runtime_put(dev); + } + + static int unicam_enum_input(struct file *file, void *priv, +@@ -1595,17 +1832,23 @@ static int unicam_enum_framesizes(struct + struct v4l2_subdev_frame_size_enum fse; + int ret; + +- /* check for valid format */ +- fmt = find_format_by_pix(dev, fsize->pixel_format); +- if (!fmt) { +- unicam_dbg(3, dev, "Invalid pixel code: %x\n", +- fsize->pixel_format); +- return -EINVAL; ++ if (node->pad_id == IMAGE_PAD) { ++ /* check for valid format */ ++ fmt = find_format_by_pix(dev, fsize->pixel_format); ++ if (!fmt) { ++ unicam_dbg(3, dev, "Invalid pixel code: %x\n", ++ fsize->pixel_format); ++ return -EINVAL; ++ } ++ fse.code = fmt->code; ++ } else { ++ /* This pad is for embedded data, so just set the format */ ++ fse.code = MEDIA_BUS_FMT_SENSOR_DATA; + } + ++ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fse.index = fsize->index; +- fse.pad = 0; +- fse.code = fmt->code; ++ fse.pad = node->pad_id; + + ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse); + if (ret) +@@ -1782,7 +2025,7 @@ static void unicam_notify(struct v4l2_su + + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: +- v4l2_event_queue(&dev->node[0].video_dev, arg); ++ v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg); + break; + default: + break; +@@ -1826,6 +2069,7 @@ static int unicam_open(struct file *file + goto unlock; + } + ++ node->open++; + ret = 0; + + unlock: +@@ -1850,6 +2094,10 @@ static int unicam_release(struct file *f + if (fh_singular) + v4l2_subdev_call(sd, core, s_power, 0); + ++ if (node->streaming) ++ unicam_stop_streaming(&node->buffer_queue); ++ ++ node->open--; + mutex_unlock(&node->lock); + + return ret; +@@ -1874,6 +2122,11 @@ static const struct v4l2_ioctl_ops unica + .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap, + ++ .vidioc_enum_fmt_meta_cap = unicam_enum_fmt_meta_cap, ++ .vidioc_g_fmt_meta_cap = unicam_g_fmt_meta_cap, ++ .vidioc_s_fmt_meta_cap = unicam_s_fmt_meta_cap, ++ .vidioc_try_fmt_meta_cap = unicam_try_fmt_meta_cap, ++ + .vidioc_enum_input = unicam_enum_input, + .vidioc_g_input = unicam_g_input, + .vidioc_s_input = unicam_s_input, +@@ -1941,42 +2194,53 @@ static int register_node(struct unicam_d + const struct unicam_fmt *fmt; + int ret; + +- ret = __subdev_get_format(unicam, &mbus_fmt, pad_id); +- if (ret) { +- unicam_err(unicam, "Failed to get_format - ret %d\n", ret); +- return ret; +- } +- +- fmt = find_format_by_code(mbus_fmt.code); +- if (!fmt) { +- /* Find the first format that the sensor and unicam both +- * support +- */ +- fmt = get_first_supported_format(unicam); ++ if (unicam->sensor_embedded_data || pad_id != METADATA_PAD) { ++ ret = __subdev_get_format(unicam, &mbus_fmt, pad_id); ++ if (ret) { ++ unicam_err(unicam, "Failed to get_format - ret %d\n", ++ ret); ++ return ret; ++ } + +- if (!fmt) +- /* No compatible formats */ +- return -EINVAL; ++ fmt = find_format_by_code(mbus_fmt.code); ++ if (!fmt) { ++ /* Find the first format that the sensor and unicam both ++ * support ++ */ ++ fmt = get_first_supported_format(unicam); + +- mbus_fmt.code = fmt->code; +- ret = __subdev_set_format(unicam, &mbus_fmt); +- if (ret) +- return -EINVAL; +- } +- if (mbus_fmt.field != V4L2_FIELD_NONE) { +- /* Interlaced not supported - disable it now. */ +- mbus_fmt.field = V4L2_FIELD_NONE; +- ret = __subdev_set_format(unicam, &mbus_fmt); +- if (ret) +- return -EINVAL; ++ if (!fmt) ++ /* No compatible formats */ ++ return -EINVAL; ++ ++ mbus_fmt.code = fmt->code; ++ ret = __subdev_set_format(unicam, &mbus_fmt, pad_id); ++ if (ret) ++ return -EINVAL; ++ } ++ if (mbus_fmt.field != V4L2_FIELD_NONE) { ++ /* Interlaced not supported - disable it now. */ ++ mbus_fmt.field = V4L2_FIELD_NONE; ++ ret = __subdev_set_format(unicam, &mbus_fmt, pad_id); ++ if (ret) ++ return -EINVAL; ++ } ++ } else { ++ /* Fix this node format as embedded data. */ ++ fmt = find_format_by_code(MEDIA_BUS_FMT_SENSOR_DATA); + } + ++ node->dev = unicam; + node->pad_id = pad_id; + node->fmt = fmt; +- if (fmt->fourcc) +- node->v_fmt.fmt.pix.pixelformat = fmt->fourcc; +- else ++ if (fmt->fourcc) { ++ if (fmt->fourcc != V4L2_META_FMT_SENSOR_DATA) ++ node->v_fmt.fmt.pix.pixelformat = fmt->fourcc; ++ else ++ node->v_fmt.fmt.meta.dataformat = fmt->fourcc; ++ } else { + node->v_fmt.fmt.pix.pixelformat = fmt->repacked_fourcc; ++ } + + /* Read current subdev format */ + unicam_reset_format(node); +@@ -2002,13 +2266,21 @@ static int register_node(struct unicam_d + spin_lock_init(&node->dma_queue_lock); + mutex_init(&node->lock); + +- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ vdev = &node->video_dev; ++ if (pad_id == IMAGE_PAD) { + /* Add controls from the subdevice */ + ret = v4l2_ctrl_add_handler(&node->ctrl_handler, + unicam->sensor->ctrl_handler, NULL, + true); + if (ret < 0) + return ret; ++ ++ /* ++ * If the sensor subdevice has any controls, associate the node ++ * with the ctrl handler to allow access from userland. ++ */ ++ if (!list_empty(&node->ctrl_handler.ctrls)) ++ vdev->ctrl_handler = &node->ctrl_handler; + } + + q = &node->buffer_queue; +@@ -2031,8 +2303,6 @@ static int register_node(struct unicam_d + + INIT_LIST_HEAD(&node->dma_queue.active); + +- vdev = &node->video_dev; +- strlcpy(vdev->name, UNICAM_MODULE_NAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &unicam_fops; + vdev->ioctl_ops = &unicam_ioctl_ops; +@@ -2040,24 +2310,28 @@ static int register_node(struct unicam_d + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &node->lock; +- vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | +- V4L2_CAP_READWRITE; +- /* If the source has no controls then remove our ctrl handler. */ +- if (list_empty(&node->ctrl_handler.ctrls)) +- unicam->v4l2_dev.ctrl_handler = NULL; ++ vdev->device_caps = (pad_id == IMAGE_PAD) ? ++ (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING) : ++ (V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING); ++ ++ /* Define the device names */ ++ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME, ++ node->pad_id == IMAGE_PAD ? "image" : "embedded"); + +- node->dev = unicam; + video_set_drvdata(vdev, node); + vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; + +- if (!v4l2_subdev_has_op(unicam->sensor, video, s_std)) { ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD); + } +- if (!v4l2_subdev_has_op(unicam->sensor, video, querystd)) ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, video, querystd)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD); +- if (!v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP); +@@ -2066,15 +2340,19 @@ static int register_node(struct unicam_d + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS); + } +- if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval)) ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); +- if (!v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval)) ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM); +- if (!v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval)) ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM); + +- if (!v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size)) ++ if (node->pad_id == METADATA_PAD || ++ !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); +@@ -2082,27 +2360,29 @@ static int register_node(struct unicam_d + unicam_err(unicam, "Unable to register video device.\n"); + return ret; + } +- node->registered = true; ++ node->registered = 1; + +- ret = media_create_pad_link(&unicam->sensor->entity, +- 0, &node->video_dev.entity, 0, +- MEDIA_LNK_FL_ENABLED | +- MEDIA_LNK_FL_IMMUTABLE); +- if (ret) +- unicam_err(unicam, "Unable to create pad links.\n"); ++ if (unicam->sensor_embedded_data) { ++ ret = media_create_pad_link(&unicam->sensor->entity, pad_id, ++ &node->video_dev.entity, 0, ++ MEDIA_LNK_FL_ENABLED | ++ MEDIA_LNK_FL_IMMUTABLE); ++ if (ret) ++ unicam_err(unicam, "Unable to create pad links.\n"); ++ } + + return ret; + } + + static void unregister_nodes(struct unicam_device *unicam) + { +- if (unicam->node[0].registered) { +- video_unregister_device(&unicam->node[0].video_dev); +- unicam->node[0].registered = false; +- } +- if (unicam->node[1].registered) { +- video_unregister_device(&unicam->node[1].video_dev); +- unicam->node[1].registered = false; ++ if (unicam->node[IMAGE_PAD].registered) { ++ video_unregister_device(&unicam->node[IMAGE_PAD].video_dev); ++ unicam->node[IMAGE_PAD].registered = 0; ++ } ++ if (unicam->node[METADATA_PAD].registered) { ++ video_unregister_device(&unicam->node[METADATA_PAD].video_dev); ++ unicam->node[METADATA_PAD].registered = 0; + } + } + +@@ -2118,20 +2398,20 @@ static int unicam_probe_complete(struct + if (!unicam->sensor_config) + return -ENOMEM; + +- ret = register_node(unicam, &unicam->node[0], +- V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); ++ unicam->sensor_embedded_data = (unicam->sensor->entity.num_pads >= 2); ++ ++ ret = register_node(unicam, &unicam->node[IMAGE_PAD], ++ V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD); + if (ret) { + unicam_err(unicam, "Unable to register subdev node 0.\n"); + goto unregister; + } +- if (unicam->sensor->entity.num_pads >= 2) { +- ret = register_node(unicam, &unicam->node[1], +- V4L2_BUF_TYPE_META_CAPTURE, 1); +- if (ret) { +- unicam_err(unicam, +- "Unable to register subdev node 1.\n"); +- goto unregister; +- } ++ ++ ret = register_node(unicam, &unicam->node[METADATA_PAD], ++ V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD); ++ if (ret) { ++ unicam_err(unicam, "Unable to register subdev node 1.\n"); ++ goto unregister; + } + + ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); +@@ -2355,8 +2635,10 @@ static int unicam_probe(struct platform_ + pdev->dev.driver->name, dev_name(&pdev->dev)); + unicam->mdev.hw_revision = 1; + +- media_entity_pads_init(&unicam->node[0].video_dev.entity, 1, +- &unicam->node[0].pad); ++ media_entity_pads_init(&unicam->node[IMAGE_PAD].video_dev.entity, 1, ++ &unicam->node[IMAGE_PAD].pad); ++ media_entity_pads_init(&unicam->node[METADATA_PAD].video_dev.entity, 1, ++ &unicam->node[METADATA_PAD].pad); + media_device_init(&unicam->mdev); + + unicam->v4l2_dev.mdev = &unicam->mdev; +@@ -2376,11 +2658,10 @@ static int unicam_probe(struct platform_ + } + + /* Reserve space for the controls */ +- hdl = &unicam->node[0].ctrl_handler; ++ hdl = &unicam->node[IMAGE_PAD].ctrl_handler; + ret = v4l2_ctrl_handler_init(hdl, 16); + if (ret < 0) + goto media_unregister; +- unicam->v4l2_dev.ctrl_handler = hdl; + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, unicam); +@@ -2417,7 +2698,7 @@ static int unicam_remove(struct platform + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&unicam->notifier); +- v4l2_ctrl_handler_free(&unicam->node[0].ctrl_handler); ++ v4l2_ctrl_handler_free(&unicam->node[IMAGE_PAD].ctrl_handler); + v4l2_device_unregister(&unicam->v4l2_dev); + unregister_nodes(unicam); + if (unicam->sensor_config) diff --git a/target/linux/bcm27xx/patches-5.4/950-0654-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch b/target/linux/bcm27xx/patches-5.4/950-0654-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch new file mode 100644 index 00000000000..836ced8a044 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0654-media-bcm2835-unicam-Use-dummy-buffer-if-none-have-b.patch @@ -0,0 +1,308 @@ +From 0eb6753788616ffed17a0484a14fd7d3df2a2a05 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 2 Apr 2020 16:08:51 +0100 +Subject: [PATCH] media: bcm2835-unicam: Use dummy buffer if none have + been queued + +If no buffer has been queued by a userland application, we use an +internal dummy buffer for the hardware to spin in. This will allow +the driver to release the existing userland buffer back to the +application for processing. + +Signed-off-by: Naushir Patuck +--- + .../media/platform/bcm2835/bcm2835-unicam.c | 160 ++++++++++++------ + 1 file changed, 110 insertions(+), 50 deletions(-) + +--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c ++++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -112,6 +113,12 @@ MODULE_PARM_DESC(debug, "Debug level 0-3 + /* Default size of the embedded buffer */ + #define UNICAM_EMBEDDED_SIZE 8192 + ++/* ++ * Size of the dummy buffer. Can be any size really, but the DMA ++ * allocation works in units of page sizes. ++ */ ++#define DUMMY_BUF_SIZE (PAGE_SIZE) ++ + enum pad_types { + IMAGE_PAD, + METADATA_PAD, +@@ -390,6 +397,12 @@ struct unicam_node { + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + unsigned int embedded_lines; ++ /* ++ * Dummy buffer intended to be used by unicam ++ * if we have no other queued buffers to swap to. ++ */ ++ void *dummy_buf_cpu_addr; ++ dma_addr_t dummy_buf_dma_addr; + }; + + struct unicam_device { +@@ -661,27 +674,24 @@ static int unicam_reset_format(struct un + return 0; + } + +-static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr, +- int pad_id) ++static void unicam_wr_dma_addr(struct unicam_cfg *cfg, dma_addr_t dmaaddr, ++ unsigned int buffer_size, int pad_id) + { +- dma_addr_t endaddr; ++ dma_addr_t endaddr = dmaaddr + buffer_size; + + /* +- * dmaaddr should be a 32-bit address with the top two bits set to 0x3 +- * to signify uncached access through the Videocore memory controller. ++ * dmaaddr and endaddr should be a 32-bit address with the top two bits ++ * set to 0x3 to signify uncached access through the Videocore memory ++ * controller. + */ +- BUG_ON((dmaaddr >> 30) != 0x3); ++ BUG_ON((dmaaddr >> 30) != 0x3 && (endaddr >> 30) != 0x3); + + if (pad_id == IMAGE_PAD) { +- endaddr = dmaaddr + +- dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage; +- reg_write(&dev->cfg, UNICAM_IBSA0, dmaaddr); +- reg_write(&dev->cfg, UNICAM_IBEA0, endaddr); ++ reg_write(cfg, UNICAM_IBSA0, dmaaddr); ++ reg_write(cfg, UNICAM_IBEA0, endaddr); + } else { +- endaddr = dmaaddr + +- dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; +- reg_write(&dev->cfg, UNICAM_DBSA0, dmaaddr); +- reg_write(&dev->cfg, UNICAM_DBEA0, endaddr); ++ reg_write(cfg, UNICAM_DBSA0, dmaaddr); ++ reg_write(cfg, UNICAM_DBEA0, endaddr); + } + } + +@@ -704,6 +714,7 @@ static inline void unicam_schedule_next_ + struct unicam_device *dev = node->dev; + struct unicam_dmaqueue *dma_q = &node->dma_queue; + struct unicam_buffer *buf; ++ unsigned int size; + dma_addr_t addr; + + buf = list_entry(dma_q->active.next, struct unicam_buffer, list); +@@ -711,7 +722,23 @@ static inline void unicam_schedule_next_ + list_del(&buf->list); + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +- unicam_wr_dma_addr(dev, addr, node->pad_id); ++ size = (node->pad_id == IMAGE_PAD) ? ++ dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage : ++ dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; ++ ++ unicam_wr_dma_addr(&dev->cfg, addr, size, node->pad_id); ++} ++ ++static inline void unicam_schedule_dummy_buffer(struct unicam_node *node) ++{ ++ struct unicam_device *dev = node->dev; ++ dma_addr_t addr = node->dummy_buf_dma_addr; ++ ++ unicam_dbg(3, dev, "Scheduling dummy buffer for node %d\n", ++ node->pad_id); ++ ++ unicam_wr_dma_addr(&dev->cfg, addr, DUMMY_BUF_SIZE, node->pad_id); ++ node->next_frm = NULL; + } + + static inline void unicam_process_buffer_complete(struct unicam_node *node, +@@ -721,7 +748,6 @@ static inline void unicam_process_buffer + node->cur_frm->vb.sequence = sequence; + + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); +- node->cur_frm = node->next_frm; + } + + static int unicam_num_nodes_streaming(struct unicam_device *dev) +@@ -788,6 +814,28 @@ static irqreturn_t unicam_isr(int irq, v + if (!(sta && (UNICAM_IS | UNICAM_PI0))) + return IRQ_HANDLED; + ++ /* ++ * We must run the frame end handler first. If we have a valid next_frm ++ * and we get a simultaneout FE + FS interrupt, running the FS handler ++ * first would null out the next_frm ptr and we would have lost the ++ * buffer forever. ++ */ ++ if (ista & UNICAM_FEI || sta & UNICAM_PI0) { ++ /* ++ * Ensure we have swapped buffers already as we can't ++ * stop the peripheral. If no buffer is available, use a ++ * dummy buffer to dump out frames until we get a new buffer ++ * to use. ++ */ ++ for (i = 0; i < num_nodes_streaming; i++) { ++ if (unicam->node[i].cur_frm) ++ unicam_process_buffer_complete(&unicam->node[i], ++ sequence); ++ unicam->node[i].cur_frm = unicam->node[i].next_frm; ++ } ++ unicam->sequence++; ++ } ++ + if (ista & UNICAM_FSI) { + /* + * Timestamp is to be when the first data byte was captured, +@@ -798,24 +846,16 @@ static irqreturn_t unicam_isr(int irq, v + if (unicam->node[i].cur_frm) + unicam->node[i].cur_frm->vb.vb2_buf.timestamp = + ts; ++ /* ++ * Set the next frame output to go to a dummy frame ++ * if we have not managed to obtain another frame ++ * from the queue. ++ */ ++ unicam_schedule_dummy_buffer(&unicam->node[i]); + } + } +- if (ista & UNICAM_FEI || sta & UNICAM_PI0) { +- /* +- * Ensure we have swapped buffers already as we can't +- * stop the peripheral. Overwrite the frame we've just +- * captured instead. +- */ +- for (i = 0; i < num_nodes_streaming; i++) { +- if (unicam->node[i].cur_frm && +- unicam->node[i].cur_frm != unicam->node[i].next_frm) +- unicam_process_buffer_complete(&unicam->node[i], +- sequence); +- } +- unicam->sequence++; +- } +- +- /* Cannot swap buffer at frame end, there may be a race condition ++ /* ++ * Cannot swap buffer at frame end, there may be a race condition + * where the HW does not actually swap it if the new frame has + * already started. + */ +@@ -823,7 +863,7 @@ static irqreturn_t unicam_isr(int irq, v + for (i = 0; i < num_nodes_streaming; i++) { + spin_lock(&unicam->node[i].dma_queue_lock); + if (!list_empty(&unicam->node[i].dma_queue.active) && +- unicam->node[i].cur_frm == unicam->node[i].next_frm) ++ !unicam->node[i].next_frm) + unicam_schedule_next_buffer(&unicam->node[i]); + spin_unlock(&unicam->node[i].dma_queue_lock); + } +@@ -1352,7 +1392,7 @@ static void unicam_start_rx(struct unica + { + struct unicam_cfg *cfg = &dev->cfg; + int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2; +- unsigned int i; ++ unsigned int size, i; + u32 val; + + if (line_int_freq < 128) +@@ -1413,7 +1453,7 @@ static void unicam_start_rx(struct unica + reg_write_field(cfg, UNICAM_ANA, 0, UNICAM_DDL); + + /* Always start in trigger frame capture mode (UNICAM_FCM set) */ +- val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM; ++ val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB; + set_field(&val, line_int_freq, UNICAM_LCIE_MASK); + reg_write(cfg, UNICAM_ICTL, val); + reg_write(cfg, UNICAM_STA, UNICAM_STA_MASK_ALL); +@@ -1501,7 +1541,8 @@ static void unicam_start_rx(struct unica + + reg_write(&dev->cfg, UNICAM_IBLS, + dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline); +- unicam_wr_dma_addr(dev, addr[IMAGE_PAD], IMAGE_PAD); ++ size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage; ++ unicam_wr_dma_addr(&dev->cfg, addr[IMAGE_PAD], size, IMAGE_PAD); + unicam_set_packing_config(dev); + unicam_cfg_image_id(dev); + +@@ -1511,8 +1552,10 @@ static void unicam_start_rx(struct unica + reg_write(cfg, UNICAM_MISC, val); + + if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) { ++ size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; + unicam_enable_ed(dev); +- unicam_wr_dma_addr(dev, addr[METADATA_PAD], METADATA_PAD); ++ unicam_wr_dma_addr(&dev->cfg, addr[METADATA_PAD], size, ++ METADATA_PAD); + } + + /* Enable peripheral */ +@@ -1686,13 +1729,14 @@ static void unicam_stop_streaming(struct + unicam_runtime_put(dev); + + } else if (node->pad_id == METADATA_PAD) { +- /* Null out the embedded data buffer address so the HW does +- * not use it. This is only really needed if the embedded data +- * pad is disabled before the image pad. The 0x3 in the top two +- * bits signifies uncached accesses through the Videocore +- * memory controller. ++ /* Allow the hardware to spin in the dummy buffer. ++ * This is only really needed if the embedded data pad is ++ * disabled before the image pad. The 0x3 in the top two bits ++ * signifies uncached accesses through the Videocore memory ++ * controller. + */ +- unicam_wr_dma_addr(dev, 0xc0000000, METADATA_PAD); ++ unicam_wr_dma_addr(&dev->cfg, node->dummy_buf_dma_addr, ++ DUMMY_BUF_SIZE, METADATA_PAD); + } + + /* Clear all queued buffers for the node */ +@@ -2321,6 +2365,15 @@ static int register_node(struct unicam_d + video_set_drvdata(vdev, node); + vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; + ++ node->dummy_buf_cpu_addr = dma_alloc_coherent(&unicam->pdev->dev, ++ DUMMY_BUF_SIZE, ++ &node->dummy_buf_dma_addr, ++ GFP_ATOMIC); ++ if (!node->dummy_buf_cpu_addr) { ++ unicam_err(unicam, "Unable to allocate dummy buffer.\n"); ++ return -ENOMEM; ++ } ++ + if (node->pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); +@@ -2376,13 +2429,20 @@ static int register_node(struct unicam_d + + static void unregister_nodes(struct unicam_device *unicam) + { +- if (unicam->node[IMAGE_PAD].registered) { +- video_unregister_device(&unicam->node[IMAGE_PAD].video_dev); +- unicam->node[IMAGE_PAD].registered = 0; +- } +- if (unicam->node[METADATA_PAD].registered) { +- video_unregister_device(&unicam->node[METADATA_PAD].video_dev); +- unicam->node[METADATA_PAD].registered = 0; ++ struct unicam_node *node; ++ int i; ++ ++ for (i = 0; i < MAX_NODES; i++) { ++ node = &unicam->node[i]; ++ if (node->dummy_buf_cpu_addr) { ++ dma_free_coherent(&unicam->pdev->dev, DUMMY_BUF_SIZE, ++ node->dummy_buf_cpu_addr, ++ node->dummy_buf_dma_addr); ++ } ++ if (node->registered) { ++ video_unregister_device(&node->video_dev); ++ node->registered = 0; ++ } + } + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0655-spi-Force-CS_HIGH-if-GPIO-descriptors-are-used.patch b/target/linux/bcm27xx/patches-5.4/950-0655-spi-Force-CS_HIGH-if-GPIO-descriptors-are-used.patch new file mode 100644 index 00000000000..43d10486def --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0655-spi-Force-CS_HIGH-if-GPIO-descriptors-are-used.patch @@ -0,0 +1,48 @@ +From 5f2eface651ba5da9caaa84ccca14b9202ba6202 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 17 Apr 2020 10:46:19 +0100 +Subject: [PATCH] spi: Force CS_HIGH if GPIO descriptors are used + +Commit f3186dd87669 ("spi: Optionally use GPIO descriptors for CS GPIOs") +amended of_spi_parse_dt() to always set SPI_CS_HIGH for SPI slaves whose +Chip Select is defined by a "cs-gpios" devicetree property. + +This change breaks drivers whose probe functions set the mode field of +the spi_device because in doing so they clear the SPI_CS_HIGH flag. + +Fix by setting SPI_CS_HIGH in spi_setup (under the same conditions as +in of_spi_parse_dt()). + +See also: 83b2a8fe43bd ("spi: spidev: Fix CS polarity if GPIO descriptors are used") + +Fixes: f3186dd87669 ("spi: Optionally use GPIO descriptors for CS GPIOs") +Signed-off-by: Phil Elwell +--- + drivers/spi/spi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -3032,6 +3032,7 @@ static int __spi_validate_bits_per_word( + */ + int spi_setup(struct spi_device *spi) + { ++ struct spi_controller *ctlr = spi->controller; + unsigned bad_bits, ugly_bits; + int status; + +@@ -3049,6 +3050,14 @@ int spi_setup(struct spi_device *spi) + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | + SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) + return -EINVAL; ++ ++ if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && ++ ctlr->cs_gpiods[spi->chip_select] && !(spi->mode & SPI_CS_HIGH)) { ++ dev_warn(&spi->dev, ++ "setup: forcing CS_HIGH (use_gpio_descriptors)\n"); ++ spi->mode |= SPI_CS_HIGH; ++ } ++ + /* help drivers fail *cleanly* when they need options + * that aren't supported with their current controller + * SPI_CS_WORD has a fallback software implementation, diff --git a/target/linux/bcm27xx/patches-5.4/950-0656-media-i2c-imx219-Fix-power-sequence.patch b/target/linux/bcm27xx/patches-5.4/950-0656-media-i2c-imx219-Fix-power-sequence.patch new file mode 100644 index 00000000000..b85d9178785 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0656-media-i2c-imx219-Fix-power-sequence.patch @@ -0,0 +1,55 @@ +From 0fec1c81707f5335d0b04b5e97d2ddd0b902377b Mon Sep 17 00:00:00 2001 +From: Lad Prabhakar +Date: Tue, 10 Mar 2020 14:17:07 +0100 +Subject: [PATCH] media: i2c: imx219: Fix power sequence + +Commit ca45448a56659c6df6e0436188e97f6cc65dea8a upstream. + +When supporting Rpi Camera v2 Module on the RZ/G2E, found the driver had +some issues with rcar mipi-csi driver. The sensor never entered into LP-11 +state. + +The powerup sequence in the datasheet[1] shows the sensor entering into +LP-11 in streaming mode, so to fix this issue transitions are performed +from "streaming -> standby" in the probe() after power up. + +With this commit the sensor is able to enter LP-11 mode during power up, +as expected by some CSI-2 controllers. + +[1] https://publiclab.org/system/images/photos/000/023/294/original/ +RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF + +Signed-off-by: Lad Prabhakar +Acked-by: Dave Stevenson +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/imx219.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -1224,6 +1224,23 @@ static int imx219_probe(struct i2c_clien + /* Set default mode to max resolution */ + imx219->mode = &supported_modes[0]; + ++ /* sensor doesn't enter LP-11 state upon power up until and unless ++ * streaming is started, so upon power up switch the modes to: ++ * streaming -> standby ++ */ ++ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, ++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); ++ if (ret < 0) ++ goto error_power_off; ++ usleep_range(100, 110); ++ ++ /* put sensor back to standby mode */ ++ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, ++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); ++ if (ret < 0) ++ goto error_power_off; ++ usleep_range(100, 110); ++ + ret = imx219_init_controls(imx219); + if (ret) + goto error_power_off; diff --git a/target/linux/bcm27xx/patches-5.4/950-0657-media-i2c-imx219-Add-support-for-RAW8-bit-bayer-form.patch b/target/linux/bcm27xx/patches-5.4/950-0657-media-i2c-imx219-Add-support-for-RAW8-bit-bayer-form.patch new file mode 100644 index 00000000000..552516bd67d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0657-media-i2c-imx219-Add-support-for-RAW8-bit-bayer-form.patch @@ -0,0 +1,319 @@ +From 1f00b84d993e1f8de17ef936e00f4264266cb5d1 Mon Sep 17 00:00:00 2001 +From: Lad Prabhakar +Date: Tue, 10 Mar 2020 14:17:08 +0100 +Subject: [PATCH] media: i2c: imx219: Add support for RAW8 bit bayer + format + +Commit 22da1d56e982151e0bdfafe9de6fe94098a51356 upstream. + +IMX219 sensor is capable for RAW8/RAW10 modes. This commit adds support +for RAW8 bayer format. + +Signed-off-by: Lad Prabhakar +Signed-off-by: Dave Stevenson +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/imx219.c | 148 +++++++++++++++++++++++++++++-------- + 1 file changed, 116 insertions(+), 32 deletions(-) + +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -168,15 +168,12 @@ static const struct imx219_reg mode_3280 + {0x0171, 0x01}, + {0x0174, 0x00}, + {0x0175, 0x00}, +- {0x018c, 0x0a}, +- {0x018d, 0x0a}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0304, 0x03}, + {0x0305, 0x03}, + {0x0306, 0x00}, + {0x0307, 0x39}, +- {0x0309, 0x0a}, + {0x030b, 0x01}, + {0x030c, 0x00}, + {0x030d, 0x72}, +@@ -230,15 +227,12 @@ static const struct imx219_reg mode_1920 + {0x0171, 0x01}, + {0x0174, 0x00}, + {0x0175, 0x00}, +- {0x018c, 0x0a}, +- {0x018d, 0x0a}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0304, 0x03}, + {0x0305, 0x03}, + {0x0306, 0x00}, + {0x0307, 0x39}, +- {0x0309, 0x0a}, + {0x030b, 0x01}, + {0x030c, 0x00}, + {0x030d, 0x72}, +@@ -290,15 +284,12 @@ static const struct imx219_reg mode_1640 + {0x0171, 0x01}, + {0x0174, 0x01}, + {0x0175, 0x01}, +- {0x018c, 0x0a}, +- {0x018d, 0x0a}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0304, 0x03}, + {0x0305, 0x03}, + {0x0306, 0x00}, + {0x0307, 0x39}, +- {0x0309, 0x0a}, + {0x030b, 0x01}, + {0x030c, 0x00}, + {0x030d, 0x72}, +@@ -322,6 +313,18 @@ static const struct imx219_reg mode_1640 + {0x0163, 0x78}, + }; + ++static const struct imx219_reg raw8_framefmt_regs[] = { ++ {0x018c, 0x08}, ++ {0x018d, 0x08}, ++ {0x0309, 0x08}, ++}; ++ ++static const struct imx219_reg raw10_framefmt_regs[] = { ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0309, 0x0a}, ++}; ++ + static const char * const imx219_test_pattern_menu[] = { + "Disabled", + "Color Bars", +@@ -349,6 +352,27 @@ static const char * const imx219_supply_ + #define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name) + + /* ++ * The supported formats. ++ * This table MUST contain 4 entries per format, to cover the various flip ++ * combinations in the order ++ * - no flip ++ * - h flip ++ * - v flip ++ * - h&v flips ++ */ ++static const u32 codes[] = { ++ MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, ++ MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SBGGR10_1X10, ++ ++ MEDIA_BUS_FMT_SRGGB8_1X8, ++ MEDIA_BUS_FMT_SGRBG8_1X8, ++ MEDIA_BUS_FMT_SGBRG8_1X8, ++ MEDIA_BUS_FMT_SBGGR8_1X8, ++}; ++ ++/* + * Initialisation delay between XCLR low->high and the moment when the sensor + * can start capture (i.e. can leave software stanby) must be not less than: + * t4 + max(t5, t6 +