# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FREEZER=y
-# CONFIG_FSL_QDMA is not set
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
CONFIG_MEMFD_CREATE=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
# CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
CONFIG_MFD_SYSCON=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGRATION=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
-# CONFIG_ARCH_MILBEAUT is not set
CONFIG_ARCH_MULTIPLATFORM=y
CONFIG_ARCH_MULTI_V6_V7=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
-# CONFIG_ARCH_RDA is not set
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
# CONFIG_ARM_BCM2835_CPUFREQ is not set
CONFIG_ARM_CPU_SUSPEND=y
-# CONFIG_ARM_ERRATA_814220 is not set
-# CONFIG_ARM_ERRATA_857271 is not set
-# CONFIG_ARM_ERRATA_857272 is not set
CONFIG_ARM_GIC=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FREEZER=y
-# CONFIG_FSL_QDMA is not set
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_GPIO_BCM_VIRT=y
CONFIG_GPIO_RASPBERRYPI_EXP=y
CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_MEMFD_CREATE=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
# CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
CONFIG_MFD_SYSCON=y
CONFIG_MICROCHIP_PHY=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_BRCMSTB=y
-# CONFIG_PCIE_BW is not set
CONFIG_PCIE_PME=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
-# CONFIG_TRUSTED_FOUNDATIONS is not set
CONFIG_UEVENT_HELPER_PATH=""
# CONFIG_UID16 is not set
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_PM=y
CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BOUNCE=y
CONFIG_BRCMSTB_THERMAL=y
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_CAVIUM_ERRATUM_22375=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EFI_EARLYCON=y
CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FRAME_POINTER=y
CONFIG_FREEZER=y
CONFIG_FSL_ERRATUM_A008585=y
-# CONFIG_FSL_QDMA is not set
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_GPIO_BCM_VIRT=y
CONFIG_GPIO_RASPBERRYPI_EXP=y
CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
# CONFIG_MEMORY_HOTPLUG is not set
CONFIG_MEMORY_ISOLATION=y
CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
# CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
CONFIG_MFD_SYSCON=y
CONFIG_MICROCHIP_PHY=y
CONFIG_MIGRATION=y
CONFIG_NR_CPUS=4
# CONFIG_NUMA is not set
CONFIG_NVMEM=y
-# CONFIG_NVMEM_REBOOT_MODE is not set
# CONFIG_OCTEONTX2_AF is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
# CONFIG_PCIE_BRCMSTB is not set
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PGTABLE_LEVELS=3
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_PM=y
CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BOUNCE=y
CONFIG_BRCMSTB_THERMAL=y
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BROADCOM_PHY=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EFI_EARLYCON=y
CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_ENERGY_MODEL is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FRAME_POINTER=y
CONFIG_FREEZER=y
CONFIG_FSL_ERRATUM_A008585=y
-# CONFIG_FSL_QDMA is not set
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_GPIO_BCM_VIRT=y
CONFIG_GPIO_RASPBERRYPI_EXP=y
CONFIG_GPIO_SYSFS=y
-# CONFIG_GVE is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
# CONFIG_MEMORY_HOTPLUG is not set
CONFIG_MEMORY_ISOLATION=y
CONFIG_MFD_CORE=y
-# CONFIG_MFD_LOCHNAGAR is not set
-# CONFIG_MFD_ROHM_BD70528 is not set
# CONFIG_MFD_RPISENSE_CORE is not set
-# CONFIG_MFD_STPMIC1 is not set
CONFIG_MFD_SYSCON=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_NR_CPUS=4
# CONFIG_NUMA is not set
CONFIG_NVMEM=y
-# CONFIG_NVMEM_REBOOT_MODE is not set
# CONFIG_OCTEONTX2_AF is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_PCIEPORTBUS=y
# CONFIG_PCIE_AL is not set
CONFIG_PCIE_BRCMSTB=y
-# CONFIG_PCIE_BW is not set
CONFIG_PCIE_PME=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PGTABLE_LEVELS=3
+++ /dev/null
-From 79624ca23c53064fefee774a89952a587b72cc01 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
- driver
-
-This commit adds the basic Broadcom STB PCIe controller. Missing is
-the ability to process MSI and also handle dma-ranges for inbound
-memory accesses. These two functionalities are added in subsequent
-commits.
-
-The PCIe block contains an MDIO interface. This is a local interface
-only accessible by the PCIe controller. It cannot be used or shared
-by any other HW. As such, the small amount of code for this
-controller is included in this driver as there is little upside to put
-it elsewhere.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/Kconfig | 9 +
- drivers/pci/controller/Makefile | 2 +-
- drivers/pci/controller/pcie-brcmstb.c | 1097 +++++++++++++++++++++++++
- include/soc/brcmstb/memory_api.h | 25 +
- 4 files changed, 1132 insertions(+), 1 deletion(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb.c
- create mode 100644 include/soc/brcmstb/memory_api.h
-
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -288,5 +288,14 @@ config PCI_HYPERV_INTERFACE
- The Hyper-V PCI Interface is a helper driver allows other drivers to
- have a common interface with the Hyper-V PCI frontend driver.
-
-+config PCIE_BRCMSTB
-+ tristate "Broadcom Brcmstb PCIe platform host driver"
-+ depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+ depends on OF
-+ depends on SOC_BRCMSTB
-+ default ARCH_BRCMSTB || BMIPS_GENERIC
-+ help
-+ Adds support for Broadcom Settop Box PCIe host controller.
-+
- source "drivers/pci/controller/dwc/Kconfig"
- endmenu
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -29,11 +29,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie
- obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y += dwc/
-
--
- # The following drivers are for devices that use the generic ACPI
- # pci_root.c driver but don't support standard ECAM config access.
- # They contain MCFG quirks to replace the generic ECAM accessors with
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -0,0 +1,1097 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright (C) 2009 - 2017 Broadcom */
-+
-+#include <linux/clk.h>
-+#include <linux/compiler.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/irqdomain.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/log2.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
-+#include <linux/pci.h>
-+#include <linux/printk.h>
-+#include <linux/sizes.h>
-+#include <linux/slab.h>
-+#include <soc/brcmstb/memory_api.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include "../pci.h"
-+
-+/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
-+#define BRCM_PCIE_CAP_REGS 0x00ac
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Offsets. The names are from
-+ * the chip's RDB and we use them here so that a script can correlate
-+ * this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
-+#define PCIE_RC_DL_MDIO_ADDR 0x1100
-+#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
-+#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
-+#define PCIE_MISC_MISC_CTRL 0x4008
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
-+#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
-+#define PCIE_MISC_PCIE_CTRL 0x4064
-+#define PCIE_MISC_PCIE_STATUS 0x4068
-+#define PCIE_MISC_REVISION 0x406c
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
-+#define PCIE_INTR2_CPU_BASE 0x4300
-+
-+/*
-+ * Broadcom Settop Box PCIe Register Field shift and mask info. The
-+ * names are from the chip's RDB and we use them here so that a script
-+ * can correlate this code and the RDB to prevent discrepancies.
-+ */
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
-+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT 0x2
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
-+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_SHIFT 0x0
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
-+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_SHIFT 0xc
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
-+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_SHIFT 0xd
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
-+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_SHIFT 0x14
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
-+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_SHIFT 0x1b
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x7c00000
-+#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_SHIFT 0x16
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x1f
-+#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
-+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_SHIFT 0x0
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
-+#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_SHIFT 0x2
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
-+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_SHIFT 0x0
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_SHIFT 0x7
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
-+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_SHIFT 0x5
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
-+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_SHIFT 0x4
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
-+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_SHIFT 0x6
-+#define PCIE_MISC_REVISION_MAJMIN_MASK 0xffff
-+#define PCIE_MISC_REVISION_MAJMIN_SHIFT 0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_SHIFT 0x14
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_SHIFT 0x4
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS 0xc
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_SHIFT 0x0
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
-+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_SHIFT 0x0
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_SHIFT 0x1
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
-+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_SHIFT 0x1b
-+#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
-+#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
-+
-+#define BRCM_NUM_PCIE_OUT_WINS 0x4
-+#define BRCM_MAX_SCB 0x4
-+
-+#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
-+#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
-+
-+#define BURST_SIZE_128 0
-+#define BURST_SIZE_256 1
-+#define BURST_SIZE_512 2
-+
-+/* Offsets from PCIE_INTR2_CPU_BASE */
-+#define STATUS 0x0
-+#define SET 0x4
-+#define CLR 0x8
-+#define MASK_STATUS 0xc
-+#define MASK_SET 0x10
-+#define MASK_CLR 0x14
-+
-+#define PCIE_BUSNUM_SHIFT 20
-+#define PCIE_SLOT_SHIFT 15
-+#define PCIE_FUNC_SHIFT 12
-+
-+#if defined(__BIG_ENDIAN)
-+#define DATA_ENDIAN 2 /* PCIe->DDR inbound traffic */
-+#define MMIO_ENDIAN 2 /* CPU->PCIe outbound traffic */
-+#else
-+#define DATA_ENDIAN 0
-+#define MMIO_ENDIAN 0
-+#endif
-+
-+#define MDIO_PORT0 0x0
-+#define MDIO_DATA_MASK 0x7fffffff
-+#define MDIO_DATA_SHIFT 0x0
-+#define MDIO_PORT_MASK 0xf0000
-+#define MDIO_PORT_SHIFT 0x16
-+#define MDIO_REGAD_MASK 0xffff
-+#define MDIO_REGAD_SHIFT 0x0
-+#define MDIO_CMD_MASK 0xfff00000
-+#define MDIO_CMD_SHIFT 0x14
-+#define MDIO_CMD_READ 0x1
-+#define MDIO_CMD_WRITE 0x0
-+#define MDIO_DATA_DONE_MASK 0x80000000
-+#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
-+#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
-+#define SSC_REGS_ADDR 0x1100
-+#define SET_ADDR_OFFSET 0x1f
-+#define SSC_CNTL_OFFSET 0x2
-+#define SSC_CNTL_OVRD_EN_MASK 0x8000
-+#define SSC_CNTL_OVRD_EN_SHIFT 0xf
-+#define SSC_CNTL_OVRD_VAL_MASK 0x4000
-+#define SSC_CNTL_OVRD_VAL_SHIFT 0xe
-+#define SSC_STATUS_OFFSET 0x1
-+#define SSC_STATUS_SSC_MASK 0x400
-+#define SSC_STATUS_SSC_SHIFT 0xa
-+#define SSC_STATUS_PLL_LOCK_MASK 0x800
-+#define SSC_STATUS_PLL_LOCK_SHIFT 0xb
-+
-+#define IDX_ADDR(pcie) \
-+ ((pcie)->reg_offsets[EXT_CFG_INDEX])
-+#define DATA_ADDR(pcie) \
-+ ((pcie)->reg_offsets[EXT_CFG_DATA])
-+#define PCIE_RGR1_SW_INIT_1(pcie) \
-+ ((pcie)->reg_offsets[RGR1_SW_INIT_1])
-+
-+enum {
-+ RGR1_SW_INIT_1,
-+ EXT_CFG_INDEX,
-+ EXT_CFG_DATA,
-+};
-+
-+enum {
-+ RGR1_SW_INIT_1_INIT_MASK,
-+ RGR1_SW_INIT_1_INIT_SHIFT,
-+ RGR1_SW_INIT_1_PERST_MASK,
-+ RGR1_SW_INIT_1_PERST_SHIFT,
-+};
-+
-+enum pcie_type {
-+ BCM7425,
-+ BCM7435,
-+ GENERIC,
-+ BCM7278,
-+};
-+
-+struct brcm_window {
-+ dma_addr_t pcie_addr;
-+ phys_addr_t cpu_addr;
-+ dma_addr_t size;
-+};
-+
-+/* Internal PCIe Host Controller Information.*/
-+struct brcm_pcie {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct list_head resources;
-+ int irq;
-+ struct clk *clk;
-+ struct pci_bus *root_bus;
-+ struct device_node *dn;
-+ int id;
-+ bool suspended;
-+ int num_out_wins;
-+ bool ssc;
-+ int gen;
-+ struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+ unsigned int rev;
-+ const int *reg_offsets;
-+ const int *reg_field_info;
-+ enum pcie_type type;
-+};
-+
-+struct pcie_cfg_data {
-+ const int *reg_field_info;
-+ const int *offsets;
-+ const enum pcie_type type;
-+};
-+
-+static const int pcie_reg_field_info[] = {
-+ [RGR1_SW_INIT_1_INIT_MASK] = 0x2,
-+ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x1,
-+};
-+
-+static const int pcie_reg_field_info_bcm7278[] = {
-+ [RGR1_SW_INIT_1_INIT_MASK] = 0x1,
-+ [RGR1_SW_INIT_1_INIT_SHIFT] = 0x0,
-+};
-+
-+static const int pcie_offset_bcm7425[] = {
-+ [RGR1_SW_INIT_1] = 0x8010,
-+ [EXT_CFG_INDEX] = 0x8300,
-+ [EXT_CFG_DATA] = 0x8304,
-+};
-+
-+static const struct pcie_cfg_data bcm7425_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offset_bcm7425,
-+ .type = BCM7425,
-+};
-+
-+static const int pcie_offsets[] = {
-+ [RGR1_SW_INIT_1] = 0x9210,
-+ [EXT_CFG_INDEX] = 0x9000,
-+ [EXT_CFG_DATA] = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7435_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .type = BCM7435,
-+};
-+
-+static const struct pcie_cfg_data generic_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .type = GENERIC,
-+};
-+
-+static const int pcie_offset_bcm7278[] = {
-+ [RGR1_SW_INIT_1] = 0xc010,
-+ [EXT_CFG_INDEX] = 0x9000,
-+ [EXT_CFG_DATA] = 0x9004,
-+};
-+
-+static const struct pcie_cfg_data bcm7278_cfg = {
-+ .reg_field_info = pcie_reg_field_info_bcm7278,
-+ .offsets = pcie_offset_bcm7278,
-+ .type = BCM7278,
-+};
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+ int where);
-+
-+static struct pci_ops brcm_pcie_ops = {
-+ .map_bus = brcm_pcie_map_conf,
-+ .read = pci_generic_config_read,
-+ .write = pci_generic_config_write,
-+};
-+
-+#if defined(CONFIG_MIPS)
-+/* Broadcom MIPs HW implicitly does the swapping if necessary */
-+#define bcm_readl(a) __raw_readl(a)
-+#define bcm_writel(d, a) __raw_writel(d, a)
-+#define bcm_readw(a) __raw_readw(a)
-+#define bcm_writew(d, a) __raw_writew(d, a)
-+#else
-+#define bcm_readl(a) readl(a)
-+#define bcm_writel(d, a) writel(d, a)
-+#define bcm_readw(a) readw(a)
-+#define bcm_writew(d, a) writew(d, a)
-+#endif
-+
-+/* These macros extract/insert fields to host controller's register set. */
-+#define RD_FLD(base, reg, field) \
-+ rd_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT)
-+#define WR_FLD(base, reg, field, val) \
-+ wr_fld(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_RB(base, reg, field, val) \
-+ wr_fld_rb(base + reg, reg##_##field##_MASK, reg##_##field##_SHIFT, val)
-+#define WR_FLD_WITH_OFFSET(base, off, reg, field, val) \
-+ wr_fld(base + reg + off, reg##_##field##_MASK, \
-+ reg##_##field##_SHIFT, val)
-+#define EXTRACT_FIELD(val, reg, field) \
-+ ((val & reg##_##field##_MASK) >> reg##_##field##_SHIFT)
-+#define INSERT_FIELD(val, reg, field, field_val) \
-+ ((val & ~reg##_##field##_MASK) | \
-+ (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-+
-+static phys_addr_t scb_size[BRCM_MAX_SCB];
-+static int num_memc;
-+static int num_pcie;
-+static DEFINE_MUTEX(brcm_pcie_lock);
-+
-+static u32 rd_fld(void __iomem *p, u32 mask, int shift)
-+{
-+ return (bcm_readl(p) & mask) >> shift;
-+}
-+
-+static void wr_fld(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+ u32 reg = bcm_readl(p);
-+
-+ reg = (reg & ~mask) | ((val << shift) & mask);
-+ bcm_writel(reg, p);
-+}
-+
-+static void wr_fld_rb(void __iomem *p, u32 mask, int shift, u32 val)
-+{
-+ wr_fld(p, mask, shift, val);
-+ (void)bcm_readl(p);
-+}
-+
-+static const char *link_speed_to_str(int s)
-+{
-+ switch (s) {
-+ case 1:
-+ return "2.5";
-+ case 2:
-+ return "5.0";
-+ case 3:
-+ return "8.0";
-+ default:
-+ break;
-+ }
-+ return "???";
-+}
-+
-+/*
-+ * The roundup_pow_of_two() from log2.h invokes
-+ * __roundup_pow_of_two(unsigned long), but we really need a
-+ * such a function to take a native u64 since unsigned long
-+ * is 32 bits on some configurations. So we provide this helper
-+ * function below.
-+ */
-+static u64 roundup_pow_of_two_64(u64 n)
-+{
-+ return 1ULL << fls64(n - 1);
-+}
-+
-+/*
-+ * This is to convert the size of the inbound "BAR" region to the
-+ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
-+ */
-+int encode_ibar_size(u64 size)
-+{
-+ int log2_in = ilog2(size);
-+
-+ if (log2_in >= 12 && log2_in <= 15)
-+ /* Covers 4KB to 32KB (inclusive) */
-+ return (log2_in - 12) + 0x1c;
-+ else if (log2_in >= 16 && log2_in <= 37)
-+ /* Covers 64KB to 32GB, (inclusive) */
-+ return log2_in - 15;
-+ /* Something is awry so disable */
-+ return 0;
-+}
-+
-+static u32 mdio_form_pkt(int port, int regad, int cmd)
-+{
-+ u32 pkt = 0;
-+
-+ pkt |= (port << MDIO_PORT_SHIFT) & MDIO_PORT_MASK;
-+ pkt |= (regad << MDIO_REGAD_SHIFT) & MDIO_REGAD_MASK;
-+ pkt |= (cmd << MDIO_CMD_SHIFT) & MDIO_CMD_MASK;
-+
-+ return pkt;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_read(void __iomem *base, u8 port, u8 regad)
-+{
-+ int tries;
-+ u32 data;
-+
-+ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_READ),
-+ base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
-+ udelay(10);
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_RD_DATA);
-+ }
-+
-+ return MDIO_RD_DONE(data)
-+ ? (data & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT
-+ : -EIO;
-+}
-+
-+/* negative return value indicates error */
-+static int mdio_write(void __iomem *base, u8 port, u8 regad, u16 wrdata)
-+{
-+ int tries;
-+ u32 data;
-+
-+ bcm_writel(mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
-+ base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_readl(base + PCIE_RC_DL_MDIO_ADDR);
-+ bcm_writel(MDIO_DATA_DONE_MASK | wrdata,
-+ base + PCIE_RC_DL_MDIO_WR_DATA);
-+
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
-+ udelay(10);
-+ data = bcm_readl(base + PCIE_RC_DL_MDIO_WR_DATA);
-+ }
-+
-+ return MDIO_WT_DONE(data) ? 0 : -EIO;
-+}
-+
-+/*
-+ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
-+ * return value indicates error.
-+ */
-+static int set_ssc(void __iomem *base)
-+{
-+ int tmp;
-+ u16 wrdata;
-+ int pll, ssc;
-+
-+ tmp = mdio_write(base, MDIO_PORT0, SET_ADDR_OFFSET, SSC_REGS_ADDR);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ tmp = mdio_read(base, MDIO_PORT0, SSC_CNTL_OFFSET);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ wrdata = INSERT_FIELD(tmp, SSC_CNTL_OVRD, EN, 1);
-+ wrdata = INSERT_FIELD(wrdata, SSC_CNTL_OVRD, VAL, 1);
-+ tmp = mdio_write(base, MDIO_PORT0, SSC_CNTL_OFFSET, wrdata);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ usleep_range(1000, 2000);
-+ tmp = mdio_read(base, MDIO_PORT0, SSC_STATUS_OFFSET);
-+ if (tmp < 0)
-+ return tmp;
-+
-+ ssc = EXTRACT_FIELD(tmp, SSC_STATUS, SSC);
-+ pll = EXTRACT_FIELD(tmp, SSC_STATUS, PLL_LOCK);
-+
-+ return (ssc && pll) ? 0 : -EIO;
-+}
-+
-+/* Limits operation to a specific generation (1, 2, or 3) */
-+static void set_gen(void __iomem *base, int gen)
-+{
-+ u32 lnkcap = bcm_readl(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+ u16 lnkctl2 = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+
-+ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
-+ bcm_writel(lnkcap, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
-+
-+ lnkctl2 = (lnkctl2 & ~0xf) | gen;
-+ bcm_writew(lnkctl2, base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
-+}
-+
-+static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
-+ unsigned int win, phys_addr_t cpu_addr,
-+ dma_addr_t pcie_addr, dma_addr_t size)
-+{
-+ void __iomem *base = pcie->base;
-+ phys_addr_t cpu_addr_mb, limit_addr_mb;
-+ u32 tmp;
-+
-+ /* Set the base of the pcie_addr window */
-+ bcm_writel(lower_32_bits(pcie_addr) + MMIO_ENDIAN,
-+ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + (win * 8));
-+ bcm_writel(upper_32_bits(pcie_addr),
-+ base + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + (win * 8));
-+
-+ cpu_addr_mb = cpu_addr >> 20;
-+ limit_addr_mb = (cpu_addr + size - 1) >> 20;
-+
-+ /* Write the addr base low register */
-+ WR_FLD_WITH_OFFSET(base, (win * 4),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+ BASE, cpu_addr_mb);
-+ /* Write the addr limit low register */
-+ WR_FLD_WITH_OFFSET(base, (win * 4),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
-+ LIMIT, limit_addr_mb);
-+
-+ if (pcie->type != BCM7435 && pcie->type != BCM7425) {
-+ /* Write the cpu addr high register */
-+ tmp = (u32)(cpu_addr_mb >>
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+ WR_FLD_WITH_OFFSET(base, (win * 8),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
-+ BASE, tmp);
-+ /* Write the cpu limit high register */
-+ tmp = (u32)(limit_addr_mb >>
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_NUM_MASK_BITS);
-+ WR_FLD_WITH_OFFSET(base, (win * 8),
-+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
-+ LIMIT, tmp);
-+ }
-+}
-+
-+/* Configuration space read/write support */
-+static int cfg_index(int busnr, int devfn, int reg)
-+{
-+ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_SLOT_SHIFT)
-+ | ((PCI_FUNC(devfn) & 0x07) << PCIE_FUNC_SHIFT)
-+ | (busnr << PCIE_BUSNUM_SHIFT)
-+ | (reg & ~3);
-+}
-+
-+/* The controller is capable of serving in both RC and EP roles */
-+static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+
-+ return !!EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PORT);
-+}
-+
-+static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ u32 val = bcm_readl(base + PCIE_MISC_PCIE_STATUS);
-+ u32 dla = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_DL_ACTIVE);
-+ u32 plu = EXTRACT_FIELD(val, PCIE_MISC_PCIE_STATUS, PCIE_PHYLINKUP);
-+
-+ return (dla && plu) ? true : false;
-+}
-+
-+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
-+ int where)
-+{
-+ struct brcm_pcie *pcie = bus->sysdata;
-+ void __iomem *base = pcie->base;
-+ int idx;
-+
-+ /* Accesses to the RC go right to the RC registers if slot==0 */
-+ if (pci_is_root_bus(bus))
-+ return PCI_SLOT(devfn) ? NULL : base + where;
-+
-+ /* For devices, write to the config space index register */
-+ idx = cfg_index(bus->number, devfn, where);
-+ bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
-+ return base + DATA_ADDR(pcie) + (where & 0x3);
-+}
-+
-+static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-+ unsigned int val)
-+{
-+ unsigned int shift = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_SHIFT];
-+ u32 mask = pcie->reg_field_info[RGR1_SW_INIT_1_INIT_MASK];
-+
-+ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie), mask, shift, val);
-+}
-+
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+ unsigned int val)
-+{
-+ if (pcie->type != BCM7278)
-+ wr_fld_rb(pcie->base + PCIE_RGR1_SW_INIT_1(pcie),
-+ PCIE_RGR1_SW_INIT_1_PERST_MASK,
-+ PCIE_RGR1_SW_INIT_1_PERST_SHIFT, val);
-+ else
-+ /* Assert = 0, de-assert = 1 on 7278 */
-+ WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
-+}
-+
-+static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
-+{
-+ int i, ret = 0;
-+
-+ mutex_lock(&brcm_pcie_lock);
-+ if (num_pcie > 0) {
-+ num_pcie++;
-+ goto done;
-+ }
-+
-+ /* Determine num_memc and their sizes */
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+ ret = -EINVAL;
-+ goto done;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ num_memc++;
-+ } else {
-+ break;
-+ }
-+ }
-+ if (!ret && num_memc == 0) {
-+ ret = -EINVAL;
-+ goto done;
-+ }
-+
-+ num_pcie++;
-+done:
-+ mutex_unlock(&brcm_pcie_lock);
-+ return ret;
-+}
-+
-+static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
-+{
-+ mutex_lock(&brcm_pcie_lock);
-+ if (--num_pcie == 0)
-+ num_memc = 0;
-+ mutex_unlock(&brcm_pcie_lock);
-+}
-+
-+static int brcm_pcie_parse_request_of_pci_ranges(struct brcm_pcie *pcie)
-+{
-+ struct resource_entry *win;
-+ int ret;
-+
-+ ret = devm_of_pci_get_host_bridge_resources(pcie->dev, 0, 0xff,
-+ &pcie->resources, NULL);
-+ if (ret) {
-+ dev_err(pcie->dev, "failed to get host resources\n");
-+ return ret;
-+ }
-+
-+ resource_list_for_each_entry(win, &pcie->resources) {
-+ struct resource *parent, *res = win->res;
-+ dma_addr_t offset = (dma_addr_t)win->offset;
-+
-+ if (resource_type(res) == IORESOURCE_IO) {
-+ parent = &ioport_resource;
-+ } else if (resource_type(res) == IORESOURCE_MEM) {
-+ if (pcie->num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
-+ dev_err(pcie->dev, "too many outbound wins\n");
-+ return -EINVAL;
-+ }
-+ pcie->out_wins[pcie->num_out_wins].cpu_addr
-+ = (phys_addr_t)res->start;
-+ pcie->out_wins[pcie->num_out_wins].pcie_addr
-+ = (dma_addr_t)(res->start
-+ - (phys_addr_t)offset);
-+ pcie->out_wins[pcie->num_out_wins].size
-+ = (dma_addr_t)(res->end - res->start + 1);
-+ pcie->num_out_wins++;
-+ parent = &iomem_resource;
-+ } else {
-+ continue;
-+ }
-+
-+ ret = devm_request_resource(pcie->dev, parent, res);
-+ if (ret) {
-+ dev_err(pcie->dev, "failed to get res %pR\n", res);
-+ return ret;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int brcm_pcie_setup(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ unsigned int scb_size_val;
-+ u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
-+ u32 tmp, burst;
-+ int i, j, ret, limit;
-+ u16 nlw, cls, lnksta;
-+ bool ssc_good = false;
-+ struct device *dev = pcie->dev;
-+
-+ /* Reset the bridge */
-+ brcm_pcie_bridge_sw_init_set(pcie, 1);
-+
-+ /*
-+ * Ensure that the fundamental reset is asserted, except for 7278,
-+ * which fails if we do this.
-+ */
-+ if (pcie->type != BCM7278)
-+ brcm_pcie_perst_set(pcie, 1);
-+
-+ usleep_range(100, 200);
-+
-+ /* Take the bridge out of reset */
-+ brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+ /* Wait for SerDes to be stable */
-+ usleep_range(100, 200);
-+
-+ /* Grab the PCIe hw revision number */
-+ tmp = bcm_readl(base + PCIE_MISC_REVISION);
-+ pcie->rev = EXTRACT_FIELD(tmp, PCIE_MISC_REVISION, MAJMIN);
-+
-+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
-+ tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
-+ burst = (pcie->type == GENERIC || pcie->type == BCM7278)
-+ ? BURST_SIZE_512 : BURST_SIZE_256;
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+ bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-+
-+ /*
-+ * Set up inbound memory view for the EP (called RC_BAR2,
-+ * not to be confused with the BARs that are advertised by
-+ * the EP).
-+ */
-+ for (i = 0; i < num_memc; i++)
-+ total_mem_size += scb_size[i];
-+
-+ /*
-+ * The PCIe host controller by design must set the inbound
-+ * viewport to be a contiguous arrangement of all of the
-+ * system's memory. In addition, its size mut be a power of
-+ * two. To further complicate matters, the viewport must
-+ * start on a pcie-address that is aligned on a multiple of its
-+ * size. If a portion of the viewport does not represent
-+ * system memory -- e.g. 3GB of memory requires a 4GB viewport
-+ * -- we can map the outbound memory in or after 3GB and even
-+ * though the viewport will overlap the outbound memory the
-+ * controller will know to send outbound memory downstream and
-+ * everything else upstream.
-+ */
-+ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-+
-+ /*
-+ * Set simple configuration based on memory sizes
-+ * only. We always start the viewport at address 0.
-+ */
-+ rc_bar2_offset = 0;
-+
-+ tmp = lower_32_bits(rc_bar2_offset);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-+ encode_ibar_size(rc_bar2_size));
-+ bcm_writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
-+ bcm_writel(upper_32_bits(rc_bar2_offset),
-+ base + PCIE_MISC_RC_BAR2_CONFIG_HI);
-+
-+ scb_size_val = scb_size[0]
-+ ? ilog2(scb_size[0]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB0_SIZE, scb_size_val);
-+
-+ if (num_memc > 1) {
-+ scb_size_val = scb_size[1]
-+ ? ilog2(scb_size[1]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB1_SIZE, scb_size_val);
-+ }
-+
-+ if (num_memc > 2) {
-+ scb_size_val = scb_size[2]
-+ ? ilog2(scb_size[2]) - 15 : 0xf; /* 0xf is 1GB */
-+ WR_FLD(base, PCIE_MISC_MISC_CTRL, SCB2_SIZE, scb_size_val);
-+ }
-+
-+ /* disable the PCIe->GISB memory window (RC_BAR1) */
-+ WR_FLD(base, PCIE_MISC_RC_BAR1_CONFIG_LO, SIZE, 0);
-+
-+ /* disable the PCIe->SCB memory window (RC_BAR3) */
-+ WR_FLD(base, PCIE_MISC_RC_BAR3_CONFIG_LO, SIZE, 0);
-+
-+ if (!pcie->suspended) {
-+ /* clear any interrupts we find on boot */
-+ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + CLR);
-+ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + CLR);
-+ }
-+
-+ /* Mask all interrupts since we are not handling any yet */
-+ bcm_writel(0xffffffff, base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+ (void)bcm_readl(base + PCIE_INTR2_CPU_BASE + MASK_SET);
-+
-+ if (pcie->gen)
-+ set_gen(base, pcie->gen);
-+
-+ /* Unassert the fundamental reset */
-+ brcm_pcie_perst_set(pcie, 0);
-+
-+ /*
-+ * Give the RC/EP time to wake up, before trying to configure RC.
-+ * Intermittently check status for link-up, up to a total of 100ms
-+ * when we don't know if the device is there, and up to 1000ms if
-+ * we do know the device is there.
-+ */
-+ limit = pcie->suspended ? 1000 : 100;
-+ for (i = 1, j = 0; j < limit && !brcm_pcie_link_up(pcie);
-+ j += i, i = i * 2)
-+ msleep(i + j > limit ? limit - j : i);
-+
-+ if (!brcm_pcie_link_up(pcie)) {
-+ dev_info(dev, "link down\n");
-+ return -ENODEV;
-+ }
-+
-+ if (!brcm_pcie_rc_mode(pcie)) {
-+ dev_err(dev, "PCIe misconfigured; is in EP mode\n");
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < pcie->num_out_wins; i++)
-+ brcm_pcie_set_outbound_win(pcie, i, pcie->out_wins[i].cpu_addr,
-+ pcie->out_wins[i].pcie_addr,
-+ pcie->out_wins[i].size);
-+
-+ /*
-+ * For config space accesses on the RC, show the right class for
-+ * a PCIe-PCIe bridge (the default setting is to be EP mode).
-+ */
-+ WR_FLD_RB(base, PCIE_RC_CFG_PRIV1_ID_VAL3, CLASS_CODE, 0x060400);
-+
-+ if (pcie->ssc) {
-+ ret = set_ssc(base);
-+ if (ret == 0)
-+ ssc_good = true;
-+ else
-+ dev_err(dev, "failed attempt to enter ssc mode\n");
-+ }
-+
-+ lnksta = bcm_readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
-+ cls = lnksta & PCI_EXP_LNKSTA_CLS;
-+ nlw = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
-+ dev_info(dev, "link up, %s Gbps x%u %s\n", link_speed_to_str(cls),
-+ nlw, ssc_good ? "(SSC)" : "(!SSC)");
-+
-+ /* PCIe->SCB endian mode for BAR */
-+ /* field ENDIAN_MODE_BAR2 = DATA_ENDIAN */
-+ WR_FLD_RB(base, PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
-+ ENDIAN_MODE_BAR2, DATA_ENDIAN);
-+
-+ /*
-+ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
-+ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
-+ */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, CLKREQ_DEBUG_ENABLE, 1);
-+
-+ return 0;
-+}
-+
-+/* L23 is a low-power PCIe link state */
-+static void enter_l23(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+ int tries, l23;
-+
-+ /* assert request for L23 */
-+ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 1);
-+ /* poll L23 status */
-+ for (tries = 0, l23 = 0; tries < 1000 && !l23; tries++)
-+ l23 = RD_FLD(base, PCIE_MISC_PCIE_STATUS, PCIE_LINK_IN_L23);
-+ if (!l23)
-+ dev_err(pcie->dev, "failed to enter L23\n");
-+}
-+
-+static void turn_off(struct brcm_pcie *pcie)
-+{
-+ void __iomem *base = pcie->base;
-+
-+ if (brcm_pcie_link_up(pcie))
-+ enter_l23(pcie);
-+ /* Assert fundamental reset */
-+ brcm_pcie_perst_set(pcie, 1);
-+ /* Deassert request for L23 in case it was asserted */
-+ WR_FLD_RB(base, PCIE_MISC_PCIE_CTRL, PCIE_L23_REQUEST, 0);
-+ /* Turn off SerDes */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 1);
-+ /* Shutdown PCIe bridge */
-+ brcm_pcie_bridge_sw_init_set(pcie, 1);
-+}
-+
-+static int brcm_pcie_suspend(struct device *dev)
-+{
-+ struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+
-+ turn_off(pcie);
-+ clk_disable_unprepare(pcie->clk);
-+ pcie->suspended = true;
-+
-+ return 0;
-+}
-+
-+static int brcm_pcie_resume(struct device *dev)
-+{
-+ struct brcm_pcie *pcie = dev_get_drvdata(dev);
-+ void __iomem *base;
-+ int ret;
-+
-+ base = pcie->base;
-+ clk_prepare_enable(pcie->clk);
-+
-+ /* Take bridge out of reset so we can access the SerDes reg */
-+ brcm_pcie_bridge_sw_init_set(pcie, 0);
-+
-+ /* Turn on SerDes */
-+ WR_FLD_RB(base, PCIE_MISC_HARD_PCIE_HARD_DEBUG, SERDES_IDDQ, 0);
-+ /* Wait for SerDes to be stable */
-+ usleep_range(100, 200);
-+
-+ ret = brcm_pcie_setup(pcie);
-+ if (ret)
-+ return ret;
-+
-+ pcie->suspended = false;
-+
-+ return 0;
-+}
-+
-+static void _brcm_pcie_remove(struct brcm_pcie *pcie)
-+{
-+ turn_off(pcie);
-+ clk_disable_unprepare(pcie->clk);
-+ clk_put(pcie->clk);
-+ brcm_pcie_remove_controller(pcie);
-+}
-+
-+static int brcm_pcie_remove(struct platform_device *pdev)
-+{
-+ struct brcm_pcie *pcie = platform_get_drvdata(pdev);
-+
-+ pci_stop_root_bus(pcie->root_bus);
-+ pci_remove_root_bus(pcie->root_bus);
-+ _brcm_pcie_remove(pcie);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id brcm_pcie_match[] = {
-+ { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
-+ { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
-+ { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
-+ { .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, brcm_pcie_match);
-+
-+static int brcm_pcie_probe(struct platform_device *pdev)
-+{
-+ struct device_node *dn = pdev->dev.of_node;
-+ const struct of_device_id *of_id;
-+ const struct pcie_cfg_data *data;
-+ int ret;
-+ struct brcm_pcie *pcie;
-+ struct resource *res;
-+ void __iomem *base;
-+ u32 tmp;
-+ struct pci_host_bridge *bridge;
-+ struct pci_bus *child;
-+
-+ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-+ if (!bridge)
-+ return -ENOMEM;
-+
-+ pcie = pci_host_bridge_priv(bridge);
-+ INIT_LIST_HEAD(&pcie->resources);
-+
-+ of_id = of_match_node(brcm_pcie_match, dn);
-+ if (!of_id) {
-+ dev_err(&pdev->dev, "failed to look up compatible string\n");
-+ return -EINVAL;
-+ }
-+
-+ if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
-+ dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
-+ return -EINVAL;
-+ }
-+
-+ data = of_id->data;
-+ pcie->reg_offsets = data->offsets;
-+ pcie->reg_field_info = data->reg_field_info;
-+ pcie->type = data->type;
-+ pcie->dn = dn;
-+ pcie->dev = &pdev->dev;
-+
-+ /* We use the domain number as our controller number */
-+ pcie->id = of_get_pci_domain_nr(dn);
-+ if (pcie->id < 0)
-+ return pcie->id;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res)
-+ return -EINVAL;
-+
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
-+ if (IS_ERR(pcie->clk)) {
-+ dev_err(&pdev->dev, "could not get clock\n");
-+ pcie->clk = NULL;
-+ }
-+ pcie->base = base;
-+
-+ ret = of_pci_get_max_link_speed(dn);
-+ pcie->gen = (ret < 0) ? 0 : ret;
-+
-+ pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
-+
-+ ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
-+ if (ret == 0)
-+ /* keep going, as we don't use this intr yet */
-+ dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
-+ else
-+ pcie->irq = ret;
-+
-+ ret = brcm_pcie_parse_request_of_pci_ranges(pcie);
-+ if (ret)
-+ return ret;
-+
-+ ret = clk_prepare_enable(pcie->clk);
-+ if (ret) {
-+ dev_err(&pdev->dev, "could not enable clock\n");
-+ return ret;
-+ }
-+
-+ ret = brcm_pcie_add_controller(pcie);
-+ if (ret)
-+ return ret;
-+
-+ ret = brcm_pcie_setup(pcie);
-+ if (ret)
-+ goto fail;
-+
-+ list_splice_init(&pcie->resources, &bridge->windows);
-+ bridge->dev.parent = &pdev->dev;
-+ bridge->busnr = 0;
-+ bridge->ops = &brcm_pcie_ops;
-+ bridge->sysdata = pcie;
-+ bridge->map_irq = of_irq_parse_and_map_pci;
-+ bridge->swizzle_irq = pci_common_swizzle;
-+
-+ ret = pci_scan_root_bus_bridge(bridge);
-+ if (ret < 0) {
-+ dev_err(pcie->dev, "Scanning root bridge failed\n");
-+ goto fail;
-+ }
-+
-+ pci_assign_unassigned_bus_resources(bridge->bus);
-+ list_for_each_entry(child, &bridge->bus->children, node)
-+ pcie_bus_configure_settings(child);
-+ pci_bus_add_devices(bridge->bus);
-+ platform_set_drvdata(pdev, pcie);
-+ pcie->root_bus = bridge->bus;
-+
-+ return 0;
-+
-+fail:
-+ _brcm_pcie_remove(pcie);
-+ return ret;
-+}
-+
-+static const struct dev_pm_ops brcm_pcie_pm_ops = {
-+ .suspend_noirq = brcm_pcie_suspend,
-+ .resume_noirq = brcm_pcie_resume,
-+};
-+
-+static struct platform_driver brcm_pcie_driver = {
-+ .probe = brcm_pcie_probe,
-+ .remove = brcm_pcie_remove,
-+ .driver = {
-+ .name = "brcm-pcie",
-+ .owner = THIS_MODULE,
-+ .of_match_table = brcm_pcie_match,
-+ .pm = &brcm_pcie_pm_ops,
-+ },
-+};
-+
-+module_platform_driver(brcm_pcie_driver);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
-+MODULE_AUTHOR("Broadcom");
---- /dev/null
-+++ b/include/soc/brcmstb/memory_api.h
-@@ -0,0 +1,25 @@
-+#ifndef __MEMORY_API_H
-+#define __MEMORY_API_H
-+
-+/*
-+ * Bus Interface Unit control register setup, must happen early during boot,
-+ * before SMP is brought up, called by machine entry point.
-+ */
-+void brcmstb_biuctrl_init(void);
-+
-+#ifdef CONFIG_SOC_BRCMSTB
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa);
-+u64 brcmstb_memory_memc_size(int memc);
-+#else
-+static inline int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ return -EINVAL;
-+}
-+
-+static inline u64 brcmstb_memory_memc_size(int memc)
-+{
-+ return -1;
-+}
-+#endif
-+
-+#endif /* __MEMORY_API_H */
--- /dev/null
+From 417e4745f7470ca8b9809056485eb7a81305019b Mon Sep 17 00:00:00 2001
+From: Jim Quinlan <jim2101024@gmail.com>
+Date: Mon, 15 Jan 2018 18:28:39 -0500
+Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device
+
+The DT bindings description of the Brcmstb PCIe device is described. This
+node can be used by almost all Broadcom settop box chips, using
+ARM, ARM64, or MIPS CPU architectures.
+
+Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
+---
+ .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++
+ 1 file changed, 59 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
+@@ -0,0 +1,59 @@
++Brcmstb PCIe Host Controller Device Tree Bindings
++
++Required Properties:
++- compatible
++ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs.
++ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs.
++ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including
++ the 7278).
++ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs.
++
++- reg -- the register start address and length for the PCIe reg block.
++- interrupts -- two interrupts are specified; the first interrupt is for
++ the PCI host controller and the second is for MSI if the built-in
++ MSI controller is to be used.
++- interrupt-names -- names of the interrupts (above): "pcie" and "msi".
++- #address-cells -- set to <3>.
++- #size-cells -- set to <2>.
++- #interrupt-cells: set to <1>.
++- interrupt-map-mask and interrupt-map, standard PCI properties to define the
++ mapping of the PCIe interface to interrupt numbers.
++- ranges: ranges for the PCI memory and I/O regions.
++- linux,pci-domain -- should be unique per host controller.
++
++Optional Properties:
++- clocks -- phandle of pcie clock.
++- clock-names -- set to "sw_pcie" if clocks is used.
++- dma-ranges -- Specifies the inbound memory mapping regions when
++ an "identity map" is not possible.
++- msi-controller -- this property is typically specified to have the
++ PCIe controller use its internal MSI controller.
++- msi-parent -- set to use an external MSI interrupt controller.
++- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking.
++- max-link-speed -- (integer) indicates desired generation of link:
++ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3).
++
++Example Node:
++
++pcie0: pcie@f0460000 {
++ reg = <0x0 0xf0460000 0x0 0x9310>;
++ interrupts = <0x0 0x0 0x4>;
++ compatible = "brcm,bcm7445-pcie";
++ #address-cells = <3>;
++ #size-cells = <2>;
++ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000
++ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>;
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 7>;
++ interrupt-map = <0 0 0 1 &intc 0 47 3
++ 0 0 0 2 &intc 0 48 3
++ 0 0 0 3 &intc 0 49 3
++ 0 0 0 4 &intc 0 50 3>;
++ clocks = <&sw_pcie0>;
++ clock-names = "sw_pcie";
++ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */
++ msi-controller; /* use PCIe's internal MSI controller */
++ brcm,ssc;
++ max-link-speed = <1>;
++ linux,pci-domain = <0>;
++ };
+++ /dev/null
-From d45590eb858ac7a2578d477791881ba7ffb1e615 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add dma-range mapping for inbound
- traffic
-
-The Broadcom STB PCIe host controller is intimately related to the
-memory subsystem. This close relationship adds complexity to how cpu
-system memory is mapped to PCIe memory. Ideally, this mapping is an
-identity mapping, or an identity mapping off by a constant. Not so in
-this case.
-
-Consider the Broadcom reference board BCM97445LCC_4X8 which has 6 GB
-of system memory. Here is how the PCIe controller maps the
-system memory to PCIe memory:
-
- memc0-a@[ 0....3fffffff] <=> pci@[ 0....3fffffff]
- memc0-b@[100000000...13fffffff] <=> pci@[ 40000000....7fffffff]
- memc1-a@[ 40000000....7fffffff] <=> pci@[ 80000000....bfffffff]
- memc1-b@[300000000...33fffffff] <=> pci@[ c0000000....ffffffff]
- memc2-a@[ 80000000....bfffffff] <=> pci@[100000000...13fffffff]
- memc2-b@[c00000000...c3fffffff] <=> pci@[140000000...17fffffff]
-
-Although there are some "gaps" that can be added between the
-individual mappings by software, the permutation of memory regions for
-the most part is fixed by HW. The solution of having something close
-to an identity mapping is not possible.
-
-The idea behind this HW design is that the same PCIe module can
-act as an RC or EP, and if it acts as an EP it concatenates all
-of system memory into a BAR so anything can be accessed. Unfortunately,
-when the PCIe block is in the role of an RC it also presents this
-"BAR" to downstream PCIe devices, rather than offering an identity map
-between its system memory and PCIe space.
-
-Suppose that an endpoint driver allocs some DMA memory. Suppose this
-memory is located at 0x6000_0000, which is in the middle of memc1-a.
-The driver wants a dma_addr_t value that it can pass on to the EP to
-use. Without doing any custom mapping, the EP will use this value for
-DMA: the driver will get a dma_addr_t equal to 0x6000_0000. But this
-won't work; the device needs a dma_addr_t that reflects the PCIe space
-address, namely 0xa000_0000.
-
-So, essentially the solution to this problem must modify the
-dma_addr_t returned by the DMA routines routines. There are two
-ways (I know of) of doing this:
-
-(a) overriding/redefining the dma_to_phys() and phys_to_dma() calls
-that are used by the dma_ops routines. This is the approach of
-
- arch/mips/cavium-octeon/dma-octeon.c
-
-In ARM and ARM64 these two routines are defiend in asm/dma-mapping.h
-as static inline functions.
-
-(b) Subscribe to a notifier that notifies when a device is added to a
-bus. When this happens, set_dma_ops() can be called for the device.
-This method is mentioned in:
-
- http://lxr.free-electrons.com/source/drivers/of/platform.c?v=3.16#L152
-
-where it says as a comment
-
- "In case if platform code need to use own special DMA
- configuration, it can use Platform bus notifier and
- handle BUS_NOTIFY_ADD_DEVICE event to fix up DMA
- configuration."
-
-Solution (b) is what this commit does. It uses its own set of
-dma_ops which are wrappers around the arch_dma_ops. The
-wrappers translate the dma addresses before/after invoking
-the arch_dma_ops, as appropriate.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/pcie-brcmstb.c | 420 +++++++++++++++++++++++++-
- 1 file changed, 411 insertions(+), 9 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -4,6 +4,7 @@
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-+#include <linux/dma-mapping.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
-@@ -319,11 +320,307 @@ static struct pci_ops brcm_pcie_ops = {
- ((val & ~reg##_##field##_MASK) | \
- (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-
-+static const struct dma_map_ops *arch_dma_ops;
-+static const struct dma_map_ops *brcm_dma_ops_ptr;
-+static struct of_pci_range *dma_ranges;
-+static int num_dma_ranges;
-+
- static phys_addr_t scb_size[BRCM_MAX_SCB];
- static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-
-+static dma_addr_t brcm_to_pci(dma_addr_t addr)
-+{
-+ struct of_pci_range *p;
-+
-+ if (!num_dma_ranges)
-+ return addr;
-+
-+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+ if (addr >= p->cpu_addr && addr < (p->cpu_addr + p->size))
-+ return addr - p->cpu_addr + p->pci_addr;
-+
-+ return addr;
-+}
-+
-+static dma_addr_t brcm_to_cpu(dma_addr_t addr)
-+{
-+ struct of_pci_range *p;
-+
-+ if (!num_dma_ranges)
-+ return addr;
-+
-+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
-+ if (addr >= p->pci_addr && addr < (p->pci_addr + p->size))
-+ return addr - p->pci_addr + p->cpu_addr;
-+
-+ return addr;
-+}
-+
-+static void *brcm_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-+ gfp_t gfp, unsigned long attrs)
-+{
-+ void *ret;
-+
-+ ret = arch_dma_ops->alloc(dev, size, handle, gfp, attrs);
-+ if (ret)
-+ *handle = brcm_to_pci(*handle);
-+ return ret;
-+}
-+
-+static void brcm_free(struct device *dev, size_t size, void *cpu_addr,
-+ dma_addr_t handle, unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->free(dev, size, cpu_addr, handle, attrs);
-+}
-+
-+static int brcm_mmap(struct device *dev, struct vm_area_struct *vma,
-+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
-+ unsigned long attrs)
-+{
-+ dma_addr = brcm_to_cpu(dma_addr);
-+ return arch_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-+}
-+
-+static int brcm_get_sgtable(struct device *dev, struct sg_table *sgt,
-+ void *cpu_addr, dma_addr_t handle, size_t size,
-+ unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ return arch_dma_ops->get_sgtable(dev, sgt, cpu_addr, handle, size,
-+ attrs);
-+}
-+
-+static dma_addr_t brcm_map_page(struct device *dev, struct page *page,
-+ unsigned long offset, size_t size,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ return brcm_to_pci(arch_dma_ops->map_page(dev, page, offset, size,
-+ dir, attrs));
-+}
-+
-+static void brcm_unmap_page(struct device *dev, dma_addr_t handle,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->unmap_page(dev, handle, size, dir, attrs);
-+}
-+
-+static int brcm_map_sg(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ int i, j;
-+ struct scatterlist *sg;
-+
-+ for_each_sg(sgl, sg, nents, i) {
-+#ifdef CONFIG_NEED_SG_DMA_LENGTH
-+ sg->dma_length = sg->length;
-+#endif
-+ sg->dma_address =
-+ brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
-+ sg->length, dir, attrs);
-+ if (dma_mapping_error(dev, sg->dma_address))
-+ goto bad_mapping;
-+ }
-+ return nents;
-+
-+bad_mapping:
-+ for_each_sg(sgl, sg, i, j)
-+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
-+ return 0;
-+}
-+
-+static void brcm_unmap_sg(struct device *dev,
-+ struct scatterlist *sgl, int nents,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ int i;
-+ struct scatterlist *sg;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
-+}
-+
-+static void brcm_sync_single_for_cpu(struct device *dev,
-+ dma_addr_t handle, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->sync_single_for_cpu(dev, handle, size, dir);
-+}
-+
-+static void brcm_sync_single_for_device(struct device *dev,
-+ dma_addr_t handle, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ handle = brcm_to_cpu(handle);
-+ arch_dma_ops->sync_single_for_device(dev, handle, size, dir);
-+}
-+
-+static dma_addr_t brcm_map_resource(struct device *dev, phys_addr_t phys,
-+ size_t size,
-+ enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ if (arch_dma_ops->map_resource)
-+ return brcm_to_pci(arch_dma_ops->map_resource
-+ (dev, phys, size, dir, attrs));
-+ return brcm_to_pci((dma_addr_t)phys);
-+}
-+
-+static void brcm_unmap_resource(struct device *dev, dma_addr_t handle,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ if (arch_dma_ops->unmap_resource)
-+ arch_dma_ops->unmap_resource(dev, brcm_to_cpu(handle), size,
-+ dir, attrs);
-+}
-+
-+void brcm_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir)
-+{
-+ struct scatterlist *sg;
-+ int i;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
-+ sg->length, dir);
-+}
-+
-+void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-+ int nents, enum dma_data_direction dir)
-+{
-+ struct scatterlist *sg;
-+ int i;
-+
-+ for_each_sg(sgl, sg, nents, i)
-+ brcm_dma_ops_ptr->sync_single_for_device(dev,
-+ sg_dma_address(sg),
-+ sg->length, dir);
-+}
-+
-+static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+ return arch_dma_ops->mapping_error(dev, dma_addr);
-+}
-+
-+static int brcm_dma_supported(struct device *dev, u64 mask)
-+{
-+ if (num_dma_ranges) {
-+ /*
-+ * It is our translated addresses that the EP will "see", so
-+ * we check all of the ranges for the largest possible value.
-+ */
-+ int i;
-+
-+ for (i = 0; i < num_dma_ranges; i++)
-+ if (dma_ranges[i].pci_addr + dma_ranges[i].size - 1
-+ > mask)
-+ return 0;
-+ return 1;
-+ }
-+
-+ return arch_dma_ops->dma_supported(dev, mask);
-+}
-+
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+u64 brcm_get_required_mask)(struct device *dev)
-+{
-+ return arch_dma_ops->get_required_mask(dev);
-+}
-+#endif
-+
-+static const struct dma_map_ops brcm_dma_ops = {
-+ .alloc = brcm_alloc,
-+ .free = brcm_free,
-+ .mmap = brcm_mmap,
-+ .get_sgtable = brcm_get_sgtable,
-+ .map_page = brcm_map_page,
-+ .unmap_page = brcm_unmap_page,
-+ .map_sg = brcm_map_sg,
-+ .unmap_sg = brcm_unmap_sg,
-+ .map_resource = brcm_map_resource,
-+ .unmap_resource = brcm_unmap_resource,
-+ .sync_single_for_cpu = brcm_sync_single_for_cpu,
-+ .sync_single_for_device = brcm_sync_single_for_device,
-+ .sync_sg_for_cpu = brcm_sync_sg_for_cpu,
-+ .sync_sg_for_device = brcm_sync_sg_for_device,
-+ .mapping_error = brcm_mapping_error,
-+ .dma_supported = brcm_dma_supported,
-+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
-+ .get_required_mask = brcm_get_required_mask,
-+#endif
-+};
-+
-+static void brcm_set_dma_ops(struct device *dev)
-+{
-+ int ret;
-+
-+ if (IS_ENABLED(CONFIG_ARM64)) {
-+ /*
-+ * We are going to invoke get_dma_ops(). That
-+ * function, at this point in time, invokes
-+ * get_arch_dma_ops(), and for ARM64 that function
-+ * returns a pointer to dummy_dma_ops. So then we'd
-+ * like to call arch_setup_dma_ops(), but that isn't
-+ * exported. Instead, we call of_dma_configure(),
-+ * which is exported, and this calls
-+ * arch_setup_dma_ops(). Once we do this the call to
-+ * get_dma_ops() will work properly because
-+ * dev->dma_ops will be set.
-+ */
-+ ret = of_dma_configure(dev, dev->of_node, true);
-+ if (ret) {
-+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+ return;
-+ }
-+ }
-+
-+ arch_dma_ops = get_dma_ops(dev);
-+ if (!arch_dma_ops) {
-+ dev_err(dev, "failed to get arch_dma_ops\n");
-+ return;
-+ }
-+
-+ set_dma_ops(dev, &brcm_dma_ops);
-+}
-+
-+static int brcmstb_platform_notifier(struct notifier_block *nb,
-+ unsigned long event, void *__dev)
-+{
-+ struct device *dev = __dev;
-+
-+ brcm_dma_ops_ptr = &brcm_dma_ops;
-+ if (event != BUS_NOTIFY_ADD_DEVICE)
-+ return NOTIFY_DONE;
-+
-+ brcm_set_dma_ops(dev);
-+ return NOTIFY_OK;
-+}
-+
-+static struct notifier_block brcmstb_platform_nb = {
-+ .notifier_call = brcmstb_platform_notifier,
-+};
-+
-+static int brcm_register_notifier(void)
-+{
-+ return bus_register_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
-+static int brcm_unregister_notifier(void)
-+{
-+ return bus_unregister_notifier(&pci_bus_type, &brcmstb_platform_nb);
-+}
-+
- static u32 rd_fld(void __iomem *p, u32 mask, int shift)
- {
- return (bcm_readl(p) & mask) >> shift;
-@@ -597,9 +894,71 @@ static inline void brcm_pcie_perst_set(s
- WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
- }
-
-+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-+ struct device_node *node)
-+{
-+ const int na = 3, ns = 2;
-+ int rlen;
-+
-+ parser->node = node;
-+ parser->pna = of_n_addr_cells(node);
-+ parser->np = parser->pna + na + ns;
-+
-+ parser->range = of_get_property(node, "dma-ranges", &rlen);
-+ if (!parser->range)
-+ return -ENOENT;
-+
-+ parser->end = parser->range + rlen / sizeof(__be32);
-+
-+ return 0;
-+}
-+
-+static int brcm_pcie_parse_map_dma_ranges(struct brcm_pcie *pcie)
-+{
-+ int i;
-+ struct of_pci_range_parser parser;
-+ struct device_node *dn = pcie->dn;
-+
-+ /*
-+ * Parse dma-ranges property if present. If there are multiple
-+ * PCIe controllers, we only have to parse from one of them since
-+ * the others will have an identical mapping.
-+ */
-+ if (!pci_dma_range_parser_init(&parser, dn)) {
-+ unsigned int max_ranges
-+ = (parser.end - parser.range) / parser.np;
-+
-+ dma_ranges = kcalloc(max_ranges, sizeof(struct of_pci_range),
-+ GFP_KERNEL);
-+ if (!dma_ranges)
-+ return -ENOMEM;
-+
-+ for (i = 0; of_pci_range_parser_one(&parser, dma_ranges + i);
-+ i++)
-+ num_dma_ranges++;
-+ }
-+
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(pcie->dev, "cannot get memc%d size", i);
-+ return -EINVAL;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ num_memc++;
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
- static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
- {
- int i, ret = 0;
-+ struct device *dev = pcie->dev;
-
- mutex_lock(&brcm_pcie_lock);
- if (num_pcie > 0) {
-@@ -607,12 +966,21 @@ static int brcm_pcie_add_controller(stru
- goto done;
- }
-
-+ ret = brcm_register_notifier();
-+ if (ret) {
-+ dev_err(dev, "failed to register pci bus notifier\n");
-+ goto done;
-+ }
-+ ret = brcm_pcie_parse_map_dma_ranges(pcie);
-+ if (ret)
-+ goto done;
-+
- /* Determine num_memc and their sizes */
- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
- u64 size = brcmstb_memory_memc_size(i);
-
- if (size == (u64)-1) {
-- dev_err(pcie->dev, "cannot get memc%d size\n", i);
-+ dev_err(dev, "cannot get memc%d size\n", i);
- ret = -EINVAL;
- goto done;
- } else if (size) {
-@@ -636,8 +1004,16 @@ done:
- static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
- {
- mutex_lock(&brcm_pcie_lock);
-- if (--num_pcie == 0)
-- num_memc = 0;
-+ if (--num_pcie > 0)
-+ goto out;
-+
-+ if (brcm_unregister_notifier())
-+ dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
-+ kfree(dma_ranges);
-+ dma_ranges = NULL;
-+ num_dma_ranges = 0;
-+ num_memc = 0;
-+out:
- mutex_unlock(&brcm_pcie_lock);
- }
-
-@@ -757,6 +1133,38 @@ static int brcm_pcie_setup(struct brcm_p
- */
- rc_bar2_offset = 0;
-
-+ if (dma_ranges) {
-+ /*
-+ * The best-case scenario is to place the inbound
-+ * region in the first 4GB of pci-space, as some
-+ * legacy devices can only address 32bits.
-+ * We would also like to put the MSI under 4GB
-+ * as well, since some devices require a 32bit
-+ * MSI target address.
-+ */
-+ if (total_mem_size <= 0xc0000000ULL &&
-+ rc_bar2_size <= 0x100000000ULL) {
-+ rc_bar2_offset = 0;
-+ } else {
-+ /*
-+ * The system memory is 4GB or larger so we
-+ * cannot start the inbound region at location
-+ * 0 (since we have to allow some space for
-+ * outbound memory @ 3GB). So instead we
-+ * start it at the 1x multiple of its size
-+ */
-+ rc_bar2_offset = rc_bar2_size;
-+ }
-+
-+ } else {
-+ /*
-+ * Set simple configuration based on memory sizes
-+ * only. We always start the viewport at address 0,
-+ * and set the MSI target address accordingly.
-+ */
-+ rc_bar2_offset = 0;
-+ }
-+
- tmp = lower_32_bits(rc_bar2_offset);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
- encode_ibar_size(rc_bar2_size));
-@@ -967,7 +1375,6 @@ static int brcm_pcie_probe(struct platfo
- struct brcm_pcie *pcie;
- struct resource *res;
- void __iomem *base;
-- u32 tmp;
- struct pci_host_bridge *bridge;
- struct pci_bus *child;
-
-@@ -984,11 +1391,6 @@ static int brcm_pcie_probe(struct platfo
- return -EINVAL;
- }
-
-- if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
-- dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
-- return -EINVAL;
-- }
--
- data = of_id->data;
- pcie->reg_offsets = data->offsets;
- pcie->reg_field_info = data->reg_field_info;
--- /dev/null
+From 67b31f71da2c251860dc6ddeffc5d15f8a74c675 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 May 2019 15:47:42 +0100
+Subject: [PATCH] arm: bcm2835: DMA can only address 1GB
+
+The legacy peripherals can only address the first gigabyte of RAM, so
+ensure that DMA allocations are restricted to that region.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -114,6 +114,9 @@ static const char * const bcm2835_compat
+ };
+
+ DT_MACHINE_START(BCM2835, "BCM2835")
++#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
++ .dma_zone_size = SZ_1G,
++#endif
+ .map_io = bcm2835_map_io,
+ .init_machine = bcm2835_init,
+ .dt_compat = bcm2835_compat,
+++ /dev/null
-From b1619c83208e7b804e2c3547dbf24bb02b3be239 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] PCI: brcmstb: Add MSI capability
-
-This commit adds MSI to the Broadcom STB PCIe host controller. It does
-not add MSIX since that functionality is not in the HW. The MSI
-controller is physically located within the PCIe block, however, there
-is no reason why the MSI controller could not be moved elsewhere in
-the future.
-
-Since the internal Brcmstb MSI controller is intertwined with the PCIe
-controller, it is not its own platform device but rather part of the
-PCIe platform device.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- drivers/pci/controller/pcie-brcmstb.c | 374 ++++++++++++++++++++++++--
- 1 file changed, 353 insertions(+), 21 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -1,6 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (C) 2009 - 2017 Broadcom */
-
-+#include <linux/bitops.h>
- #include <linux/clk.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
-@@ -9,11 +10,13 @@
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
-+#include <linux/irqchip/chained_irq.h>
- #include <linux/irqdomain.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/log2.h>
- #include <linux/module.h>
-+#include <linux/msi.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/of_pci.h>
-@@ -47,6 +50,9 @@
- #define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
- #define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
- #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
-+#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
-+#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
-+#define PCIE_MISC_MSI_DATA_CONFIG 0x404c
- #define PCIE_MISC_PCIE_CTRL 0x4064
- #define PCIE_MISC_PCIE_STATUS 0x4068
- #define PCIE_MISC_REVISION 0x406c
-@@ -55,6 +61,7 @@
- #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
- #define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
- #define PCIE_INTR2_CPU_BASE 0x4300
-+#define PCIE_MSI_INTR2_BASE 0x4500
-
- /*
- * Broadcom Settop Box PCIe Register Field shift and mask info. The
-@@ -115,6 +122,8 @@
-
- #define BRCM_NUM_PCIE_OUT_WINS 0x4
- #define BRCM_MAX_SCB 0x4
-+#define BRCM_INT_PCI_MSI_NR 32
-+#define BRCM_PCIE_HW_REV_33 0x0303
-
- #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
- #define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
-@@ -203,6 +212,33 @@ struct brcm_window {
- dma_addr_t size;
- };
-
-+struct brcm_msi {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct device_node *dn;
-+ struct irq_domain *msi_domain;
-+ struct irq_domain *inner_domain;
-+ struct mutex lock; /* guards the alloc/free operations */
-+ u64 target_addr;
-+ int irq;
-+
-+ /* intr_base is the base pointer for interrupt status/set/clr regs */
-+ void __iomem *intr_base;
-+
-+ /* intr_legacy_mask indicates how many bits are MSI interrupts */
-+ u32 intr_legacy_mask;
-+
-+ /*
-+ * intr_legacy_offset indicates bit position of MSI_01. It is
-+ * to map the register bit position to a hwirq that starts at 0.
-+ */
-+ u32 intr_legacy_offset;
-+
-+ /* used indicates which MSI interrupts have been alloc'd */
-+ unsigned long used;
-+ unsigned int rev;
-+};
-+
- /* Internal PCIe Host Controller Information.*/
- struct brcm_pcie {
- struct device *dev;
-@@ -217,7 +253,10 @@ struct brcm_pcie {
- int num_out_wins;
- bool ssc;
- int gen;
-+ u64 msi_target_addr;
- struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
-+ struct brcm_msi *msi;
-+ bool msi_internal;
- unsigned int rev;
- const int *reg_offsets;
- const int *reg_field_info;
-@@ -225,9 +264,9 @@ struct brcm_pcie {
- };
-
- struct pcie_cfg_data {
-- const int *reg_field_info;
-- const int *offsets;
-- const enum pcie_type type;
-+ const int *reg_field_info;
-+ const int *offsets;
-+ const enum pcie_type type;
- };
-
- static const int pcie_reg_field_info[] = {
-@@ -828,6 +867,267 @@ static void brcm_pcie_set_outbound_win(s
- }
- }
-
-+static struct irq_chip brcm_msi_irq_chip = {
-+ .name = "Brcm_MSI",
-+ .irq_mask = pci_msi_mask_irq,
-+ .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+static struct msi_domain_info brcm_msi_domain_info = {
-+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-+ MSI_FLAG_PCI_MSIX),
-+ .chip = &brcm_msi_irq_chip,
-+};
-+
-+static void brcm_pcie_msi_isr(struct irq_desc *desc)
-+{
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct brcm_msi *msi;
-+ unsigned long status, virq;
-+ u32 mask, bit, hwirq;
-+ struct device *dev;
-+
-+ chained_irq_enter(chip, desc);
-+ msi = irq_desc_get_handler_data(desc);
-+ mask = msi->intr_legacy_mask;
-+ dev = msi->dev;
-+
-+ while ((status = bcm_readl(msi->intr_base + STATUS) & mask)) {
-+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
-+ /* clear the interrupt */
-+ bcm_writel(1 << bit, msi->intr_base + CLR);
-+
-+ /* Account for legacy interrupt offset */
-+ hwirq = bit - msi->intr_legacy_offset;
-+
-+ virq = irq_find_mapping(msi->inner_domain, hwirq);
-+ if (virq) {
-+ if (msi->used & (1 << hwirq))
-+ generic_handle_irq(virq);
-+ else
-+ dev_info(dev, "unhandled MSI %d\n",
-+ hwirq);
-+ } else {
-+ /* Unknown MSI, just clear it */
-+ dev_dbg(dev, "unexpected MSI\n");
-+ }
-+ }
-+ }
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+{
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
-+ u32 temp;
-+
-+ msg->address_lo = lower_32_bits(msi->target_addr);
-+ msg->address_hi = upper_32_bits(msi->target_addr);
-+ temp = bcm_readl(msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+ msg->data = ((temp >> 16) & (temp & 0xffff)) | data->hwirq;
-+}
-+
-+static int brcm_msi_set_affinity(struct irq_data *irq_data,
-+ const struct cpumask *mask, bool force)
-+{
-+ return -EINVAL;
-+}
-+
-+static struct irq_chip brcm_msi_bottom_irq_chip = {
-+ .name = "Brcm_MSI",
-+ .irq_compose_msi_msg = brcm_compose_msi_msg,
-+ .irq_set_affinity = brcm_msi_set_affinity,
-+};
-+
-+static int brcm_msi_alloc(struct brcm_msi *msi)
-+{
-+ int bit, hwirq;
-+
-+ mutex_lock(&msi->lock);
-+ bit = ~msi->used ? ffz(msi->used) : -1;
-+
-+ if (bit >= 0 && bit < BRCM_INT_PCI_MSI_NR) {
-+ msi->used |= (1 << bit);
-+ hwirq = bit - msi->intr_legacy_offset;
-+ } else {
-+ hwirq = -ENOSPC;
-+ }
-+
-+ mutex_unlock(&msi->lock);
-+ return hwirq;
-+}
-+
-+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
-+{
-+ mutex_lock(&msi->lock);
-+ msi->used &= ~(1 << (hwirq + msi->intr_legacy_offset));
-+ mutex_unlock(&msi->lock);
-+}
-+
-+static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
-+ unsigned int nr_irqs, void *args)
-+{
-+ struct brcm_msi *msi = domain->host_data;
-+ int hwirq;
-+
-+ hwirq = brcm_msi_alloc(msi);
-+
-+ if (hwirq < 0)
-+ return hwirq;
-+
-+ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
-+ &brcm_msi_bottom_irq_chip, domain->host_data,
-+ handle_simple_irq, NULL, NULL);
-+ return 0;
-+}
-+
-+static void brcm_irq_domain_free(struct irq_domain *domain,
-+ unsigned int virq, unsigned int nr_irqs)
-+{
-+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
-+
-+ brcm_msi_free(msi, d->hwirq);
-+}
-+
-+static void brcm_msi_set_regs(struct brcm_msi *msi)
-+{
-+ u32 data_val, msi_lo, msi_hi;
-+
-+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+ /*
-+ * ffe0 -- least sig 5 bits are 0 indicating 32 msgs
-+ * 6540 -- this is our arbitrary unique data value
-+ */
-+ data_val = 0xffe06540;
-+ } else {
-+ /*
-+ * fff8 -- least sig 3 bits are 0 indicating 8 msgs
-+ * 6540 -- this is our arbitrary unique data value
-+ */
-+ data_val = 0xfff86540;
-+ }
-+
-+ /*
-+ * Make sure we are not masking MSIs. Note that MSIs can be masked,
-+ * but that occurs on the PCIe EP device
-+ */
-+ bcm_writel(0xffffffff & msi->intr_legacy_mask,
-+ msi->intr_base + MASK_CLR);
-+
-+ msi_lo = lower_32_bits(msi->target_addr);
-+ msi_hi = upper_32_bits(msi->target_addr);
-+ /*
-+ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
-+ * enable, which we set to 1.
-+ */
-+ bcm_writel(msi_lo | 1, msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
-+ bcm_writel(msi_hi, msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
-+ bcm_writel(data_val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
-+}
-+
-+static const struct irq_domain_ops msi_domain_ops = {
-+ .alloc = brcm_irq_domain_alloc,
-+ .free = brcm_irq_domain_free,
-+};
-+
-+static int brcm_allocate_domains(struct brcm_msi *msi)
-+{
-+ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->dn);
-+ struct device *dev = msi->dev;
-+
-+ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
-+ &msi_domain_ops, msi);
-+ if (!msi->inner_domain) {
-+ dev_err(dev, "failed to create IRQ domain\n");
-+ return -ENOMEM;
-+ }
-+
-+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-+ &brcm_msi_domain_info,
-+ msi->inner_domain);
-+ if (!msi->msi_domain) {
-+ dev_err(dev, "failed to create MSI domain\n");
-+ irq_domain_remove(msi->inner_domain);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static void brcm_free_domains(struct brcm_msi *msi)
-+{
-+ irq_domain_remove(msi->msi_domain);
-+ irq_domain_remove(msi->inner_domain);
-+}
-+
-+static void brcm_msi_remove(struct brcm_pcie *pcie)
-+{
-+ struct brcm_msi *msi = pcie->msi;
-+
-+ if (!msi)
-+ return;
-+ irq_set_chained_handler(msi->irq, NULL);
-+ irq_set_handler_data(msi->irq, NULL);
-+ brcm_free_domains(msi);
-+}
-+
-+static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
-+{
-+ struct brcm_msi *msi;
-+ int irq, ret;
-+ struct device *dev = pcie->dev;
-+
-+ irq = irq_of_parse_and_map(dev->of_node, 1);
-+ if (irq <= 0) {
-+ dev_err(dev, "cannot map msi intr\n");
-+ return -ENODEV;
-+ }
-+
-+ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
-+ if (!msi)
-+ return -ENOMEM;
-+
-+ msi->dev = dev;
-+ msi->base = pcie->base;
-+ msi->rev = pcie->rev;
-+ msi->dn = pcie->dn;
-+ msi->target_addr = pcie->msi_target_addr;
-+ msi->irq = irq;
-+
-+ ret = brcm_allocate_domains(msi);
-+ if (ret)
-+ return ret;
-+
-+ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
-+
-+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
-+ msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
-+ /*
-+ * This version of PCIe hw has only 32 intr bits
-+ * starting at bit position 0.
-+ */
-+ msi->intr_legacy_mask = 0xffffffff;
-+ msi->intr_legacy_offset = 0x0;
-+ msi->used = 0x0;
-+
-+ } else {
-+ msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
-+ /*
-+ * This version of PCIe hw has only 8 intr bits starting
-+ * at bit position 24.
-+ */
-+ msi->intr_legacy_mask = 0xff000000;
-+ msi->intr_legacy_offset = 24;
-+ msi->used = 0x00ffffff;
-+ }
-+
-+ brcm_msi_set_regs(msi);
-+ pcie->msi = msi;
-+
-+ return 0;
-+}
-+
- /* Configuration space read/write support */
- static int cfg_index(int busnr, int devfn, int reg)
- {
-@@ -1072,6 +1372,7 @@ static int brcm_pcie_setup(struct brcm_p
- u16 nlw, cls, lnksta;
- bool ssc_good = false;
- struct device *dev = pcie->dev;
-+ u64 msi_target_addr;
-
- /* Reset the bridge */
- brcm_pcie_bridge_sw_init_set(pcie, 1);
-@@ -1116,27 +1417,24 @@ static int brcm_pcie_setup(struct brcm_p
- * The PCIe host controller by design must set the inbound
- * viewport to be a contiguous arrangement of all of the
- * system's memory. In addition, its size mut be a power of
-- * two. To further complicate matters, the viewport must
-- * start on a pcie-address that is aligned on a multiple of its
-- * size. If a portion of the viewport does not represent
-- * system memory -- e.g. 3GB of memory requires a 4GB viewport
-- * -- we can map the outbound memory in or after 3GB and even
-- * though the viewport will overlap the outbound memory the
-- * controller will know to send outbound memory downstream and
-- * everything else upstream.
-+ * two. Further, the MSI target address must NOT be placed
-+ * inside this region, as the decoding logic will consider its
-+ * address to be inbound memory traffic. To further
-+ * complicate matters, the viewport must start on a
-+ * pcie-address that is aligned on a multiple of its size.
-+ * If a portion of the viewport does not represent system
-+ * memory -- e.g. 3GB of memory requires a 4GB viewport --
-+ * we can map the outbound memory in or after 3GB and even
-+ * though the viewport will overlap the outbound memory
-+ * the controller will know to send outbound memory downstream
-+ * and everything else upstream.
- */
- rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- /*
-- * Set simple configuration based on memory sizes
-- * only. We always start the viewport at address 0.
-- */
-- rc_bar2_offset = 0;
--
- if (dma_ranges) {
- /*
- * The best-case scenario is to place the inbound
-- * region in the first 4GB of pci-space, as some
-+ * region in the first 4GB of pcie-space, as some
- * legacy devices can only address 32bits.
- * We would also like to put the MSI under 4GB
- * as well, since some devices require a 32bit
-@@ -1145,6 +1443,14 @@ static int brcm_pcie_setup(struct brcm_p
- if (total_mem_size <= 0xc0000000ULL &&
- rc_bar2_size <= 0x100000000ULL) {
- rc_bar2_offset = 0;
-+ /* If the viewport is less then 4GB we can fit
-+ * the MSI target address under 4GB. Otherwise
-+ * put it right below 64GB.
-+ */
-+ msi_target_addr =
-+ (rc_bar2_size == 0x100000000ULL)
-+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
- } else {
- /*
- * The system memory is 4GB or larger so we
-@@ -1154,8 +1460,12 @@ static int brcm_pcie_setup(struct brcm_p
- * start it at the 1x multiple of its size
- */
- rc_bar2_offset = rc_bar2_size;
-- }
-
-+ /* Since we are starting the viewport at 4GB or
-+ * higher, put the MSI target address below 4GB
-+ */
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ }
- } else {
- /*
- * Set simple configuration based on memory sizes
-@@ -1163,7 +1473,12 @@ static int brcm_pcie_setup(struct brcm_p
- * and set the MSI target address accordingly.
- */
- rc_bar2_offset = 0;
-+
-+ msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
-+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
-+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
- }
-+ pcie->msi_target_addr = msi_target_addr;
-
- tmp = lower_32_bits(rc_bar2_offset);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
-@@ -1333,6 +1648,9 @@ static int brcm_pcie_resume(struct devic
- if (ret)
- return ret;
-
-+ if (pcie->msi && pcie->msi_internal)
-+ brcm_msi_set_regs(pcie->msi);
-+
- pcie->suspended = false;
-
- return 0;
-@@ -1340,6 +1658,7 @@ static int brcm_pcie_resume(struct devic
-
- static void _brcm_pcie_remove(struct brcm_pcie *pcie)
- {
-+ brcm_msi_remove(pcie);
- turn_off(pcie);
- clk_disable_unprepare(pcie->clk);
- clk_put(pcie->clk);
-@@ -1368,7 +1687,7 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
-
- static int brcm_pcie_probe(struct platform_device *pdev)
- {
-- struct device_node *dn = pdev->dev.of_node;
-+ struct device_node *dn = pdev->dev.of_node, *msi_dn;
- const struct of_device_id *of_id;
- const struct pcie_cfg_data *data;
- int ret;
-@@ -1448,6 +1767,20 @@ static int brcm_pcie_probe(struct platfo
- if (ret)
- goto fail;
-
-+ msi_dn = of_parse_phandle(pcie->dn, "msi-parent", 0);
-+ /* Use the internal MSI if no msi-parent property */
-+ if (!msi_dn)
-+ msi_dn = pcie->dn;
-+
-+ if (pci_msi_enabled() && msi_dn == pcie->dn) {
-+ ret = brcm_pcie_enable_msi(pcie);
-+ if (ret)
-+ dev_err(pcie->dev,
-+ "probe of internal MSI failed: %d)", ret);
-+ else
-+ pcie->msi_internal = true;
-+ }
-+
- list_splice_init(&pcie->resources, &bridge->windows);
- bridge->dev.parent = &pdev->dev;
- bridge->busnr = 0;
-@@ -1470,7 +1803,6 @@ static int brcm_pcie_probe(struct platfo
- pcie->root_bus = bridge->bus;
-
- return 0;
--
- fail:
- _brcm_pcie_remove(pcie);
- return ret;
--- /dev/null
+From cbf5cde9c460eae458829a7b357cea6734c4755b Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Sat, 4 May 2019 17:06:15 +0200
+Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support
+
+The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the
+support to this driver instead of bcm2835-rng.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ drivers/char/hw_random/Kconfig | 4 +-
+ drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++--
+ 2 files changed, 79 insertions(+), 6 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -90,11 +90,11 @@ config HW_RANDOM_BCM2835
+
+ config HW_RANDOM_IPROC_RNG200
+ tristate "Broadcom iProc/STB RNG200 support"
+- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB
++ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the RNG200
+- hardware found on the Broadcom iProc and STB SoCs.
++ hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iproc-rng200
+--- a/drivers/char/hw_random/iproc-rng200.c
++++ b/drivers/char/hw_random/iproc-rng200.c
+@@ -29,6 +29,7 @@
+ #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
+ #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
+ #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
++#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13
+
+ #define RNG_SOFT_RESET_OFFSET 0x04
+ #define RNG_SOFT_RESET 0x00000001
+@@ -36,16 +37,23 @@
+ #define RBG_SOFT_RESET_OFFSET 0x08
+ #define RBG_SOFT_RESET 0x00000001
+
++#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C
++
++#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10
++
+ #define RNG_INT_STATUS_OFFSET 0x18
+ #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
+ #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
+ #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
+ #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
+
++#define RNG_INT_ENABLE_OFFSET 0x1C
++
+ #define RNG_FIFO_DATA_OFFSET 0x20
+
+ #define RNG_FIFO_COUNT_OFFSET 0x24
+ #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
++#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8
+
+ struct iproc_rng200_dev {
+ struct hwrng rng;
+@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn
+ return 0;
+ }
+
++static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
++ bool wait)
++{
++ struct iproc_rng200_dev *priv = to_rng_priv(rng);
++ u32 max_words = max / sizeof(u32);
++ u32 num_words, count, val;
++
++ /* ensure warm up period has elapsed */
++ while (1) {
++ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
++ if (val > 16)
++ break;
++ cpu_relax();
++ }
++
++ /* ensure fifo is not empty */
++ while (1) {
++ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
++ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
++ if (num_words)
++ break;
++ if (!wait)
++ return 0;
++ cpu_relax();
++ }
++
++ if (num_words > max_words)
++ num_words = max_words;
++
++ for (count = 0; count < num_words; count++) {
++ ((u32 *)buf)[count] = ioread32(priv->base +
++ RNG_FIFO_DATA_OFFSET);
++ }
++
++ return num_words * sizeof(u32);
++}
++
++static int bcm2838_rng200_init(struct hwrng *rng)
++{
++ struct iproc_rng200_dev *priv = to_rng_priv(rng);
++ uint32_t val;
++
++ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
++ return 0;
++
++ /* initial numbers generated are "less random" so will be discarded */
++ val = 0x40000;
++ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
++ /* min fifo count to generate full interrupt */
++ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
++ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
++ /* enable the rng - 1Mhz sample rate */
++ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
++ iowrite32(val, priv->base + RNG_CTRL_OFFSET);
++
++ return 0;
++}
++
+ static void iproc_rng200_cleanup(struct hwrng *rng)
+ {
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla
+ return PTR_ERR(priv->base);
+ }
+
+- priv->rng.name = "iproc-rng200",
+- priv->rng.read = iproc_rng200_read,
+- priv->rng.init = iproc_rng200_init,
+- priv->rng.cleanup = iproc_rng200_cleanup,
++ priv->rng.name = pdev->name;
++ priv->rng.cleanup = iproc_rng200_cleanup;
++
++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
++ priv->rng.init = bcm2838_rng200_init;
++ priv->rng.read = bcm2838_rng200_read;
++ } else {
++ priv->rng.init = iproc_rng200_init;
++ priv->rng.read = iproc_rng200_read;
++ }
+
+ /* Register driver */
+ ret = devm_hwrng_register(dev, &priv->rng);
+@@ -223,6 +295,7 @@ static const struct of_device_id iproc_r
+ { .compatible = "brcm,bcm7211-rng200", },
+ { .compatible = "brcm,bcm7278-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
++ { .compatible = "brcm,bcm2838-rng200"},
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+++ /dev/null
-From 417e4745f7470ca8b9809056485eb7a81305019b Mon Sep 17 00:00:00 2001
-From: Jim Quinlan <jim2101024@gmail.com>
-Date: Mon, 15 Jan 2018 18:28:39 -0500
-Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device
-
-The DT bindings description of the Brcmstb PCIe device is described. This
-node can be used by almost all Broadcom settop box chips, using
-ARM, ARM64, or MIPS CPU architectures.
-
-Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
----
- .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++
- 1 file changed, 59 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
-@@ -0,0 +1,59 @@
-+Brcmstb PCIe Host Controller Device Tree Bindings
-+
-+Required Properties:
-+- compatible
-+ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs.
-+ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs.
-+ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including
-+ the 7278).
-+ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs.
-+
-+- reg -- the register start address and length for the PCIe reg block.
-+- interrupts -- two interrupts are specified; the first interrupt is for
-+ the PCI host controller and the second is for MSI if the built-in
-+ MSI controller is to be used.
-+- interrupt-names -- names of the interrupts (above): "pcie" and "msi".
-+- #address-cells -- set to <3>.
-+- #size-cells -- set to <2>.
-+- #interrupt-cells: set to <1>.
-+- interrupt-map-mask and interrupt-map, standard PCI properties to define the
-+ mapping of the PCIe interface to interrupt numbers.
-+- ranges: ranges for the PCI memory and I/O regions.
-+- linux,pci-domain -- should be unique per host controller.
-+
-+Optional Properties:
-+- clocks -- phandle of pcie clock.
-+- clock-names -- set to "sw_pcie" if clocks is used.
-+- dma-ranges -- Specifies the inbound memory mapping regions when
-+ an "identity map" is not possible.
-+- msi-controller -- this property is typically specified to have the
-+ PCIe controller use its internal MSI controller.
-+- msi-parent -- set to use an external MSI interrupt controller.
-+- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking.
-+- max-link-speed -- (integer) indicates desired generation of link:
-+ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3).
-+
-+Example Node:
-+
-+pcie0: pcie@f0460000 {
-+ reg = <0x0 0xf0460000 0x0 0x9310>;
-+ interrupts = <0x0 0x0 0x4>;
-+ compatible = "brcm,bcm7445-pcie";
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000
-+ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>;
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 7>;
-+ interrupt-map = <0 0 0 1 &intc 0 47 3
-+ 0 0 0 2 &intc 0 48 3
-+ 0 0 0 3 &intc 0 49 3
-+ 0 0 0 4 &intc 0 50 3>;
-+ clocks = <&sw_pcie0>;
-+ clock-names = "sw_pcie";
-+ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */
-+ msi-controller; /* use PCIe's internal MSI controller */
-+ brcm,ssc;
-+ max-link-speed = <1>;
-+ linux,pci-domain = <0>;
-+ };
--- /dev/null
+From d1066d775e67c33cc93178475c4485c5ef0a83c9 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Sat, 18 May 2019 12:26:11 +0200
+Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support
+
+The BCM2838 has an AVS TMON hardware block. This adds the necessary
+support to the brcmstb_thermal driver ( no trip handling ).
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ drivers/thermal/broadcom/Kconfig | 2 +-
+ drivers/thermal/broadcom/brcmstb_thermal.c | 61 +++++++++++++++++++---
+ 2 files changed, 54 insertions(+), 9 deletions(-)
+
+--- a/drivers/thermal/broadcom/Kconfig
++++ b/drivers/thermal/broadcom/Kconfig
+@@ -9,7 +9,7 @@ config BCM2835_THERMAL
+
+ config BRCMSTB_THERMAL
+ tristate "Broadcom STB AVS TMON thermal driver"
+- depends on ARCH_BRCMSTB || COMPILE_TEST
++ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
+ help
+ Enable this driver if you have a Broadcom STB SoC and would like
+ thermal framework support.
+--- a/drivers/thermal/broadcom/brcmstb_thermal.c
++++ b/drivers/thermal/broadcom/brcmstb_thermal.c
+@@ -10,6 +10,7 @@
+ #define pr_fmt(fmt) DRV_NAME ": " fmt
+
+ #include <linux/bitops.h>
++#include <linux/clk.h>
+ #include <linux/device.h>
+ #include <linux/err.h>
+ #include <linux/io.h>
+@@ -22,9 +23,6 @@
+ #include <linux/thermal.h>
+
+ #define AVS_TMON_STATUS 0x00
+- #define AVS_TMON_STATUS_valid_msk BIT(11)
+- #define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
+- #define AVS_TMON_STATUS_data_shift 1
+
+ #define AVS_TMON_EN_OVERTEMP_RESET 0x04
+ #define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
+@@ -102,10 +100,19 @@ static struct avs_tmon_trip avs_tmon_tri
+ },
+ };
+
++struct brcmstb_thermal_of_data {
++ const struct thermal_zone_of_device_ops *of_ops;
++ u32 status_valid_mask;
++ u32 status_data_mask;
++ u32 status_data_shift;
++};
++
+ struct brcmstb_thermal_priv {
+ void __iomem *tmon_base;
+ struct device *dev;
+ struct thermal_zone_device *thermal;
++ struct clk *clk;
++ const struct brcmstb_thermal_of_data *socdata;
+ };
+
+ /* Convert a HW code to a temperature reading (millidegree celsius) */
+@@ -142,17 +149,18 @@ static inline u32 avs_tmon_temp_to_code(
+ static int brcmstb_get_temp(void *data, int *temp)
+ {
+ struct brcmstb_thermal_priv *priv = data;
++ const struct brcmstb_thermal_of_data *socdata = priv->socdata;
+ u32 val;
+ long t;
+
+ val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
+
+- if (!(val & AVS_TMON_STATUS_valid_msk)) {
++ if (!(val & socdata->status_valid_mask)) {
+ dev_err(priv->dev, "reading not valid\n");
+ return -EIO;
+ }
+
+- val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
++ val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
+
+ t = avs_tmon_code_to_temp(priv->thermal, val);
+ if (t < 0)
+@@ -277,13 +285,34 @@ static int brcmstb_set_trips(void *data,
+ return 0;
+ }
+
+-static const struct thermal_zone_of_device_ops of_ops = {
++static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
+ .get_temp = brcmstb_get_temp,
+ .set_trips = brcmstb_set_trips,
+ };
+
++static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
++ .get_temp = brcmstb_get_temp,
++};
++
++static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
++ .of_ops = &bcm7445_thermal_of_ops,
++ .status_valid_mask = BIT(11),
++ .status_data_mask = GENMASK(10, 1),
++ .status_data_shift = 1,
++};
++
++static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
++ .of_ops = &bcm2838_thermal_of_ops,
++ .status_valid_mask = BIT(10),
++ .status_data_mask = GENMASK(9, 0),
++ .status_data_shift = 0,
++};
++
+ static const struct of_device_id brcmstb_thermal_id_table[] = {
+- { .compatible = "brcm,avs-tmon" },
++ { .compatible = "brcm,avs-tmon",
++ .data = &bcm7445_thermal_of_data },
++ { .compatible = "brcm,avs-tmon-bcm2838",
++ .data = &bcm2838_thermal_of_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+@@ -304,11 +333,27 @@ static int brcmstb_thermal_probe(struct
+ if (IS_ERR(priv->tmon_base))
+ return PTR_ERR(priv->tmon_base);
+
++ priv->socdata = of_device_get_match_data(&pdev->dev);
++ if (!priv->socdata) {
++ dev_err(&pdev->dev, "no device match found\n");
++ return -ENODEV;
++ }
++
++ priv->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++
++ if (!IS_ERR(priv->clk)) {
++ ret = clk_prepare_enable(priv->clk);
++ if (ret)
++ return ret;
++ }
++
+ priv->dev = &pdev->dev;
+ platform_set_drvdata(pdev, priv);
+
+ thermal = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
+- &of_ops);
++ priv->socdata->of_ops);
+ if (IS_ERR(thermal)) {
+ ret = PTR_ERR(thermal);
+ dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
+++ /dev/null
-From 1dab5ded41ed07adc12f26e529aa64209a7c44b6 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 19 Feb 2019 22:06:59 +0000
-Subject: [PATCH] pcie-brcmstb: Changes for BCM2711
-
-The initial brcmstb PCIe driver - originally taken from the V3(?)
-patch set - has been modified significantly for the BCM2711.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/dma/bcm2835-dma.c | 107 ++++
- drivers/pci/controller/Makefile | 4 +
- drivers/pci/controller/pcie-brcmstb-bounce.c | 558 +++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb-bounce.h | 32 ++
- drivers/pci/controller/pcie-brcmstb.c | 245 ++++----
- drivers/soc/bcm/brcmstb/Makefile | 2 +-
- drivers/soc/bcm/brcmstb/memory.c | 158 ++++++
- 7 files changed, 991 insertions(+), 115 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.c
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce.h
- create mode 100644 drivers/soc/bcm/brcmstb/memory.c
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -64,6 +64,17 @@ struct bcm2835_dma_cb {
- uint32_t pad[2];
- };
-
-+struct bcm2838_dma40_scb {
-+ uint32_t ti;
-+ uint32_t src;
-+ uint32_t srci;
-+ uint32_t dst;
-+ uint32_t dsti;
-+ uint32_t len;
-+ uint32_t next_cb;
-+ uint32_t rsvd;
-+};
-+
- struct bcm2835_cb_entry {
- struct bcm2835_dma_cb *cb;
- dma_addr_t paddr;
-@@ -180,6 +191,45 @@ struct bcm2835_desc {
- #define MAX_DMA_LEN SZ_1G
- #define MAX_LITE_DMA_LEN (SZ_64K - 4)
-
-+/* 40-bit DMA support */
-+#define BCM2838_DMA40_CS 0x00
-+#define BCM2838_DMA40_CB 0x04
-+#define BCM2838_DMA40_DEBUG 0x0c
-+#define BCM2858_DMA40_TI 0x10
-+#define BCM2838_DMA40_SRC 0x14
-+#define BCM2838_DMA40_SRCI 0x18
-+#define BCM2838_DMA40_DEST 0x1c
-+#define BCM2838_DMA40_DESTI 0x20
-+#define BCM2838_DMA40_LEN 0x24
-+#define BCM2838_DMA40_NEXT_CB 0x28
-+#define BCM2838_DMA40_DEBUG2 0x2c
-+
-+#define BCM2838_DMA40_CS_ACTIVE BIT(0)
-+#define BCM2838_DMA40_CS_END BIT(1)
-+
-+#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
-+
-+#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
-+#define BCM2838_DMA40_INC BIT(12)
-+#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+
-+#define BCM2838_DMA40_MEMCPY_QOS \
-+ (BCM2838_DMA40_CS_QOS(0x0) | \
-+ BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
-+ BCM2838_DMA40_CS_WRITE_WAIT)
-+
-+#define BCM2838_DMA40_MEMCPY_XFER_INFO \
-+ (BCM2838_DMA40_SIZE_128 | \
-+ BCM2838_DMA40_INC | \
-+ BCM2838_DMA40_BURST_LEN(16))
-+
-+static void __iomem *memcpy_chan;
-+static struct bcm2838_dma40_scb *memcpy_scb;
-+static dma_addr_t memcpy_scb_dma;
-+DEFINE_SPINLOCK(memcpy_lock);
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
- /* lite and normal channels have different max frame length */
-@@ -866,6 +916,56 @@ static void bcm2835_dma_free(struct bcm2
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
-
-+int bcm2838_dma40_memcpy_init(struct device *dev)
-+{
-+ if (memcpy_scb)
-+ return 0;
-+
-+ memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
-+ &memcpy_scb_dma, GFP_KERNEL);
-+
-+ if (!memcpy_scb) {
-+ pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
-+
-+void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
-+{
-+ struct bcm2838_dma40_scb *scb = memcpy_scb;
-+ unsigned long flags;
-+
-+ if (!scb) {
-+ pr_err("bcm2838_dma40_memcpy not initialised!\n");
-+ return;
-+ }
-+
-+ spin_lock_irqsave(&memcpy_lock, flags);
-+
-+ scb->ti = 0;
-+ scb->src = lower_32_bits(src);
-+ scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->dst = lower_32_bits(dst);
-+ scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->len = size;
-+ scb->next_cb = 0;
-+
-+ writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-+ writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+ memcpy_chan + BCM2838_DMA40_CS);
-+ /* Poll for completion */
-+ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+ cpu_relax();
-+
-+ writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+
-+ spin_unlock_irqrestore(&memcpy_lock, flags);
-+}
-+EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-+
- static const struct of_device_id bcm2835_dma_of_match[] = {
- { .compatible = "brcm,bcm2835-dma", },
- {},
-@@ -971,6 +1071,13 @@ static int bcm2835_dma_probe(struct plat
- /* Channel 0 is used by the legacy API */
- chans_available &= ~BCM2835_DMA_BULK_MASK;
-
-+ /* We can't use channels 11-13 yet */
-+ chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+
-+ /* Grab channel 14 for the 40-bit DMA memcpy */
-+ chans_available &= ~BIT(14);
-+ memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+
- /* get irqs for each channel that we support */
- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
- /* skip masked out channels */
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -30,6 +30,10 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
- obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
- obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
-+ifdef CONFIG_ARM
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
-+endif
-+
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y += dwc/
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -0,0 +1,558 @@
-+/*
-+ * This code started out as a version of arch/arm/common/dmabounce.c,
-+ * modified to cope with highmem pages. Now it has been changed heavily -
-+ * it now preallocates a large block (currently 4MB) and carves it up
-+ * sequentially in ring fashion, and DMA is used to copy the data - to the
-+ * point where very little of the original remains.
-+ *
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Original version by Brad Parker (brad@heeltoe.com)
-+ * Re-written by Christopher Hoover <ch@murgatroid.com>
-+ * Made generic by Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ * Copyright (C) 2002 Hewlett Packard Company.
-+ * Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+
-+#include <asm/cacheflush.h>
-+#include <asm/dma-iommu.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+ struct list_head node;
-+
-+ /* original request */
-+ size_t size;
-+ int direction;
-+
-+ struct dmabounce_pool *pool;
-+ void *safe;
-+ dma_addr_t unsafe_dma_addr;
-+ dma_addr_t safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+ unsigned long pages;
-+ void *virt_addr;
-+ dma_addr_t dma_addr;
-+ unsigned long *alloc_map;
-+ unsigned long alloc_pos;
-+ spinlock_t lock;
-+ struct device *dev;
-+ unsigned long num_pages;
-+#ifdef STATS
-+ size_t max_size;
-+ unsigned long num_bufs;
-+ unsigned long max_bufs;
-+ unsigned long max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+ struct device *dev;
-+ dma_addr_t threshold;
-+ struct list_head safe_buffers;
-+ struct dmabounce_pool pool;
-+ rwlock_t lock;
-+#ifdef STATS
-+ unsigned long map_count;
-+ unsigned long unmap_count;
-+ unsigned long sync_dev_count;
-+ unsigned long sync_cpu_count;
-+ unsigned long fail_count;
-+ int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+ device_info->map_count,
-+ device_info->unmap_count,
-+ device_info->sync_dev_count,
-+ device_info->sync_cpu_count,
-+ device_info->fail_count,
-+ device_info->pool.max_size,
-+ device_info->pool.num_bufs,
-+ device_info->pool.max_bufs,
-+ device_info->pool.num_pages * PAGE_SIZE,
-+ device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+ unsigned long buffer_size)
-+{
-+ int ret = -ENOMEM;
-+ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+ if (!pool->alloc_map)
-+ goto err_bitmap;
-+ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+ &pool->dma_addr, GFP_KERNEL);
-+ if (!pool->virt_addr)
-+ goto err_dmabuf;
-+
-+ pool->alloc_pos = 0;
-+ spin_lock_init(&pool->lock);
-+ pool->dev = dev;
-+ pool->num_pages = 0;
-+
-+ DO_STATS(pool->max_size = 0);
-+ DO_STATS(pool->num_bufs = 0);
-+ DO_STATS(pool->max_bufs = 0);
-+ DO_STATS(pool->max_pages = 0);
-+
-+ return 0;
-+
-+err_dmabuf:
-+ bitmap_free(pool->alloc_map);
-+err_bitmap:
-+ return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+ pool->dma_addr);
-+
-+ bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+ dma_addr_t *dmaaddrp)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+ DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ pool->alloc_pos, pages, 0);
-+ /* If not found, try from the start */
-+ if (pos >= pool->pages && pool->alloc_pos)
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ 0, pages, 0);
-+
-+ if (pos >= pool->pages) {
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+ return NULL;
-+ }
-+
-+ bitmap_set(pool->alloc_map, pos, pages);
-+ pool->alloc_pos = (pos + pages) % pool->pages;
-+ pool->num_pages += pages;
-+
-+ DO_STATS(pool->num_bufs++);
-+ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+
-+ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+ return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ bitmap_clear(pool->alloc_map, pos, pages);
-+ pool->num_pages -= pages;
-+ if (pool->num_pages == 0)
-+ pool->alloc_pos = 0;
-+ DO_STATS(pool->num_bufs--);
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+ struct dmabounce_pool *pool = &device_info->pool;
-+ struct device *dev = device_info->dev;
-+ unsigned long flags;
-+
-+ /*
-+ * Although one might expect this to be called in thread context,
-+ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+ * was previously used to select the appropriate allocation mode,
-+ * but this is unsafe.
-+ */
-+ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+ if (!buf) {
-+ dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+ return NULL;
-+ }
-+
-+ buf->unsafe_dma_addr = dma_addr;
-+ buf->size = size;
-+ buf->direction = dir;
-+ buf->pool = pool;
-+
-+ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+ if (!buf->safe) {
-+ dev_warn(dev,
-+ "%s: could not alloc dma memory (size=%d)\n",
-+ __func__, size);
-+ kfree(buf);
-+ return NULL;
-+ }
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_add(&buf->node, &device_info->safe_buffers);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t safe_dma_addr)
-+{
-+ struct safe_buffer *b, *rb = NULL;
-+ unsigned long flags;
-+
-+ read_lock_irqsave(&device_info->lock, flags);
-+
-+ list_for_each_entry(b, &device_info->safe_buffers, node)
-+ if (b->safe_dma_addr <= safe_dma_addr &&
-+ b->safe_dma_addr + b->size > safe_dma_addr) {
-+ rb = b;
-+ break;
-+ }
-+
-+ read_unlock_irqrestore(&device_info->lock, flags);
-+ return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+ struct safe_buffer *buf)
-+{
-+ unsigned long flags;
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_del(&buf->node);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ bounce_free(buf->pool, buf->safe, buf->size);
-+
-+ kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+ if (!dev || !g_dmabounce_device_info)
-+ return NULL;
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ dev_err(dev, "Trying to %s invalid mapping\n", where);
-+ return NULL;
-+ }
-+ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+ (u64)buf->safe_dma_addr);
-+
-+ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ size);
-+
-+ return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+ (u64)buf->unsafe_dma_addr);
-+
-+ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ size);
-+ }
-+ return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range. if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ dma_addr_t dma_addr;
-+
-+ dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
-+
-+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+ if (device_info && (dma_addr + size) > device_info->threshold) {
-+ struct safe_buffer *buf;
-+
-+ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+ if (!buf) {
-+ DO_STATS(device_info->fail_count++);
-+ return DMA_MAPPING_ERROR;
-+ }
-+
-+ DO_STATS(device_info->map_count++);
-+
-+ dma_addr = map_single(dev, buf, size, dir, attrs);
-+ }
-+
-+ return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer. (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->unmap_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+ free_safe_buffer(g_dmabounce_device_info, buf);
-+ }
-+
-+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+ map_single(dev, buf, size, dir, 0);
-+ }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+ size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, 0);
-+ }
-+
-+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+ if (g_dmabounce_device_info)
-+ return 0;
-+
-+ return arm_dma_ops.dma_supported(dev, dma_mask);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+ .alloc = arm_dma_alloc,
-+ .free = arm_dma_free,
-+ .mmap = arm_dma_mmap,
-+ .get_sgtable = arm_dma_get_sgtable,
-+ .map_page = dmabounce_map_page,
-+ .unmap_page = dmabounce_unmap_page,
-+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
-+ .sync_single_for_device = dmabounce_sync_for_device,
-+ .map_sg = arm_dma_map_sg,
-+ .unmap_sg = arm_dma_unmap_sg,
-+ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
-+ .sync_sg_for_device = arm_dma_sync_sg_for_device,
-+ .dma_supported = dmabounce_dma_supported,
-+};
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ struct dmabounce_device_info *device_info;
-+ int ret;
-+
-+ /* Only support a single client */
-+ if (g_dmabounce_device_info)
-+ return -EBUSY;
-+
-+ ret = bcm2838_dma40_memcpy_init(dev);
-+ if (ret)
-+ return ret;
-+
-+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+ if (!device_info) {
-+ dev_err(dev,
-+ "Could not allocated dmabounce_device_info\n");
-+ return -ENOMEM;
-+ }
-+
-+ ret = bounce_create(&device_info->pool, dev, buffer_size);
-+ if (ret) {
-+ dev_err(dev,
-+ "dmabounce: could not allocate %ld byte DMA pool\n",
-+ buffer_size);
-+ goto err_bounce;
-+ }
-+
-+ device_info->dev = dev;
-+ device_info->threshold = threshold;
-+ INIT_LIST_HEAD(&device_info->safe_buffers);
-+ rwlock_init(&device_info->lock);
-+
-+ DO_STATS(device_info->map_count = 0);
-+ DO_STATS(device_info->unmap_count = 0);
-+ DO_STATS(device_info->sync_dev_count = 0);
-+ DO_STATS(device_info->sync_cpu_count = 0);
-+ DO_STATS(device_info->fail_count = 0);
-+ DO_STATS(device_info->attr_res =
-+ device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+ g_dmabounce_device_info = device_info;
-+ set_dma_ops(dev, &dmabounce_ops);
-+
-+ dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+ buffer_size / 1024, &threshold);
-+
-+ return 0;
-+
-+ err_bounce:
-+ kfree(device_info);
-+ return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+ g_dmabounce_device_info = NULL;
-+ set_dma_ops(dev, NULL);
-+
-+ if (!device_info) {
-+ dev_warn(dev,
-+ "Never registered with dmabounce but attempting"
-+ "to unregister!\n");
-+ return;
-+ }
-+
-+ if (!list_empty(&device_info->safe_buffers)) {
-+ dev_err(dev,
-+ "Removing from dmabounce with pending buffers!\n");
-+ BUG();
-+ }
-+
-+ bounce_destroy(&device_info->pool);
-+
-+ DO_STATS(if (device_info->attr_res == 0)
-+ device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+ kfree(device_info);
-+
-+ dev_info(dev, "dmabounce: device unregistered\n");
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+
-+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -0,0 +1,32 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ */
-+
-+#ifndef _PCIE_BRCMSTB_BOUNCE_H
-+#define _PCIE_BRCMSTB_BOUNCE_H
-+
-+#ifdef CONFIG_ARM
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
-+ dma_addr_t threshold);
-+
-+int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+
-+#else
-+
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+{
-+ return 0;
-+}
-+
-+#endif
-+
-+#endif /* _PCIE_BRCMSTB_BOUNCE_H */
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -29,6 +29,7 @@
- #include <linux/string.h>
- #include <linux/types.h>
- #include "../pci.h"
-+#include "pcie-brcmstb-bounce.h"
-
- /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
- #define BRCM_PCIE_CAP_REGS 0x00ac
-@@ -53,6 +54,7 @@
- #define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
- #define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
- #define PCIE_MISC_MSI_DATA_CONFIG 0x404c
-+#define PCIE_MISC_EOI_CTRL 0x4060
- #define PCIE_MISC_PCIE_CTRL 0x4064
- #define PCIE_MISC_PCIE_STATUS 0x4068
- #define PCIE_MISC_REVISION 0x406c
-@@ -260,12 +262,14 @@ struct brcm_pcie {
- unsigned int rev;
- const int *reg_offsets;
- const int *reg_field_info;
-+ u32 max_burst_size;
- enum pcie_type type;
- };
-
- struct pcie_cfg_data {
- const int *reg_field_info;
- const int *offsets;
-+ const u32 max_burst_size;
- const enum pcie_type type;
- };
-
-@@ -288,24 +292,27 @@ static const int pcie_offset_bcm7425[] =
- static const struct pcie_cfg_data bcm7425_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offset_bcm7425,
-+ .max_burst_size = BURST_SIZE_256,
- .type = BCM7425,
- };
-
- static const int pcie_offsets[] = {
- [RGR1_SW_INIT_1] = 0x9210,
- [EXT_CFG_INDEX] = 0x9000,
-- [EXT_CFG_DATA] = 0x9004,
-+ [EXT_CFG_DATA] = 0x8000,
- };
-
- static const struct pcie_cfg_data bcm7435_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_256,
- .type = BCM7435,
- };
-
- static const struct pcie_cfg_data generic_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
- .type = GENERIC,
- };
-
-@@ -318,6 +325,7 @@ static const int pcie_offset_bcm7278[] =
- static const struct pcie_cfg_data bcm7278_cfg = {
- .reg_field_info = pcie_reg_field_info_bcm7278,
- .offsets = pcie_offset_bcm7278,
-+ .max_burst_size = BURST_SIZE_512,
- .type = BCM7278,
- };
-
-@@ -360,7 +368,6 @@ static struct pci_ops brcm_pcie_ops = {
- (reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
-
- static const struct dma_map_ops *arch_dma_ops;
--static const struct dma_map_ops *brcm_dma_ops_ptr;
- static struct of_pci_range *dma_ranges;
- static int num_dma_ranges;
-
-@@ -369,6 +376,16 @@ static int num_memc;
- static int num_pcie;
- static DEFINE_MUTEX(brcm_pcie_lock);
-
-+static unsigned int bounce_buffer = 32*1024*1024;
-+module_param(bounce_buffer, uint, 0644);
-+MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
-+
-+static unsigned int bounce_threshold = 0xc0000000;
-+module_param(bounce_threshold, uint, 0644);
-+MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
-+
-+static struct brcm_pcie *g_pcie;
-+
- static dma_addr_t brcm_to_pci(dma_addr_t addr)
- {
- struct of_pci_range *p;
-@@ -457,12 +474,10 @@ static int brcm_map_sg(struct device *de
- struct scatterlist *sg;
-
- for_each_sg(sgl, sg, nents, i) {
--#ifdef CONFIG_NEED_SG_DMA_LENGTH
-- sg->dma_length = sg->length;
--#endif
-+ sg_dma_len(sg) = sg->length;
- sg->dma_address =
-- brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
-- sg->length, dir, attrs);
-+ brcm_map_page(dev, sg_page(sg), sg->offset,
-+ sg->length, dir, attrs);
- if (dma_mapping_error(dev, sg->dma_address))
- goto bad_mapping;
- }
-@@ -470,8 +485,8 @@ static int brcm_map_sg(struct device *de
-
- bad_mapping:
- for_each_sg(sgl, sg, i, j)
-- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-- sg_dma_len(sg), dir, attrs);
-+ brcm_unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
- return 0;
- }
-
-@@ -484,8 +499,8 @@ static void brcm_unmap_sg(struct device
- struct scatterlist *sg;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
-- sg_dma_len(sg), dir, attrs);
-+ brcm_unmap_page(dev, sg_dma_address(sg),
-+ sg_dma_len(sg), dir, attrs);
- }
-
- static void brcm_sync_single_for_cpu(struct device *dev,
-@@ -531,8 +546,8 @@ void brcm_sync_sg_for_cpu(struct device
- int i;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
-- sg->length, dir);
-+ brcm_sync_single_for_cpu(dev, sg_dma_address(sg),
-+ sg->length, dir);
- }
-
- void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
-@@ -542,14 +557,9 @@ void brcm_sync_sg_for_device(struct devi
- int i;
-
- for_each_sg(sgl, sg, nents, i)
-- brcm_dma_ops_ptr->sync_single_for_device(dev,
-- sg_dma_address(sg),
-- sg->length, dir);
--}
--
--static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
--{
-- return arch_dma_ops->mapping_error(dev, dma_addr);
-+ brcm_sync_single_for_device(dev,
-+ sg_dma_address(sg),
-+ sg->length, dir);
- }
-
- static int brcm_dma_supported(struct device *dev, u64 mask)
-@@ -572,7 +582,7 @@ static int brcm_dma_supported(struct dev
- }
-
- #ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
--u64 brcm_get_required_mask)(struct device *dev)
-+u64 brcm_get_required_mask(struct device *dev)
- {
- return arch_dma_ops->get_required_mask(dev);
- }
-@@ -593,7 +603,6 @@ static const struct dma_map_ops brcm_dma
- .sync_single_for_device = brcm_sync_single_for_device,
- .sync_sg_for_cpu = brcm_sync_sg_for_cpu,
- .sync_sg_for_device = brcm_sync_sg_for_device,
-- .mapping_error = brcm_mapping_error,
- .dma_supported = brcm_dma_supported,
- #ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
- .get_required_mask = brcm_get_required_mask,
-@@ -633,17 +642,47 @@ static void brcm_set_dma_ops(struct devi
- set_dma_ops(dev, &brcm_dma_ops);
- }
-
-+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
-+ unsigned int val);
- static int brcmstb_platform_notifier(struct notifier_block *nb,
- unsigned long event, void *__dev)
- {
-+ extern unsigned long max_pfn;
- struct device *dev = __dev;
-+ const char *rc_name = "0000:00:00.0";
-
-- brcm_dma_ops_ptr = &brcm_dma_ops;
-- if (event != BUS_NOTIFY_ADD_DEVICE)
-- return NOTIFY_DONE;
-+ switch (event) {
-+ case BUS_NOTIFY_ADD_DEVICE:
-+ if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
-+ strcmp(dev->kobj.name, rc_name)) {
-+ int ret;
-+
-+ ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
-+ (dma_addr_t)bounce_threshold);
-+ if (ret) {
-+ dev_err(dev,
-+ "brcm_pcie_bounce_register_dev() failed: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+ brcm_set_dma_ops(dev);
-+ return NOTIFY_OK;
-
-- brcm_set_dma_ops(dev);
-- return NOTIFY_OK;
-+ case BUS_NOTIFY_DEL_DEVICE:
-+ if (!strcmp(dev->kobj.name, rc_name) && g_pcie) {
-+ /* Force a bus reset */
-+ brcm_pcie_perst_set(g_pcie, 1);
-+ msleep(100);
-+ brcm_pcie_perst_set(g_pcie, 0);
-+ } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ brcm_pcie_bounce_unregister_dev(dev);
-+ }
-+ return NOTIFY_OK;
-+
-+ default:
-+ return NOTIFY_DONE;
-+ }
- }
-
- static struct notifier_block brcmstb_platform_nb = {
-@@ -914,6 +953,7 @@ static void brcm_pcie_msi_isr(struct irq
- }
- }
- chained_irq_exit(chip, desc);
-+ bcm_writel(1, msi->base + PCIE_MISC_EOI_CTRL);
- }
-
- static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-@@ -930,7 +970,8 @@ static void brcm_compose_msi_msg(struct
- static int brcm_msi_set_affinity(struct irq_data *irq_data,
- const struct cpumask *mask, bool force)
- {
-- return -EINVAL;
-+ struct brcm_msi *msi = irq_data_get_irq_chip_data(irq_data);
-+ return __irq_set_affinity(msi->irq, mask, force);
- }
-
- static struct irq_chip brcm_msi_bottom_irq_chip = {
-@@ -1168,9 +1209,9 @@ static void __iomem *brcm_pcie_map_conf(
- return PCI_SLOT(devfn) ? NULL : base + where;
-
- /* For devices, write to the config space index register */
-- idx = cfg_index(bus->number, devfn, where);
-+ idx = cfg_index(bus->number, devfn, 0);
- bcm_writel(idx, pcie->base + IDX_ADDR(pcie));
-- return base + DATA_ADDR(pcie) + (where & 0x3);
-+ return base + DATA_ADDR(pcie) + where;
- }
-
- static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie,
-@@ -1238,20 +1279,6 @@ static int brcm_pcie_parse_map_dma_range
- num_dma_ranges++;
- }
-
-- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-- u64 size = brcmstb_memory_memc_size(i);
--
-- if (size == (u64)-1) {
-- dev_err(pcie->dev, "cannot get memc%d size", i);
-- return -EINVAL;
-- } else if (size) {
-- scb_size[i] = roundup_pow_of_two_64(size);
-- num_memc++;
-- } else {
-- break;
-- }
-- }
--
- return 0;
- }
-
-@@ -1275,26 +1302,25 @@ static int brcm_pcie_add_controller(stru
- if (ret)
- goto done;
-
-- /* Determine num_memc and their sizes */
-- for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-- u64 size = brcmstb_memory_memc_size(i);
--
-- if (size == (u64)-1) {
-- dev_err(dev, "cannot get memc%d size\n", i);
-- ret = -EINVAL;
-- goto done;
-- } else if (size) {
-- scb_size[i] = roundup_pow_of_two_64(size);
-- num_memc++;
-- } else {
-- break;
-+ if (!num_dma_ranges) {
-+ /* Determine num_memc and their sizes by other means */
-+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
-+ u64 size = brcmstb_memory_memc_size(i);
-+
-+ if (size == (u64)-1) {
-+ dev_err(dev, "cannot get memc%d size\n", i);
-+ ret = -EINVAL;
-+ goto done;
-+ } else if (size) {
-+ scb_size[i] = roundup_pow_of_two_64(size);
-+ } else {
-+ break;
-+ }
- }
-- }
-- if (!ret && num_memc == 0) {
-- ret = -EINVAL;
-- goto done;
-+ num_memc = i;
- }
-
-+ g_pcie = pcie;
- num_pcie++;
- done:
- mutex_unlock(&brcm_pcie_lock);
-@@ -1307,6 +1333,7 @@ static void brcm_pcie_remove_controller(
- if (--num_pcie > 0)
- goto out;
-
-+ g_pcie = NULL;
- if (brcm_unregister_notifier())
- dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
- kfree(dma_ranges);
-@@ -1367,7 +1394,7 @@ static int brcm_pcie_setup(struct brcm_p
- void __iomem *base = pcie->base;
- unsigned int scb_size_val;
- u64 rc_bar2_offset, rc_bar2_size, total_mem_size = 0;
-- u32 tmp, burst;
-+ u32 tmp;
- int i, j, ret, limit;
- u16 nlw, cls, lnksta;
- bool ssc_good = false;
-@@ -1400,20 +1427,15 @@ static int brcm_pcie_setup(struct brcm_p
- /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
- tmp = INSERT_FIELD(0, PCIE_MISC_MISC_CTRL, SCB_ACCESS_EN, 1);
- tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, CFG_READ_UR_MODE, 1);
-- burst = (pcie->type == GENERIC || pcie->type == BCM7278)
-- ? BURST_SIZE_512 : BURST_SIZE_256;
-- tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE, burst);
-+ tmp = INSERT_FIELD(tmp, PCIE_MISC_MISC_CTRL, MAX_BURST_SIZE,
-+ pcie->max_burst_size);
- bcm_writel(tmp, base + PCIE_MISC_MISC_CTRL);
-
- /*
- * Set up inbound memory view for the EP (called RC_BAR2,
- * not to be confused with the BARs that are advertised by
- * the EP).
-- */
-- for (i = 0; i < num_memc; i++)
-- total_mem_size += scb_size[i];
--
-- /*
-+ *
- * The PCIe host controller by design must set the inbound
- * viewport to be a contiguous arrangement of all of the
- * system's memory. In addition, its size mut be a power of
-@@ -1429,55 +1451,49 @@ static int brcm_pcie_setup(struct brcm_p
- * the controller will know to send outbound memory downstream
- * and everything else upstream.
- */
-- rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- if (dma_ranges) {
-+ if (num_dma_ranges) {
- /*
-- * The best-case scenario is to place the inbound
-- * region in the first 4GB of pcie-space, as some
-- * legacy devices can only address 32bits.
-- * We would also like to put the MSI under 4GB
-- * as well, since some devices require a 32bit
-- * MSI target address.
-+ * Use the base address and size(s) provided in the dma-ranges
-+ * property.
- */
-- if (total_mem_size <= 0xc0000000ULL &&
-- rc_bar2_size <= 0x100000000ULL) {
-- rc_bar2_offset = 0;
-- /* If the viewport is less then 4GB we can fit
-- * the MSI target address under 4GB. Otherwise
-- * put it right below 64GB.
-- */
-- msi_target_addr =
-- (rc_bar2_size == 0x100000000ULL)
-- ? BRCM_MSI_TARGET_ADDR_GT_4GB
-- : BRCM_MSI_TARGET_ADDR_LT_4GB;
-- } else {
-- /*
-- * The system memory is 4GB or larger so we
-- * cannot start the inbound region at location
-- * 0 (since we have to allow some space for
-- * outbound memory @ 3GB). So instead we
-- * start it at the 1x multiple of its size
-- */
-- rc_bar2_offset = rc_bar2_size;
--
-- /* Since we are starting the viewport at 4GB or
-- * higher, put the MSI target address below 4GB
-- */
-- msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-- }
-- } else {
-+ for (i = 0; i < num_dma_ranges; i++)
-+ scb_size[i] = roundup_pow_of_two_64(dma_ranges[i].size);
-+
-+ num_memc = num_dma_ranges;
-+ rc_bar2_offset = dma_ranges[0].pci_addr;
-+ } else if (num_memc) {
- /*
- * Set simple configuration based on memory sizes
-- * only. We always start the viewport at address 0,
-- * and set the MSI target address accordingly.
-+ * only. We always start the viewport at address 0.
- */
- rc_bar2_offset = 0;
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < num_memc; i++)
-+ total_mem_size += scb_size[i];
-+
-+ rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
-
-- msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
-- ? BRCM_MSI_TARGET_ADDR_GT_4GB
-- : BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ /* Verify the alignment is correct */
-+ if (rc_bar2_offset & (rc_bar2_size - 1)) {
-+ dev_err(dev, "inbound window is misaligned\n");
-+ return -EINVAL;
- }
-+
-+ /*
-+ * Position the MSI target low if possible.
-+ *
-+ * TO DO: Consider outbound window when choosing MSI target and
-+ * verifying configuration.
-+ */
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
-+ if (rc_bar2_offset <= msi_target_addr &&
-+ rc_bar2_offset + rc_bar2_size > msi_target_addr)
-+ msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
-+
- pcie->msi_target_addr = msi_target_addr;
-
- tmp = lower_32_bits(rc_bar2_offset);
-@@ -1713,6 +1729,7 @@ static int brcm_pcie_probe(struct platfo
- data = of_id->data;
- pcie->reg_offsets = data->offsets;
- pcie->reg_field_info = data->reg_field_info;
-+ pcie->max_burst_size = data->max_burst_size;
- pcie->type = data->type;
- pcie->dn = dn;
- pcie->dev = &pdev->dev;
-@@ -1732,7 +1749,7 @@ static int brcm_pcie_probe(struct platfo
-
- pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
- if (IS_ERR(pcie->clk)) {
-- dev_err(&pdev->dev, "could not get clock\n");
-+ dev_warn(&pdev->dev, "could not get clock\n");
- pcie->clk = NULL;
- }
- pcie->base = base;
-@@ -1755,7 +1772,8 @@ static int brcm_pcie_probe(struct platfo
-
- ret = clk_prepare_enable(pcie->clk);
- if (ret) {
-- dev_err(&pdev->dev, "could not enable clock\n");
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev, "could not enable clock\n");
- return ret;
- }
-
-@@ -1818,7 +1836,6 @@ static struct platform_driver brcm_pcie_
- .remove = brcm_pcie_remove,
- .driver = {
- .name = "brcm-pcie",
-- .owner = THIS_MODULE,
- .of_match_table = brcm_pcie_match,
- .pm = &brcm_pcie_pm_ops,
- },
---- a/drivers/soc/bcm/brcmstb/Makefile
-+++ b/drivers/soc/bcm/brcmstb/Makefile
-@@ -1,3 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0-only
--obj-y += common.o biuctrl.o
-+obj-y += common.o biuctrl.o memory.o
- obj-$(CONFIG_BRCMSTB_PM) += pm/
---- /dev/null
-+++ b/drivers/soc/bcm/brcmstb/memory.c
-@@ -0,0 +1,158 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* Copyright © 2015-2017 Broadcom */
-+
-+#include <linux/device.h>
-+#include <linux/io.h>
-+#include <linux/libfdt.h>
-+#include <linux/of_address.h>
-+#include <linux/of_fdt.h>
-+#include <linux/sizes.h>
-+#include <soc/brcmstb/memory_api.h>
-+
-+/* Macro to help extract property data */
-+#define DT_PROP_DATA_TO_U32(b, offs) (fdt32_to_cpu(*(u32 *)(b + offs)))
-+
-+/* Constants used when retrieving memc info */
-+#define NUM_BUS_RANGES 10
-+#define BUS_RANGE_ULIMIT_SHIFT 4
-+#define BUS_RANGE_LLIMIT_SHIFT 4
-+#define BUS_RANGE_PA_SHIFT 12
-+
-+enum {
-+ BUSNUM_MCP0 = 0x4,
-+ BUSNUM_MCP1 = 0x5,
-+ BUSNUM_MCP2 = 0x6,
-+};
-+
-+/*
-+ * If the DT nodes are handy, determine which MEMC holds the specified
-+ * physical address.
-+ */
-+#ifdef CONFIG_ARCH_BRCMSTB
-+int __brcmstb_memory_phys_addr_to_memc(phys_addr_t pa, void __iomem *base)
-+{
-+ int memc = -1;
-+ int i;
-+
-+ for (i = 0; i < NUM_BUS_RANGES; i++, base += 8) {
-+ const u64 ulimit_raw = readl(base);
-+ const u64 llimit_raw = readl(base + 4);
-+ const u64 ulimit =
-+ ((ulimit_raw >> BUS_RANGE_ULIMIT_SHIFT)
-+ << BUS_RANGE_PA_SHIFT) | 0xfff;
-+ const u64 llimit = (llimit_raw >> BUS_RANGE_LLIMIT_SHIFT)
-+ << BUS_RANGE_PA_SHIFT;
-+ const u32 busnum = (u32)(ulimit_raw & 0xf);
-+
-+ if (pa >= llimit && pa <= ulimit) {
-+ if (busnum >= BUSNUM_MCP0 && busnum <= BUSNUM_MCP2) {
-+ memc = busnum - BUSNUM_MCP0;
-+ break;
-+ }
-+ }
-+ }
-+
-+ return memc;
-+}
-+
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ int memc = -1;
-+ struct device_node *np;
-+ void __iomem *cpubiuctrl;
-+
-+ np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
-+ if (!np)
-+ return memc;
-+
-+ cpubiuctrl = of_iomap(np, 0);
-+ if (!cpubiuctrl)
-+ goto cleanup;
-+
-+ memc = __brcmstb_memory_phys_addr_to_memc(pa, cpubiuctrl);
-+ iounmap(cpubiuctrl);
-+
-+cleanup:
-+ of_node_put(np);
-+
-+ return memc;
-+}
-+
-+#elif defined(CONFIG_MIPS)
-+int brcmstb_memory_phys_addr_to_memc(phys_addr_t pa)
-+{
-+ /* The logic here is fairly simple and hardcoded: if pa <= 0x5000_0000,
-+ * then this is MEMC0, else MEMC1.
-+ *
-+ * For systems with 2GB on MEMC0, MEMC1 starts at 9000_0000, with 1GB
-+ * on MEMC0, MEMC1 starts at 6000_0000.
-+ */
-+ if (pa >= 0x50000000ULL)
-+ return 1;
-+ else
-+ return 0;
-+}
-+#endif
-+
-+u64 brcmstb_memory_memc_size(int memc)
-+{
-+ const void *fdt = initial_boot_params;
-+ const int mem_offset = fdt_path_offset(fdt, "/memory");
-+ int addr_cells = 1, size_cells = 1;
-+ const struct fdt_property *prop;
-+ int proplen, cellslen;
-+ u64 memc_size = 0;
-+ int i;
-+
-+ /* Get root size and address cells if specified */
-+ prop = fdt_get_property(fdt, 0, "#size-cells", &proplen);
-+ if (prop)
-+ size_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+ prop = fdt_get_property(fdt, 0, "#address-cells", &proplen);
-+ if (prop)
-+ addr_cells = DT_PROP_DATA_TO_U32(prop->data, 0);
-+
-+ if (mem_offset < 0)
-+ return -1;
-+
-+ prop = fdt_get_property(fdt, mem_offset, "reg", &proplen);
-+ cellslen = (int)sizeof(u32) * (addr_cells + size_cells);
-+ if ((proplen % cellslen) != 0)
-+ return -1;
-+
-+ for (i = 0; i < proplen / cellslen; ++i) {
-+ u64 addr = 0;
-+ u64 size = 0;
-+ int memc_idx;
-+ int j;
-+
-+ for (j = 0; j < addr_cells; ++j) {
-+ int offset = (cellslen * i) + (sizeof(u32) * j);
-+
-+ addr |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+ ((addr_cells - j - 1) * 32);
-+ }
-+ for (j = 0; j < size_cells; ++j) {
-+ int offset = (cellslen * i) +
-+ (sizeof(u32) * (j + addr_cells));
-+
-+ size |= (u64)DT_PROP_DATA_TO_U32(prop->data, offset) <<
-+ ((size_cells - j - 1) * 32);
-+ }
-+
-+ if ((phys_addr_t)addr != addr) {
-+ pr_err("phys_addr_t is smaller than provided address 0x%llx!\n",
-+ addr);
-+ return -1;
-+ }
-+
-+ memc_idx = brcmstb_memory_phys_addr_to_memc((phys_addr_t)addr);
-+ if (memc_idx == memc)
-+ memc_size += size;
-+ }
-+
-+ return memc_size;
-+}
-+EXPORT_SYMBOL_GPL(brcmstb_memory_memc_size);
-+
--- /dev/null
+From 2cba27bce0470a06237b3bd7883d43ade0d5c39c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 1 Nov 2018 17:31:37 +0000
+Subject: [PATCH] vchiq: Add 36-bit address support
+
+Conditional on a new compatible string, change the pagelist encoding
+such that the top 24 bits are the pfn, leaving 8 bits for run length
+(-1).
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++-----
+ .../interface/vchiq_arm/vchiq_arm.c | 6 ++
+ .../interface/vchiq_arm/vchiq_arm.h | 1 +
+ 3 files changed, 75 insertions(+), 22 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+@@ -16,6 +16,8 @@
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
++#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x))
++#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1)
+
+ #include "vchiq_arm.h"
+ #include "vchiq_connected.h"
+@@ -63,6 +65,7 @@ static void __iomem *g_regs;
+ */
+ static unsigned int g_cache_line_size = 32;
+ static struct dma_pool *g_dma_pool;
++static unsigned int g_use_36bit_addrs = 0;
+ static unsigned int g_fragments_size;
+ static char *g_fragments_base;
+ static char *g_free_fragments;
+@@ -106,6 +109,8 @@ int vchiq_platform_init(struct platform_
+ g_cache_line_size = drvdata->cache_line_size;
+ g_fragments_size = 2 * g_cache_line_size;
+
++ g_use_36bit_addrs = (dev->dma_pfn_offset == 0);
++
+ /* Allocate space for the channels in coherent memory */
+ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
+ frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
+@@ -117,14 +122,21 @@ int vchiq_platform_init(struct platform_
+ return -ENOMEM;
+ }
+
++ if (!IS_VC_SAFE(slot_phys)) {
++ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n",
++ &slot_phys);
++ return -ENOMEM;
++ }
++
+ WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0);
++ channelbase = VC_SAFE(slot_phys);
+
+ vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
+ if (!vchiq_slot_zero)
+ return -EINVAL;
+
+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
+- (int)slot_phys + slot_mem_size;
++ channelbase + slot_mem_size;
+ vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
+ MAX_FRAGMENTS;
+
+@@ -158,7 +170,6 @@ int vchiq_platform_init(struct platform_
+ }
+
+ /* Send the base address of the slots to VideoCore */
+- channelbase = slot_phys;
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
+ &channelbase, sizeof(channelbase));
+ if (err || channelbase) {
+@@ -244,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul
+ if (!pagelistinfo)
+ return VCHIQ_ERROR;
+
+- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr;
++ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
+
+ /*
+ * Store the pagelistinfo address in remote_data,
+@@ -522,25 +533,60 @@ create_pagelist(char __user *buf, size_t
+
+ /* Combine adjacent blocks for performance */
+ k = 0;
+- for_each_sg(scatterlist, sg, dma_buffers, i) {
+- u32 len = sg_dma_len(sg);
+- u32 addr = sg_dma_address(sg);
+-
+- /* Note: addrs is the address + page_count - 1
+- * The firmware expects blocks after the first to be page-
+- * aligned and a multiple of the page size
+- */
+- WARN_ON(len == 0);
+- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
+- WARN_ON(i && (addr & ~PAGE_MASK));
+- if (k > 0 &&
+- ((addrs[k - 1] & PAGE_MASK) +
+- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
+- == (addr & PAGE_MASK))
+- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
+- else
+- addrs[k++] = (addr & PAGE_MASK) |
+- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
++ if (g_use_36bit_addrs) {
++ for_each_sg(scatterlist, sg, dma_buffers, i) {
++ u32 len = sg_dma_len(sg);
++ u64 addr = sg_dma_address(sg);
++ u32 page_id = (u32)((addr >> 4) & ~0xff);
++ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++
++ /* Note: addrs is the address + page_count - 1
++ * The firmware expects blocks after the first to be page-
++ * aligned and a multiple of the page size
++ */
++ WARN_ON(len == 0);
++ WARN_ON(i &&
++ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
++ WARN_ON(i && (addr & ~PAGE_MASK));
++ WARN_ON(upper_32_bits(addr) > 0xf);
++ if (k > 0 &&
++ ((addrs[k - 1] & ~0xff) +
++ (((addrs[k - 1] & 0xff) + 1) << 8)
++ == page_id)) {
++ u32 inc_pages = min(sg_pages,
++ 0xff - (addrs[k - 1] & 0xff));
++ addrs[k - 1] += inc_pages;
++ page_id += inc_pages << 8;
++ sg_pages -= inc_pages;
++ }
++ while (sg_pages) {
++ u32 inc_pages = min(sg_pages, 0x100u);
++ addrs[k++] = page_id | (inc_pages - 1);
++ page_id += inc_pages << 8;
++ sg_pages -= inc_pages;
++ }
++ }
++ } else {
++ for_each_sg(scatterlist, sg, dma_buffers, i) {
++ u32 len = sg_dma_len(sg);
++ u32 addr = VC_SAFE(sg_dma_address(sg));
++ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++
++ /* Note: addrs is the address + page_count - 1
++ * The firmware expects blocks after the first to be page-
++ * aligned and a multiple of the page size
++ */
++ WARN_ON(len == 0);
++ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
++ WARN_ON(i && (addr & ~PAGE_MASK));
++ if (k > 0 &&
++ ((addrs[k - 1] & PAGE_MASK) +
++ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
++ == (addr & PAGE_MASK))
++ addrs[k - 1] += new_pages;
++ else
++ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1);
++ }
+ }
+
+ /* Partial cache lines (fragments) require special measures */
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -149,6 +149,11 @@ static struct vchiq_drvdata bcm2836_drvd
+ .cache_line_size = 64,
+ };
+
++static struct vchiq_drvdata bcm2838_drvdata = {
++ .cache_line_size = 64,
++ .use_36bit_addrs = true,
++};
++
+ static const char *const ioctl_names[] = {
+ "CONNECT",
+ "SHUTDOWN",
+@@ -3164,6 +3169,7 @@ void vchiq_platform_conn_state_changed(s
+ static const struct of_device_id vchiq_of_match[] = {
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
++ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, vchiq_of_match);
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+@@ -97,6 +97,7 @@ struct vchiq_arm_state {
+
+ struct vchiq_drvdata {
+ const unsigned int cache_line_size;
++ const bool use_36bit_addrs;
+ struct rpi_firmware *fw;
+ };
+
+++ /dev/null
-From 67b31f71da2c251860dc6ddeffc5d15f8a74c675 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 29 May 2019 15:47:42 +0100
-Subject: [PATCH] arm: bcm2835: DMA can only address 1GB
-
-The legacy peripherals can only address the first gigabyte of RAM, so
-ensure that DMA allocations are restricted to that region.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/mach-bcm/board_bcm2835.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -114,6 +114,9 @@ static const char * const bcm2835_compat
- };
-
- DT_MACHINE_START(BCM2835, "BCM2835")
-+#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
-+ .dma_zone_size = SZ_1G,
-+#endif
- .map_io = bcm2835_map_io,
- .init_machine = bcm2835_init,
- .dt_compat = bcm2835_compat,
--- /dev/null
+From c76427651677c03c9611b20b914ab2a2ea173522 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 30 Apr 2019 19:15:30 +0100
+Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio
+
+---
+ .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+ .rate_min = 8000,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_APPLPTR),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+- SNDRV_PCM_RATE_48000,
++ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .rate_min = 44100,
+- .rate_max = 48000,
++ .rate_max = 192000,
+ .channels_min = 2,
+- .channels_max = 2,
+- .buffer_bytes_max = 128 * 1024,
++ .channels_max = 8,
++ .buffer_bytes_max = 512 * 1024,
+ .period_bytes_min = 1 * 1024,
+- .period_bytes_max = 128 * 1024,
++ .period_bytes_max = 512 * 1024,
+ .periods_min = 1,
+ .periods_max = 128,
+ };
--- /dev/null
+From f4d211891064eef8b133838c213485a228ad75f3 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Wed, 12 Sep 2018 14:44:53 +0100
+Subject: [PATCH] bcmgenet: constrain max DMA burst length
+
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+@@ -28,7 +28,7 @@
+ #define ENET_PAD 8
+ #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
+ ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+-#define DMA_MAX_BURST_LENGTH 0x10
++#define DMA_MAX_BURST_LENGTH 0x08
+
+ /* misc. configuration */
+ #define CLEAR_ALL_HFB 0xFF
+++ /dev/null
-From cbf5cde9c460eae458829a7b357cea6734c4755b Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Sat, 4 May 2019 17:06:15 +0200
-Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support
-
-The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the
-support to this driver instead of bcm2835-rng.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- drivers/char/hw_random/Kconfig | 4 +-
- drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++--
- 2 files changed, 79 insertions(+), 6 deletions(-)
-
---- a/drivers/char/hw_random/Kconfig
-+++ b/drivers/char/hw_random/Kconfig
-@@ -90,11 +90,11 @@ config HW_RANDOM_BCM2835
-
- config HW_RANDOM_IPROC_RNG200
- tristate "Broadcom iProc/STB RNG200 support"
-- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB
-+ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB
- default HW_RANDOM
- ---help---
- This driver provides kernel-side support for the RNG200
-- hardware found on the Broadcom iProc and STB SoCs.
-+ hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
-
- To compile this driver as a module, choose M here: the
- module will be called iproc-rng200
---- a/drivers/char/hw_random/iproc-rng200.c
-+++ b/drivers/char/hw_random/iproc-rng200.c
-@@ -29,6 +29,7 @@
- #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
- #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
- #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000
-+#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13
-
- #define RNG_SOFT_RESET_OFFSET 0x04
- #define RNG_SOFT_RESET 0x00000001
-@@ -36,16 +37,23 @@
- #define RBG_SOFT_RESET_OFFSET 0x08
- #define RBG_SOFT_RESET 0x00000001
-
-+#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C
-+
-+#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10
-+
- #define RNG_INT_STATUS_OFFSET 0x18
- #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000
- #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000
- #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020
- #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001
-
-+#define RNG_INT_ENABLE_OFFSET 0x1C
-+
- #define RNG_FIFO_DATA_OFFSET 0x20
-
- #define RNG_FIFO_COUNT_OFFSET 0x24
- #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF
-+#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8
-
- struct iproc_rng200_dev {
- struct hwrng rng;
-@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn
- return 0;
- }
-
-+static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
-+ bool wait)
-+{
-+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
-+ u32 max_words = max / sizeof(u32);
-+ u32 num_words, count, val;
-+
-+ /* ensure warm up period has elapsed */
-+ while (1) {
-+ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET);
-+ if (val > 16)
-+ break;
-+ cpu_relax();
-+ }
-+
-+ /* ensure fifo is not empty */
-+ while (1) {
-+ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) &
-+ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK;
-+ if (num_words)
-+ break;
-+ if (!wait)
-+ return 0;
-+ cpu_relax();
-+ }
-+
-+ if (num_words > max_words)
-+ num_words = max_words;
-+
-+ for (count = 0; count < num_words; count++) {
-+ ((u32 *)buf)[count] = ioread32(priv->base +
-+ RNG_FIFO_DATA_OFFSET);
-+ }
-+
-+ return num_words * sizeof(u32);
-+}
-+
-+static int bcm2838_rng200_init(struct hwrng *rng)
-+{
-+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
-+ uint32_t val;
-+
-+ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK)
-+ return 0;
-+
-+ /* initial numbers generated are "less random" so will be discarded */
-+ val = 0x40000;
-+ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET);
-+ /* min fifo count to generate full interrupt */
-+ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT;
-+ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET);
-+ /* enable the rng - 1Mhz sample rate */
-+ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK;
-+ iowrite32(val, priv->base + RNG_CTRL_OFFSET);
-+
-+ return 0;
-+}
-+
- static void iproc_rng200_cleanup(struct hwrng *rng)
- {
- struct iproc_rng200_dev *priv = to_rng_priv(rng);
-@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla
- return PTR_ERR(priv->base);
- }
-
-- priv->rng.name = "iproc-rng200",
-- priv->rng.read = iproc_rng200_read,
-- priv->rng.init = iproc_rng200_init,
-- priv->rng.cleanup = iproc_rng200_cleanup,
-+ priv->rng.name = pdev->name;
-+ priv->rng.cleanup = iproc_rng200_cleanup;
-+
-+ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
-+ priv->rng.init = bcm2838_rng200_init;
-+ priv->rng.read = bcm2838_rng200_read;
-+ } else {
-+ priv->rng.init = iproc_rng200_init;
-+ priv->rng.read = iproc_rng200_read;
-+ }
-
- /* Register driver */
- ret = devm_hwrng_register(dev, &priv->rng);
-@@ -223,6 +295,7 @@ static const struct of_device_id iproc_r
- { .compatible = "brcm,bcm7211-rng200", },
- { .compatible = "brcm,bcm7278-rng200", },
- { .compatible = "brcm,iproc-rng200", },
-+ { .compatible = "brcm,bcm2838-rng200"},
- {},
- };
- MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
--- /dev/null
+From b3344ca9ef887c4004c61be39f7d8d058a569d4d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 27 Mar 2019 13:45:46 +0000
+Subject: [PATCH] bcmgenet: Better coalescing parameter defaults
+
+Set defaults for TX and RX packet coalescing to be equivalent to:
+
+ # ethtool -C eth0 tx-frames 10
+ # ethtool -C eth0 rx-usecs 50
+
+This may be something we want to set via DT parameters in the
+future.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -2145,7 +2145,7 @@ static void bcmgenet_init_tx_ring(struct
+
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
+ bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
+- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
++ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
+ /* Disable rate control for now */
+ bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
+ TDMA_FLOW_PERIOD);
+@@ -3567,9 +3567,12 @@ static int bcmgenet_probe(struct platfor
+ netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
+
+ /* Set default coalescing parameters */
+- for (i = 0; i < priv->hw_params->rx_queues; i++)
++ for (i = 0; i < priv->hw_params->rx_queues; i++) {
+ priv->rx_rings[i].rx_max_coalesced_frames = 1;
++ priv->rx_rings[i].rx_coalesce_usecs = 50;
++ }
+ priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
++ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
+
+ /* libphy will determine the link state */
+ netif_carrier_off(dev);
+++ /dev/null
-From d1066d775e67c33cc93178475c4485c5ef0a83c9 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Sat, 18 May 2019 12:26:11 +0200
-Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support
-
-The BCM2838 has an AVS TMON hardware block. This adds the necessary
-support to the brcmstb_thermal driver ( no trip handling ).
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- drivers/thermal/broadcom/Kconfig | 2 +-
- drivers/thermal/broadcom/brcmstb_thermal.c | 61 +++++++++++++++++++---
- 2 files changed, 54 insertions(+), 9 deletions(-)
-
---- a/drivers/thermal/broadcom/Kconfig
-+++ b/drivers/thermal/broadcom/Kconfig
-@@ -9,7 +9,7 @@ config BCM2835_THERMAL
-
- config BRCMSTB_THERMAL
- tristate "Broadcom STB AVS TMON thermal driver"
-- depends on ARCH_BRCMSTB || COMPILE_TEST
-+ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
- help
- Enable this driver if you have a Broadcom STB SoC and would like
- thermal framework support.
---- a/drivers/thermal/broadcom/brcmstb_thermal.c
-+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
-@@ -10,6 +10,7 @@
- #define pr_fmt(fmt) DRV_NAME ": " fmt
-
- #include <linux/bitops.h>
-+#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/err.h>
- #include <linux/io.h>
-@@ -22,9 +23,6 @@
- #include <linux/thermal.h>
-
- #define AVS_TMON_STATUS 0x00
-- #define AVS_TMON_STATUS_valid_msk BIT(11)
-- #define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
-- #define AVS_TMON_STATUS_data_shift 1
-
- #define AVS_TMON_EN_OVERTEMP_RESET 0x04
- #define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
-@@ -102,10 +100,19 @@ static struct avs_tmon_trip avs_tmon_tri
- },
- };
-
-+struct brcmstb_thermal_of_data {
-+ const struct thermal_zone_of_device_ops *of_ops;
-+ u32 status_valid_mask;
-+ u32 status_data_mask;
-+ u32 status_data_shift;
-+};
-+
- struct brcmstb_thermal_priv {
- void __iomem *tmon_base;
- struct device *dev;
- struct thermal_zone_device *thermal;
-+ struct clk *clk;
-+ const struct brcmstb_thermal_of_data *socdata;
- };
-
- /* Convert a HW code to a temperature reading (millidegree celsius) */
-@@ -142,17 +149,18 @@ static inline u32 avs_tmon_temp_to_code(
- static int brcmstb_get_temp(void *data, int *temp)
- {
- struct brcmstb_thermal_priv *priv = data;
-+ const struct brcmstb_thermal_of_data *socdata = priv->socdata;
- u32 val;
- long t;
-
- val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
-
-- if (!(val & AVS_TMON_STATUS_valid_msk)) {
-+ if (!(val & socdata->status_valid_mask)) {
- dev_err(priv->dev, "reading not valid\n");
- return -EIO;
- }
-
-- val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
-+ val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
-
- t = avs_tmon_code_to_temp(priv->thermal, val);
- if (t < 0)
-@@ -277,13 +285,34 @@ static int brcmstb_set_trips(void *data,
- return 0;
- }
-
--static const struct thermal_zone_of_device_ops of_ops = {
-+static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
- .get_temp = brcmstb_get_temp,
- .set_trips = brcmstb_set_trips,
- };
-
-+static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
-+ .get_temp = brcmstb_get_temp,
-+};
-+
-+static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
-+ .of_ops = &bcm7445_thermal_of_ops,
-+ .status_valid_mask = BIT(11),
-+ .status_data_mask = GENMASK(10, 1),
-+ .status_data_shift = 1,
-+};
-+
-+static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
-+ .of_ops = &bcm2838_thermal_of_ops,
-+ .status_valid_mask = BIT(10),
-+ .status_data_mask = GENMASK(9, 0),
-+ .status_data_shift = 0,
-+};
-+
- static const struct of_device_id brcmstb_thermal_id_table[] = {
-- { .compatible = "brcm,avs-tmon" },
-+ { .compatible = "brcm,avs-tmon",
-+ .data = &bcm7445_thermal_of_data },
-+ { .compatible = "brcm,avs-tmon-bcm2838",
-+ .data = &bcm2838_thermal_of_data },
- {},
- };
- MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
-@@ -304,11 +333,27 @@ static int brcmstb_thermal_probe(struct
- if (IS_ERR(priv->tmon_base))
- return PTR_ERR(priv->tmon_base);
-
-+ priv->socdata = of_device_get_match_data(&pdev->dev);
-+ if (!priv->socdata) {
-+ dev_err(&pdev->dev, "no device match found\n");
-+ return -ENODEV;
-+ }
-+
-+ priv->clk = devm_clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+
-+ if (!IS_ERR(priv->clk)) {
-+ ret = clk_prepare_enable(priv->clk);
-+ if (ret)
-+ return ret;
-+ }
-+
- priv->dev = &pdev->dev;
- platform_set_drvdata(pdev, priv);
-
- thermal = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
-- &of_ops);
-+ priv->socdata->of_ops);
- if (IS_ERR(thermal)) {
- ret = PTR_ERR(thermal);
- dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
--- /dev/null
+From cbe8b55622fc2f0a959da599447c87cf1f967a91 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 14 May 2019 17:17:59 +0100
+Subject: [PATCH] net: genet: enable link energy detect powerdown for
+ external PHYs
+
+There are several warts surrounding bcmgenet_mii_probe() as this
+function is called from ndo_open, but it's calling registration-type
+functions. The probe should be called at probe time and refactored
+such that the PHY device data can be extracted to limit the scope
+of this flag to Broadcom PHYs.
+
+For now, pass this flag in as it puts our attached PHY into a low-power
+state when disconnected.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+@@ -316,6 +316,8 @@ int bcmgenet_mii_probe(struct net_device
+ /* Communicate the integrated PHY revision */
+ if (priv->internal_phy)
+ phy_flags = priv->gphy_rev;
++ else
++ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
+
+ /* Initialize link state variables that bcmgenet_mii_setup() uses */
+ priv->old_link = -1;
+++ /dev/null
-From 2cba27bce0470a06237b3bd7883d43ade0d5c39c Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 1 Nov 2018 17:31:37 +0000
-Subject: [PATCH] vchiq: Add 36-bit address support
-
-Conditional on a new compatible string, change the pagelist encoding
-such that the top 24 bits are the pfn, leaving 8 bits for run length
-(-1).
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++-----
- .../interface/vchiq_arm/vchiq_arm.c | 6 ++
- .../interface/vchiq_arm/vchiq_arm.h | 1 +
- 3 files changed, 75 insertions(+), 22 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-@@ -16,6 +16,8 @@
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
- #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
-+#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x))
-+#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1)
-
- #include "vchiq_arm.h"
- #include "vchiq_connected.h"
-@@ -63,6 +65,7 @@ static void __iomem *g_regs;
- */
- static unsigned int g_cache_line_size = 32;
- static struct dma_pool *g_dma_pool;
-+static unsigned int g_use_36bit_addrs = 0;
- static unsigned int g_fragments_size;
- static char *g_fragments_base;
- static char *g_free_fragments;
-@@ -106,6 +109,8 @@ int vchiq_platform_init(struct platform_
- g_cache_line_size = drvdata->cache_line_size;
- g_fragments_size = 2 * g_cache_line_size;
-
-+ g_use_36bit_addrs = (dev->dma_pfn_offset == 0);
-+
- /* Allocate space for the channels in coherent memory */
- slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
- frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
-@@ -117,14 +122,21 @@ int vchiq_platform_init(struct platform_
- return -ENOMEM;
- }
-
-+ if (!IS_VC_SAFE(slot_phys)) {
-+ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n",
-+ &slot_phys);
-+ return -ENOMEM;
-+ }
-+
- WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0);
-+ channelbase = VC_SAFE(slot_phys);
-
- vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
- if (!vchiq_slot_zero)
- return -EINVAL;
-
- vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
-- (int)slot_phys + slot_mem_size;
-+ channelbase + slot_mem_size;
- vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
- MAX_FRAGMENTS;
-
-@@ -158,7 +170,6 @@ int vchiq_platform_init(struct platform_
- }
-
- /* Send the base address of the slots to VideoCore */
-- channelbase = slot_phys;
- err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
- &channelbase, sizeof(channelbase));
- if (err || channelbase) {
-@@ -244,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul
- if (!pagelistinfo)
- return VCHIQ_ERROR;
-
-- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr;
-+ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
-
- /*
- * Store the pagelistinfo address in remote_data,
-@@ -522,25 +533,60 @@ create_pagelist(char __user *buf, size_t
-
- /* Combine adjacent blocks for performance */
- k = 0;
-- for_each_sg(scatterlist, sg, dma_buffers, i) {
-- u32 len = sg_dma_len(sg);
-- u32 addr = sg_dma_address(sg);
--
-- /* Note: addrs is the address + page_count - 1
-- * The firmware expects blocks after the first to be page-
-- * aligned and a multiple of the page size
-- */
-- WARN_ON(len == 0);
-- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-- WARN_ON(i && (addr & ~PAGE_MASK));
-- if (k > 0 &&
-- ((addrs[k - 1] & PAGE_MASK) +
-- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
-- == (addr & PAGE_MASK))
-- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
-- else
-- addrs[k++] = (addr & PAGE_MASK) |
-- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1);
-+ if (g_use_36bit_addrs) {
-+ for_each_sg(scatterlist, sg, dma_buffers, i) {
-+ u32 len = sg_dma_len(sg);
-+ u64 addr = sg_dma_address(sg);
-+ u32 page_id = (u32)((addr >> 4) & ~0xff);
-+ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-+
-+ /* Note: addrs is the address + page_count - 1
-+ * The firmware expects blocks after the first to be page-
-+ * aligned and a multiple of the page size
-+ */
-+ WARN_ON(len == 0);
-+ WARN_ON(i &&
-+ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-+ WARN_ON(i && (addr & ~PAGE_MASK));
-+ WARN_ON(upper_32_bits(addr) > 0xf);
-+ if (k > 0 &&
-+ ((addrs[k - 1] & ~0xff) +
-+ (((addrs[k - 1] & 0xff) + 1) << 8)
-+ == page_id)) {
-+ u32 inc_pages = min(sg_pages,
-+ 0xff - (addrs[k - 1] & 0xff));
-+ addrs[k - 1] += inc_pages;
-+ page_id += inc_pages << 8;
-+ sg_pages -= inc_pages;
-+ }
-+ while (sg_pages) {
-+ u32 inc_pages = min(sg_pages, 0x100u);
-+ addrs[k++] = page_id | (inc_pages - 1);
-+ page_id += inc_pages << 8;
-+ sg_pages -= inc_pages;
-+ }
-+ }
-+ } else {
-+ for_each_sg(scatterlist, sg, dma_buffers, i) {
-+ u32 len = sg_dma_len(sg);
-+ u32 addr = VC_SAFE(sg_dma_address(sg));
-+ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-+
-+ /* Note: addrs is the address + page_count - 1
-+ * The firmware expects blocks after the first to be page-
-+ * aligned and a multiple of the page size
-+ */
-+ WARN_ON(len == 0);
-+ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
-+ WARN_ON(i && (addr & ~PAGE_MASK));
-+ if (k > 0 &&
-+ ((addrs[k - 1] & PAGE_MASK) +
-+ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
-+ == (addr & PAGE_MASK))
-+ addrs[k - 1] += new_pages;
-+ else
-+ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1);
-+ }
- }
-
- /* Partial cache lines (fragments) require special measures */
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -149,6 +149,11 @@ static struct vchiq_drvdata bcm2836_drvd
- .cache_line_size = 64,
- };
-
-+static struct vchiq_drvdata bcm2838_drvdata = {
-+ .cache_line_size = 64,
-+ .use_36bit_addrs = true,
-+};
-+
- static const char *const ioctl_names[] = {
- "CONNECT",
- "SHUTDOWN",
-@@ -3164,6 +3169,7 @@ void vchiq_platform_conn_state_changed(s
- static const struct of_device_id vchiq_of_match[] = {
- { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
- { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
-+ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
- {},
- };
- MODULE_DEVICE_TABLE(of, vchiq_of_match);
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
-@@ -97,6 +97,7 @@ struct vchiq_arm_state {
-
- struct vchiq_drvdata {
- const unsigned int cache_line_size;
-+ const bool use_36bit_addrs;
- struct rpi_firmware *fw;
- };
-
+++ /dev/null
-From c76427651677c03c9611b20b914ab2a2ea173522 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 30 Apr 2019 19:15:30 +0100
-Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio
-
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++--------
- 1 file changed, 9 insertions(+), 8 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
- .rate_min = 8000,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = 128 * 1024,
-@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_SYNC_APPLPTR),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
-- SNDRV_PCM_RATE_48000,
-+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
-+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
-+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
- .rate_min = 44100,
-- .rate_max = 48000,
-+ .rate_max = 192000,
- .channels_min = 2,
-- .channels_max = 2,
-- .buffer_bytes_max = 128 * 1024,
-+ .channels_max = 8,
-+ .buffer_bytes_max = 512 * 1024,
- .period_bytes_min = 1 * 1024,
-- .period_bytes_max = 128 * 1024,
-+ .period_bytes_max = 512 * 1024,
- .periods_min = 1,
- .periods_max = 128,
- };
--- /dev/null
+From a71750c83a6f1f2f7c22864bbb4e62af5e70c214 Mon Sep 17 00:00:00 2001
+From: Tim Gover <tim.gover@raspberrypi.org>
+Date: Fri, 22 Mar 2019 09:47:14 +0000
+Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout
+
+If the VL805 EEPROM has not been programmed then boot will hang for five
+seconds. The timeout seems to be arbitrary and is an unecessary
+delay on the first boot. Remove the timeout.
+
+This is common code and probably can't be upstreamed unless the timeout
+can be configurable somehow or perhaps the XHCI driver can be skipped
+on the first boot.
+---
+ drivers/usb/host/xhci.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci)
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ udelay(1000);
+
++ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805
+ ret = xhci_handshake(&xhci->op_regs->command,
+- CMD_RESET, 0, 10 * 1000 * 1000);
++ CMD_RESET, 0, 500 * 1000);
+ if (ret)
+ return ret;
+
+++ /dev/null
-From f4d211891064eef8b133838c213485a228ad75f3 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Wed, 12 Sep 2018 14:44:53 +0100
-Subject: [PATCH] bcmgenet: constrain max DMA burst length
-
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-@@ -28,7 +28,7 @@
- #define ENET_PAD 8
- #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
- ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
--#define DMA_MAX_BURST_LENGTH 0x10
-+#define DMA_MAX_BURST_LENGTH 0x08
-
- /* misc. configuration */
- #define CLEAR_ALL_HFB 0xFF
--- /dev/null
+From 605cd2341a6be51fd91da8d985a4698db7d9a623 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 23 May 2019 15:08:30 +0100
+Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/usb/host/xhci-pci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -243,6 +243,10 @@ static void xhci_pci_quirks(struct devic
+ pdev->device == 0x3432)
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
+
++ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
++ pdev->device == 0x3483)
++ xhci->quirks |= XHCI_LPM_SUPPORT;
++
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == 0x1042)
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
+++ /dev/null
-From b3344ca9ef887c4004c61be39f7d8d058a569d4d Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 27 Mar 2019 13:45:46 +0000
-Subject: [PATCH] bcmgenet: Better coalescing parameter defaults
-
-Set defaults for TX and RX packet coalescing to be equivalent to:
-
- # ethtool -C eth0 tx-frames 10
- # ethtool -C eth0 rx-usecs 50
-
-This may be something we want to set via DT parameters in the
-future.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -2145,7 +2145,7 @@ static void bcmgenet_init_tx_ring(struct
-
- bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
- bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
-- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
-+ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
- /* Disable rate control for now */
- bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
- TDMA_FLOW_PERIOD);
-@@ -3567,9 +3567,12 @@ static int bcmgenet_probe(struct platfor
- netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
-
- /* Set default coalescing parameters */
-- for (i = 0; i < priv->hw_params->rx_queues; i++)
-+ for (i = 0; i < priv->hw_params->rx_queues; i++) {
- priv->rx_rings[i].rx_max_coalesced_frames = 1;
-+ priv->rx_rings[i].rx_coalesce_usecs = 50;
-+ }
- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1;
-+ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50;
-
- /* libphy will determine the link state */
- netif_carrier_off(dev);
--- /dev/null
+From ac94635b678715af00a685ada0a1b60dfb54c771 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 13 May 2019 11:05:27 +0000
+Subject: [PATCH] spi: bcm2835: enable shared interrupt support
+
+Add shared interrupt support for this driver.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+---
+ drivers/spi/spi-bcm2835.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -379,6 +379,10 @@ static irqreturn_t bcm2835_spi_interrupt
+ if (bs->tx_len && cs & BCM2835_SPI_CS_DONE)
+ bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
+
++ /* check if we got interrupt enabled */
++ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR))
++ return IRQ_NONE;
++
+ /* Read as many bytes as possible from FIFO */
+ bcm2835_rd_fifo(bs);
+ /* Write as many bytes as possible to FIFO */
+@@ -1335,7 +1339,8 @@ static int bcm2835_spi_probe(struct plat
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+
+- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
++ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
++ IRQF_SHARED,
+ dev_name(&pdev->dev), ctlr);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
--- /dev/null
+From 35d84e9f2944b72ccfc508dc5c540c526ab351c1 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 23 Jan 2019 16:11:50 +0000
+Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -628,15 +628,17 @@ static int bcm2835_pll_on(struct clk_hw
+ spin_unlock(&cprman->regs_lock);
+
+ /* Wait for the PLL to lock. */
+- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
+- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
+- if (ktime_after(ktime_get(), timeout)) {
+- dev_err(cprman->dev, "%s: couldn't lock PLL\n",
+- clk_hw_get_name(hw));
+- return -ETIMEDOUT;
+- }
++ if (strcmp(data->name, "pllh")) {
++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
++ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
++ if (ktime_after(ktime_get(), timeout)) {
++ dev_err(cprman->dev, "%s: couldn't lock PLL\n",
++ clk_hw_get_name(hw));
++ return -ETIMEDOUT;
++ }
+
+- cpu_relax();
++ cpu_relax();
++ }
+ }
+
+ cprman_write(cprman, data->a2w_ctrl_reg,
+++ /dev/null
-From cbe8b55622fc2f0a959da599447c87cf1f967a91 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 14 May 2019 17:17:59 +0100
-Subject: [PATCH] net: genet: enable link energy detect powerdown for
- external PHYs
-
-There are several warts surrounding bcmgenet_mii_probe() as this
-function is called from ndo_open, but it's calling registration-type
-functions. The probe should be called at probe time and refactored
-such that the PHY device data can be extracted to limit the scope
-of this flag to Broadcom PHYs.
-
-For now, pass this flag in as it puts our attached PHY into a low-power
-state when disconnected.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
-@@ -316,6 +316,8 @@ int bcmgenet_mii_probe(struct net_device
- /* Communicate the integrated PHY revision */
- if (priv->internal_phy)
- phy_flags = priv->gphy_rev;
-+ else
-+ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
-
- /* Initialize link state variables that bcmgenet_mii_setup() uses */
- priv->old_link = -1;
--- /dev/null
+From 0cb69292622e3530a72d3173d78c484c8f4d3eab Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 11 Jan 2019 17:31:07 -0800
+Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711.
+
+Without the actual power management part any more, there's a lot less
+to set up for V3D. We just need to clear the RSTN field for the power
+domain, and expose the reset controller for toggling it again.
+
+This is definitely incomplete -- the old ISP and H264 is in the old
+bridge, but since we have no consumers of it I've just done the
+minimum to get V3D working.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/mfd/bcm2835-pm.c | 11 +++++++++++
+ drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++
+ include/linux/mfd/bcm2835-pm.h | 1 +
+ 3 files changed, 34 insertions(+)
+
+--- a/drivers/mfd/bcm2835-pm.c
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf
+ if (ret)
+ return ret;
+
++ /* Map the ARGON ASB regs if present. */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ if (res) {
++ pm->arg_asb = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->arg_asb)) {
++ dev_err(dev, "Failed to map ARGON ASB: %ld\n",
++ PTR_ERR(pm->arg_asb));
++ return PTR_ERR(pm->arg_asb);
++ }
++ }
++
+ /* We'll use the presence of the AXI ASB regs in the
+ * bcm2835-pm binding as the key for whether we can reference
+ * the full PM register range and support power domains.
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -143,6 +143,8 @@ struct bcm2835_power {
+ /* AXI Async bridge registers. */
+ void __iomem *asb;
+
++ bool is_2711;
++
+ struct genpd_onecell_data pd_xlate;
+ struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
+ struct reset_controller_dev reset;
+@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc
+ {
+ struct bcm2835_power *power = pd->power;
+
++ /* 2711 has no power domains above the reset controller. */
++ if (power->is_2711)
++ return 0;
++
+ /* Enable functional isolation */
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
+
+@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct
+ int inrush;
+ bool powok;
+
++ /* 2711 has no power domains above the reset controller. */
++ if (power->is_2711)
++ return 0;
++
+ /* If it was already powered on by the fw, leave it that way. */
+ if (PM_READ(pm_reg) & PM_POWUP)
+ return 0;
+@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl
+ power->base = pm->base;
+ power->asb = pm->asb;
+
++ /* 2711 hack: the new ARGON ASB took over V3D, which is our
++ * only consumer of this driver so far. The old ASB seems to
++ * still be present with ISP and H264 bits but no V3D, but I
++ * don't know if that's real or not. The V3D is in the same
++ * place in the new ASB as the old one, so just poke the new
++ * one for now.
++ */
++ if (pm->arg_asb) {
++ power->asb = pm->arg_asb;
++ power->is_2711 = true;
++ }
++
+ id = ASB_READ(ASB_AXI_BRDG_ID);
+ if (id != 0x62726467 /* "BRDG" */) {
+ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
+--- a/include/linux/mfd/bcm2835-pm.h
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -9,6 +9,7 @@ struct bcm2835_pm {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *asb;
++ void __iomem *arg_asb;
+ };
+
+ #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From a71750c83a6f1f2f7c22864bbb4e62af5e70c214 Mon Sep 17 00:00:00 2001
-From: Tim Gover <tim.gover@raspberrypi.org>
-Date: Fri, 22 Mar 2019 09:47:14 +0000
-Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout
-
-If the VL805 EEPROM has not been programmed then boot will hang for five
-seconds. The timeout seems to be arbitrary and is an unecessary
-delay on the first boot. Remove the timeout.
-
-This is common code and probably can't be upstreamed unless the timeout
-can be configurable somehow or perhaps the XHCI driver can be skipped
-on the first boot.
----
- drivers/usb/host/xhci.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/usb/host/xhci.c
-+++ b/drivers/usb/host/xhci.c
-@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci)
- if (xhci->quirks & XHCI_INTEL_HOST)
- udelay(1000);
-
-+ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805
- ret = xhci_handshake(&xhci->op_regs->command,
-- CMD_RESET, 0, 10 * 1000 * 1000);
-+ CMD_RESET, 0, 500 * 1000);
- if (ret)
- return ret;
-
--- /dev/null
+From 15880303abc8b93cda3c62203fa5303726f53ca6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 4 Sep 2018 11:50:25 +0100
+Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835
+
+---
+ arch/arm/mach-bcm/Kconfig | 4 ++++
+ drivers/pci/controller/Kconfig | 4 ++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -161,6 +161,7 @@ config ARCH_BCM2835
+ select GPIOLIB
+ select ARM_AMBA
+ select ARM_ERRATA_411920 if ARCH_MULTI_V6
++ select ARM_GIC
+ select ARM_TIMER_SP804
+ select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
+ select TIMER_OF
+@@ -170,6 +171,9 @@ config ARCH_BCM2835
+ select PINCTRL_BCM2835
+ select MFD_CORE
+ select MFD_SYSCON if ARCH_MULTI_V7
++ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
++ select ZONE_DMA if ARM_LPAE
++ select MFD_CORE
+ help
+ This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
+ This SoC is used in the Raspberry Pi and Roku 2 devices.
+++ /dev/null
-From 605cd2341a6be51fd91da8d985a4698db7d9a623 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 23 May 2019 15:08:30 +0100
-Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/usb/host/xhci-pci.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -243,6 +243,10 @@ static void xhci_pci_quirks(struct devic
- pdev->device == 0x3432)
- xhci->quirks |= XHCI_BROKEN_STREAMS;
-
-+ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
-+ pdev->device == 0x3483)
-+ xhci->quirks |= XHCI_LPM_SUPPORT;
-+
- if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
- pdev->device == 0x1042)
- xhci->quirks |= XHCI_BROKEN_STREAMS;
--- /dev/null
+From cfe0832e8306cd9955f682b7314a5a6fc3b9d514 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 2 May 2019 15:11:05 -0700
+Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock
+ rates while running.
+
+As long as you wait for !BUSY, you can do glitch-free updates of clock
+rate while the clock is running.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
+ 1 file changed, 13 insertions(+), 9 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1098,15 +1098,19 @@ static int bcm2835_clock_set_rate(struct
+
+ spin_lock(&cprman->regs_lock);
+
+- /*
+- * Setting up frac support
+- *
+- * In principle it is recommended to stop/start the clock first,
+- * but as we set CLK_SET_RATE_GATE during registration of the
+- * clock this requirement should be take care of by the
+- * clk-framework.
++ ctl = cprman_read(cprman, data->ctl_reg);
++
++ /* If the clock is running, we have to pause clock generation while
++ * updating the control and div regs. This is glitchless (no clock
++ * signals generated faster than the rate) but each reg access is two
++ * OSC cycles so the clock will slow down for a moment.
+ */
+- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
++ if (ctl & CM_ENABLE) {
++ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
++ bcm2835_clock_wait_busy(clock);
++ }
++
++ ctl &= ~CM_FRAC;
+ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
+ cprman_write(cprman, data->ctl_reg, ctl);
+
+@@ -1476,7 +1480,7 @@ static struct clk_hw *bcm2835_register_c
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
++ init.flags |= CLK_SET_PARENT_GATE;
+
+ /* If the clock wasn't actually enabled at boot, it's not
+ * critical.
+++ /dev/null
-From ac94635b678715af00a685ada0a1b60dfb54c771 Mon Sep 17 00:00:00 2001
-From: Martin Sperl <kernel@martin.sperl.org>
-Date: Mon, 13 May 2019 11:05:27 +0000
-Subject: [PATCH] spi: bcm2835: enable shared interrupt support
-
-Add shared interrupt support for this driver.
-
-Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
----
- drivers/spi/spi-bcm2835.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/spi/spi-bcm2835.c
-+++ b/drivers/spi/spi-bcm2835.c
-@@ -379,6 +379,10 @@ static irqreturn_t bcm2835_spi_interrupt
- if (bs->tx_len && cs & BCM2835_SPI_CS_DONE)
- bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
-
-+ /* check if we got interrupt enabled */
-+ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR))
-+ return IRQ_NONE;
-+
- /* Read as many bytes as possible from FIFO */
- bcm2835_rd_fifo(bs);
- /* Write as many bytes as possible to FIFO */
-@@ -1335,7 +1339,8 @@ static int bcm2835_spi_probe(struct plat
- bcm2835_wr(bs, BCM2835_SPI_CS,
- BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
-
-- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-+ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
-+ IRQF_SHARED,
- dev_name(&pdev->dev), ctlr);
- if (err) {
- dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
--- /dev/null
+From 1ee90bb75979c183e241c14f7c31d72cdb4bcc9b Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 2 May 2019 15:24:04 -0700
+Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while
+ they're running.
+
+This falls under the same "we can reprogram glitch-free as long as we
+pause generation" rule as updating the div/frac fields. This can be
+used for runtime reclocking of V3D to manage power leakage.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1087,8 +1087,10 @@ static int bcm2835_clock_on(struct clk_h
+ return 0;
+ }
+
+-static int bcm2835_clock_set_rate(struct clk_hw *hw,
+- unsigned long rate, unsigned long parent_rate)
++static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
++ unsigned long rate,
++ unsigned long parent_rate,
++ u8 parent)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+@@ -1110,6 +1112,11 @@ static int bcm2835_clock_set_rate(struct
+ bcm2835_clock_wait_busy(clock);
+ }
+
++ if (parent != 0xff) {
++ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT);
++ ctl |= parent << CM_SRC_SHIFT;
++ }
++
+ ctl &= ~CM_FRAC;
+ ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
+ cprman_write(cprman, data->ctl_reg, ctl);
+@@ -1121,6 +1128,12 @@ static int bcm2835_clock_set_rate(struct
+ return 0;
+ }
+
++static int bcm2835_clock_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff);
++}
++
+ static bool
+ bcm2835_clk_is_pllc(struct clk_hw *hw)
+ {
+@@ -1304,6 +1317,7 @@ static const struct clk_ops bcm2835_cloc
+ .unprepare = bcm2835_clock_off,
+ .recalc_rate = bcm2835_clock_get_rate,
+ .set_rate = bcm2835_clock_set_rate,
++ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+ .get_parent = bcm2835_clock_get_parent,
+@@ -1480,7 +1494,6 @@ static struct clk_hw *bcm2835_register_c
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+- init.flags |= CLK_SET_PARENT_GATE;
+
+ /* If the clock wasn't actually enabled at boot, it's not
+ * critical.
+++ /dev/null
-From 35d84e9f2944b72ccfc508dc5c540c526ab351c1 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 23 Jan 2019 16:11:50 +0000
-Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++--------
- 1 file changed, 10 insertions(+), 8 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -628,15 +628,17 @@ static int bcm2835_pll_on(struct clk_hw
- spin_unlock(&cprman->regs_lock);
-
- /* Wait for the PLL to lock. */
-- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
-- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
-- if (ktime_after(ktime_get(), timeout)) {
-- dev_err(cprman->dev, "%s: couldn't lock PLL\n",
-- clk_hw_get_name(hw));
-- return -ETIMEDOUT;
-- }
-+ if (strcmp(data->name, "pllh")) {
-+ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
-+ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) {
-+ if (ktime_after(ktime_get(), timeout)) {
-+ dev_err(cprman->dev, "%s: couldn't lock PLL\n",
-+ clk_hw_get_name(hw));
-+ return -ETIMEDOUT;
-+ }
-
-- cpu_relax();
-+ cpu_relax();
-+ }
- }
-
- cprman_write(cprman, data->a2w_ctrl_reg,
+++ /dev/null
-From 0cb69292622e3530a72d3173d78c484c8f4d3eab Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Fri, 11 Jan 2019 17:31:07 -0800
-Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711.
-
-Without the actual power management part any more, there's a lot less
-to set up for V3D. We just need to clear the RSTN field for the power
-domain, and expose the reset controller for toggling it again.
-
-This is definitely incomplete -- the old ISP and H264 is in the old
-bridge, but since we have no consumers of it I've just done the
-minimum to get V3D working.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/mfd/bcm2835-pm.c | 11 +++++++++++
- drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++
- include/linux/mfd/bcm2835-pm.h | 1 +
- 3 files changed, 34 insertions(+)
-
---- a/drivers/mfd/bcm2835-pm.c
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf
- if (ret)
- return ret;
-
-+ /* Map the ARGON ASB regs if present. */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-+ if (res) {
-+ pm->arg_asb = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->arg_asb)) {
-+ dev_err(dev, "Failed to map ARGON ASB: %ld\n",
-+ PTR_ERR(pm->arg_asb));
-+ return PTR_ERR(pm->arg_asb);
-+ }
-+ }
-+
- /* We'll use the presence of the AXI ASB regs in the
- * bcm2835-pm binding as the key for whether we can reference
- * the full PM register range and support power domains.
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -143,6 +143,8 @@ struct bcm2835_power {
- /* AXI Async bridge registers. */
- void __iomem *asb;
-
-+ bool is_2711;
-+
- struct genpd_onecell_data pd_xlate;
- struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
- struct reset_controller_dev reset;
-@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc
- {
- struct bcm2835_power *power = pd->power;
-
-+ /* 2711 has no power domains above the reset controller. */
-+ if (power->is_2711)
-+ return 0;
-+
- /* Enable functional isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
-
-@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct
- int inrush;
- bool powok;
-
-+ /* 2711 has no power domains above the reset controller. */
-+ if (power->is_2711)
-+ return 0;
-+
- /* If it was already powered on by the fw, leave it that way. */
- if (PM_READ(pm_reg) & PM_POWUP)
- return 0;
-@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl
- power->base = pm->base;
- power->asb = pm->asb;
-
-+ /* 2711 hack: the new ARGON ASB took over V3D, which is our
-+ * only consumer of this driver so far. The old ASB seems to
-+ * still be present with ISP and H264 bits but no V3D, but I
-+ * don't know if that's real or not. The V3D is in the same
-+ * place in the new ASB as the old one, so just poke the new
-+ * one for now.
-+ */
-+ if (pm->arg_asb) {
-+ power->asb = pm->arg_asb;
-+ power->is_2711 = true;
-+ }
-+
- id = ASB_READ(ASB_AXI_BRDG_ID);
- if (id != 0x62726467 /* "BRDG" */) {
- dev_err(dev, "ASB register ID returned 0x%08x\n", id);
---- a/include/linux/mfd/bcm2835-pm.h
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -9,6 +9,7 @@ struct bcm2835_pm {
- struct device *dev;
- void __iomem *base;
- void __iomem *asb;
-+ void __iomem *arg_asb;
- };
-
- #endif /* BCM2835_MFD_PM_H */
--- /dev/null
+From 2669f337d78306667e4243fda9282fb8c07d0d3d Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 11 Jun 2019 10:55:00 +0100
+Subject: [PATCH] usb: add plumbing for updating interrupt endpoint
+ interval state
+
+xHCI caches device and endpoint data after the interface is configured,
+so an explicit command needs to be issued for any device driver wanting
+to alter the polling interval of an endpoint.
+
+Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be
+called after calculating endpoint bandwidth requirements but before any
+URBs are submitted.
+
+If polling intervals are shortened, any bandwidth reservations are no
+longer valid but in practice polling intervals are only ever relaxed.
+
+Limit the scope to interrupt transfers for now.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/core/hcd.c | 10 ++++++++++
+ drivers/usb/core/message.c | 15 +++++++++++++++
+ include/linux/usb.h | 2 ++
+ include/linux/usb/hcd.h | 7 +++++++
+ 4 files changed, 34 insertions(+)
+
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -1941,6 +1941,16 @@ reset:
+ return ret;
+ }
+
++void usb_hcd_fixup_endpoint(struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval)
++{
++ struct usb_hcd *hcd;
++
++ hcd = bus_to_hcd(udev->bus);
++ if (hcd->driver->fixup_endpoint)
++ hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
++}
++
+ /* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1113,6 +1113,21 @@ static void remove_intf_ep_devs(struct u
+ intf->ep_devs_created = 0;
+ }
+
++void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval)
++{
++ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
++ struct usb_host_endpoint *ep;
++
++ if (usb_endpoint_out(epaddr))
++ ep = dev->ep_out[epnum];
++ else
++ ep = dev->ep_in[epnum];
++
++ if (ep && usb_endpoint_xfer_int(&ep->desc))
++ usb_hcd_fixup_endpoint(dev, ep, interval);
++}
++EXPORT_SYMBOL_GPL(usb_fixup_endpoint);
++
+ /**
+ * usb_disable_endpoint -- Disable an endpoint by address
+ * @dev: the device whose endpoint is being disabled
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -1816,6 +1816,8 @@ extern int usb_clear_halt(struct usb_dev
+ extern int usb_reset_configuration(struct usb_device *dev);
+ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+ extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
++extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
++ int interval);
+
+ /* this request isn't really synchronous, but it belongs with the others */
+ extern int usb_driver_set_configuration(struct usb_device *udev, int config);
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -382,6 +382,11 @@ struct hc_driver {
+ * or bandwidth constraints.
+ */
+ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
++ /* Override the endpoint-derived interval
++ * (if there is any cached hardware state).
++ */
++ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval);
+ /* Returns the hardware-chosen device address */
+ int (*address_device)(struct usb_hcd *, struct usb_device *udev);
+ /* prepares the hardware to send commands to the device */
+@@ -443,6 +448,8 @@ extern void usb_hcd_unmap_urb_setup_for_
+ extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
+ extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
++extern void usb_hcd_fixup_endpoint(struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval);
+ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+ extern void usb_hcd_reset_endpoint(struct usb_device *udev,
+++ /dev/null
-From 15880303abc8b93cda3c62203fa5303726f53ca6 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 4 Sep 2018 11:50:25 +0100
-Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835
-
----
- arch/arm/mach-bcm/Kconfig | 4 ++++
- drivers/pci/controller/Kconfig | 4 ++--
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/arch/arm/mach-bcm/Kconfig
-+++ b/arch/arm/mach-bcm/Kconfig
-@@ -161,6 +161,7 @@ config ARCH_BCM2835
- select GPIOLIB
- select ARM_AMBA
- select ARM_ERRATA_411920 if ARCH_MULTI_V6
-+ select ARM_GIC
- select ARM_TIMER_SP804
- select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
- select TIMER_OF
-@@ -170,6 +171,9 @@ config ARCH_BCM2835
- select PINCTRL_BCM2835
- select MFD_CORE
- select MFD_SYSCON if ARCH_MULTI_V7
-+ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-+ select ZONE_DMA if ARM_LPAE
-+ select MFD_CORE
- help
- This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
- This SoC is used in the Raspberry Pi and Roku 2 devices.
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -290,9 +290,9 @@ config PCI_HYPERV_INTERFACE
-
- config PCIE_BRCMSTB
- tristate "Broadcom Brcmstb PCIe platform host driver"
-- depends on ARCH_BRCMSTB || BMIPS_GENERIC
-+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835
- depends on OF
-- depends on SOC_BRCMSTB
-+ depends on SOC_BRCMSTB || ARCH_BCM2835
- default ARCH_BRCMSTB || BMIPS_GENERIC
- help
- Adds support for Broadcom Settop Box PCIe host controller.
--- /dev/null
+From 00e1a43b64abc8950b471678b7ed4415f3513f3e Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 11 Jun 2019 11:33:39 +0100
+Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval
+ adjustments
+
+Must be called in a non-atomic context, after the endpoint
+has been registered with the hardware via xhci_add_endpoint
+and before the first URB is submitted for the endpoint.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 98 insertions(+)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -1450,6 +1450,103 @@ command_cleanup:
+ }
+
+ /*
++ * RPI: Fixup endpoint intervals when requested
++ * - Check interval versus the (cached) endpoint context
++ * - set the endpoint interval to the new value
++ * - force an endpoint configure command
++ * XXX: bandwidth is not recalculated. We should probably do that.
++ */
++static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
++ struct usb_host_endpoint *ep, int interval)
++{
++ struct xhci_hcd *xhci;
++ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in;
++ struct xhci_command *command;
++ struct xhci_input_control_ctx *ctrl_ctx;
++ struct xhci_virt_device *vdev;
++ int xhci_interval;
++ int ret;
++ int ep_index;
++ unsigned long flags;
++ u32 ep_info_tmp;
++
++ xhci = hcd_to_xhci(hcd);
++ ep_index = xhci_get_endpoint_index(&ep->desc);
++
++ /* FS/LS interval translations */
++ if ((udev->speed == USB_SPEED_FULL ||
++ udev->speed == USB_SPEED_LOW))
++ interval *= 8;
++
++ mutex_lock(&xhci->mutex);
++
++ spin_lock_irqsave(&xhci->lock, flags);
++
++ vdev = xhci->devs[udev->slot_id];
++ /* Get context-derived endpoint interval */
++ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
++ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
++ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info));
++
++ if (interval == xhci_interval) {
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++
++ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n",
++ interval, xhci_interval);
++ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC);
++ if (!command) {
++ /* Failure here is benign, poll at the original rate */
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++
++ /* xHCI uses exponents for intervals... */
++ xhci_interval = fls(interval) - 1;
++ xhci_interval = clamp_val(xhci_interval, 3, 10);
++ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info);
++ ep_info_tmp &= ~EP_INTERVAL(255);
++ ep_info_tmp |= EP_INTERVAL(xhci_interval);
++
++ /* Keep the endpoint context up-to-date while issuing the command. */
++ xhci_endpoint_copy(xhci, vdev->in_ctx,
++ vdev->out_ctx, ep_index);
++ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp);
++
++ /*
++ * We need to drop the lock, so take an explicit copy
++ * of the ep context.
++ */
++ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index);
++
++ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
++ if (!ctrl_ctx) {
++ xhci_warn(xhci,
++ "%s: Could not get input context, bad type.\n",
++ __func__);
++ spin_unlock_irqrestore(&xhci->lock, flags);
++ xhci_free_command(xhci, command);
++ mutex_unlock(&xhci->mutex);
++ return;
++ }
++ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
++ ctrl_ctx->drop_flags = 0;
++
++ spin_unlock_irqrestore(&xhci->lock, flags);
++
++ ret = xhci_configure_endpoint(xhci, udev, command,
++ false, false);
++ if (ret)
++ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
++ __func__, ret);
++ xhci_free_command(xhci, command);
++ mutex_unlock(&xhci->mutex);
++}
++
++/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ */
+@@ -5325,6 +5422,7 @@ static const struct hc_driver xhci_hc_dr
+ .endpoint_reset = xhci_endpoint_reset,
+ .check_bandwidth = xhci_check_bandwidth,
+ .reset_bandwidth = xhci_reset_bandwidth,
++ .fixup_endpoint = xhci_fixup_endpoint,
+ .address_device = xhci_address_device,
+ .enable_device = xhci_enable_device,
+ .update_hub_device = xhci_update_hub_device,
+++ /dev/null
-From cfe0832e8306cd9955f682b7314a5a6fc3b9d514 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 2 May 2019 15:11:05 -0700
-Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock
- rates while running.
-
-As long as you wait for !BUSY, you can do glitch-free updates of clock
-rate while the clock is running.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
- 1 file changed, 13 insertions(+), 9 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1098,15 +1098,19 @@ static int bcm2835_clock_set_rate(struct
-
- spin_lock(&cprman->regs_lock);
-
-- /*
-- * Setting up frac support
-- *
-- * In principle it is recommended to stop/start the clock first,
-- * but as we set CLK_SET_RATE_GATE during registration of the
-- * clock this requirement should be take care of by the
-- * clk-framework.
-+ ctl = cprman_read(cprman, data->ctl_reg);
-+
-+ /* If the clock is running, we have to pause clock generation while
-+ * updating the control and div regs. This is glitchless (no clock
-+ * signals generated faster than the rate) but each reg access is two
-+ * OSC cycles so the clock will slow down for a moment.
- */
-- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
-+ if (ctl & CM_ENABLE) {
-+ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE);
-+ bcm2835_clock_wait_busy(clock);
-+ }
-+
-+ ctl &= ~CM_FRAC;
- ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
- cprman_write(cprman, data->ctl_reg, ctl);
-
-@@ -1476,7 +1480,7 @@ static struct clk_hw *bcm2835_register_c
- init.ops = &bcm2835_vpu_clock_clk_ops;
- } else {
- init.ops = &bcm2835_clock_clk_ops;
-- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
-+ init.flags |= CLK_SET_PARENT_GATE;
-
- /* If the clock wasn't actually enabled at boot, it's not
- * critical.
--- /dev/null
+From df28fdf0b853c0951bab5c9cbb5aa82819f7b34b Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 11 Jun 2019 11:42:03 +0100
+Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling
+ intervals
+
+Lets the mousepoll override mechanism work with xhci.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/hid/usbhid/hid-core.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -1115,6 +1115,7 @@ static int usbhid_start(struct hid_devic
+ interval = hid_kbpoll_interval;
+ break;
+ }
++ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval);
+
+ ret = -ENOMEM;
+ if (usb_endpoint_dir_in(endpoint)) {
--- /dev/null
+From 8af54831d1d377b6a4ab087c409f1684e1e985a7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 11 Jun 2019 17:38:28 +0100
+Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -109,6 +109,7 @@ static const char * const bcm2835_compat
+ #ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+ "brcm,bcm2837",
++ "brcm,bcm2838",
+ #endif
+ NULL
+ };
+++ /dev/null
-From 1ee90bb75979c183e241c14f7c31d72cdb4bcc9b Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 2 May 2019 15:24:04 -0700
-Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while
- they're running.
-
-This falls under the same "we can reprogram glitch-free as long as we
-pause generation" rule as updating the div/frac fields. This can be
-used for runtime reclocking of V3D to manage power leakage.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++---
- 1 file changed, 16 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1087,8 +1087,10 @@ static int bcm2835_clock_on(struct clk_h
- return 0;
- }
-
--static int bcm2835_clock_set_rate(struct clk_hw *hw,
-- unsigned long rate, unsigned long parent_rate)
-+static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw,
-+ unsigned long rate,
-+ unsigned long parent_rate,
-+ u8 parent)
- {
- struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
- struct bcm2835_cprman *cprman = clock->cprman;
-@@ -1110,6 +1112,11 @@ static int bcm2835_clock_set_rate(struct
- bcm2835_clock_wait_busy(clock);
- }
-
-+ if (parent != 0xff) {
-+ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT);
-+ ctl |= parent << CM_SRC_SHIFT;
-+ }
-+
- ctl &= ~CM_FRAC;
- ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
- cprman_write(cprman, data->ctl_reg, ctl);
-@@ -1121,6 +1128,12 @@ static int bcm2835_clock_set_rate(struct
- return 0;
- }
-
-+static int bcm2835_clock_set_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long parent_rate)
-+{
-+ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff);
-+}
-+
- static bool
- bcm2835_clk_is_pllc(struct clk_hw *hw)
- {
-@@ -1304,6 +1317,7 @@ static const struct clk_ops bcm2835_cloc
- .unprepare = bcm2835_clock_off,
- .recalc_rate = bcm2835_clock_get_rate,
- .set_rate = bcm2835_clock_set_rate,
-+ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent,
- .determine_rate = bcm2835_clock_determine_rate,
- .set_parent = bcm2835_clock_set_parent,
- .get_parent = bcm2835_clock_get_parent,
-@@ -1480,7 +1494,6 @@ static struct clk_hw *bcm2835_register_c
- init.ops = &bcm2835_vpu_clock_clk_ops;
- } else {
- init.ops = &bcm2835_clock_clk_ops;
-- init.flags |= CLK_SET_PARENT_GATE;
-
- /* If the clock wasn't actually enabled at boot, it's not
- * critical.
--- /dev/null
+From 50f3c90e2400a0391a7461e5e2fea86ffb3f8f60 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 4 Mar 2019 11:59:34 -0800
+Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -116,6 +116,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
+ struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
+ struct drm_color_ctm *ctm = ctm_state->ctm;
+
++ if (vc4->firmware_kms)
++ return;
++
+ if (ctm_state->fifo) {
+ HVS_WRITE(SCALER_OLEDCOEF2,
+ VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
+++ /dev/null
-From 2669f337d78306667e4243fda9282fb8c07d0d3d Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 11 Jun 2019 10:55:00 +0100
-Subject: [PATCH] usb: add plumbing for updating interrupt endpoint
- interval state
-
-xHCI caches device and endpoint data after the interface is configured,
-so an explicit command needs to be issued for any device driver wanting
-to alter the polling interval of an endpoint.
-
-Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be
-called after calculating endpoint bandwidth requirements but before any
-URBs are submitted.
-
-If polling intervals are shortened, any bandwidth reservations are no
-longer valid but in practice polling intervals are only ever relaxed.
-
-Limit the scope to interrupt transfers for now.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/core/hcd.c | 10 ++++++++++
- drivers/usb/core/message.c | 15 +++++++++++++++
- include/linux/usb.h | 2 ++
- include/linux/usb/hcd.h | 7 +++++++
- 4 files changed, 34 insertions(+)
-
---- a/drivers/usb/core/hcd.c
-+++ b/drivers/usb/core/hcd.c
-@@ -1941,6 +1941,16 @@ reset:
- return ret;
- }
-
-+void usb_hcd_fixup_endpoint(struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval)
-+{
-+ struct usb_hcd *hcd;
-+
-+ hcd = bus_to_hcd(udev->bus);
-+ if (hcd->driver->fixup_endpoint)
-+ hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
-+}
-+
- /* Disables the endpoint: synchronizes with the hcd to make sure all
- * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
- * have been called previously. Use for set_configuration, set_interface,
---- a/drivers/usb/core/message.c
-+++ b/drivers/usb/core/message.c
-@@ -1113,6 +1113,21 @@ static void remove_intf_ep_devs(struct u
- intf->ep_devs_created = 0;
- }
-
-+void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval)
-+{
-+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-+ struct usb_host_endpoint *ep;
-+
-+ if (usb_endpoint_out(epaddr))
-+ ep = dev->ep_out[epnum];
-+ else
-+ ep = dev->ep_in[epnum];
-+
-+ if (ep && usb_endpoint_xfer_int(&ep->desc))
-+ usb_hcd_fixup_endpoint(dev, ep, interval);
-+}
-+EXPORT_SYMBOL_GPL(usb_fixup_endpoint);
-+
- /**
- * usb_disable_endpoint -- Disable an endpoint by address
- * @dev: the device whose endpoint is being disabled
---- a/include/linux/usb.h
-+++ b/include/linux/usb.h
-@@ -1816,6 +1816,8 @@ extern int usb_clear_halt(struct usb_dev
- extern int usb_reset_configuration(struct usb_device *dev);
- extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
- extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
-+extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
-+ int interval);
-
- /* this request isn't really synchronous, but it belongs with the others */
- extern int usb_driver_set_configuration(struct usb_device *udev, int config);
---- a/include/linux/usb/hcd.h
-+++ b/include/linux/usb/hcd.h
-@@ -382,6 +382,11 @@ struct hc_driver {
- * or bandwidth constraints.
- */
- void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
-+ /* Override the endpoint-derived interval
-+ * (if there is any cached hardware state).
-+ */
-+ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval);
- /* Returns the hardware-chosen device address */
- int (*address_device)(struct usb_hcd *, struct usb_device *udev);
- /* prepares the hardware to send commands to the device */
-@@ -443,6 +448,8 @@ extern void usb_hcd_unmap_urb_setup_for_
- extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
- extern void usb_hcd_flush_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep);
-+extern void usb_hcd_fixup_endpoint(struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval);
- extern void usb_hcd_disable_endpoint(struct usb_device *udev,
- struct usb_host_endpoint *ep);
- extern void usb_hcd_reset_endpoint(struct usb_device *udev,
--- /dev/null
+From c023f241d93059ba6ee2ab5acdb2b54b85b12f53 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 4 Oct 2018 17:22:43 -0700
+Subject: [PATCH] drm/v3d: Add support for 2711.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -221,6 +221,7 @@ static struct drm_driver v3d_drm_driver
+ static const struct of_device_id v3d_of_match[] = {
+ { .compatible = "brcm,7268-v3d" },
+ { .compatible = "brcm,7278-v3d" },
++ { .compatible = "brcm,2711-v3d" },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, v3d_of_match);
+++ /dev/null
-From 00e1a43b64abc8950b471678b7ed4415f3513f3e Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 11 Jun 2019 11:33:39 +0100
-Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval
- adjustments
-
-Must be called in a non-atomic context, after the endpoint
-has been registered with the hardware via xhci_add_endpoint
-and before the first URB is submitted for the endpoint.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 98 insertions(+)
-
---- a/drivers/usb/host/xhci.c
-+++ b/drivers/usb/host/xhci.c
-@@ -1450,6 +1450,103 @@ command_cleanup:
- }
-
- /*
-+ * RPI: Fixup endpoint intervals when requested
-+ * - Check interval versus the (cached) endpoint context
-+ * - set the endpoint interval to the new value
-+ * - force an endpoint configure command
-+ * XXX: bandwidth is not recalculated. We should probably do that.
-+ */
-+static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
-+ struct usb_host_endpoint *ep, int interval)
-+{
-+ struct xhci_hcd *xhci;
-+ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in;
-+ struct xhci_command *command;
-+ struct xhci_input_control_ctx *ctrl_ctx;
-+ struct xhci_virt_device *vdev;
-+ int xhci_interval;
-+ int ret;
-+ int ep_index;
-+ unsigned long flags;
-+ u32 ep_info_tmp;
-+
-+ xhci = hcd_to_xhci(hcd);
-+ ep_index = xhci_get_endpoint_index(&ep->desc);
-+
-+ /* FS/LS interval translations */
-+ if ((udev->speed == USB_SPEED_FULL ||
-+ udev->speed == USB_SPEED_LOW))
-+ interval *= 8;
-+
-+ mutex_lock(&xhci->mutex);
-+
-+ spin_lock_irqsave(&xhci->lock, flags);
-+
-+ vdev = xhci->devs[udev->slot_id];
-+ /* Get context-derived endpoint interval */
-+ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
-+ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
-+ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info));
-+
-+ if (interval == xhci_interval) {
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+
-+ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n",
-+ interval, xhci_interval);
-+ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC);
-+ if (!command) {
-+ /* Failure here is benign, poll at the original rate */
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+
-+ /* xHCI uses exponents for intervals... */
-+ xhci_interval = fls(interval) - 1;
-+ xhci_interval = clamp_val(xhci_interval, 3, 10);
-+ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info);
-+ ep_info_tmp &= ~EP_INTERVAL(255);
-+ ep_info_tmp |= EP_INTERVAL(xhci_interval);
-+
-+ /* Keep the endpoint context up-to-date while issuing the command. */
-+ xhci_endpoint_copy(xhci, vdev->in_ctx,
-+ vdev->out_ctx, ep_index);
-+ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp);
-+
-+ /*
-+ * We need to drop the lock, so take an explicit copy
-+ * of the ep context.
-+ */
-+ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index);
-+
-+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
-+ if (!ctrl_ctx) {
-+ xhci_warn(xhci,
-+ "%s: Could not get input context, bad type.\n",
-+ __func__);
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+ xhci_free_command(xhci, command);
-+ mutex_unlock(&xhci->mutex);
-+ return;
-+ }
-+ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index);
-+ ctrl_ctx->drop_flags = 0;
-+
-+ spin_unlock_irqrestore(&xhci->lock, flags);
-+
-+ ret = xhci_configure_endpoint(xhci, udev, command,
-+ false, false);
-+ if (ret)
-+ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
-+ __func__, ret);
-+ xhci_free_command(xhci, command);
-+ mutex_unlock(&xhci->mutex);
-+}
-+
-+/*
- * non-error returns are a promise to giveback() the urb later
- * we drop ownership so next owner (or urb unlink) can get it
- */
-@@ -5325,6 +5422,7 @@ static const struct hc_driver xhci_hc_dr
- .endpoint_reset = xhci_endpoint_reset,
- .check_bandwidth = xhci_check_bandwidth,
- .reset_bandwidth = xhci_reset_bandwidth,
-+ .fixup_endpoint = xhci_fixup_endpoint,
- .address_device = xhci_address_device,
- .enable_device = xhci_enable_device,
- .update_hub_device = xhci_update_hub_device,
--- /dev/null
+From f34daf3b5ae9533f88d31eef74bbf38099e96aa1 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 14 Jan 2019 12:35:43 -0800
+Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently
+ off.
+
+If it's off, we know it will be reset on poweron, so the MMU won't
+have any TLB cached from before this point. Avoids failed waits for
+MMU flush to reply.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b)
+---
+ drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_mmu.c
++++ b/drivers/gpu/drm/v3d/v3d_mmu.c
+@@ -18,6 +18,8 @@
+ * each client. This is not yet implemented.
+ */
+
++#include <linux/pm_runtime.h>
++
+ #include "v3d_drv.h"
+ #include "v3d_regs.h"
+
+@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_
+ {
+ int ret;
+
++ /* Keep power on the device on until we're done with this
++ * call, but skip the flush if the device is off and will be
++ * reset when powered back on.
++ */
++ ret = pm_runtime_get_if_in_use(v3d->dev);
++ if (ret == 0)
++ return 0;
++
+ /* Make sure that another flush isn't already running when we
+ * start this one.
+ */
+@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_
+ if (ret)
+ dev_err(v3d->dev, "MMUC flush wait idle failed\n");
+
++ pm_runtime_mark_last_busy(v3d->dev);
++ pm_runtime_put_autosuspend(v3d->dev);
++
+ return ret;
+ }
+
+++ /dev/null
-From df28fdf0b853c0951bab5c9cbb5aa82819f7b34b Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 11 Jun 2019 11:42:03 +0100
-Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling
- intervals
-
-Lets the mousepoll override mechanism work with xhci.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/hid/usbhid/hid-core.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/hid/usbhid/hid-core.c
-+++ b/drivers/hid/usbhid/hid-core.c
-@@ -1115,6 +1115,7 @@ static int usbhid_start(struct hid_devic
- interval = hid_kbpoll_interval;
- break;
- }
-+ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval);
-
- ret = -ENOMEM;
- if (usb_endpoint_dir_in(endpoint)) {
+++ /dev/null
-From 8af54831d1d377b6a4ab087c409f1684e1e985a7 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 11 Jun 2019 17:38:28 +0100
-Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/mach-bcm/board_bcm2835.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -109,6 +109,7 @@ static const char * const bcm2835_compat
- #ifdef CONFIG_ARCH_MULTI_V7
- "brcm,bcm2836",
- "brcm,bcm2837",
-+ "brcm,bcm2838",
- #endif
- NULL
- };
--- /dev/null
+From 0b1f35dfb545dab884df2b4761e1af731f41ca9e Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 14 Jan 2019 14:47:57 -0800
+Subject: [PATCH] drm/v3d: Hook up the runtime PM ops.
+
+In translating the runtime PM code from vc4, I missed the ".pm"
+assignment to actually connect them up. Fixes missing MMU setup if
+runtime PM resets V3D.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06)
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -69,7 +69,7 @@ static int v3d_runtime_resume(struct dev
+ }
+ #endif
+
+-static const struct dev_pm_ops v3d_v3d_pm_ops = {
++static const struct dev_pm_ops v3d_pm_ops = {
+ SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL)
+ };
+
+@@ -362,6 +362,7 @@ static struct platform_driver v3d_platfo
+ .driver = {
+ .name = "v3d",
+ .of_match_table = v3d_of_match,
++ .pm = &v3d_pm_ops,
+ },
+ };
+
+++ /dev/null
-From 50f3c90e2400a0391a7461e5e2fea86ffb3f8f60 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 4 Mar 2019 11:59:34 -0800
-Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -116,6 +116,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
- struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
- struct drm_color_ctm *ctm = ctm_state->ctm;
-
-+ if (vc4->firmware_kms)
-+ return;
-+
- if (ctm_state->fifo) {
- HVS_WRITE(SCALER_OLEDCOEF2,
- VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
--- /dev/null
+From 87df00d6b301f5de54443ac7e3765dce983e8b6a Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 28 Mar 2019 11:58:51 -0700
+Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL
+ rendering.
+
+We would present the framebuffer immediately without waiting for
+rendering to finish first, resulting in stuttering and flickering as a
+window was dragged around when the GPU was busy enough to not just win
+the race.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include "drm/drm_atomic_helper.h"
++#include "drm/drm_gem_framebuffer_helper.h"
+ #include "drm/drm_plane_helper.h"
+ #include "drm/drm_crtc_helper.h"
+ #include "drm/drm_fourcc.h"
+@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_
+ };
+
+ static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+- .prepare_fb = NULL,
++ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+ .atomic_update = vc4_primary_plane_atomic_update,
+@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun
+ };
+
+ static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
+- .prepare_fb = NULL,
++ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+ .atomic_update = vc4_cursor_plane_atomic_update,
+++ /dev/null
-From c023f241d93059ba6ee2ab5acdb2b54b85b12f53 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 4 Oct 2018 17:22:43 -0700
-Subject: [PATCH] drm/v3d: Add support for 2711.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/v3d/v3d_drv.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -221,6 +221,7 @@ static struct drm_driver v3d_drm_driver
- static const struct of_device_id v3d_of_match[] = {
- { .compatible = "brcm,7268-v3d" },
- { .compatible = "brcm,7278-v3d" },
-+ { .compatible = "brcm,2711-v3d" },
- {},
- };
- MODULE_DEVICE_TABLE(of, v3d_of_match);
--- /dev/null
+From c27d4bbba9593a6ded8f482610a0247da66d78a9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 18 Mar 2019 16:38:32 -0700
+Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware
+ kms.
+
+This should technically not expose VC4_T_TILED on pi4. However, if we
+don't expose anything, then userspace will assume that display can
+handle whatever modifiers 3d can do (UIF on 2711). By exposing a
+list, that will get intersected with what 3D can do so that we get T
+tiling for display on 2710 and linear on 2711.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm
+ drm_plane_cleanup(plane);
+ }
+
++static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
++ uint32_t format,
++ uint64_t modifier)
++{
++ /* Support T_TILING for RGB formats only. */
++ switch (format) {
++ case DRM_FORMAT_XRGB8888:
++ case DRM_FORMAT_ARGB8888:
++ switch (modifier) {
++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
++ case DRM_FORMAT_MOD_LINEAR:
++ case DRM_FORMAT_MOD_BROADCOM_UIF:
++ return true;
++ default:
++ return false;
++ }
++ default:
++ return false;
++ }
++}
++
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
++ .format_mod_supported = vc4_fkms_format_mod_supported,
+ };
+
+ static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_
+ u32 argb8888 = DRM_FORMAT_ARGB8888;
+ int ret = 0;
+ bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
++ static const uint64_t modifiers[] = {
++ DRM_FORMAT_MOD_LINEAR,
++ /* VC4_T_TILED should come after linear, because we
++ * would prefer to scan out linear (less bus traffic).
++ */
++ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
++ DRM_FORMAT_MOD_INVALID,
++ };
+
+ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
+ GFP_KERNEL);
+@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- primary ? &xrgb8888 : &argb8888, 1, NULL,
++ primary ? &xrgb8888 : &argb8888, 1,
++ modifiers,
+ type, primary ? "primary" : "cursor");
+
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
+++ /dev/null
-From f34daf3b5ae9533f88d31eef74bbf38099e96aa1 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 14 Jan 2019 12:35:43 -0800
-Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently
- off.
-
-If it's off, we know it will be reset on poweron, so the MMU won't
-have any TLB cached from before this point. Avoids failed waits for
-MMU flush to reply.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
-(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b)
----
- drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_mmu.c
-+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
-@@ -18,6 +18,8 @@
- * each client. This is not yet implemented.
- */
-
-+#include <linux/pm_runtime.h>
-+
- #include "v3d_drv.h"
- #include "v3d_regs.h"
-
-@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_
- {
- int ret;
-
-+ /* Keep power on the device on until we're done with this
-+ * call, but skip the flush if the device is off and will be
-+ * reset when powered back on.
-+ */
-+ ret = pm_runtime_get_if_in_use(v3d->dev);
-+ if (ret == 0)
-+ return 0;
-+
- /* Make sure that another flush isn't already running when we
- * start this one.
- */
-@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_
- if (ret)
- dev_err(v3d->dev, "MMUC flush wait idle failed\n");
-
-+ pm_runtime_mark_last_busy(v3d->dev);
-+ pm_runtime_put_autosuspend(v3d->dev);
-+
- return ret;
- }
-
--- /dev/null
+From c71f09dafd82a37a488029f33552a45a99d0a9a6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 2 Apr 2019 13:29:00 -0700
+Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms.
+
+The core doesn't expect a false return from the scanoutpos function in
+normal usage, so we were doing the precise vblank timestamping path
+and thus "immediate" vblank disables (even though firmwarekms can't
+actually disable vblanks interrupts, sigh), and the kernel would get
+confused when getting timestamp info when also turning vblanks back
+on.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 3 ---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -97,9 +97,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_
+ int vblank_lines;
+ bool ret = false;
+
+- if (vc4->firmware_kms)
+- return 0;
+-
+ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
+
+ /* Get optional system timestamp before query. */
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -20,6 +20,7 @@
+ #include "drm/drm_crtc_helper.h"
+ #include "drm/drm_fourcc.h"
+ #include "drm/drm_probe_helper.h"
++#include "drm/drm_drv.h"
+ #include "linux/clk.h"
+ #include "linux/debugfs.h"
+ #include "drm/drm_fb_cma_helper.h"
+@@ -673,6 +674,12 @@ static int vc4_fkms_bind(struct device *
+
+ vc4->firmware_kms = true;
+
++ /* firmware kms doesn't have precise a scanoutpos implementation, so
++ * we can't do the precise vblank timestamp mode.
++ */
++ drm->driver->get_scanout_position = NULL;
++ drm->driver->get_vblank_timestamp = NULL;
++
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+ if (!vc4_crtc)
+ return -ENOMEM;
+++ /dev/null
-From 0b1f35dfb545dab884df2b4761e1af731f41ca9e Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 14 Jan 2019 14:47:57 -0800
-Subject: [PATCH] drm/v3d: Hook up the runtime PM ops.
-
-In translating the runtime PM code from vc4, I missed the ".pm"
-assignment to actually connect them up. Fixes missing MMU setup if
-runtime PM resets V3D.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
-(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06)
----
- drivers/gpu/drm/v3d/v3d_drv.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -69,7 +69,7 @@ static int v3d_runtime_resume(struct dev
- }
- #endif
-
--static const struct dev_pm_ops v3d_v3d_pm_ops = {
-+static const struct dev_pm_ops v3d_pm_ops = {
- SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL)
- };
-
-@@ -362,6 +362,7 @@ static struct platform_driver v3d_platfo
- .driver = {
- .name = "v3d",
- .of_match_table = v3d_of_match,
-+ .pm = &v3d_pm_ops,
- },
- };
-
--- /dev/null
+From b721bcc62759ae7a2d9730d1121974702be96d7c Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 26 Mar 2019 14:43:06 +0000
+Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame
+ buffer API.
+
+The old mailbox FB API was ideally deprecated but still used by
+the FKMS driver.
+Update to the newer API.
+
+NB This needs current firmware that accepts ARM allocated buffers
+through the newer API.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++++------------
+ 1 file changed, 57 insertions(+), 52 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -30,6 +30,25 @@
+ #include "vc4_regs.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct fb_alloc_tags {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 xres, yres;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 xres_virtual, yres_virtual;
++ struct rpi_firmware_property_tag_header tag3;
++ u32 bpp;
++ struct rpi_firmware_property_tag_header tag4;
++ u32 xoffset, yoffset;
++ struct rpi_firmware_property_tag_header tag5;
++ u32 base, screen_size;
++ struct rpi_firmware_property_tag_header tag6;
++ u32 pitch;
++ struct rpi_firmware_property_tag_header tag7;
++ u32 alpha_mode;
++ struct rpi_firmware_property_tag_header tag8;
++ u32 layer;
++};
++
+ /* The firmware delivers a vblank interrupt to us through the SMI
+ * hardware, which has only this one register.
+ */
+@@ -123,45 +142,39 @@ static void vc4_primary_plane_atomic_upd
+ struct drm_plane_state *old_state)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
++ u32 format = fb->format->format;
++ struct fb_alloc_tags fbinfo = {
++ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
++ 8, 0, },
++ .xres = state->crtc_w,
++ .yres = state->crtc_h,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
++ 8, 0, },
++ .xres_virtual = state->crtc_w,
++ .yres_virtual = state->crtc_h,
++ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
++ .bpp = 32,
++ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
++ .xoffset = 0,
++ .yoffset = 0,
++ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
++ .base = bo->paddr + fb->offsets[0],
++ .screen_size = state->crtc_w * state->crtc_h * 4,
++ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
++ .pitch = fb->pitches[0],
++ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
++ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
++ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
++ .layer = -127,
++ };
+ u32 bpp = 32;
+ int ret;
+
+- fbinfo->xres = state->crtc_w;
+- fbinfo->yres = state->crtc_h;
+- fbinfo->xres_virtual = state->crtc_w;
+- fbinfo->yres_virtual = state->crtc_h;
+- fbinfo->bpp = bpp;
+- fbinfo->xoffset = state->crtc_x;
+- fbinfo->yoffset = state->crtc_y;
+- fbinfo->base = bo->paddr + fb->offsets[0];
+- fbinfo->pitch = fb->pitches[0];
+-
+ if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+- fbinfo->bpp |= BIT(31);
+-
+- /* A bug in the firmware makes it so that if the fb->base is
+- * set to nonzero, the configured pitch gets overwritten with
+- * the previous pitch. So, to get the configured pitch
+- * recomputed, we have to make it allocate itself a new buffer
+- * in VC memory, first.
+- */
+- if (vc4_plane->pitch != fb->pitches[0]) {
+- u32 saved_base = fbinfo->base;
+- fbinfo->base = 0;
+-
+- ret = rpi_firmware_transaction(vc4->firmware,
+- RPI_FIRMWARE_CHAN_FB,
+- vc4_plane->fbinfo_bus_addr);
+- fbinfo->base = saved_base;
+-
+- vc4_plane->pitch = fbinfo->pitch;
+- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
+- }
++ fbinfo.bpp |= BIT(31);
+
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
+ plane->base.id, plane->name,
+@@ -170,14 +183,13 @@ static void vc4_primary_plane_atomic_upd
+ bpp,
+ state->crtc_x,
+ state->crtc_y,
+- &fbinfo->base,
++ &fbinfo.base,
+ fb->pitches[0]);
+
+- ret = rpi_firmware_transaction(vc4->firmware,
+- RPI_FIRMWARE_CHAN_FB,
+- vc4_plane->fbinfo_bus_addr);
+- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
+- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
++ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
++ sizeof(fbinfo));
++ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
++ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
+
+ /* If the CRTC is on (or going to be on) and we're enabled,
+ * then unblank. Otherwise, stay blank until CRTC enable.
+@@ -333,10 +345,10 @@ static const struct drm_plane_helper_fun
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+ enum drm_plane_type type)
+ {
++ /* Primary and cursor planes only */
+ struct drm_plane *plane = NULL;
+ struct vc4_fkms_plane *vc4_plane;
+- u32 xrgb8888 = DRM_FORMAT_XRGB8888;
+- u32 argb8888 = DRM_FORMAT_ARGB8888;
++ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
+ int ret = 0;
+ bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
+ static const uint64_t modifiers[] = {
+@@ -358,22 +370,15 @@ static struct drm_plane *vc4_fkms_plane_
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- primary ? &xrgb8888 : &argb8888, 1,
+- modifiers,
++ formats, primary ? 2 : 1, modifiers,
+ type, primary ? "primary" : "cursor");
+
+- if (type == DRM_PLANE_TYPE_PRIMARY) {
+- vc4_plane->fbinfo =
+- dma_alloc_coherent(dev->dev,
+- sizeof(*vc4_plane->fbinfo),
+- &vc4_plane->fbinfo_bus_addr,
+- GFP_KERNEL);
+- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
+-
++ if (type == DRM_PLANE_TYPE_PRIMARY)
+ drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
+- } else {
++ else
+ drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
+- }
++
++ drm_plane_create_alpha_property(plane);
+
+ return plane;
+ fail:
--- /dev/null
+From 75e1dce99c260cb1365edd9af68cb5c07487831c Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 27 Mar 2019 17:45:01 +0000
+Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms
+
+This uses a new API that is exposed via the mailbox service
+to stick an element straight on the screen using DispmanX.
+
+The primary and cursor planes have also been switched to using
+the new plane API, and it supports layering based on the DRM
+zpos parameter.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++-------
+ drivers/gpu/drm/vc4/vc4_kms.c | 1 +
+ drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +
+ 4 files changed, 495 insertions(+), 169 deletions(-)
+ create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -28,8 +28,46 @@
+ #include "linux/of_device.h"
+ #include "vc4_drv.h"
+ #include "vc4_regs.h"
++#include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct set_plane {
++ u8 display;
++ u8 plane_id;
++ u8 vc_image_type;
++ s8 layer;
++
++ u16 width;
++ u16 height;
++
++ u16 pitch;
++ u16 vpitch;
++
++ u32 src_x; /* 16p16 */
++ u32 src_y; /* 16p16 */
++
++ u32 src_w; /* 16p16 */
++ u32 src_h; /* 16p16 */
++
++ s16 dst_x;
++ s16 dst_y;
++
++ u16 dst_w;
++ u16 dst_h;
++
++ u8 alpha;
++ u8 num_planes;
++ u8 is_vu;
++ u8 padding;
++
++ u32 planes[4]; /* DMA address of each plane */
++};
++
++struct mailbox_set_plane {
++ struct rpi_firmware_property_tag_header tag;
++ struct set_plane plane;
++};
++
+ struct fb_alloc_tags {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 xres, yres;
+@@ -49,6 +87,79 @@ struct fb_alloc_tags {
+ u32 layer;
+ };
+
++static const struct vc_image_format {
++ u32 drm; /* DRM_FORMAT_* */
++ u32 vc_image; /* VC_IMAGE_* */
++ u32 is_vu;
++} vc_image_formats[] = {
++ {
++ .drm = DRM_FORMAT_XRGB8888,
++ .vc_image = VC_IMAGE_XRGB8888,
++ },
++ {
++ .drm = DRM_FORMAT_ARGB8888,
++ .vc_image = VC_IMAGE_ARGB8888,
++ },
++/*
++ * FIXME: Need to resolve which DRM format goes to which vc_image format
++ * for the remaining RGBA and RGBX formats.
++ * {
++ * .drm = DRM_FORMAT_ABGR8888,
++ * .vc_image = VC_IMAGE_RGBA8888,
++ * },
++ * {
++ * .drm = DRM_FORMAT_XBGR8888,
++ * .vc_image = VC_IMAGE_RGBA8888,
++ * },
++ */
++ {
++ .drm = DRM_FORMAT_RGB565,
++ .vc_image = VC_IMAGE_RGB565,
++ },
++ {
++ .drm = DRM_FORMAT_RGB888,
++ .vc_image = VC_IMAGE_BGR888,
++ },
++ {
++ .drm = DRM_FORMAT_BGR888,
++ .vc_image = VC_IMAGE_RGB888,
++ },
++ {
++ .drm = DRM_FORMAT_YUV422,
++ .vc_image = VC_IMAGE_YUV422PLANAR,
++ },
++ {
++ .drm = DRM_FORMAT_YUV420,
++ .vc_image = VC_IMAGE_YUV420,
++ },
++ {
++ .drm = DRM_FORMAT_YVU420,
++ .vc_image = VC_IMAGE_YUV420,
++ .is_vu = 1,
++ },
++ {
++ .drm = DRM_FORMAT_NV12,
++ .vc_image = VC_IMAGE_YUV420SP,
++ },
++ {
++ .drm = DRM_FORMAT_NV21,
++ .vc_image = VC_IMAGE_YUV420SP,
++ .is_vu = 1,
++ },
++};
++
++static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
++ if (vc_image_formats[i].drm == drm_format)
++ return &vc_image_formats[i];
++ }
++
++ return NULL;
++}
++
+ /* The firmware delivers a vblank interrupt to us through the SMI
+ * hardware, which has only this one register.
+ */
+@@ -115,6 +226,7 @@ struct vc4_fkms_plane {
+ struct fbinfo_s *fbinfo;
+ dma_addr_t fbinfo_bus_addr;
+ u32 pitch;
++ struct mailbox_set_plane mb;
+ };
+
+ static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
+@@ -122,165 +234,183 @@ static inline struct vc4_fkms_plane *to_
+ return (struct vc4_fkms_plane *)plane;
+ }
+
+-/* Turns the display on/off. */
+-static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
++static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
+ {
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++ struct mailbox_set_plane blank_mb = {
++ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
++ .plane = {
++ .display = vc4_plane->mb.plane.display,
++ .plane_id = vc4_plane->mb.plane.plane_id,
++ }
++ };
++ int ret;
+
+- u32 packet = blank;
+-
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
+ plane->base.id, plane->name,
+ blank ? "blank" : "unblank");
+
+- return rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+- &packet, sizeof(packet));
++ if (blank)
++ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
++ sizeof(blank_mb));
++ else
++ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
++ sizeof(vc4_plane->mb));
++
++ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
++ __func__);
++ return ret;
+ }
+
+-static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static void vc4_plane_atomic_update(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
+ {
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- u32 format = fb->format->format;
+- struct fb_alloc_tags fbinfo = {
+- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
+- 8, 0, },
+- .xres = state->crtc_w,
+- .yres = state->crtc_h,
+- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
+- 8, 0, },
+- .xres_virtual = state->crtc_w,
+- .yres_virtual = state->crtc_h,
+- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
+- .bpp = 32,
+- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
+- .xoffset = 0,
+- .yoffset = 0,
+- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
+- .base = bo->paddr + fb->offsets[0],
+- .screen_size = state->crtc_w * state->crtc_h * 4,
+- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
+- .pitch = fb->pitches[0],
+- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
+- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
+- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
+- .layer = -127,
+- };
+- u32 bpp = 32;
+- int ret;
++ const struct drm_format_info *drm_fmt = fb->format;
++ const struct vc_image_format *vc_fmt =
++ vc4_get_vc_image_fmt(drm_fmt->format);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++ struct mailbox_set_plane *mb = &vc4_plane->mb;
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
++ int num_planes = fb->format->num_planes;
++ struct drm_display_mode *mode = &state->crtc->mode;
+
+- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+- fbinfo.bpp |= BIT(31);
++ mb->plane.vc_image_type = vc_fmt->vc_image;
++ mb->plane.width = fb->width;
++ mb->plane.height = fb->height;
++ mb->plane.pitch = fb->pitches[0];
++ mb->plane.src_w = state->src_w;
++ mb->plane.src_h = state->src_h;
++ mb->plane.src_x = state->src_x;
++ mb->plane.src_y = state->src_y;
++ mb->plane.dst_w = state->crtc_w;
++ mb->plane.dst_h = state->crtc_h;
++ mb->plane.dst_x = state->crtc_x;
++ mb->plane.dst_y = state->crtc_y;
++ mb->plane.alpha = state->alpha >> 8;
++ mb->plane.layer = state->normalized_zpos ?
++ state->normalized_zpos : -127;
++ mb->plane.num_planes = num_planes;
++ mb->plane.is_vu = vc_fmt->is_vu;
++ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
++ /* FIXME: If the dest rect goes off screen then clip the src rect so we
++ * don't have off-screen pixels.
++ */
++ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
++ /* There is no scaling on the cursor plane, therefore the calcs
++ * to alter the source crop as the cursor goes off the screen
++ * are simple.
++ */
++ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
++ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
++ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
++ << 16;
++ }
++ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
++ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
++ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
++ << 16;
++ }
++ }
++
++ if (num_planes > 1) {
++ /* Assume this must be YUV */
++ /* Makes assumptions on the stride for the chroma planes as we
++ * can't easily plumb in non-standard pitches.
++ */
++ mb->plane.planes[1] = bo->paddr + fb->offsets[1];
++ if (num_planes > 2)
++ mb->plane.planes[2] = bo->paddr + fb->offsets[2];
++ else
++ mb->plane.planes[2] = 0;
++
++ /* Special case the YUV420 with U and V as line interleaved
++ * planes as we have special handling for that case.
++ */
++ if (num_planes == 3 &&
++ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
++ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
++ } else {
++ mb->plane.planes[1] = 0;
++ mb->plane.planes[2] = 0;
++ }
++ mb->plane.planes[3] = 0;
++
++ switch (fb->modifier) {
++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
++ switch (mb->plane.vc_image_type) {
++ case VC_IMAGE_RGBX32:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
++ break;
++ case VC_IMAGE_RGBA32:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
++ break;
++ case VC_IMAGE_RGB565:
++ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
++ break;
++ }
++ break;
++ case DRM_FORMAT_MOD_BROADCOM_SAND128:
++ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
++ break;
++ }
++
++ if (vc4_crtc) {
++ mb->plane.dst_x += vc4_crtc->overscan[0];
++ mb->plane.dst_y += vc4_crtc->overscan[1];
++ }
++
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
+ plane->base.id, plane->name,
+- state->crtc_w,
+- state->crtc_h,
+- bpp,
++ mb->plane.width,
++ mb->plane.height,
++ mb->plane.vc_image_type,
+ state->crtc_x,
+ state->crtc_y,
+- &fbinfo.base,
+- fb->pitches[0]);
+-
+- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
+- sizeof(fbinfo));
+- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
+- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
+-
+- /* If the CRTC is on (or going to be on) and we're enabled,
++ state->crtc_w,
++ state->crtc_h,
++ mb->plane.src_x,
++ mb->plane.src_y,
++ mb->plane.src_w,
++ mb->plane.src_h,
++ mb->plane.planes[0],
++ mb->plane.planes[1],
++ mb->plane.planes[2],
++ fb->pitches[0],
++ state->alpha,
++ state->normalized_zpos);
++
++ /*
++ * Do NOT set now, as we haven't checked if the crtc is active or not.
++ * Set from vc4_plane_set_blank instead.
++ *
++ * If the CRTC is on (or going to be on) and we're enabled,
+ * then unblank. Otherwise, stay blank until CRTC enable.
+- */
++ */
+ if (state->crtc->state->active)
+- vc4_plane_set_primary_blank(plane, false);
++ vc4_plane_set_blank(plane, false);
+ }
+
+-static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static void vc4_plane_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
+ {
+- vc4_plane_set_primary_blank(plane, true);
+-}
+-
+-static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
+-{
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
++ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+ struct drm_plane_state *state = plane->state;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+- struct drm_framebuffer *fb = state->fb;
+- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+- dma_addr_t addr = bo->paddr + fb->offsets[0];
+- int ret;
+- u32 packet_state[] = {
+- state->crtc->state->active,
+- state->crtc_x,
+- state->crtc_y,
+- 0
+- };
+- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+ plane->base.id, plane->name,
+ state->crtc_w,
+ state->crtc_h,
++ vc4_plane->mb.plane.vc_image_type,
+ state->crtc_x,
+- state->crtc_y,
+- &addr,
+- fb->pitches[0]);
+-
+- /* add on the top/left offsets when overscan is active */
+- if (vc4_crtc) {
+- packet_state[1] += vc4_crtc->overscan[0];
+- packet_state[2] += vc4_crtc->overscan[1];
+- }
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_STATE,
+- &packet_state,
+- sizeof(packet_state));
+- if (ret || packet_state[0] != 0)
+- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
+-
+- /* Note: When the cursor contents change, the modesetting
+- * driver calls drm_mode_cursor_univeral() with
+- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated.
+- */
+- if (!old_state ||
+- state->crtc_w != old_state->crtc_w ||
+- state->crtc_h != old_state->crtc_h ||
+- fb != old_state->fb) {
+- u32 packet_info[] = { state->crtc_w, state->crtc_h,
+- 0, /* unused */
+- addr,
+- 0, 0, /* hotx, hoty */};
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_INFO,
+- &packet_info,
+- sizeof(packet_info));
+- if (ret || packet_info[0] != 0)
+- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
+- }
+-}
+-
+-static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
+-{
+- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- u32 packet_state[] = { false, 0, 0, 0 };
+- int ret;
+-
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
+-
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_SET_CURSOR_STATE,
+- &packet_state,
+- sizeof(packet_state));
+- if (ret || packet_state[0] != 0)
+- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
++ state->crtc_y);
++ vc4_plane_set_blank(plane, true);
+ }
+
+ static int vc4_plane_atomic_check(struct drm_plane *plane,
+@@ -302,6 +432,7 @@ static bool vc4_fkms_format_mod_supporte
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
++ case DRM_FORMAT_RGB565:
+ switch (modifier) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ case DRM_FORMAT_MOD_LINEAR:
+@@ -310,8 +441,22 @@ static bool vc4_fkms_format_mod_supporte
+ default:
+ return false;
+ }
++ case DRM_FORMAT_NV12:
++ case DRM_FORMAT_NV21:
++ switch (fourcc_mod_broadcom_mod(modifier)) {
++ case DRM_FORMAT_MOD_LINEAR:
++ case DRM_FORMAT_MOD_BROADCOM_SAND128:
++ return true;
++ default:
++ return false;
++ }
++ case DRM_FORMAT_RGB888:
++ case DRM_FORMAT_BGR888:
++ case DRM_FORMAT_YUV422:
++ case DRM_FORMAT_YUV420:
++ case DRM_FORMAT_YVU420:
+ default:
+- return false;
++ return (modifier == DRM_FORMAT_MOD_LINEAR);
+ }
+ }
+
+@@ -326,31 +471,24 @@ static const struct drm_plane_funcs vc4_
+ .format_mod_supported = vc4_fkms_format_mod_supported,
+ };
+
+-static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
+- .prepare_fb = drm_gem_fb_prepare_fb,
+- .cleanup_fb = NULL,
+- .atomic_check = vc4_plane_atomic_check,
+- .atomic_update = vc4_primary_plane_atomic_update,
+- .atomic_disable = vc4_primary_plane_atomic_disable,
+-};
+-
+-static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
++static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
+ .prepare_fb = drm_gem_fb_prepare_fb,
+ .cleanup_fb = NULL,
+ .atomic_check = vc4_plane_atomic_check,
+- .atomic_update = vc4_cursor_plane_atomic_update,
+- .atomic_disable = vc4_cursor_plane_atomic_disable,
++ .atomic_update = vc4_plane_atomic_update,
++ .atomic_disable = vc4_plane_atomic_disable,
+ };
+
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+- enum drm_plane_type type)
++ enum drm_plane_type type,
++ u8 plane_id)
+ {
+- /* Primary and cursor planes only */
+ struct drm_plane *plane = NULL;
+ struct vc4_fkms_plane *vc4_plane;
+- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
++ u32 formats[ARRAY_SIZE(vc_image_formats)];
++ unsigned int default_zpos = 0;
++ u32 num_formats = 0;
+ int ret = 0;
+- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
+ static const uint64_t modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ /* VC4_T_TILED should come after linear, because we
+@@ -359,6 +497,7 @@ static struct drm_plane *vc4_fkms_plane_
+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
+ DRM_FORMAT_MOD_INVALID,
+ };
++ int i;
+
+ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
+ GFP_KERNEL);
+@@ -367,19 +506,48 @@ static struct drm_plane *vc4_fkms_plane_
+ goto fail;
+ }
+
++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
++ formats[num_formats++] = vc_image_formats[i].drm;
++
+ plane = &vc4_plane->base;
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &vc4_plane_funcs,
+- formats, primary ? 2 : 1, modifiers,
+- type, primary ? "primary" : "cursor");
++ formats, num_formats, modifiers,
++ type, NULL);
+
+- if (type == DRM_PLANE_TYPE_PRIMARY)
+- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
+- else
+- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
++ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+
+ drm_plane_create_alpha_property(plane);
+
++ /*
++ * Default frame buffer setup is with FB on -127, and raspistill etc
++ * tend to drop overlays on layer 2. Cursor plane was on layer +127.
++ *
++ * For F-KMS the mailbox call allows for a s8.
++ * Remap zpos 0 to -127 for the background layer, but leave all the
++ * other layers as requested by KMS.
++ */
++ switch (type) {
++ case DRM_PLANE_TYPE_PRIMARY:
++ default_zpos = 0;
++ break;
++ case DRM_PLANE_TYPE_OVERLAY:
++ default_zpos = 1;
++ break;
++ case DRM_PLANE_TYPE_CURSOR:
++ default_zpos = 2;
++ break;
++ }
++ drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
++
++ /* Prepare the static elements of the mailbox structure */
++ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
++ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
++ vc4_plane->mb.tag.req_resp_size = 0;
++ vc4_plane->mb.plane.display = 0;
++ vc4_plane->mb.plane.plane_id = plane_id;
++ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
++
+ return plane;
+ fail:
+ if (plane)
+@@ -401,19 +569,23 @@ static void vc4_crtc_disable(struct drm_
+ * whether anything scans out at all, but the firmware doesn't
+ * give us a CRTC-level control for that.
+ */
+- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
+- vc4_plane_set_primary_blank(crtc->primary, true);
++
++ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
++ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
++
++ /* FIXME: Disable overlay planes */
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
+ /* Unblank the planes (if they're supposed to be displayed). */
++
+ if (crtc->primary->state->fb)
+- vc4_plane_set_primary_blank(crtc->primary, false);
+- if (crtc->cursor->state->fb) {
+- vc4_cursor_plane_atomic_update(crtc->cursor,
+- crtc->cursor->state);
+- }
++ vc4_plane_set_blank(crtc->primary, false);
++ if (crtc->cursor->state->fb)
++ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
++
++ /* FIXME: Enable overlay planes */
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+@@ -673,8 +845,10 @@ static int vc4_fkms_bind(struct device *
+ struct vc4_crtc *vc4_crtc;
+ struct vc4_fkms_encoder *vc4_encoder;
+ struct drm_crtc *crtc;
+- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
++ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
++ struct drm_plane *destroy_plane, *temp;
+ struct device_node *firmware_node;
++ u32 blank = 1;
+ int ret;
+
+ vc4->firmware_kms = true;
+@@ -703,20 +877,26 @@ static int vc4_fkms_bind(struct device *
+ if (IS_ERR(vc4_crtc->regs))
+ return PTR_ERR(vc4_crtc->regs);
+
+- /* For now, we create just the primary and the legacy cursor
+- * planes. We should be able to stack more planes on easily,
+- * but to do that we would need to compute the bandwidth
+- * requirement of the plane configuration, and reject ones
+- * that will take too much.
+- */
+- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
++ /* Blank the firmware provided framebuffer */
++ rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
++ &blank, sizeof(blank));
++
++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
+ if (IS_ERR(primary_plane)) {
+ dev_err(dev, "failed to construct primary plane\n");
+ ret = PTR_ERR(primary_plane);
+ goto err;
+ }
+
+- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
++ if (IS_ERR(overlay_plane)) {
++ dev_err(dev, "failed to construct overlay plane\n");
++ ret = PTR_ERR(overlay_plane);
++ goto err;
++ }
++
++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
+ if (IS_ERR(cursor_plane)) {
+ dev_err(dev, "failed to construct cursor plane\n");
+ ret = PTR_ERR(cursor_plane);
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -542,6 +542,7 @@ int vc4_kms_load(struct drm_device *dev)
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+ dev->mode_config.allow_fb_modifiers = true;
++ dev->mode_config.normalize_zpos = true;
+
+ drm_modeset_lock_init(&vc4->ctm_state_lock);
+
+--- /dev/null
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -0,0 +1,143 @@
++
++/*
++ * Copyright (c) 2012, Broadcom Europe Ltd
++ *
++ * Values taken from vc_image_types.h released by Broadcom at
++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
++ *
++ * 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.
++ */
++
++enum {
++ VC_IMAGE_MIN = 0, //bounds for error checking
++
++ VC_IMAGE_RGB565 = 1,
++ VC_IMAGE_1BPP,
++ VC_IMAGE_YUV420,
++ VC_IMAGE_48BPP,
++ VC_IMAGE_RGB888,
++ VC_IMAGE_8BPP,
++ /* 4bpp palettised image */
++ VC_IMAGE_4BPP,
++ /* A separated format of 16 colour/light shorts followed by 16 z
++ * values
++ */
++ VC_IMAGE_3D32,
++ /* 16 colours followed by 16 z values */
++ VC_IMAGE_3D32B,
++ /* A separated format of 16 material/colour/light shorts followed by
++ * 16 z values
++ */
++ VC_IMAGE_3D32MAT,
++ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
++ VC_IMAGE_RGB2X9,
++ /* 32-bit format holding 18 bits of 6.6.6 RGB */
++ VC_IMAGE_RGB666,
++ /* 4bpp palettised image with embedded palette */
++ VC_IMAGE_PAL4_OBSOLETE,
++ /* 8bpp palettised image with embedded palette */
++ VC_IMAGE_PAL8_OBSOLETE,
++ /* RGB888 with an alpha byte after each pixel */
++ VC_IMAGE_RGBA32,
++ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
++ * line of V (16-byte padded)
++ */
++ VC_IMAGE_YUV422,
++ /* RGB565 with a transparent patch */
++ VC_IMAGE_RGBA565,
++ /* Compressed (4444) version of RGBA32 */
++ VC_IMAGE_RGBA16,
++ /* VCIII codec format */
++ VC_IMAGE_YUV_UV,
++ /* VCIII T-format RGBA8888 */
++ VC_IMAGE_TF_RGBA32,
++ /* VCIII T-format RGBx8888 */
++ VC_IMAGE_TF_RGBX32,
++ /* VCIII T-format float */
++ VC_IMAGE_TF_FLOAT,
++ /* VCIII T-format RGBA4444 */
++ VC_IMAGE_TF_RGBA16,
++ /* VCIII T-format RGB5551 */
++ VC_IMAGE_TF_RGBA5551,
++ /* VCIII T-format RGB565 */
++ VC_IMAGE_TF_RGB565,
++ /* VCIII T-format 8-bit luma and 8-bit alpha */
++ VC_IMAGE_TF_YA88,
++ /* VCIII T-format 8 bit generic sample */
++ VC_IMAGE_TF_BYTE,
++ /* VCIII T-format 8-bit palette */
++ VC_IMAGE_TF_PAL8,
++ /* VCIII T-format 4-bit palette */
++ VC_IMAGE_TF_PAL4,
++ /* VCIII T-format Ericsson Texture Compressed */
++ VC_IMAGE_TF_ETC1,
++ /* RGB888 with R & B swapped */
++ VC_IMAGE_BGR888,
++ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
++ * each row of pixels
++ */
++ VC_IMAGE_BGR888_NP,
++ /* Bayer image, extra defines which variant is being used */
++ VC_IMAGE_BAYER,
++ /* General wrapper for codec images e.g. JPEG from camera */
++ VC_IMAGE_CODEC,
++ /* VCIII codec format */
++ VC_IMAGE_YUV_UV32,
++ /* VCIII T-format 8-bit luma */
++ VC_IMAGE_TF_Y8,
++ /* VCIII T-format 8-bit alpha */
++ VC_IMAGE_TF_A8,
++ /* VCIII T-format 16-bit generic sample */
++ VC_IMAGE_TF_SHORT,
++ /* VCIII T-format 1bpp black/white */
++ VC_IMAGE_TF_1BPP,
++ VC_IMAGE_OPENGL,
++ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
++ VC_IMAGE_YUV444I,
++ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
++ * a per line basis)
++ */
++ VC_IMAGE_YUV422PLANAR,
++ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
++ VC_IMAGE_ARGB8888,
++ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
++ VC_IMAGE_XRGB8888,
++
++ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
++ VC_IMAGE_YUV422YUYV,
++ VC_IMAGE_YUV422YVYU,
++ VC_IMAGE_YUV422UYVY,
++ VC_IMAGE_YUV422VYUY,
++
++ /* 32bpp like RGBA32 but with unused alpha */
++ VC_IMAGE_RGBX32,
++ /* 32bpp, corresponding to RGBA with unused alpha */
++ VC_IMAGE_RGBX8888,
++ /* 32bpp, corresponding to BGRA with unused alpha */
++ VC_IMAGE_BGRX8888,
++
++ /* Y as a plane, then UV byte interleaved in plane with with same pitch,
++ * half height
++ */
++ VC_IMAGE_YUV420SP,
++
++ /* Y, U, & V planes separately 4:4:4 */
++ VC_IMAGE_YUV444PLANAR,
++
++ /* T-format 8-bit U - same as TF_Y8 buf from U plane */
++ VC_IMAGE_TF_U8,
++ /* T-format 8-bit U - same as TF_Y8 buf from V plane */
++ VC_IMAGE_TF_V8,
++
++ /* YUV4:2:0 planar, 16bit values */
++ VC_IMAGE_YUV420_16,
++ /* YUV4:2:0 codec format, 16bit values */
++ VC_IMAGE_YUV_UV_16,
++ /* YUV4:2:0 with U,V in side-by-side format */
++ VC_IMAGE_YUV420_S,
++
++ VC_IMAGE_MAX, /* bounds for error checking */
++ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
++};
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -147,6 +147,8 @@ enum rpi_firmware_property_tag {
+
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
++ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+ };
+++ /dev/null
-From 87df00d6b301f5de54443ac7e3765dce983e8b6a Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 28 Mar 2019 11:58:51 -0700
-Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL
- rendering.
-
-We would present the framebuffer immediately without waiting for
-rendering to finish first, resulting in stuttering and flickering as a
-window was dragged around when the GPU was busy enough to not just win
-the race.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -15,6 +15,7 @@
- */
-
- #include "drm/drm_atomic_helper.h"
-+#include "drm/drm_gem_framebuffer_helper.h"
- #include "drm/drm_plane_helper.h"
- #include "drm/drm_crtc_helper.h"
- #include "drm/drm_fourcc.h"
-@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_
- };
-
- static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-- .prepare_fb = NULL,
-+ .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
- .atomic_update = vc4_primary_plane_atomic_update,
-@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun
- };
-
- static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
-- .prepare_fb = NULL,
-+ .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
- .atomic_update = vc4_cursor_plane_atomic_update,
+++ /dev/null
-From c27d4bbba9593a6ded8f482610a0247da66d78a9 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 18 Mar 2019 16:38:32 -0700
-Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware
- kms.
-
-This should technically not expose VC4_T_TILED on pi4. However, if we
-don't expose anything, then userspace will assume that display can
-handle whatever modifiers 3d can do (UIF on 2711). By exposing a
-list, that will get intersected with what 3D can do so that we get T
-tiling for display on 2710 and linear on 2711.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++-
- 1 file changed, 32 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm
- drm_plane_cleanup(plane);
- }
-
-+static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
-+ uint32_t format,
-+ uint64_t modifier)
-+{
-+ /* Support T_TILING for RGB formats only. */
-+ switch (format) {
-+ case DRM_FORMAT_XRGB8888:
-+ case DRM_FORMAT_ARGB8888:
-+ switch (modifier) {
-+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
-+ case DRM_FORMAT_MOD_LINEAR:
-+ case DRM_FORMAT_MOD_BROADCOM_UIF:
-+ return true;
-+ default:
-+ return false;
-+ }
-+ default:
-+ return false;
-+ }
-+}
-+
- static const struct drm_plane_funcs vc4_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
-@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-+ .format_mod_supported = vc4_fkms_format_mod_supported,
- };
-
- static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_
- u32 argb8888 = DRM_FORMAT_ARGB8888;
- int ret = 0;
- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
-+ static const uint64_t modifiers[] = {
-+ DRM_FORMAT_MOD_LINEAR,
-+ /* VC4_T_TILED should come after linear, because we
-+ * would prefer to scan out linear (less bus traffic).
-+ */
-+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
-+ DRM_FORMAT_MOD_INVALID,
-+ };
-
- vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
- GFP_KERNEL);
-@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- primary ? &xrgb8888 : &argb8888, 1, NULL,
-+ primary ? &xrgb8888 : &argb8888, 1,
-+ modifiers,
- type, primary ? "primary" : "cursor");
-
- if (type == DRM_PLANE_TYPE_PRIMARY) {
--- /dev/null
+From a954d2d91eff32d1ab8baae12b8ac7dc856711cb Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 3 Apr 2019 15:20:05 +0100
+Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096.
+
+We now should support 4k screens, therefore this limit needs to
+be increased.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 2048;
+- dev->mode_config.max_height = 2048;
++ dev->mode_config.max_width = 4096;
++ dev->mode_config.max_height = 4096;
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
--- /dev/null
+From b7a52df8162e1eb55a8403e9e9af79c581206335 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 3 Apr 2019 17:15:45 +0100
+Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms
+
+There is a slightly nasty hack in that all crtcs share the
+same SMI interrupt from the firmware. This seems to currently
+work well enough, but ought to be fixed at a later date.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 162 +++++++++++++++++--------
+ 1 file changed, 113 insertions(+), 49 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -31,6 +31,8 @@
+ #include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++#define PLANES_PER_CRTC 3
++
+ struct set_plane {
+ u8 display;
+ u8 plane_id;
+@@ -177,6 +179,7 @@ struct vc4_crtc {
+ struct drm_pending_vblank_event *event;
+ u32 overscan[4];
+ bool vblank_enabled;
++ u32 display_number;
+ };
+
+ static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
+@@ -481,6 +484,7 @@ static const struct drm_plane_helper_fun
+
+ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
+ enum drm_plane_type type,
++ u8 display_num,
+ u8 plane_id)
+ {
+ struct drm_plane *plane = NULL;
+@@ -544,7 +548,7 @@ static struct drm_plane *vc4_fkms_plane_
+ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
+ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
+ vc4_plane->mb.tag.req_resp_size = 0;
+- vc4_plane->mb.plane.display = 0;
++ vc4_plane->mb.plane.display = display_num;
+ vc4_plane->mb.plane.plane_id = plane_id;
+ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
+
+@@ -631,16 +635,20 @@ static void vc4_crtc_handle_page_flip(st
+
+ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
+ {
+- struct vc4_crtc *vc4_crtc = data;
+- u32 stat = readl(vc4_crtc->regs + SMICS);
++ struct vc4_crtc **crtc_list = data;
++ int i;
++ u32 stat = readl(crtc_list[0]->regs + SMICS);
+ irqreturn_t ret = IRQ_NONE;
+
+ if (stat & SMICS_INTERRUPTS) {
+- writel(0, vc4_crtc->regs + SMICS);
+- if (vc4_crtc->vblank_enabled)
+- drm_crtc_handle_vblank(&vc4_crtc->base);
+- vc4_crtc_handle_page_flip(vc4_crtc);
+- ret = IRQ_HANDLED;
++ writel(0, crtc_list[0]->regs + SMICS);
++
++ for (i = 0; crtc_list[i]; i++) {
++ if (crtc_list[i]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[i]->base);
++ vc4_crtc_handle_page_flip(crtc_list[i]);
++ ret = IRQ_HANDLED;
++ }
+ }
+
+ return ret;
+@@ -837,66 +845,55 @@ static const struct drm_encoder_helper_f
+ .disable = vc4_fkms_encoder_disable,
+ };
+
+-static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
++static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
++ int display_idx, int display_ref,
++ struct vc4_crtc **ret_crtc)
+ {
+- 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 vc4_fkms_encoder *vc4_encoder;
+ struct drm_crtc *crtc;
+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
+ struct drm_plane *destroy_plane, *temp;
+- struct device_node *firmware_node;
+ u32 blank = 1;
+ int ret;
+
+- vc4->firmware_kms = true;
+-
+- /* firmware kms doesn't have precise a scanoutpos implementation, so
+- * we can't do the precise vblank timestamp mode.
+- */
+- drm->driver->get_scanout_position = NULL;
+- drm->driver->get_vblank_timestamp = NULL;
+-
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+ if (!vc4_crtc)
+ return -ENOMEM;
+ crtc = &vc4_crtc->base;
+
+- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
+- vc4->firmware = rpi_firmware_get(firmware_node);
+- if (!vc4->firmware) {
+- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
+- return -EPROBE_DEFER;
+- }
+- of_node_put(firmware_node);
+-
+- /* Map the SMI interrupt reg */
+- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
+- if (IS_ERR(vc4_crtc->regs))
+- return PTR_ERR(vc4_crtc->regs);
++ vc4_crtc->display_number = display_ref;
+
+ /* Blank the firmware provided framebuffer */
+ rpi_firmware_property(vc4->firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+ &blank, sizeof(blank));
+
+- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
++ display_ref,
++ 0 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(primary_plane)) {
+ dev_err(dev, "failed to construct primary plane\n");
+ ret = PTR_ERR(primary_plane);
+ goto err;
+ }
+
+- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
++ display_ref,
++ 1 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(overlay_plane)) {
+ dev_err(dev, "failed to construct overlay plane\n");
+ ret = PTR_ERR(overlay_plane);
+ goto err;
+ }
+
+- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
++ display_ref,
++ 2 + (display_idx * PLANES_PER_CRTC)
++ );
+ if (IS_ERR(cursor_plane)) {
+ dev_err(dev, "failed to construct cursor plane\n");
+ ret = PTR_ERR(cursor_plane);
+@@ -923,13 +920,6 @@ static int vc4_fkms_bind(struct device *
+ goto err_destroy_encoder;
+ }
+
+- writel(0, vc4_crtc->regs + SMICS);
+- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
+- vc4_crtc);
+- if (ret)
+- goto err_destroy_connector;
+-
+ ret = rpi_firmware_property(vc4->firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
+ &vc4_crtc->overscan,
+@@ -939,7 +929,7 @@ static int vc4_fkms_bind(struct device *
+ memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
+ }
+
+- platform_set_drvdata(pdev, vc4_crtc);
++ *ret_crtc = vc4_crtc;
+
+ return 0;
+
+@@ -956,17 +946,91 @@ err:
+ return ret;
+ }
+
++static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
++{
++ 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 device_node *firmware_node;
++ struct vc4_crtc **crtc_list;
++ u32 num_displays, display_num;
++ int ret;
++ const u32 display_num_lookup[] = {2, 7, 1};
++
++ vc4->firmware_kms = true;
++
++ /* firmware kms doesn't have precise a scanoutpos implementation, so
++ * we can't do the precise vblank timestamp mode.
++ */
++ drm->driver->get_scanout_position = NULL;
++ drm->driver->get_vblank_timestamp = NULL;
++
++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
++ vc4->firmware = rpi_firmware_get(firmware_node);
++ if (!vc4->firmware) {
++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
++ return -EPROBE_DEFER;
++ }
++ of_node_put(firmware_node);
++
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
++ &num_displays, sizeof(u32));
++
++ /* If we fail to get the number of displays, or it returns 0, then
++ * assume old firmware that doesn't have the mailbox call, so just
++ * set one display
++ */
++ if (ret || num_displays == 0) {
++ num_displays = 1;
++ DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
++ ret = 0;
++ }
++
++ /* Allocate a list, with space for a NULL on the end */
++ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
++ GFP_KERNEL);
++ if (!crtc_list)
++ return -ENOMEM;
++
++ for (display_num = 0; display_num < num_displays; display_num++) {
++ ret = vc4_fkms_create_screen(dev, drm, display_num,
++ display_num_lookup[display_num],
++ &crtc_list[display_num]);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to create display %u\n",
++ display_num);
++ }
++
++ /* Map the SMI interrupt reg */
++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(crtc_list[0]->regs))
++ DRM_ERROR("Oh dear, failed to map registers\n");
++
++ writel(0, crtc_list[0]->regs + SMICS);
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
++ vc4_crtc_irq_handler, 0, "vc4 firmware kms",
++ crtc_list);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to register IRQ\n");
++
++ platform_set_drvdata(pdev, crtc_list);
++
++ return 0;
++}
++
+ static void vc4_fkms_unbind(struct device *dev, struct device *master,
+ void *data)
+ {
+- struct drm_device *drm = dev_get_drvdata(master);
+ struct platform_device *pdev = to_platform_device(dev);
+- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
++ struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
++ int i;
+
+- vc4_fkms_connector_destroy(vc4_crtc->connector);
+- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
+- drm_atomic_helper_shutdown(drm);
+- drm_crtc_cleanup(&vc4_crtc->base);
++ for (i = 0; crtc_list[i]; i++) {
++ vc4_fkms_connector_destroy(crtc_list[i]->connector);
++ vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
++ drm_crtc_cleanup(&crtc_list[i]->base);
++ }
+
+ platform_set_drvdata(pdev, NULL);
+ }
+++ /dev/null
-From c71f09dafd82a37a488029f33552a45a99d0a9a6 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Tue, 2 Apr 2019 13:29:00 -0700
-Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms.
-
-The core doesn't expect a false return from the scanoutpos function in
-normal usage, so we were doing the precise vblank timestamping path
-and thus "immediate" vblank disables (even though firmwarekms can't
-actually disable vblanks interrupts, sigh), and the kernel would get
-confused when getting timestamp info when also turning vblanks back
-on.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/vc4/vc4_crtc.c | 3 ---
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
- 2 files changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -97,9 +97,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- int vblank_lines;
- bool ret = false;
-
-- if (vc4->firmware_kms)
-- return 0;
--
- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
-
- /* Get optional system timestamp before query. */
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -20,6 +20,7 @@
- #include "drm/drm_crtc_helper.h"
- #include "drm/drm_fourcc.h"
- #include "drm/drm_probe_helper.h"
-+#include "drm/drm_drv.h"
- #include "linux/clk.h"
- #include "linux/debugfs.h"
- #include "drm/drm_fb_cma_helper.h"
-@@ -673,6 +674,12 @@ static int vc4_fkms_bind(struct device *
-
- vc4->firmware_kms = true;
-
-+ /* firmware kms doesn't have precise a scanoutpos implementation, so
-+ * we can't do the precise vblank timestamp mode.
-+ */
-+ drm->driver->get_scanout_position = NULL;
-+ drm->driver->get_vblank_timestamp = NULL;
-+
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
- if (!vc4_crtc)
- return -ENOMEM;
--- /dev/null
+From a06b826c199e6de39d4e91e41e8347a5629bb54a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 5 Apr 2019 17:21:56 +0100
+Subject: [PATCH] drm: vc4: Fix build warning
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -933,8 +933,6 @@ static int vc4_fkms_create_screen(struct
+
+ return 0;
+
+-err_destroy_connector:
+- vc4_fkms_connector_destroy(vc4_crtc->connector);
+ err_destroy_encoder:
+ vc4_fkms_encoder_destroy(vc4_crtc->encoder);
+ list_for_each_entry_safe(destroy_plane, temp,
+++ /dev/null
-From b721bcc62759ae7a2d9730d1121974702be96d7c Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 26 Mar 2019 14:43:06 +0000
-Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame
- buffer API.
-
-The old mailbox FB API was ideally deprecated but still used by
-the FKMS driver.
-Update to the newer API.
-
-NB This needs current firmware that accepts ARM allocated buffers
-through the newer API.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++++------------
- 1 file changed, 57 insertions(+), 52 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -30,6 +30,25 @@
- #include "vc4_regs.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct fb_alloc_tags {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 xres, yres;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 xres_virtual, yres_virtual;
-+ struct rpi_firmware_property_tag_header tag3;
-+ u32 bpp;
-+ struct rpi_firmware_property_tag_header tag4;
-+ u32 xoffset, yoffset;
-+ struct rpi_firmware_property_tag_header tag5;
-+ u32 base, screen_size;
-+ struct rpi_firmware_property_tag_header tag6;
-+ u32 pitch;
-+ struct rpi_firmware_property_tag_header tag7;
-+ u32 alpha_mode;
-+ struct rpi_firmware_property_tag_header tag8;
-+ u32 layer;
-+};
-+
- /* The firmware delivers a vblank interrupt to us through the SMI
- * hardware, which has only this one register.
- */
-@@ -123,45 +142,39 @@ static void vc4_primary_plane_atomic_upd
- struct drm_plane_state *old_state)
- {
- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
-+ u32 format = fb->format->format;
-+ struct fb_alloc_tags fbinfo = {
-+ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ .xres = state->crtc_w,
-+ .yres = state->crtc_h,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ .xres_virtual = state->crtc_w,
-+ .yres_virtual = state->crtc_h,
-+ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
-+ .bpp = 32,
-+ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
-+ .xoffset = 0,
-+ .yoffset = 0,
-+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-+ .base = bo->paddr + fb->offsets[0],
-+ .screen_size = state->crtc_w * state->crtc_h * 4,
-+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-+ .pitch = fb->pitches[0],
-+ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
-+ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
-+ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
-+ .layer = -127,
-+ };
- u32 bpp = 32;
- int ret;
-
-- fbinfo->xres = state->crtc_w;
-- fbinfo->yres = state->crtc_h;
-- fbinfo->xres_virtual = state->crtc_w;
-- fbinfo->yres_virtual = state->crtc_h;
-- fbinfo->bpp = bpp;
-- fbinfo->xoffset = state->crtc_x;
-- fbinfo->yoffset = state->crtc_y;
-- fbinfo->base = bo->paddr + fb->offsets[0];
-- fbinfo->pitch = fb->pitches[0];
--
- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
-- fbinfo->bpp |= BIT(31);
--
-- /* A bug in the firmware makes it so that if the fb->base is
-- * set to nonzero, the configured pitch gets overwritten with
-- * the previous pitch. So, to get the configured pitch
-- * recomputed, we have to make it allocate itself a new buffer
-- * in VC memory, first.
-- */
-- if (vc4_plane->pitch != fb->pitches[0]) {
-- u32 saved_base = fbinfo->base;
-- fbinfo->base = 0;
--
-- ret = rpi_firmware_transaction(vc4->firmware,
-- RPI_FIRMWARE_CHAN_FB,
-- vc4_plane->fbinfo_bus_addr);
-- fbinfo->base = saved_base;
--
-- vc4_plane->pitch = fbinfo->pitch;
-- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
-- }
-+ fbinfo.bpp |= BIT(31);
-
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
- plane->base.id, plane->name,
-@@ -170,14 +183,13 @@ static void vc4_primary_plane_atomic_upd
- bpp,
- state->crtc_x,
- state->crtc_y,
-- &fbinfo->base,
-+ &fbinfo.base,
- fb->pitches[0]);
-
-- ret = rpi_firmware_transaction(vc4->firmware,
-- RPI_FIRMWARE_CHAN_FB,
-- vc4_plane->fbinfo_bus_addr);
-- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
-- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
-+ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
-+ sizeof(fbinfo));
-+ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
-+ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
-
- /* If the CRTC is on (or going to be on) and we're enabled,
- * then unblank. Otherwise, stay blank until CRTC enable.
-@@ -333,10 +345,10 @@ static const struct drm_plane_helper_fun
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
- enum drm_plane_type type)
- {
-+ /* Primary and cursor planes only */
- struct drm_plane *plane = NULL;
- struct vc4_fkms_plane *vc4_plane;
-- u32 xrgb8888 = DRM_FORMAT_XRGB8888;
-- u32 argb8888 = DRM_FORMAT_ARGB8888;
-+ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
- int ret = 0;
- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
- static const uint64_t modifiers[] = {
-@@ -358,22 +370,15 @@ static struct drm_plane *vc4_fkms_plane_
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- primary ? &xrgb8888 : &argb8888, 1,
-- modifiers,
-+ formats, primary ? 2 : 1, modifiers,
- type, primary ? "primary" : "cursor");
-
-- if (type == DRM_PLANE_TYPE_PRIMARY) {
-- vc4_plane->fbinfo =
-- dma_alloc_coherent(dev->dev,
-- sizeof(*vc4_plane->fbinfo),
-- &vc4_plane->fbinfo_bus_addr,
-- GFP_KERNEL);
-- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
--
-+ if (type == DRM_PLANE_TYPE_PRIMARY)
- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
-- } else {
-+ else
- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
-- }
-+
-+ drm_plane_create_alpha_property(plane);
-
- return plane;
- fail:
+++ /dev/null
-From 75e1dce99c260cb1365edd9af68cb5c07487831c Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 27 Mar 2019 17:45:01 +0000
-Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms
-
-This uses a new API that is exposed via the mailbox service
-to stick an element straight on the screen using DispmanX.
-
-The primary and cursor planes have also been switched to using
-the new plane API, and it supports layering based on the DRM
-zpos parameter.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++-------
- drivers/gpu/drm/vc4/vc4_kms.c | 1 +
- drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +
- 4 files changed, 495 insertions(+), 169 deletions(-)
- create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -28,8 +28,46 @@
- #include "linux/of_device.h"
- #include "vc4_drv.h"
- #include "vc4_regs.h"
-+#include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct set_plane {
-+ u8 display;
-+ u8 plane_id;
-+ u8 vc_image_type;
-+ s8 layer;
-+
-+ u16 width;
-+ u16 height;
-+
-+ u16 pitch;
-+ u16 vpitch;
-+
-+ u32 src_x; /* 16p16 */
-+ u32 src_y; /* 16p16 */
-+
-+ u32 src_w; /* 16p16 */
-+ u32 src_h; /* 16p16 */
-+
-+ s16 dst_x;
-+ s16 dst_y;
-+
-+ u16 dst_w;
-+ u16 dst_h;
-+
-+ u8 alpha;
-+ u8 num_planes;
-+ u8 is_vu;
-+ u8 padding;
-+
-+ u32 planes[4]; /* DMA address of each plane */
-+};
-+
-+struct mailbox_set_plane {
-+ struct rpi_firmware_property_tag_header tag;
-+ struct set_plane plane;
-+};
-+
- struct fb_alloc_tags {
- struct rpi_firmware_property_tag_header tag1;
- u32 xres, yres;
-@@ -49,6 +87,79 @@ struct fb_alloc_tags {
- u32 layer;
- };
-
-+static const struct vc_image_format {
-+ u32 drm; /* DRM_FORMAT_* */
-+ u32 vc_image; /* VC_IMAGE_* */
-+ u32 is_vu;
-+} vc_image_formats[] = {
-+ {
-+ .drm = DRM_FORMAT_XRGB8888,
-+ .vc_image = VC_IMAGE_XRGB8888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_ARGB8888,
-+ .vc_image = VC_IMAGE_ARGB8888,
-+ },
-+/*
-+ * FIXME: Need to resolve which DRM format goes to which vc_image format
-+ * for the remaining RGBA and RGBX formats.
-+ * {
-+ * .drm = DRM_FORMAT_ABGR8888,
-+ * .vc_image = VC_IMAGE_RGBA8888,
-+ * },
-+ * {
-+ * .drm = DRM_FORMAT_XBGR8888,
-+ * .vc_image = VC_IMAGE_RGBA8888,
-+ * },
-+ */
-+ {
-+ .drm = DRM_FORMAT_RGB565,
-+ .vc_image = VC_IMAGE_RGB565,
-+ },
-+ {
-+ .drm = DRM_FORMAT_RGB888,
-+ .vc_image = VC_IMAGE_BGR888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_BGR888,
-+ .vc_image = VC_IMAGE_RGB888,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV422,
-+ .vc_image = VC_IMAGE_YUV422PLANAR,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YUV420,
-+ .vc_image = VC_IMAGE_YUV420,
-+ },
-+ {
-+ .drm = DRM_FORMAT_YVU420,
-+ .vc_image = VC_IMAGE_YUV420,
-+ .is_vu = 1,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV12,
-+ .vc_image = VC_IMAGE_YUV420SP,
-+ },
-+ {
-+ .drm = DRM_FORMAT_NV21,
-+ .vc_image = VC_IMAGE_YUV420SP,
-+ .is_vu = 1,
-+ },
-+};
-+
-+static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
-+ if (vc_image_formats[i].drm == drm_format)
-+ return &vc_image_formats[i];
-+ }
-+
-+ return NULL;
-+}
-+
- /* The firmware delivers a vblank interrupt to us through the SMI
- * hardware, which has only this one register.
- */
-@@ -115,6 +226,7 @@ struct vc4_fkms_plane {
- struct fbinfo_s *fbinfo;
- dma_addr_t fbinfo_bus_addr;
- u32 pitch;
-+ struct mailbox_set_plane mb;
- };
-
- static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
-@@ -122,165 +234,183 @@ static inline struct vc4_fkms_plane *to_
- return (struct vc4_fkms_plane *)plane;
- }
-
--/* Turns the display on/off. */
--static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
-+static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
- {
- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+ struct mailbox_set_plane blank_mb = {
-+ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
-+ .plane = {
-+ .display = vc4_plane->mb.plane.display,
-+ .plane_id = vc4_plane->mb.plane.plane_id,
-+ }
-+ };
-+ int ret;
-
-- u32 packet = blank;
--
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
- plane->base.id, plane->name,
- blank ? "blank" : "unblank");
-
-- return rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-- &packet, sizeof(packet));
-+ if (blank)
-+ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
-+ sizeof(blank_mb));
-+ else
-+ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
-+ sizeof(vc4_plane->mb));
-+
-+ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
-+ __func__);
-+ return ret;
- }
-
--static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static void vc4_plane_atomic_update(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
- {
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
- struct drm_plane_state *state = plane->state;
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- u32 format = fb->format->format;
-- struct fb_alloc_tags fbinfo = {
-- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
-- 8, 0, },
-- .xres = state->crtc_w,
-- .yres = state->crtc_h,
-- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
-- 8, 0, },
-- .xres_virtual = state->crtc_w,
-- .yres_virtual = state->crtc_h,
-- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
-- .bpp = 32,
-- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
-- .xoffset = 0,
-- .yoffset = 0,
-- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
-- .base = bo->paddr + fb->offsets[0],
-- .screen_size = state->crtc_w * state->crtc_h * 4,
-- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
-- .pitch = fb->pitches[0],
-- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
-- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
-- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
-- .layer = -127,
-- };
-- u32 bpp = 32;
-- int ret;
-+ const struct drm_format_info *drm_fmt = fb->format;
-+ const struct vc_image_format *vc_fmt =
-+ vc4_get_vc_image_fmt(drm_fmt->format);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+ struct mailbox_set_plane *mb = &vc4_plane->mb;
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
-+ int num_planes = fb->format->num_planes;
-+ struct drm_display_mode *mode = &state->crtc->mode;
-
-- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
-- fbinfo.bpp |= BIT(31);
-+ mb->plane.vc_image_type = vc_fmt->vc_image;
-+ mb->plane.width = fb->width;
-+ mb->plane.height = fb->height;
-+ mb->plane.pitch = fb->pitches[0];
-+ mb->plane.src_w = state->src_w;
-+ mb->plane.src_h = state->src_h;
-+ mb->plane.src_x = state->src_x;
-+ mb->plane.src_y = state->src_y;
-+ mb->plane.dst_w = state->crtc_w;
-+ mb->plane.dst_h = state->crtc_h;
-+ mb->plane.dst_x = state->crtc_x;
-+ mb->plane.dst_y = state->crtc_y;
-+ mb->plane.alpha = state->alpha >> 8;
-+ mb->plane.layer = state->normalized_zpos ?
-+ state->normalized_zpos : -127;
-+ mb->plane.num_planes = num_planes;
-+ mb->plane.is_vu = vc_fmt->is_vu;
-+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
-+ /* FIXME: If the dest rect goes off screen then clip the src rect so we
-+ * don't have off-screen pixels.
-+ */
-+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-+ /* There is no scaling on the cursor plane, therefore the calcs
-+ * to alter the source crop as the cursor goes off the screen
-+ * are simple.
-+ */
-+ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
-+ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
-+ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
-+ << 16;
-+ }
-+ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
-+ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
-+ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
-+ << 16;
-+ }
-+ }
-+
-+ if (num_planes > 1) {
-+ /* Assume this must be YUV */
-+ /* Makes assumptions on the stride for the chroma planes as we
-+ * can't easily plumb in non-standard pitches.
-+ */
-+ mb->plane.planes[1] = bo->paddr + fb->offsets[1];
-+ if (num_planes > 2)
-+ mb->plane.planes[2] = bo->paddr + fb->offsets[2];
-+ else
-+ mb->plane.planes[2] = 0;
-+
-+ /* Special case the YUV420 with U and V as line interleaved
-+ * planes as we have special handling for that case.
-+ */
-+ if (num_planes == 3 &&
-+ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
-+ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
-+ } else {
-+ mb->plane.planes[1] = 0;
-+ mb->plane.planes[2] = 0;
-+ }
-+ mb->plane.planes[3] = 0;
-+
-+ switch (fb->modifier) {
-+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
-+ switch (mb->plane.vc_image_type) {
-+ case VC_IMAGE_RGBX32:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
-+ break;
-+ case VC_IMAGE_RGBA32:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
-+ break;
-+ case VC_IMAGE_RGB565:
-+ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
-+ break;
-+ }
-+ break;
-+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
-+ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
-+ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
-+ break;
-+ }
-+
-+ if (vc4_crtc) {
-+ mb->plane.dst_x += vc4_crtc->overscan[0];
-+ mb->plane.dst_y += vc4_crtc->overscan[1];
-+ }
-+
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
- plane->base.id, plane->name,
-- state->crtc_w,
-- state->crtc_h,
-- bpp,
-+ mb->plane.width,
-+ mb->plane.height,
-+ mb->plane.vc_image_type,
- state->crtc_x,
- state->crtc_y,
-- &fbinfo.base,
-- fb->pitches[0]);
--
-- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
-- sizeof(fbinfo));
-- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
-- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
--
-- /* If the CRTC is on (or going to be on) and we're enabled,
-+ state->crtc_w,
-+ state->crtc_h,
-+ mb->plane.src_x,
-+ mb->plane.src_y,
-+ mb->plane.src_w,
-+ mb->plane.src_h,
-+ mb->plane.planes[0],
-+ mb->plane.planes[1],
-+ mb->plane.planes[2],
-+ fb->pitches[0],
-+ state->alpha,
-+ state->normalized_zpos);
-+
-+ /*
-+ * Do NOT set now, as we haven't checked if the crtc is active or not.
-+ * Set from vc4_plane_set_blank instead.
-+ *
-+ * If the CRTC is on (or going to be on) and we're enabled,
- * then unblank. Otherwise, stay blank until CRTC enable.
-- */
-+ */
- if (state->crtc->state->active)
-- vc4_plane_set_primary_blank(plane, false);
-+ vc4_plane_set_blank(plane, false);
- }
-
--static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static void vc4_plane_atomic_disable(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
- {
-- vc4_plane_set_primary_blank(plane, true);
--}
--
--static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
--{
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-+ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
- struct drm_plane_state *state = plane->state;
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
-- struct drm_framebuffer *fb = state->fb;
-- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
-- dma_addr_t addr = bo->paddr + fb->offsets[0];
-- int ret;
-- u32 packet_state[] = {
-- state->crtc->state->active,
-- state->crtc_x,
-- state->crtc_y,
-- 0
-- };
-- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
- plane->base.id, plane->name,
- state->crtc_w,
- state->crtc_h,
-+ vc4_plane->mb.plane.vc_image_type,
- state->crtc_x,
-- state->crtc_y,
-- &addr,
-- fb->pitches[0]);
--
-- /* add on the top/left offsets when overscan is active */
-- if (vc4_crtc) {
-- packet_state[1] += vc4_crtc->overscan[0];
-- packet_state[2] += vc4_crtc->overscan[1];
-- }
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_STATE,
-- &packet_state,
-- sizeof(packet_state));
-- if (ret || packet_state[0] != 0)
-- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
--
-- /* Note: When the cursor contents change, the modesetting
-- * driver calls drm_mode_cursor_univeral() with
-- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated.
-- */
-- if (!old_state ||
-- state->crtc_w != old_state->crtc_w ||
-- state->crtc_h != old_state->crtc_h ||
-- fb != old_state->fb) {
-- u32 packet_info[] = { state->crtc_w, state->crtc_h,
-- 0, /* unused */
-- addr,
-- 0, 0, /* hotx, hoty */};
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_INFO,
-- &packet_info,
-- sizeof(packet_info));
-- if (ret || packet_info[0] != 0)
-- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
-- }
--}
--
--static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
--{
-- struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- u32 packet_state[] = { false, 0, 0, 0 };
-- int ret;
--
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
--
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_SET_CURSOR_STATE,
-- &packet_state,
-- sizeof(packet_state));
-- if (ret || packet_state[0] != 0)
-- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
-+ state->crtc_y);
-+ vc4_plane_set_blank(plane, true);
- }
-
- static int vc4_plane_atomic_check(struct drm_plane *plane,
-@@ -302,6 +432,7 @@ static bool vc4_fkms_format_mod_supporte
- switch (format) {
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
-+ case DRM_FORMAT_RGB565:
- switch (modifier) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- case DRM_FORMAT_MOD_LINEAR:
-@@ -310,8 +441,22 @@ static bool vc4_fkms_format_mod_supporte
- default:
- return false;
- }
-+ case DRM_FORMAT_NV12:
-+ case DRM_FORMAT_NV21:
-+ switch (fourcc_mod_broadcom_mod(modifier)) {
-+ case DRM_FORMAT_MOD_LINEAR:
-+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
-+ return true;
-+ default:
-+ return false;
-+ }
-+ case DRM_FORMAT_RGB888:
-+ case DRM_FORMAT_BGR888:
-+ case DRM_FORMAT_YUV422:
-+ case DRM_FORMAT_YUV420:
-+ case DRM_FORMAT_YVU420:
- default:
-- return false;
-+ return (modifier == DRM_FORMAT_MOD_LINEAR);
- }
- }
-
-@@ -326,31 +471,24 @@ static const struct drm_plane_funcs vc4_
- .format_mod_supported = vc4_fkms_format_mod_supported,
- };
-
--static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
-- .prepare_fb = drm_gem_fb_prepare_fb,
-- .cleanup_fb = NULL,
-- .atomic_check = vc4_plane_atomic_check,
-- .atomic_update = vc4_primary_plane_atomic_update,
-- .atomic_disable = vc4_primary_plane_atomic_disable,
--};
--
--static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
-+static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
- .prepare_fb = drm_gem_fb_prepare_fb,
- .cleanup_fb = NULL,
- .atomic_check = vc4_plane_atomic_check,
-- .atomic_update = vc4_cursor_plane_atomic_update,
-- .atomic_disable = vc4_cursor_plane_atomic_disable,
-+ .atomic_update = vc4_plane_atomic_update,
-+ .atomic_disable = vc4_plane_atomic_disable,
- };
-
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
-- enum drm_plane_type type)
-+ enum drm_plane_type type,
-+ u8 plane_id)
- {
-- /* Primary and cursor planes only */
- struct drm_plane *plane = NULL;
- struct vc4_fkms_plane *vc4_plane;
-- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
-+ u32 formats[ARRAY_SIZE(vc_image_formats)];
-+ unsigned int default_zpos = 0;
-+ u32 num_formats = 0;
- int ret = 0;
-- bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
- static const uint64_t modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- /* VC4_T_TILED should come after linear, because we
-@@ -359,6 +497,7 @@ static struct drm_plane *vc4_fkms_plane_
- DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
- DRM_FORMAT_MOD_INVALID,
- };
-+ int i;
-
- vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
- GFP_KERNEL);
-@@ -367,19 +506,48 @@ static struct drm_plane *vc4_fkms_plane_
- goto fail;
- }
-
-+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
-+ formats[num_formats++] = vc_image_formats[i].drm;
-+
- plane = &vc4_plane->base;
- ret = drm_universal_plane_init(dev, plane, 0xff,
- &vc4_plane_funcs,
-- formats, primary ? 2 : 1, modifiers,
-- type, primary ? "primary" : "cursor");
-+ formats, num_formats, modifiers,
-+ type, NULL);
-
-- if (type == DRM_PLANE_TYPE_PRIMARY)
-- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
-- else
-- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
-+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
-
- drm_plane_create_alpha_property(plane);
-
-+ /*
-+ * Default frame buffer setup is with FB on -127, and raspistill etc
-+ * tend to drop overlays on layer 2. Cursor plane was on layer +127.
-+ *
-+ * For F-KMS the mailbox call allows for a s8.
-+ * Remap zpos 0 to -127 for the background layer, but leave all the
-+ * other layers as requested by KMS.
-+ */
-+ switch (type) {
-+ case DRM_PLANE_TYPE_PRIMARY:
-+ default_zpos = 0;
-+ break;
-+ case DRM_PLANE_TYPE_OVERLAY:
-+ default_zpos = 1;
-+ break;
-+ case DRM_PLANE_TYPE_CURSOR:
-+ default_zpos = 2;
-+ break;
-+ }
-+ drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
-+
-+ /* Prepare the static elements of the mailbox structure */
-+ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
-+ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
-+ vc4_plane->mb.tag.req_resp_size = 0;
-+ vc4_plane->mb.plane.display = 0;
-+ vc4_plane->mb.plane.plane_id = plane_id;
-+ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
-+
- return plane;
- fail:
- if (plane)
-@@ -401,19 +569,23 @@ static void vc4_crtc_disable(struct drm_
- * whether anything scans out at all, but the firmware doesn't
- * give us a CRTC-level control for that.
- */
-- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-- vc4_plane_set_primary_blank(crtc->primary, true);
-+
-+ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-+ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
-+
-+ /* FIXME: Disable overlay planes */
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
- /* Unblank the planes (if they're supposed to be displayed). */
-+
- if (crtc->primary->state->fb)
-- vc4_plane_set_primary_blank(crtc->primary, false);
-- if (crtc->cursor->state->fb) {
-- vc4_cursor_plane_atomic_update(crtc->cursor,
-- crtc->cursor->state);
-- }
-+ vc4_plane_set_blank(crtc->primary, false);
-+ if (crtc->cursor->state->fb)
-+ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
-+
-+ /* FIXME: Enable overlay planes */
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
-@@ -673,8 +845,10 @@ static int vc4_fkms_bind(struct device *
- struct vc4_crtc *vc4_crtc;
- struct vc4_fkms_encoder *vc4_encoder;
- struct drm_crtc *crtc;
-- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
-+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
-+ struct drm_plane *destroy_plane, *temp;
- struct device_node *firmware_node;
-+ u32 blank = 1;
- int ret;
-
- vc4->firmware_kms = true;
-@@ -703,20 +877,26 @@ static int vc4_fkms_bind(struct device *
- if (IS_ERR(vc4_crtc->regs))
- return PTR_ERR(vc4_crtc->regs);
-
-- /* For now, we create just the primary and the legacy cursor
-- * planes. We should be able to stack more planes on easily,
-- * but to do that we would need to compute the bandwidth
-- * requirement of the plane configuration, and reject ones
-- * that will take too much.
-- */
-- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
-+ /* Blank the firmware provided framebuffer */
-+ rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-+ &blank, sizeof(blank));
-+
-+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
- if (IS_ERR(primary_plane)) {
- dev_err(dev, "failed to construct primary plane\n");
- ret = PTR_ERR(primary_plane);
- goto err;
- }
-
-- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
-+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
-+ if (IS_ERR(overlay_plane)) {
-+ dev_err(dev, "failed to construct overlay plane\n");
-+ ret = PTR_ERR(overlay_plane);
-+ goto err;
-+ }
-+
-+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
- if (IS_ERR(cursor_plane)) {
- dev_err(dev, "failed to construct cursor plane\n");
- ret = PTR_ERR(cursor_plane);
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -542,6 +542,7 @@ int vc4_kms_load(struct drm_device *dev)
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
- dev->mode_config.allow_fb_modifiers = true;
-+ dev->mode_config.normalize_zpos = true;
-
- drm_modeset_lock_init(&vc4->ctm_state_lock);
-
---- /dev/null
-+++ b/drivers/gpu/drm/vc4/vc_image_types.h
-@@ -0,0 +1,143 @@
-+
-+/*
-+ * Copyright (c) 2012, Broadcom Europe Ltd
-+ *
-+ * Values taken from vc_image_types.h released by Broadcom at
-+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
-+ *
-+ * 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.
-+ */
-+
-+enum {
-+ VC_IMAGE_MIN = 0, //bounds for error checking
-+
-+ VC_IMAGE_RGB565 = 1,
-+ VC_IMAGE_1BPP,
-+ VC_IMAGE_YUV420,
-+ VC_IMAGE_48BPP,
-+ VC_IMAGE_RGB888,
-+ VC_IMAGE_8BPP,
-+ /* 4bpp palettised image */
-+ VC_IMAGE_4BPP,
-+ /* A separated format of 16 colour/light shorts followed by 16 z
-+ * values
-+ */
-+ VC_IMAGE_3D32,
-+ /* 16 colours followed by 16 z values */
-+ VC_IMAGE_3D32B,
-+ /* A separated format of 16 material/colour/light shorts followed by
-+ * 16 z values
-+ */
-+ VC_IMAGE_3D32MAT,
-+ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
-+ VC_IMAGE_RGB2X9,
-+ /* 32-bit format holding 18 bits of 6.6.6 RGB */
-+ VC_IMAGE_RGB666,
-+ /* 4bpp palettised image with embedded palette */
-+ VC_IMAGE_PAL4_OBSOLETE,
-+ /* 8bpp palettised image with embedded palette */
-+ VC_IMAGE_PAL8_OBSOLETE,
-+ /* RGB888 with an alpha byte after each pixel */
-+ VC_IMAGE_RGBA32,
-+ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
-+ * line of V (16-byte padded)
-+ */
-+ VC_IMAGE_YUV422,
-+ /* RGB565 with a transparent patch */
-+ VC_IMAGE_RGBA565,
-+ /* Compressed (4444) version of RGBA32 */
-+ VC_IMAGE_RGBA16,
-+ /* VCIII codec format */
-+ VC_IMAGE_YUV_UV,
-+ /* VCIII T-format RGBA8888 */
-+ VC_IMAGE_TF_RGBA32,
-+ /* VCIII T-format RGBx8888 */
-+ VC_IMAGE_TF_RGBX32,
-+ /* VCIII T-format float */
-+ VC_IMAGE_TF_FLOAT,
-+ /* VCIII T-format RGBA4444 */
-+ VC_IMAGE_TF_RGBA16,
-+ /* VCIII T-format RGB5551 */
-+ VC_IMAGE_TF_RGBA5551,
-+ /* VCIII T-format RGB565 */
-+ VC_IMAGE_TF_RGB565,
-+ /* VCIII T-format 8-bit luma and 8-bit alpha */
-+ VC_IMAGE_TF_YA88,
-+ /* VCIII T-format 8 bit generic sample */
-+ VC_IMAGE_TF_BYTE,
-+ /* VCIII T-format 8-bit palette */
-+ VC_IMAGE_TF_PAL8,
-+ /* VCIII T-format 4-bit palette */
-+ VC_IMAGE_TF_PAL4,
-+ /* VCIII T-format Ericsson Texture Compressed */
-+ VC_IMAGE_TF_ETC1,
-+ /* RGB888 with R & B swapped */
-+ VC_IMAGE_BGR888,
-+ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
-+ * each row of pixels
-+ */
-+ VC_IMAGE_BGR888_NP,
-+ /* Bayer image, extra defines which variant is being used */
-+ VC_IMAGE_BAYER,
-+ /* General wrapper for codec images e.g. JPEG from camera */
-+ VC_IMAGE_CODEC,
-+ /* VCIII codec format */
-+ VC_IMAGE_YUV_UV32,
-+ /* VCIII T-format 8-bit luma */
-+ VC_IMAGE_TF_Y8,
-+ /* VCIII T-format 8-bit alpha */
-+ VC_IMAGE_TF_A8,
-+ /* VCIII T-format 16-bit generic sample */
-+ VC_IMAGE_TF_SHORT,
-+ /* VCIII T-format 1bpp black/white */
-+ VC_IMAGE_TF_1BPP,
-+ VC_IMAGE_OPENGL,
-+ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
-+ VC_IMAGE_YUV444I,
-+ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
-+ * a per line basis)
-+ */
-+ VC_IMAGE_YUV422PLANAR,
-+ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
-+ VC_IMAGE_ARGB8888,
-+ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
-+ VC_IMAGE_XRGB8888,
-+
-+ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
-+ VC_IMAGE_YUV422YUYV,
-+ VC_IMAGE_YUV422YVYU,
-+ VC_IMAGE_YUV422UYVY,
-+ VC_IMAGE_YUV422VYUY,
-+
-+ /* 32bpp like RGBA32 but with unused alpha */
-+ VC_IMAGE_RGBX32,
-+ /* 32bpp, corresponding to RGBA with unused alpha */
-+ VC_IMAGE_RGBX8888,
-+ /* 32bpp, corresponding to BGRA with unused alpha */
-+ VC_IMAGE_BGRX8888,
-+
-+ /* Y as a plane, then UV byte interleaved in plane with with same pitch,
-+ * half height
-+ */
-+ VC_IMAGE_YUV420SP,
-+
-+ /* Y, U, & V planes separately 4:4:4 */
-+ VC_IMAGE_YUV444PLANAR,
-+
-+ /* T-format 8-bit U - same as TF_Y8 buf from U plane */
-+ VC_IMAGE_TF_U8,
-+ /* T-format 8-bit U - same as TF_Y8 buf from V plane */
-+ VC_IMAGE_TF_V8,
-+
-+ /* YUV4:2:0 planar, 16bit values */
-+ VC_IMAGE_YUV420_16,
-+ /* YUV4:2:0 codec format, 16bit values */
-+ VC_IMAGE_YUV_UV_16,
-+ /* YUV4:2:0 with U,V in side-by-side format */
-+ VC_IMAGE_YUV420_S,
-+
-+ VC_IMAGE_MAX, /* bounds for error checking */
-+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
-+};
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -147,6 +147,8 @@ enum rpi_firmware_property_tag {
-
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
-+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
- };
--- /dev/null
+From c2666d7b749ade8ed250ab115a71d420c1403b24 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 5 Apr 2019 17:23:15 +0100
+Subject: [PATCH] drm: vc4: Select display to blank during
+ initialisation
+
+Otherwise the rainbow splash screen remained in the display list
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -89,6 +89,13 @@ struct fb_alloc_tags {
+ u32 layer;
+ };
+
++struct mailbox_blank_display {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 blank;
++};
++
+ static const struct vc_image_format {
+ u32 drm; /* DRM_FORMAT_* */
+ u32 vc_image; /* VC_IMAGE_* */
+@@ -855,7 +862,12 @@ static int vc4_fkms_create_screen(struct
+ struct drm_crtc *crtc;
+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
+ struct drm_plane *destroy_plane, *temp;
+- u32 blank = 1;
++ struct mailbox_blank_display blank = {
++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
++ .display = display_idx,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
++ .blank = 1,
++ };
+ int ret;
+
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
+@@ -866,9 +878,7 @@ static int vc4_fkms_create_screen(struct
+ vc4_crtc->display_number = display_ref;
+
+ /* Blank the firmware provided framebuffer */
+- rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
+- &blank, sizeof(blank));
++ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
+
+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
+ display_ref,
+++ /dev/null
-From a954d2d91eff32d1ab8baae12b8ac7dc856711cb Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 3 Apr 2019 15:20:05 +0100
-Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096.
-
-We now should support 4k screens, therefore this limit needs to
-be increased.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 2048;
-- dev->mode_config.max_height = 2048;
-+ dev->mode_config.max_width = 4096;
-+ dev->mode_config.max_height = 4096;
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
--- /dev/null
+From dc19d8552bc0b6e0261fe7d28be81fe808a659e8 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 5 Apr 2019 17:24:20 +0100
+Subject: [PATCH] drm: vc4: Remove now unused structure.
+
+Cleaning up structure that was unused after
+fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 -------------------
+ 1 file changed, 19 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -70,25 +70,6 @@ struct mailbox_set_plane {
+ struct set_plane plane;
+ };
+
+-struct fb_alloc_tags {
+- struct rpi_firmware_property_tag_header tag1;
+- u32 xres, yres;
+- struct rpi_firmware_property_tag_header tag2;
+- u32 xres_virtual, yres_virtual;
+- struct rpi_firmware_property_tag_header tag3;
+- u32 bpp;
+- struct rpi_firmware_property_tag_header tag4;
+- u32 xoffset, yoffset;
+- struct rpi_firmware_property_tag_header tag5;
+- u32 base, screen_size;
+- struct rpi_firmware_property_tag_header tag6;
+- u32 pitch;
+- struct rpi_firmware_property_tag_header tag7;
+- u32 alpha_mode;
+- struct rpi_firmware_property_tag_header tag8;
+- u32 layer;
+-};
+-
+ struct mailbox_blank_display {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 display;
+++ /dev/null
-From b7a52df8162e1eb55a8403e9e9af79c581206335 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 3 Apr 2019 17:15:45 +0100
-Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms
-
-There is a slightly nasty hack in that all crtcs share the
-same SMI interrupt from the firmware. This seems to currently
-work well enough, but ought to be fixed at a later date.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 162 +++++++++++++++++--------
- 1 file changed, 113 insertions(+), 49 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -31,6 +31,8 @@
- #include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+#define PLANES_PER_CRTC 3
-+
- struct set_plane {
- u8 display;
- u8 plane_id;
-@@ -177,6 +179,7 @@ struct vc4_crtc {
- struct drm_pending_vblank_event *event;
- u32 overscan[4];
- bool vblank_enabled;
-+ u32 display_number;
- };
-
- static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
-@@ -481,6 +484,7 @@ static const struct drm_plane_helper_fun
-
- static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
- enum drm_plane_type type,
-+ u8 display_num,
- u8 plane_id)
- {
- struct drm_plane *plane = NULL;
-@@ -544,7 +548,7 @@ static struct drm_plane *vc4_fkms_plane_
- vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
- vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
- vc4_plane->mb.tag.req_resp_size = 0;
-- vc4_plane->mb.plane.display = 0;
-+ vc4_plane->mb.plane.display = display_num;
- vc4_plane->mb.plane.plane_id = plane_id;
- vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
-
-@@ -631,16 +635,20 @@ static void vc4_crtc_handle_page_flip(st
-
- static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
- {
-- struct vc4_crtc *vc4_crtc = data;
-- u32 stat = readl(vc4_crtc->regs + SMICS);
-+ struct vc4_crtc **crtc_list = data;
-+ int i;
-+ u32 stat = readl(crtc_list[0]->regs + SMICS);
- irqreturn_t ret = IRQ_NONE;
-
- if (stat & SMICS_INTERRUPTS) {
-- writel(0, vc4_crtc->regs + SMICS);
-- if (vc4_crtc->vblank_enabled)
-- drm_crtc_handle_vblank(&vc4_crtc->base);
-- vc4_crtc_handle_page_flip(vc4_crtc);
-- ret = IRQ_HANDLED;
-+ writel(0, crtc_list[0]->regs + SMICS);
-+
-+ for (i = 0; crtc_list[i]; i++) {
-+ if (crtc_list[i]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[i]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[i]);
-+ ret = IRQ_HANDLED;
-+ }
- }
-
- return ret;
-@@ -837,66 +845,55 @@ static const struct drm_encoder_helper_f
- .disable = vc4_fkms_encoder_disable,
- };
-
--static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
-+static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
-+ int display_idx, int display_ref,
-+ struct vc4_crtc **ret_crtc)
- {
-- 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 vc4_fkms_encoder *vc4_encoder;
- struct drm_crtc *crtc;
- struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
- struct drm_plane *destroy_plane, *temp;
-- struct device_node *firmware_node;
- u32 blank = 1;
- int ret;
-
-- vc4->firmware_kms = true;
--
-- /* firmware kms doesn't have precise a scanoutpos implementation, so
-- * we can't do the precise vblank timestamp mode.
-- */
-- drm->driver->get_scanout_position = NULL;
-- drm->driver->get_vblank_timestamp = NULL;
--
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
- if (!vc4_crtc)
- return -ENOMEM;
- crtc = &vc4_crtc->base;
-
-- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-- vc4->firmware = rpi_firmware_get(firmware_node);
-- if (!vc4->firmware) {
-- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
-- return -EPROBE_DEFER;
-- }
-- of_node_put(firmware_node);
--
-- /* Map the SMI interrupt reg */
-- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
-- if (IS_ERR(vc4_crtc->regs))
-- return PTR_ERR(vc4_crtc->regs);
-+ vc4_crtc->display_number = display_ref;
-
- /* Blank the firmware provided framebuffer */
- rpi_firmware_property(vc4->firmware,
- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
- &blank, sizeof(blank));
-
-- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
-+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
-+ display_ref,
-+ 0 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(primary_plane)) {
- dev_err(dev, "failed to construct primary plane\n");
- ret = PTR_ERR(primary_plane);
- goto err;
- }
-
-- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
-+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
-+ display_ref,
-+ 1 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(overlay_plane)) {
- dev_err(dev, "failed to construct overlay plane\n");
- ret = PTR_ERR(overlay_plane);
- goto err;
- }
-
-- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
-+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
-+ display_ref,
-+ 2 + (display_idx * PLANES_PER_CRTC)
-+ );
- if (IS_ERR(cursor_plane)) {
- dev_err(dev, "failed to construct cursor plane\n");
- ret = PTR_ERR(cursor_plane);
-@@ -923,13 +920,6 @@ static int vc4_fkms_bind(struct device *
- goto err_destroy_encoder;
- }
-
-- writel(0, vc4_crtc->regs + SMICS);
-- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-- vc4_crtc);
-- if (ret)
-- goto err_destroy_connector;
--
- ret = rpi_firmware_property(vc4->firmware,
- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
- &vc4_crtc->overscan,
-@@ -939,7 +929,7 @@ static int vc4_fkms_bind(struct device *
- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
- }
-
-- platform_set_drvdata(pdev, vc4_crtc);
-+ *ret_crtc = vc4_crtc;
-
- return 0;
-
-@@ -956,17 +946,91 @@ err:
- return ret;
- }
-
-+static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
-+{
-+ 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 device_node *firmware_node;
-+ struct vc4_crtc **crtc_list;
-+ u32 num_displays, display_num;
-+ int ret;
-+ const u32 display_num_lookup[] = {2, 7, 1};
-+
-+ vc4->firmware_kms = true;
-+
-+ /* firmware kms doesn't have precise a scanoutpos implementation, so
-+ * we can't do the precise vblank timestamp mode.
-+ */
-+ drm->driver->get_scanout_position = NULL;
-+ drm->driver->get_vblank_timestamp = NULL;
-+
-+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-+ vc4->firmware = rpi_firmware_get(firmware_node);
-+ if (!vc4->firmware) {
-+ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
-+ return -EPROBE_DEFER;
-+ }
-+ of_node_put(firmware_node);
-+
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
-+ &num_displays, sizeof(u32));
-+
-+ /* If we fail to get the number of displays, or it returns 0, then
-+ * assume old firmware that doesn't have the mailbox call, so just
-+ * set one display
-+ */
-+ if (ret || num_displays == 0) {
-+ num_displays = 1;
-+ DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
-+ ret = 0;
-+ }
-+
-+ /* Allocate a list, with space for a NULL on the end */
-+ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
-+ GFP_KERNEL);
-+ if (!crtc_list)
-+ return -ENOMEM;
-+
-+ for (display_num = 0; display_num < num_displays; display_num++) {
-+ ret = vc4_fkms_create_screen(dev, drm, display_num,
-+ display_num_lookup[display_num],
-+ &crtc_list[display_num]);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to create display %u\n",
-+ display_num);
-+ }
-+
-+ /* Map the SMI interrupt reg */
-+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-+ if (IS_ERR(crtc_list[0]->regs))
-+ DRM_ERROR("Oh dear, failed to map registers\n");
-+
-+ writel(0, crtc_list[0]->regs + SMICS);
-+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-+ vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-+ crtc_list);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to register IRQ\n");
-+
-+ platform_set_drvdata(pdev, crtc_list);
-+
-+ return 0;
-+}
-+
- static void vc4_fkms_unbind(struct device *dev, struct device *master,
- void *data)
- {
-- struct drm_device *drm = dev_get_drvdata(master);
- struct platform_device *pdev = to_platform_device(dev);
-- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
-+ struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
-+ int i;
-
-- vc4_fkms_connector_destroy(vc4_crtc->connector);
-- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
-- drm_atomic_helper_shutdown(drm);
-- drm_crtc_cleanup(&vc4_crtc->base);
-+ for (i = 0; crtc_list[i]; i++) {
-+ vc4_fkms_connector_destroy(crtc_list[i]->connector);
-+ vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
-+ drm_crtc_cleanup(&crtc_list[i]->base);
-+ }
-
- platform_set_drvdata(pdev, NULL);
- }
--- /dev/null
+From 5357e5991f09f78e945b3adcc5db0ebfa1766dc1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 9 Apr 2019 12:37:28 +0100
+Subject: [PATCH] drm: vc4: Query the display ID for each display in
+ FKMS
+
+Replace the hard coded list of display IDs for a mailbox call
+that returns the display ID for each display that has been
+detected.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++---
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 14 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -944,7 +944,7 @@ static int vc4_fkms_bind(struct device *
+ struct vc4_crtc **crtc_list;
+ u32 num_displays, display_num;
+ int ret;
+- const u32 display_num_lookup[] = {2, 7, 1};
++ u32 display_id;
+
+ vc4->firmware_kms = true;
+
+@@ -983,8 +983,18 @@ static int vc4_fkms_bind(struct device *
+ return -ENOMEM;
+
+ for (display_num = 0; display_num < num_displays; display_num++) {
+- ret = vc4_fkms_create_screen(dev, drm, display_num,
+- display_num_lookup[display_num],
++ display_id = display_num;
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
++ &display_id, sizeof(display_id));
++ /* FIXME: Determine the correct error handling here.
++ * Should we fail to create the one "screen" but keep the
++ * others, or fail the whole thing?
++ */
++ if (ret)
++ DRM_ERROR("Failed to get display id %u\n", display_num);
++
++ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
+ &crtc_list[display_num]);
+ if (ret)
+ DRM_ERROR("Oh dear, failed to create display %u\n",
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -114,6 +114,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
+++ /dev/null
-From a06b826c199e6de39d4e91e41e8347a5629bb54a Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 5 Apr 2019 17:21:56 +0100
-Subject: [PATCH] drm: vc4: Fix build warning
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -933,8 +933,6 @@ static int vc4_fkms_create_screen(struct
-
- return 0;
-
--err_destroy_connector:
-- vc4_fkms_connector_destroy(vc4_crtc->connector);
- err_destroy_encoder:
- vc4_fkms_encoder_destroy(vc4_crtc->encoder);
- list_for_each_entry_safe(destroy_plane, temp,
--- /dev/null
+From d72d6e2388c082ef48d776105ebb285c2d470fa6 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 9 Apr 2019 14:00:07 +0100
+Subject: [PATCH] drm/vc4: Set the display number when querying the
+ display resolution
+
+Without this the two displays got set to the same resolution.
+(Requires a firmware bug fix to work).
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 10 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -77,6 +77,13 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
++struct mailbox_get_width_height {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ struct rpi_firmware_property_tag_header tag2;
++ u32 wh[2];
++};
++
+ static const struct vc_image_format {
+ u32 drm; /* DRM_FORMAT_* */
+ u32 vc_image; /* VC_IMAGE_* */
+@@ -194,6 +201,7 @@ struct vc4_fkms_connector {
+ * hook.
+ */
+ struct drm_encoder *encoder;
++ u32 display_idx;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -724,21 +732,27 @@ vc4_fkms_connector_detect(struct drm_con
+ static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
+ {
+ struct drm_device *dev = connector->dev;
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+- u32 wh[2] = {0, 0};
+- int ret;
+ struct drm_display_mode *mode;
++ struct mailbox_get_width_height wh = {
++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
++ .display = fkms_connector->display_idx,
++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
++ 8, 0, },
++ };
++ int ret;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
+
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
+- &wh, sizeof(wh));
+ if (ret) {
+ DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
+- ret, wh[0], wh[1]);
++ ret, wh.wh[0], wh.wh[1]);
+ return 0;
+ }
+
+- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
++ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
+ 0, 0, false);
+ drm_mode_probed_add(connector, mode);
+
+@@ -773,8 +787,9 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
+-static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
+- struct drm_encoder *encoder)
++static struct drm_connector *
++vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
++ u32 display_idx)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
+@@ -789,6 +804,7 @@ static struct drm_connector *vc4_fkms_co
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
++ fkms_connector->display_idx = display_idx;
+
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+@@ -905,7 +921,8 @@ static int vc4_fkms_create_screen(struct
+ drm_encoder_helper_add(&vc4_encoder->base,
+ &vc4_fkms_encoder_helper_funcs);
+
+- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
++ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
++ display_idx);
+ if (IS_ERR(vc4_crtc->connector)) {
+ ret = PTR_ERR(vc4_crtc->connector);
+ goto err_destroy_encoder;
--- /dev/null
+From 236758b499086e0de280407396550125f1b6647a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 9 Apr 2019 18:14:44 +0100
+Subject: [PATCH] from
+ vc4_crtc_[en|dis]able
+
+vblank needs to be enabled and disabled by the driver to avoid the
+DRM framework complaining in the kernel log.
+
+vc4_fkms_disable_vblank needs to signal that we don't want vblank
+callbacks too.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -21,6 +21,7 @@
+ #include "drm/drm_fourcc.h"
+ #include "drm/drm_probe_helper.h"
+ #include "drm/drm_drv.h"
++#include "drm/drm_vblank.h"
+ #include "linux/clk.h"
+ #include "linux/debugfs.h"
+ #include "drm/drm_fb_cma_helper.h"
+@@ -563,6 +564,8 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ drm_crtc_vblank_off(crtc);
++
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+ * are enabled/disabled through the update/disable hooks
+ * above, and the CRTC enable/disable independently controls
+@@ -578,6 +581,7 @@ static void vc4_crtc_disable(struct drm_
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ drm_crtc_vblank_on(crtc);
+ /* Unblank the planes (if they're supposed to be displayed). */
+
+ if (crtc->primary->state->fb)
+@@ -674,6 +678,9 @@ static int vc4_fkms_enable_vblank(struct
+
+ static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
+ {
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++
++ vc4_crtc->vblank_enabled = false;
+ }
+
+ static const struct drm_crtc_funcs vc4_crtc_funcs = {
+++ /dev/null
-From c2666d7b749ade8ed250ab115a71d420c1403b24 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 5 Apr 2019 17:23:15 +0100
-Subject: [PATCH] drm: vc4: Select display to blank during
- initialisation
-
-Otherwise the rainbow splash screen remained in the display list
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++----
- 1 file changed, 14 insertions(+), 4 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -89,6 +89,13 @@ struct fb_alloc_tags {
- u32 layer;
- };
-
-+struct mailbox_blank_display {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 blank;
-+};
-+
- static const struct vc_image_format {
- u32 drm; /* DRM_FORMAT_* */
- u32 vc_image; /* VC_IMAGE_* */
-@@ -855,7 +862,12 @@ static int vc4_fkms_create_screen(struct
- struct drm_crtc *crtc;
- struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
- struct drm_plane *destroy_plane, *temp;
-- u32 blank = 1;
-+ struct mailbox_blank_display blank = {
-+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-+ .display = display_idx,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
-+ .blank = 1,
-+ };
- int ret;
-
- vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
-@@ -866,9 +878,7 @@ static int vc4_fkms_create_screen(struct
- vc4_crtc->display_number = display_ref;
-
- /* Blank the firmware provided framebuffer */
-- rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_BLANK,
-- &blank, sizeof(blank));
-+ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
-
- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY,
- display_ref,
--- /dev/null
+From 495fd0373ad234c8547697e3a7de1f1724c8498d Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 9 Apr 2019 17:19:51 +0100
+Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane
+ for FKMS
+
+They are near zero cost options for the HVS, therefore they
+may as well be implemented, and it allows us to invert the
+DSI display.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -64,8 +64,21 @@ struct set_plane {
+ u8 padding;
+
+ u32 planes[4]; /* DMA address of each plane */
++
++ u32 transform;
+ };
+
++/* Values for the transform field */
++#define TRANSFORM_NO_ROTATE 0
++#define TRANSFORM_ROTATE_180 BIT(1)
++#define TRANSFORM_FLIP_HRIZ BIT(16)
++#define TRANSFORM_FLIP_VERT BIT(17)
++
++#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
++ DRM_MODE_ROTATE_180 | \
++ DRM_MODE_REFLECT_X | \
++ DRM_MODE_REFLECT_Y)
++
+ struct mailbox_set_plane {
+ struct rpi_firmware_property_tag_header tag;
+ struct set_plane plane;
+@@ -277,6 +290,7 @@ static void vc4_plane_atomic_update(stru
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
++ unsigned int rotation = SUPPORTED_ROTATIONS;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+ mb->plane.width = fb->width;
+@@ -297,6 +311,24 @@ static void vc4_plane_atomic_update(stru
+ mb->plane.is_vu = vc_fmt->is_vu;
+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
++ rotation = drm_rotation_simplify(state->rotation, rotation);
++
++ switch (rotation) {
++ default:
++ case DRM_MODE_ROTATE_0:
++ mb->plane.transform = TRANSFORM_NO_ROTATE;
++ break;
++ case DRM_MODE_ROTATE_180:
++ mb->plane.transform = TRANSFORM_ROTATE_180;
++ break;
++ case DRM_MODE_REFLECT_X:
++ mb->plane.transform = TRANSFORM_FLIP_HRIZ;
++ break;
++ case DRM_MODE_REFLECT_Y:
++ mb->plane.transform = TRANSFORM_FLIP_VERT;
++ break;
++ }
++
+ /* FIXME: If the dest rect goes off screen then clip the src rect so we
+ * don't have off-screen pixels.
+ */
+@@ -516,9 +548,13 @@ static struct drm_plane *vc4_fkms_plane_
+ formats, num_formats, modifiers,
+ type, NULL);
+
++ /* FIXME: Do we need to be checking return values from all these calls?
++ */
+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+
+ drm_plane_create_alpha_property(plane);
++ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
++ SUPPORTED_ROTATIONS);
+
+ /*
+ * Default frame buffer setup is with FB on -127, and raspistill etc
+++ /dev/null
-From dc19d8552bc0b6e0261fe7d28be81fe808a659e8 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 5 Apr 2019 17:24:20 +0100
-Subject: [PATCH] drm: vc4: Remove now unused structure.
-
-Cleaning up structure that was unused after
-fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 -------------------
- 1 file changed, 19 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -70,25 +70,6 @@ struct mailbox_set_plane {
- struct set_plane plane;
- };
-
--struct fb_alloc_tags {
-- struct rpi_firmware_property_tag_header tag1;
-- u32 xres, yres;
-- struct rpi_firmware_property_tag_header tag2;
-- u32 xres_virtual, yres_virtual;
-- struct rpi_firmware_property_tag_header tag3;
-- u32 bpp;
-- struct rpi_firmware_property_tag_header tag4;
-- u32 xoffset, yoffset;
-- struct rpi_firmware_property_tag_header tag5;
-- u32 base, screen_size;
-- struct rpi_firmware_property_tag_header tag6;
-- u32 pitch;
-- struct rpi_firmware_property_tag_header tag7;
-- u32 alpha_mode;
-- struct rpi_firmware_property_tag_header tag8;
-- u32 layer;
--};
--
- struct mailbox_blank_display {
- struct rpi_firmware_property_tag_header tag1;
- u32 display;
+++ /dev/null
-From 5357e5991f09f78e945b3adcc5db0ebfa1766dc1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 9 Apr 2019 12:37:28 +0100
-Subject: [PATCH] drm: vc4: Query the display ID for each display in
- FKMS
-
-Replace the hard coded list of display IDs for a mailbox call
-that returns the display ID for each display that has been
-detected.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++---
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 14 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -944,7 +944,7 @@ static int vc4_fkms_bind(struct device *
- struct vc4_crtc **crtc_list;
- u32 num_displays, display_num;
- int ret;
-- const u32 display_num_lookup[] = {2, 7, 1};
-+ u32 display_id;
-
- vc4->firmware_kms = true;
-
-@@ -983,8 +983,18 @@ static int vc4_fkms_bind(struct device *
- return -ENOMEM;
-
- for (display_num = 0; display_num < num_displays; display_num++) {
-- ret = vc4_fkms_create_screen(dev, drm, display_num,
-- display_num_lookup[display_num],
-+ display_id = display_num;
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
-+ &display_id, sizeof(display_id));
-+ /* FIXME: Determine the correct error handling here.
-+ * Should we fail to create the one "screen" but keep the
-+ * others, or fail the whole thing?
-+ */
-+ if (ret)
-+ DRM_ERROR("Failed to get display id %u\n", display_num);
-+
-+ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
- &crtc_list[display_num]);
- if (ret)
- DRM_ERROR("Oh dear, failed to create display %u\n",
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -114,6 +114,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
- RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
- RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016,
- RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
- RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
- RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
--- /dev/null
+From 99d029e3a379efb75725460b03465f80e0111da1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 10 Apr 2019 17:35:05 +0100
+Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip
+ function
+
+"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip,
+but vc4_fkms_cancel_page_flip was still be added to with the
+fkms driver, even though it was never called.
+Nuke it too.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 -
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 --------------------
+ 2 files changed, 21 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -795,7 +795,6 @@ extern const struct dma_fence_ops vc4_fe
+
+ /* vc4_firmware_kms.c */
+ extern struct platform_driver vc4_firmware_kms_driver;
+-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
+
+ /* vc4_gem.c */
+ void vc4_gem_init(struct drm_device *dev);
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -741,26 +741,6 @@ static const struct drm_crtc_helper_func
+ .atomic_flush = vc4_crtc_atomic_flush,
+ };
+
+-/* Frees the page flip event when the DRM device is closed with the
+- * event still outstanding.
+- */
+-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
+-{
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+- struct drm_device *dev = crtc->dev;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&dev->event_lock, flags);
+-
+- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
+- kfree(&vc4_crtc->event->base);
+- drm_crtc_vblank_put(crtc);
+- vc4_crtc->event = NULL;
+- }
+-
+- spin_unlock_irqrestore(&dev->event_lock, flags);
+-}
+-
+ static const struct of_device_id vc4_firmware_kms_dt_match[] = {
+ { .compatible = "raspberrypi,rpi-firmware-kms" },
+ {}
--- /dev/null
+From 016e6e68a119d3f4cae3c148433e2d661c7835be Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 10 Apr 2019 17:42:37 +0100
+Subject: [PATCH] drm: vc4: Iterate over all planes in
+ vc4_crtc_[dis|en]able
+
+Fixes a FIXME where the overlay plane wouldn't be restored.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -600,6 +600,8 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_plane *plane;
++
+ drm_crtc_vblank_off(crtc);
+
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+@@ -609,23 +611,23 @@ static void vc4_crtc_disable(struct drm_
+ * give us a CRTC-level control for that.
+ */
+
+- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
+- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
+-
+- /* FIXME: Disable overlay planes */
++ drm_atomic_crtc_for_each_plane(plane, crtc)
++ vc4_plane_atomic_disable(plane, plane->state);
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_plane *plane;
++
+ drm_crtc_vblank_on(crtc);
++
+ /* Unblank the planes (if they're supposed to be displayed). */
++ drm_atomic_crtc_for_each_plane(plane, crtc)
++ if (plane->state->fb)
++ vc4_plane_set_blank(plane, plane->state->visible);
++}
+
+- if (crtc->primary->state->fb)
+- vc4_plane_set_blank(crtc->primary, false);
+- if (crtc->cursor->state->fb)
+- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
+
+- /* FIXME: Enable overlay planes */
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+++ /dev/null
-From d72d6e2388c082ef48d776105ebb285c2d470fa6 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 9 Apr 2019 14:00:07 +0100
-Subject: [PATCH] drm/vc4: Set the display number when querying the
- display resolution
-
-Without this the two displays got set to the same resolution.
-(Requires a firmware bug fix to work).
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++-------
- 1 file changed, 27 insertions(+), 10 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -77,6 +77,13 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
-+struct mailbox_get_width_height {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ struct rpi_firmware_property_tag_header tag2;
-+ u32 wh[2];
-+};
-+
- static const struct vc_image_format {
- u32 drm; /* DRM_FORMAT_* */
- u32 vc_image; /* VC_IMAGE_* */
-@@ -194,6 +201,7 @@ struct vc4_fkms_connector {
- * hook.
- */
- struct drm_encoder *encoder;
-+ u32 display_idx;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -724,21 +732,27 @@ vc4_fkms_connector_detect(struct drm_con
- static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
- {
- struct drm_device *dev = connector->dev;
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- u32 wh[2] = {0, 0};
-- int ret;
- struct drm_display_mode *mode;
-+ struct mailbox_get_width_height wh = {
-+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-+ .display = fkms_connector->display_idx,
-+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-+ 8, 0, },
-+ };
-+ int ret;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
-
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-- &wh, sizeof(wh));
- if (ret) {
- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
-- ret, wh[0], wh[1]);
-+ ret, wh.wh[0], wh.wh[1]);
- return 0;
- }
-
-- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
-+ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
- 0, 0, false);
- drm_mode_probed_add(connector, mode);
-
-@@ -773,8 +787,9 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
--static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
-- struct drm_encoder *encoder)
-+static struct drm_connector *
-+vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
-+ u32 display_idx)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-@@ -789,6 +804,7 @@ static struct drm_connector *vc4_fkms_co
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-+ fkms_connector->display_idx = display_idx;
-
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
-@@ -905,7 +921,8 @@ static int vc4_fkms_create_screen(struct
- drm_encoder_helper_add(&vc4_encoder->base,
- &vc4_fkms_encoder_helper_funcs);
-
-- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
-+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
-+ display_idx);
- if (IS_ERR(vc4_crtc->connector)) {
- ret = PTR_ERR(vc4_crtc->connector);
- goto err_destroy_encoder;
--- /dev/null
+From 9185a16ce8804d35339402c6aec38a528cc2c7a1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 10 Apr 2019 17:43:57 +0100
+Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking
+ doublescan modes
+
+Implement vc4_crtc_mode_valid so that it blocks doublescan modes
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -627,7 +627,17 @@ static void vc4_crtc_enable(struct drm_c
+ vc4_plane_set_blank(plane, plane->state->visible);
+ }
+
++static enum drm_mode_status
++vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
++{
++ /* Do not allow doublescan modes from user space */
++ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
++ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
++ crtc->base.id);
++ return MODE_NO_DBLESCAN;
++ }
+
++ return MODE_OK;
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+@@ -737,10 +747,11 @@ static const struct drm_crtc_funcs vc4_c
+
+ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
+ .mode_set_nofb = vc4_crtc_mode_set_nofb,
+- .atomic_disable = vc4_crtc_disable,
+- .atomic_enable = vc4_crtc_enable,
++ .mode_valid = vc4_crtc_mode_valid,
+ .atomic_check = vc4_crtc_atomic_check,
+ .atomic_flush = vc4_crtc_atomic_flush,
++ .atomic_enable = vc4_crtc_enable,
++ .atomic_disable = vc4_crtc_disable,
+ };
+
+ static const struct of_device_id vc4_firmware_kms_dt_match[] = {
+++ /dev/null
-From 236758b499086e0de280407396550125f1b6647a Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 9 Apr 2019 18:14:44 +0100
-Subject: [PATCH] from
- vc4_crtc_[en|dis]able
-
-vblank needs to be enabled and disabled by the driver to avoid the
-DRM framework complaining in the kernel log.
-
-vc4_fkms_disable_vblank needs to signal that we don't want vblank
-callbacks too.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -21,6 +21,7 @@
- #include "drm/drm_fourcc.h"
- #include "drm/drm_probe_helper.h"
- #include "drm/drm_drv.h"
-+#include "drm/drm_vblank.h"
- #include "linux/clk.h"
- #include "linux/debugfs.h"
- #include "drm/drm_fb_cma_helper.h"
-@@ -563,6 +564,8 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ drm_crtc_vblank_off(crtc);
-+
- /* Always turn the planes off on CRTC disable. In DRM, planes
- * are enabled/disabled through the update/disable hooks
- * above, and the CRTC enable/disable independently controls
-@@ -578,6 +581,7 @@ static void vc4_crtc_disable(struct drm_
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ drm_crtc_vblank_on(crtc);
- /* Unblank the planes (if they're supposed to be displayed). */
-
- if (crtc->primary->state->fb)
-@@ -674,6 +678,9 @@ static int vc4_fkms_enable_vblank(struct
-
- static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
- {
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+
-+ vc4_crtc->vblank_enabled = false;
- }
-
- static const struct drm_crtc_funcs vc4_crtc_funcs = {
+++ /dev/null
-From 495fd0373ad234c8547697e3a7de1f1724c8498d Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 9 Apr 2019 17:19:51 +0100
-Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane
- for FKMS
-
-They are near zero cost options for the HVS, therefore they
-may as well be implemented, and it allows us to invert the
-DSI display.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -64,8 +64,21 @@ struct set_plane {
- u8 padding;
-
- u32 planes[4]; /* DMA address of each plane */
-+
-+ u32 transform;
- };
-
-+/* Values for the transform field */
-+#define TRANSFORM_NO_ROTATE 0
-+#define TRANSFORM_ROTATE_180 BIT(1)
-+#define TRANSFORM_FLIP_HRIZ BIT(16)
-+#define TRANSFORM_FLIP_VERT BIT(17)
-+
-+#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
-+ DRM_MODE_ROTATE_180 | \
-+ DRM_MODE_REFLECT_X | \
-+ DRM_MODE_REFLECT_Y)
-+
- struct mailbox_set_plane {
- struct rpi_firmware_property_tag_header tag;
- struct set_plane plane;
-@@ -277,6 +290,7 @@ static void vc4_plane_atomic_update(stru
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
-+ unsigned int rotation = SUPPORTED_ROTATIONS;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
- mb->plane.width = fb->width;
-@@ -297,6 +311,24 @@ static void vc4_plane_atomic_update(stru
- mb->plane.is_vu = vc_fmt->is_vu;
- mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-+ rotation = drm_rotation_simplify(state->rotation, rotation);
-+
-+ switch (rotation) {
-+ default:
-+ case DRM_MODE_ROTATE_0:
-+ mb->plane.transform = TRANSFORM_NO_ROTATE;
-+ break;
-+ case DRM_MODE_ROTATE_180:
-+ mb->plane.transform = TRANSFORM_ROTATE_180;
-+ break;
-+ case DRM_MODE_REFLECT_X:
-+ mb->plane.transform = TRANSFORM_FLIP_HRIZ;
-+ break;
-+ case DRM_MODE_REFLECT_Y:
-+ mb->plane.transform = TRANSFORM_FLIP_VERT;
-+ break;
-+ }
-+
- /* FIXME: If the dest rect goes off screen then clip the src rect so we
- * don't have off-screen pixels.
- */
-@@ -516,9 +548,13 @@ static struct drm_plane *vc4_fkms_plane_
- formats, num_formats, modifiers,
- type, NULL);
-
-+ /* FIXME: Do we need to be checking return values from all these calls?
-+ */
- drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
-
- drm_plane_create_alpha_property(plane);
-+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-+ SUPPORTED_ROTATIONS);
-
- /*
- * Default frame buffer setup is with FB on -127, and raspistill etc
--- /dev/null
+From 11801b1f71144478ab6c19a4c309667d340cb9e2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Mon, 29 Apr 2019 18:45:00 +0100
+Subject: [PATCH] drm: vc4: Increase max_width/height to 7680.
+
+There are some limits still being investigated that stop
+us going up to 8192, but 7680 is sufficient for dual 4k
+displays.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 4096;
+- dev->mode_config.max_height = 4096;
++ dev->mode_config.max_width = 7680;
++ dev->mode_config.max_height = 7680;
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
--- /dev/null
+From 52add140c76c0a211ab340ced8e7e1ea8bef9c79 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 9 Apr 2019 18:23:41 +0100
+Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports
+ mode setting
+
+This extends FKMS to read the EDID from the display, and support
+requesting a particular mode via KMS.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++---
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +
+ 2 files changed, 302 insertions(+), 34 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -91,11 +91,60 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
+-struct mailbox_get_width_height {
++struct mailbox_get_edid {
+ struct rpi_firmware_property_tag_header tag1;
+- u32 display;
+- struct rpi_firmware_property_tag_header tag2;
+- u32 wh[2];
++ u32 block;
++ u32 display_number;
++ u8 edid[128];
++};
++
++struct set_timings {
++ u8 display;
++ u8 padding;
++ u16 video_id_code;
++
++ u32 clock; /* in kHz */
++
++ u16 hdisplay;
++ u16 hsync_start;
++
++ u16 hsync_end;
++ u16 htotal;
++
++ u16 hskew;
++ u16 vdisplay;
++
++ u16 vsync_start;
++ u16 vsync_end;
++
++ u16 vtotal;
++ u16 vscan;
++
++ u16 vrefresh;
++ u16 padding2;
++
++ u32 flags;
++#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
++#define TIMINGS_FLAGS_H_SYNC_NEG 0
++#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
++#define TIMINGS_FLAGS_V_SYNC_NEG 0
++
++#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
++#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
++#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
++#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
++#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
++#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
++
++/* Limited range RGB flag. Not set corresponds to full range. */
++#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
++/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
++#define TIMINGS_FLAGS_DVI BIT(9)
++};
++
++struct mailbox_set_mode {
++ struct rpi_firmware_property_tag_header tag1;
++ struct set_timings timings;
+ };
+
+ static const struct vc_image_format {
+@@ -189,6 +238,7 @@ struct vc4_crtc {
+ u32 overscan[4];
+ bool vblank_enabled;
+ u32 display_number;
++ u32 display_type;
+ };
+
+ static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
+@@ -198,6 +248,8 @@ static inline struct vc4_crtc *to_vc4_cr
+
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
++ bool hdmi_monitor;
++ bool rgb_range_selectable;
+ };
+
+ static inline struct vc4_fkms_encoder *
+@@ -215,7 +267,9 @@ struct vc4_fkms_connector {
+ * hook.
+ */
+ struct drm_encoder *encoder;
+- u32 display_idx;
++ struct vc4_dev *vc4_dev;
++ u32 display_number;
++ u32 display_type;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -224,6 +278,26 @@ to_vc4_fkms_connector(struct drm_connect
+ return container_of(connector, struct vc4_fkms_connector, base);
+ }
+
++static u32 vc4_get_display_type(u32 display_number)
++{
++ const u32 display_types[] = {
++ /* The firmware display (DispmanX) IDs map to specific types in
++ * a fixed manner.
++ */
++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
++ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
++ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
++ DRM_MODE_ENCODER_TVDAC, /* VEC */
++ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
++ DRM_MODE_ENCODER_NONE, /* FORCE_TV */
++ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
++ DRM_MODE_ENCODER_TMDS, /* HDMI1 */
++ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
++ };
++ return display_number > ARRAY_SIZE(display_types) - 1 ?
++ DRM_MODE_ENCODER_NONE : display_types[display_number];
++}
++
+ /* Firmware's structure for making an FB mbox call. */
+ struct fbinfo_s {
+ u32 xres, yres, xres_virtual, yres_virtual;
+@@ -258,10 +332,15 @@ static int vc4_plane_set_blank(struct dr
+ .plane_id = vc4_plane->mb.plane.plane_id,
+ }
+ };
++ static const char * const plane_types[] = {
++ "overlay",
++ "primary",
++ "cursor"
++ };
+ int ret;
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
+- plane->base.id, plane->name,
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
++ plane->base.id, plane->name, plane_types[plane->type],
+ blank ? "blank" : "unblank");
+
+ if (blank)
+@@ -595,13 +674,102 @@ fail:
+
+ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
+ {
+- /* Everyting is handled in the planes. */
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
++ struct vc4_fkms_encoder *vc4_encoder =
++ to_vc4_fkms_encoder(vc4_crtc->encoder);
++ struct mailbox_set_mode mb = {
++ .tag1 = { RPI_FIRMWARE_SET_TIMING,
++ sizeof(struct set_timings), 0},
++ };
++ union hdmi_infoframe frame;
++ int ret;
++
++ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
++ if (ret < 0) {
++ DRM_ERROR("couldn't fill AVI infoframe\n");
++ return;
++ }
++
++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
++ vc4_crtc->display_number, mode->name, mode->clock,
++ mode->hdisplay, mode->hsync_start, mode->hsync_end,
++ mode->htotal, mode->hskew, mode->vdisplay,
++ mode->vsync_start, mode->vsync_end, mode->vtotal,
++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
++ mb.timings.display = vc4_crtc->display_number;
++
++ mb.timings.video_id_code = frame.avi.video_code;
++
++ mb.timings.clock = mode->clock;
++ mb.timings.hdisplay = mode->hdisplay;
++ mb.timings.hsync_start = mode->hsync_start;
++ mb.timings.hsync_end = mode->hsync_end;
++ mb.timings.htotal = mode->htotal;
++ mb.timings.hskew = mode->hskew;
++ mb.timings.vdisplay = mode->vdisplay;
++ mb.timings.vsync_start = mode->vsync_start;
++ mb.timings.vsync_end = mode->vsync_end;
++ mb.timings.vtotal = mode->vtotal;
++ mb.timings.vscan = mode->vscan;
++ mb.timings.vrefresh = 0;
++ mb.timings.flags = 0;
++ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
++ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
++ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
++ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
++
++ switch (frame.avi.picture_aspect) {
++ default:
++ case HDMI_PICTURE_ASPECT_NONE:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
++ break;
++ case HDMI_PICTURE_ASPECT_4_3:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
++ break;
++ case HDMI_PICTURE_ASPECT_16_9:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
++ break;
++ case HDMI_PICTURE_ASPECT_64_27:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
++ break;
++ case HDMI_PICTURE_ASPECT_256_135:
++ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
++ break;
++ }
++
++ if (!vc4_encoder->hdmi_monitor)
++ mb.timings.flags |= TIMINGS_FLAGS_DVI;
++ else if (drm_default_rgb_quant_range(mode) ==
++ HDMI_QUANTIZATION_RANGE_LIMITED)
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++
++ /*
++ FIXME: To implement
++ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
++ case DRM_MODE_FLAG_3D_NONE:
++ case DRM_MODE_FLAG_3D_FRAME_PACKING:
++ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
++ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
++ case DRM_MODE_FLAG_3D_L_DEPTH:
++ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
++ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
++ }
++ */
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+ }
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
+ struct drm_plane *plane;
+
++ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
++ crtc->base.id);
+ drm_crtc_vblank_off(crtc);
+
+ /* Always turn the planes off on CRTC disable. In DRM, planes
+@@ -619,6 +787,8 @@ static void vc4_crtc_enable(struct drm_c
+ {
+ struct drm_plane *plane;
+
++ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
++ crtc->base.id);
+ drm_crtc_vblank_on(crtc);
+
+ /* Unblank the planes (if they're supposed to be displayed). */
+@@ -637,12 +807,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
++ * working.
++ */
++ if (mode->clock > 340000)
++ return MODE_CLOCK_HIGH;
++
+ return MODE_OK;
+ }
+
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
++ crtc->base.id);
+ return 0;
+ }
+
+@@ -652,6 +830,8 @@ static void vc4_crtc_atomic_flush(struct
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
++ crtc->base.id);
+ if (crtc->state->event) {
+ unsigned long flags;
+
+@@ -719,6 +899,8 @@ static int vc4_fkms_enable_vblank(struct
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
++ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
++ crtc->base.id);
+ vc4_crtc->vblank_enabled = true;
+
+ return 0;
+@@ -728,6 +910,8 @@ static void vc4_fkms_disable_vblank(stru
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
++ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
++ crtc->base.id);
+ vc4_crtc->vblank_enabled = false;
+ }
+
+@@ -762,36 +946,92 @@ static const struct of_device_id vc4_fir
+ static enum drm_connector_status
+ vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
+ {
++ DRM_DEBUG_KMS("connector detect.\n");
+ return connector_status_connected;
+ }
+
+-static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
++static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
++ size_t len)
+ {
+- struct drm_device *dev = connector->dev;
+ struct vc4_fkms_connector *fkms_connector =
+- to_vc4_fkms_connector(connector);
+- struct vc4_dev *vc4 = to_vc4_dev(dev);
+- struct drm_display_mode *mode;
+- struct mailbox_get_width_height wh = {
+- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
+- .display = fkms_connector->display_idx,
+- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
+- 8, 0, },
++ (struct vc4_fkms_connector *)data;
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
++ struct mailbox_get_edid mb = {
++ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
++ 128 + 8, 0 },
++ .block = block,
++ .display_number = fkms_connector->display_number,
+ };
+- int ret;
++ int ret = 0;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
++
++ if (!ret)
++ memcpy(buf, mb.edid, len);
++
++ return ret;
++}
++
++static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct drm_encoder *encoder = fkms_connector->encoder;
++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ int ret = 0;
++ struct edid *edid;
++
++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
++ fkms_connector);
++
++ /* FIXME: Can we do CEC?
++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
++ * if (!edid)
++ * return -ENODEV;
++ */
++
++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
++ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
++ vc4_encoder->rgb_range_selectable =
++ drm_rgb_quant_range_selectable(edid);
++ }
++
++ drm_connector_update_edid_property(connector, edid);
++ ret = drm_add_edid_modes(connector, edid);
++ kfree(edid);
++
++ return ret;
++}
++
++/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
++static const struct drm_display_mode lcd_mode = {
++ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
++ 25979400 / 1000,
++ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
++ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
++ DRM_MODE_FLAG_INTERLACE)
++};
++
++static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
++{
++ //struct vc4_fkms_connector *fkms_connector =
++ // to_vc4_fkms_connector(connector);
++ //struct drm_encoder *encoder = fkms_connector->encoder;
++ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct drm_display_mode *mode;
++ //int ret = 0;
+
+- if (ret) {
+- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
+- ret, wh.wh[0], wh.wh[1]);
+- return 0;
++ mode = drm_mode_duplicate(connector->dev,
++ &lcd_mode);
++ if (!mode) {
++ DRM_ERROR("Failed to create a new display mode\n");
++ return -ENOMEM;
+ }
+
+- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
+- 0, 0, false);
+ drm_mode_probed_add(connector, mode);
+
++ /* We have one mode */
+ return 1;
+ }
+
+@@ -800,11 +1040,14 @@ vc4_fkms_connector_best_encoder(struct d
+ {
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
++ DRM_DEBUG_KMS("best_connector.\n");
+ return fkms_connector->encoder;
+ }
+
+ static void vc4_fkms_connector_destroy(struct drm_connector *connector)
+ {
++ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
++ connector->base.id);
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+ }
+@@ -823,14 +1066,22 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
++static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
++ .get_modes = vc4_fkms_lcd_connector_get_modes,
++ .best_encoder = vc4_fkms_connector_best_encoder,
++};
++
+ static struct drm_connector *
+ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
+- u32 display_idx)
++ u32 display_num)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
++ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
+ int ret = 0;
+
++ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
++
+ fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
+ GFP_KERNEL);
+ if (!fkms_connector) {
+@@ -840,11 +1091,21 @@ vc4_fkms_connector_init(struct drm_devic
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
+- fkms_connector->display_idx = display_idx;
+-
+- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+- DRM_MODE_CONNECTOR_HDMIA);
+- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
++ fkms_connector->display_number = display_num;
++ fkms_connector->display_type = vc4_get_display_type(display_num);
++ fkms_connector->vc4_dev = vc4_dev;
++
++ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_DSI);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_lcd_conn_helper_funcs);
++ } else {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_HDMIA);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_connector_helper_funcs);
++ }
+
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+@@ -865,6 +1126,7 @@ vc4_fkms_connector_init(struct drm_devic
+
+ static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_destroy\n");
+ drm_encoder_cleanup(encoder);
+ }
+
+@@ -874,10 +1136,12 @@ static const struct drm_encoder_funcs vc
+
+ static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_enable\n");
+ }
+
+ static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
+ {
++ DRM_DEBUG_KMS("Encoder_disable\n");
+ }
+
+ static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
+@@ -909,6 +1173,7 @@ static int vc4_fkms_create_screen(struct
+ crtc = &vc4_crtc->base;
+
+ vc4_crtc->display_number = display_ref;
++ vc4_crtc->display_type = vc4_get_display_type(display_ref);
+
+ /* Blank the firmware provided framebuffer */
+ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
+@@ -952,13 +1217,14 @@ static int vc4_fkms_create_screen(struct
+ return -ENOMEM;
+ vc4_crtc->encoder = &vc4_encoder->base;
+ vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
++
+ drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
+- DRM_MODE_ENCODER_TMDS, NULL);
++ vc4_crtc->display_type, NULL);
+ drm_encoder_helper_add(&vc4_encoder->base,
+ &vc4_fkms_encoder_helper_funcs);
+
+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
+- display_idx);
++ display_ref);
+ if (IS_ERR(vc4_crtc->connector)) {
+ ret = PTR_ERR(vc4_crtc->connector);
+ goto err_destroy_encoder;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
++ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
+ RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
+ RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
+ RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
+@@ -149,6 +150,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+++ /dev/null
-From 99d029e3a379efb75725460b03465f80e0111da1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 10 Apr 2019 17:35:05 +0100
-Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip
- function
-
-"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip,
-but vc4_fkms_cancel_page_flip was still be added to with the
-fkms driver, even though it was never called.
-Nuke it too.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_drv.h | 1 -
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 --------------------
- 2 files changed, 21 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -795,7 +795,6 @@ extern const struct dma_fence_ops vc4_fe
-
- /* vc4_firmware_kms.c */
- extern struct platform_driver vc4_firmware_kms_driver;
--void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
-
- /* vc4_gem.c */
- void vc4_gem_init(struct drm_device *dev);
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -741,26 +741,6 @@ static const struct drm_crtc_helper_func
- .atomic_flush = vc4_crtc_atomic_flush,
- };
-
--/* Frees the page flip event when the DRM device is closed with the
-- * event still outstanding.
-- */
--void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
--{
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-- struct drm_device *dev = crtc->dev;
-- unsigned long flags;
--
-- spin_lock_irqsave(&dev->event_lock, flags);
--
-- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
-- kfree(&vc4_crtc->event->base);
-- drm_crtc_vblank_put(crtc);
-- vc4_crtc->event = NULL;
-- }
--
-- spin_unlock_irqrestore(&dev->event_lock, flags);
--}
--
- static const struct of_device_id vc4_firmware_kms_dt_match[] = {
- { .compatible = "raspberrypi,rpi-firmware-kms" },
- {}
+++ /dev/null
-From 016e6e68a119d3f4cae3c148433e2d661c7835be Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 10 Apr 2019 17:42:37 +0100
-Subject: [PATCH] drm: vc4: Iterate over all planes in
- vc4_crtc_[dis|en]able
-
-Fixes a FIXME where the overlay plane wouldn't be restored.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++---------
- 1 file changed, 11 insertions(+), 9 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -600,6 +600,8 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_plane *plane;
-+
- drm_crtc_vblank_off(crtc);
-
- /* Always turn the planes off on CRTC disable. In DRM, planes
-@@ -609,23 +611,23 @@ static void vc4_crtc_disable(struct drm_
- * give us a CRTC-level control for that.
- */
-
-- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
-- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
--
-- /* FIXME: Disable overlay planes */
-+ drm_atomic_crtc_for_each_plane(plane, crtc)
-+ vc4_plane_atomic_disable(plane, plane->state);
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_plane *plane;
-+
- drm_crtc_vblank_on(crtc);
-+
- /* Unblank the planes (if they're supposed to be displayed). */
-+ drm_atomic_crtc_for_each_plane(plane, crtc)
-+ if (plane->state->fb)
-+ vc4_plane_set_blank(plane, plane->state->visible);
-+}
-
-- if (crtc->primary->state->fb)
-- vc4_plane_set_blank(crtc->primary, false);
-- if (crtc->cursor->state->fb)
-- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
-
-- /* FIXME: Enable overlay planes */
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
--- /dev/null
+From 8848465a8f8934a06891823815c3176e394f5f1c Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 3 May 2019 13:58:03 +0100
+Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan
+ support.
+
+The overscan support was required for the old mailbox API
+in order to match up the cursor and frame buffer planes.
+With the newer API directly talking to dispmanx there is no
+difference, therefore FKMS does not need to make any
+adjustments.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -235,7 +235,6 @@ struct vc4_crtc {
+ void __iomem *regs;
+
+ struct drm_pending_vblank_event *event;
+- u32 overscan[4];
+ bool vblank_enabled;
+ u32 display_number;
+ u32 display_type;
+@@ -471,11 +470,6 @@ static void vc4_plane_atomic_update(stru
+ break;
+ }
+
+- if (vc4_crtc) {
+- mb->plane.dst_x += vc4_crtc->overscan[0];
+- mb->plane.dst_y += vc4_crtc->overscan[1];
+- }
+-
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
+ plane->base.id, plane->name,
+ mb->plane.width,
+@@ -1230,15 +1224,6 @@ static int vc4_fkms_create_screen(struct
+ goto err_destroy_encoder;
+ }
+
+- ret = rpi_firmware_property(vc4->firmware,
+- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
+- &vc4_crtc->overscan,
+- sizeof(vc4_crtc->overscan));
+- if (ret) {
+- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]);
+- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
+- }
+-
+ *ret_crtc = vc4_crtc;
+
+ return 0;
+++ /dev/null
-From 9185a16ce8804d35339402c6aec38a528cc2c7a1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 10 Apr 2019 17:43:57 +0100
-Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking
- doublescan modes
-
-Implement vc4_crtc_mode_valid so that it blocks doublescan modes
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -627,7 +627,17 @@ static void vc4_crtc_enable(struct drm_c
- vc4_plane_set_blank(plane, plane->state->visible);
- }
-
-+static enum drm_mode_status
-+vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
-+{
-+ /* Do not allow doublescan modes from user space */
-+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
-+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
-+ crtc->base.id);
-+ return MODE_NO_DBLESCAN;
-+ }
-
-+ return MODE_OK;
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
-@@ -737,10 +747,11 @@ static const struct drm_crtc_funcs vc4_c
-
- static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
- .mode_set_nofb = vc4_crtc_mode_set_nofb,
-- .atomic_disable = vc4_crtc_disable,
-- .atomic_enable = vc4_crtc_enable,
-+ .mode_valid = vc4_crtc_mode_valid,
- .atomic_check = vc4_crtc_atomic_check,
- .atomic_flush = vc4_crtc_atomic_flush,
-+ .atomic_enable = vc4_crtc_enable,
-+ .atomic_disable = vc4_crtc_disable,
- };
-
- static const struct of_device_id vc4_firmware_kms_dt_match[] = {
--- /dev/null
+From 0a93d1777bdd640a717a019ab53ab5c231dfa875 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 7 May 2019 12:13:34 +0100
+Subject: [PATCH] drm: vc4: Log flags in fkms mode set
+
+The flags contain info such as limited/full range RGB, aspect
+ratio, and a fwe other useful things.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -687,12 +687,13 @@ static void vc4_crtc_mode_set_nofb(struc
+ return;
+ }
+
+- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
+ vc4_crtc->display_number, mode->name, mode->clock,
+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hskew, mode->vdisplay,
+ mode->vsync_start, mode->vsync_end, mode->vtotal,
+- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
++ mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+ mb.timings.video_id_code = frame.avi.video_code;
+++ /dev/null
-From 11801b1f71144478ab6c19a4c309667d340cb9e2 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Mon, 29 Apr 2019 18:45:00 +0100
-Subject: [PATCH] drm: vc4: Increase max_width/height to 7680.
-
-There are some limits still being investigated that stop
-us going up to 8192, but 7680 is sufficient for dual 4k
-displays.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 4096;
-- dev->mode_config.max_height = 4096;
-+ dev->mode_config.max_width = 7680;
-+ dev->mode_config.max_height = 7680;
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
--- /dev/null
+From b0f9ee06c9e611592715f9d9d31170d55d2aeded Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 16 May 2019 17:49:42 +0100
+Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support
+
+The mode was incorrectly listed as interlaced, which was then
+rejected.
+Correct this and FKMS works with the DSI display.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1005,7 +1005,7 @@ static const struct drm_display_mode lcd
+ 25979400 / 1000,
+ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
+ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
+- DRM_MODE_FLAG_INTERLACE)
++ 0)
+ };
+
+ static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
+++ /dev/null
-From 52add140c76c0a211ab340ced8e7e1ea8bef9c79 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 9 Apr 2019 18:23:41 +0100
-Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports
- mode setting
-
-This extends FKMS to read the EDID from the display, and support
-requesting a particular mode via KMS.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++---
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +
- 2 files changed, 302 insertions(+), 34 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -91,11 +91,60 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
--struct mailbox_get_width_height {
-+struct mailbox_get_edid {
- struct rpi_firmware_property_tag_header tag1;
-- u32 display;
-- struct rpi_firmware_property_tag_header tag2;
-- u32 wh[2];
-+ u32 block;
-+ u32 display_number;
-+ u8 edid[128];
-+};
-+
-+struct set_timings {
-+ u8 display;
-+ u8 padding;
-+ u16 video_id_code;
-+
-+ u32 clock; /* in kHz */
-+
-+ u16 hdisplay;
-+ u16 hsync_start;
-+
-+ u16 hsync_end;
-+ u16 htotal;
-+
-+ u16 hskew;
-+ u16 vdisplay;
-+
-+ u16 vsync_start;
-+ u16 vsync_end;
-+
-+ u16 vtotal;
-+ u16 vscan;
-+
-+ u16 vrefresh;
-+ u16 padding2;
-+
-+ u32 flags;
-+#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
-+#define TIMINGS_FLAGS_H_SYNC_NEG 0
-+#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
-+#define TIMINGS_FLAGS_V_SYNC_NEG 0
-+
-+#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
-+#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
-+#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
-+#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
-+#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
-+#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
-+
-+/* Limited range RGB flag. Not set corresponds to full range. */
-+#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
-+/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
-+#define TIMINGS_FLAGS_DVI BIT(9)
-+};
-+
-+struct mailbox_set_mode {
-+ struct rpi_firmware_property_tag_header tag1;
-+ struct set_timings timings;
- };
-
- static const struct vc_image_format {
-@@ -189,6 +238,7 @@ struct vc4_crtc {
- u32 overscan[4];
- bool vblank_enabled;
- u32 display_number;
-+ u32 display_type;
- };
-
- static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
-@@ -198,6 +248,8 @@ static inline struct vc4_crtc *to_vc4_cr
-
- struct vc4_fkms_encoder {
- struct drm_encoder base;
-+ bool hdmi_monitor;
-+ bool rgb_range_selectable;
- };
-
- static inline struct vc4_fkms_encoder *
-@@ -215,7 +267,9 @@ struct vc4_fkms_connector {
- * hook.
- */
- struct drm_encoder *encoder;
-- u32 display_idx;
-+ struct vc4_dev *vc4_dev;
-+ u32 display_number;
-+ u32 display_type;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -224,6 +278,26 @@ to_vc4_fkms_connector(struct drm_connect
- return container_of(connector, struct vc4_fkms_connector, base);
- }
-
-+static u32 vc4_get_display_type(u32 display_number)
-+{
-+ const u32 display_types[] = {
-+ /* The firmware display (DispmanX) IDs map to specific types in
-+ * a fixed manner.
-+ */
-+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
-+ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
-+ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
-+ DRM_MODE_ENCODER_TVDAC, /* VEC */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_TV */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
-+ DRM_MODE_ENCODER_TMDS, /* HDMI1 */
-+ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
-+ };
-+ return display_number > ARRAY_SIZE(display_types) - 1 ?
-+ DRM_MODE_ENCODER_NONE : display_types[display_number];
-+}
-+
- /* Firmware's structure for making an FB mbox call. */
- struct fbinfo_s {
- u32 xres, yres, xres_virtual, yres_virtual;
-@@ -258,10 +332,15 @@ static int vc4_plane_set_blank(struct dr
- .plane_id = vc4_plane->mb.plane.plane_id,
- }
- };
-+ static const char * const plane_types[] = {
-+ "overlay",
-+ "primary",
-+ "cursor"
-+ };
- int ret;
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
-- plane->base.id, plane->name,
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
-+ plane->base.id, plane->name, plane_types[plane->type],
- blank ? "blank" : "unblank");
-
- if (blank)
-@@ -595,13 +674,102 @@ fail:
-
- static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
- {
-- /* Everyting is handled in the planes. */
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
-+ struct vc4_fkms_encoder *vc4_encoder =
-+ to_vc4_fkms_encoder(vc4_crtc->encoder);
-+ struct mailbox_set_mode mb = {
-+ .tag1 = { RPI_FIRMWARE_SET_TIMING,
-+ sizeof(struct set_timings), 0},
-+ };
-+ union hdmi_infoframe frame;
-+ int ret;
-+
-+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
-+ if (ret < 0) {
-+ DRM_ERROR("couldn't fill AVI infoframe\n");
-+ return;
-+ }
-+
-+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
-+ vc4_crtc->display_number, mode->name, mode->clock,
-+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
-+ mode->htotal, mode->hskew, mode->vdisplay,
-+ mode->vsync_start, mode->vsync_end, mode->vtotal,
-+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
-+ mb.timings.display = vc4_crtc->display_number;
-+
-+ mb.timings.video_id_code = frame.avi.video_code;
-+
-+ mb.timings.clock = mode->clock;
-+ mb.timings.hdisplay = mode->hdisplay;
-+ mb.timings.hsync_start = mode->hsync_start;
-+ mb.timings.hsync_end = mode->hsync_end;
-+ mb.timings.htotal = mode->htotal;
-+ mb.timings.hskew = mode->hskew;
-+ mb.timings.vdisplay = mode->vdisplay;
-+ mb.timings.vsync_start = mode->vsync_start;
-+ mb.timings.vsync_end = mode->vsync_end;
-+ mb.timings.vtotal = mode->vtotal;
-+ mb.timings.vscan = mode->vscan;
-+ mb.timings.vrefresh = 0;
-+ mb.timings.flags = 0;
-+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-+ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
-+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-+ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
-+
-+ switch (frame.avi.picture_aspect) {
-+ default:
-+ case HDMI_PICTURE_ASPECT_NONE:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
-+ break;
-+ case HDMI_PICTURE_ASPECT_4_3:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
-+ break;
-+ case HDMI_PICTURE_ASPECT_16_9:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
-+ break;
-+ case HDMI_PICTURE_ASPECT_64_27:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
-+ break;
-+ case HDMI_PICTURE_ASPECT_256_135:
-+ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
-+ break;
-+ }
-+
-+ if (!vc4_encoder->hdmi_monitor)
-+ mb.timings.flags |= TIMINGS_FLAGS_DVI;
-+ else if (drm_default_rgb_quant_range(mode) ==
-+ HDMI_QUANTIZATION_RANGE_LIMITED)
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+
-+ /*
-+ FIXME: To implement
-+ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
-+ case DRM_MODE_FLAG_3D_NONE:
-+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
-+ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
-+ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
-+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
-+ case DRM_MODE_FLAG_3D_L_DEPTH:
-+ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
-+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
-+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
-+ }
-+ */
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
- }
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
- struct drm_plane *plane;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
-+ crtc->base.id);
- drm_crtc_vblank_off(crtc);
-
- /* Always turn the planes off on CRTC disable. In DRM, planes
-@@ -619,6 +787,8 @@ static void vc4_crtc_enable(struct drm_c
- {
- struct drm_plane *plane;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
-+ crtc->base.id);
- drm_crtc_vblank_on(crtc);
-
- /* Unblank the planes (if they're supposed to be displayed). */
-@@ -637,12 +807,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
-+ * working.
-+ */
-+ if (mode->clock > 340000)
-+ return MODE_CLOCK_HIGH;
-+
- return MODE_OK;
- }
-
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
- {
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
-+ crtc->base.id);
- return 0;
- }
-
-@@ -652,6 +830,8 @@ static void vc4_crtc_atomic_flush(struct
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- struct drm_device *dev = crtc->dev;
-
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
-+ crtc->base.id);
- if (crtc->state->event) {
- unsigned long flags;
-
-@@ -719,6 +899,8 @@ static int vc4_fkms_enable_vblank(struct
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-
-+ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
-+ crtc->base.id);
- vc4_crtc->vblank_enabled = true;
-
- return 0;
-@@ -728,6 +910,8 @@ static void vc4_fkms_disable_vblank(stru
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-
-+ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
-+ crtc->base.id);
- vc4_crtc->vblank_enabled = false;
- }
-
-@@ -762,36 +946,92 @@ static const struct of_device_id vc4_fir
- static enum drm_connector_status
- vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
- {
-+ DRM_DEBUG_KMS("connector detect.\n");
- return connector_status_connected;
- }
-
--static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
-+static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
-+ size_t len)
- {
-- struct drm_device *dev = connector->dev;
- struct vc4_fkms_connector *fkms_connector =
-- to_vc4_fkms_connector(connector);
-- struct vc4_dev *vc4 = to_vc4_dev(dev);
-- struct drm_display_mode *mode;
-- struct mailbox_get_width_height wh = {
-- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
-- .display = fkms_connector->display_idx,
-- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
-- 8, 0, },
-+ (struct vc4_fkms_connector *)data;
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
-+ struct mailbox_get_edid mb = {
-+ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
-+ 128 + 8, 0 },
-+ .block = block,
-+ .display_number = fkms_connector->display_number,
- };
-- int ret;
-+ int ret = 0;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-+
-+ if (!ret)
-+ memcpy(buf, mb.edid, len);
-+
-+ return ret;
-+}
-+
-+static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct drm_encoder *encoder = fkms_connector->encoder;
-+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ int ret = 0;
-+ struct edid *edid;
-+
-+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-+ fkms_connector);
-+
-+ /* FIXME: Can we do CEC?
-+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-+ * if (!edid)
-+ * return -ENODEV;
-+ */
-+
-+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
-
-- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh));
-+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-+ vc4_encoder->rgb_range_selectable =
-+ drm_rgb_quant_range_selectable(edid);
-+ }
-+
-+ drm_connector_update_edid_property(connector, edid);
-+ ret = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
-+
-+ return ret;
-+}
-+
-+/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
-+static const struct drm_display_mode lcd_mode = {
-+ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
-+ 25979400 / 1000,
-+ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
-+ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
-+ DRM_MODE_FLAG_INTERLACE)
-+};
-+
-+static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
-+{
-+ //struct vc4_fkms_connector *fkms_connector =
-+ // to_vc4_fkms_connector(connector);
-+ //struct drm_encoder *encoder = fkms_connector->encoder;
-+ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct drm_display_mode *mode;
-+ //int ret = 0;
-
-- if (ret) {
-- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
-- ret, wh.wh[0], wh.wh[1]);
-- return 0;
-+ mode = drm_mode_duplicate(connector->dev,
-+ &lcd_mode);
-+ if (!mode) {
-+ DRM_ERROR("Failed to create a new display mode\n");
-+ return -ENOMEM;
- }
-
-- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */,
-- 0, 0, false);
- drm_mode_probed_add(connector, mode);
-
-+ /* We have one mode */
- return 1;
- }
-
-@@ -800,11 +1040,14 @@ vc4_fkms_connector_best_encoder(struct d
- {
- struct vc4_fkms_connector *fkms_connector =
- to_vc4_fkms_connector(connector);
-+ DRM_DEBUG_KMS("best_connector.\n");
- return fkms_connector->encoder;
- }
-
- static void vc4_fkms_connector_destroy(struct drm_connector *connector)
- {
-+ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
-+ connector->base.id);
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- }
-@@ -823,14 +1066,22 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
-+static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
-+ .get_modes = vc4_fkms_lcd_connector_get_modes,
-+ .best_encoder = vc4_fkms_connector_best_encoder,
-+};
-+
- static struct drm_connector *
- vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
-- u32 display_idx)
-+ u32 display_num)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-+ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
- int ret = 0;
-
-+ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
-+
- fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
- GFP_KERNEL);
- if (!fkms_connector) {
-@@ -840,11 +1091,21 @@ vc4_fkms_connector_init(struct drm_devic
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-- fkms_connector->display_idx = display_idx;
--
-- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-- DRM_MODE_CONNECTOR_HDMIA);
-- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
-+ fkms_connector->display_number = display_num;
-+ fkms_connector->display_type = vc4_get_display_type(display_num);
-+ fkms_connector->vc4_dev = vc4_dev;
-+
-+ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_DSI);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_lcd_conn_helper_funcs);
-+ } else {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_HDMIA);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_connector_helper_funcs);
-+ }
-
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-@@ -865,6 +1126,7 @@ vc4_fkms_connector_init(struct drm_devic
-
- static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_destroy\n");
- drm_encoder_cleanup(encoder);
- }
-
-@@ -874,10 +1136,12 @@ static const struct drm_encoder_funcs vc
-
- static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_enable\n");
- }
-
- static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
- {
-+ DRM_DEBUG_KMS("Encoder_disable\n");
- }
-
- static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
-@@ -909,6 +1173,7 @@ static int vc4_fkms_create_screen(struct
- crtc = &vc4_crtc->base;
-
- vc4_crtc->display_number = display_ref;
-+ vc4_crtc->display_type = vc4_get_display_type(display_ref);
-
- /* Blank the firmware provided framebuffer */
- rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
-@@ -952,13 +1217,14 @@ static int vc4_fkms_create_screen(struct
- return -ENOMEM;
- vc4_crtc->encoder = &vc4_encoder->base;
- vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
-+
- drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
-- DRM_MODE_ENCODER_TMDS, NULL);
-+ vc4_crtc->display_type, NULL);
- drm_encoder_helper_add(&vc4_encoder->base,
- &vc4_fkms_encoder_helper_funcs);
-
- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
-- display_idx);
-+ display_ref);
- if (IS_ERR(vc4_crtc->connector)) {
- ret = PTR_ERR(vc4_crtc->connector);
- goto err_destroy_encoder;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
- RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
- RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
-+ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
- RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
- RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
- RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
-@@ -149,6 +150,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
--- /dev/null
+From e8f126acd6da4f7d2e0df3c735fccf9971d95254 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 21 May 2019 11:50:00 +0100
+Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware
+
+For DPI and DSI displays query the firmware as to the configuration
+and add it as the only mode for DRM.
+
+In theory we can add plumbing for setting the DPI/DSI mode from
+KMS, but this is not being added at present as the support frameworks
+aren't present in the firmware.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 64 ++++++++++++++++------
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 2 files changed, 49 insertions(+), 16 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -248,7 +248,6 @@ static inline struct vc4_crtc *to_vc4_cr
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
+- bool rgb_range_selectable;
+ };
+
+ static inline struct vc4_fkms_encoder *
+@@ -283,7 +282,7 @@ static u32 vc4_get_display_type(u32 disp
+ /* The firmware display (DispmanX) IDs map to specific types in
+ * a fixed manner.
+ */
+- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
+ DRM_MODE_ENCODER_DSI, /* AUX_LCD */
+ DRM_MODE_ENCODER_TMDS, /* HDMI0 */
+ DRM_MODE_ENCODER_TVDAC, /* VEC */
+@@ -365,7 +364,6 @@ static void vc4_plane_atomic_update(stru
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+ struct mailbox_set_plane *mb = &vc4_plane->mb;
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+@@ -987,11 +985,6 @@ static int vc4_fkms_connector_get_modes(
+
+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+
+- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+- vc4_encoder->rgb_range_selectable =
+- drm_rgb_quant_range_selectable(edid);
+- }
+-
+ drm_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+@@ -999,7 +992,9 @@ static int vc4_fkms_connector_get_modes(
+ return ret;
+ }
+
+-/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
++/* This is the DSI panel resolution. Use this as a default should the firmware
++ * not respond to our request for the timings.
++ */
+ static const struct drm_display_mode lcd_mode = {
+ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ 25979400 / 1000,
+@@ -1010,15 +1005,52 @@ static const struct drm_display_mode lcd
+
+ static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
+ {
+- //struct vc4_fkms_connector *fkms_connector =
+- // to_vc4_fkms_connector(connector);
+- //struct drm_encoder *encoder = fkms_connector->encoder;
+- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+ struct drm_display_mode *mode;
+- //int ret = 0;
++ struct mailbox_set_mode mb = {
++ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
++ sizeof(struct set_timings), 0},
++ .timings = { .display = fkms_connector->display_number },
++ };
++ struct drm_display_mode fw_mode;
++ int ret = 0;
++
++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
++ if (!ret) {
++ /* Equivalent to DRM_MODE macro. */
++ memset(&fw_mode, 0, sizeof(fw_mode));
++ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
++ fw_mode.status = 0;
++ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
++ fw_mode.clock = mb.timings.clock;
++ fw_mode.hdisplay = mb.timings.hdisplay;
++ fw_mode.hsync_start = mb.timings.hsync_start;
++ fw_mode.hsync_end = mb.timings.hsync_end;
++ fw_mode.htotal = mb.timings.htotal;
++ fw_mode.hskew = 0;
++ fw_mode.vdisplay = mb.timings.vdisplay;
++ fw_mode.vsync_start = mb.timings.vsync_start;
++ fw_mode.vsync_end = mb.timings.vsync_end;
++ fw_mode.vtotal = mb.timings.vtotal;
++ fw_mode.vscan = mb.timings.vscan;
++ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++
++ mode = drm_mode_duplicate(connector->dev,
++ &fw_mode);
++ } else {
++ mode = drm_mode_duplicate(connector->dev,
++ &lcd_mode);
++ }
+
+- mode = drm_mode_duplicate(connector->dev,
+- &lcd_mode);
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+ return -ENOMEM;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -150,6 +150,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
++ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+++ /dev/null
-From 8848465a8f8934a06891823815c3176e394f5f1c Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 3 May 2019 13:58:03 +0100
-Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan
- support.
-
-The overscan support was required for the old mailbox API
-in order to match up the cursor and frame buffer planes.
-With the newer API directly talking to dispmanx there is no
-difference, therefore FKMS does not need to make any
-adjustments.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 ---------------
- 1 file changed, 15 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -235,7 +235,6 @@ struct vc4_crtc {
- void __iomem *regs;
-
- struct drm_pending_vblank_event *event;
-- u32 overscan[4];
- bool vblank_enabled;
- u32 display_number;
- u32 display_type;
-@@ -471,11 +470,6 @@ static void vc4_plane_atomic_update(stru
- break;
- }
-
-- if (vc4_crtc) {
-- mb->plane.dst_x += vc4_crtc->overscan[0];
-- mb->plane.dst_y += vc4_crtc->overscan[1];
-- }
--
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
- plane->base.id, plane->name,
- mb->plane.width,
-@@ -1230,15 +1224,6 @@ static int vc4_fkms_create_screen(struct
- goto err_destroy_encoder;
- }
-
-- ret = rpi_firmware_property(vc4->firmware,
-- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN,
-- &vc4_crtc->overscan,
-- sizeof(vc4_crtc->overscan));
-- if (ret) {
-- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]);
-- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
-- }
--
- *ret_crtc = vc4_crtc;
-
- return 0;
--- /dev/null
+From 1fbbd377bd1c6b4e3342d03091f19089ccb7fcbe Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 28 May 2019 13:56:06 +0100
+Subject: [PATCH] drm: vc4: handle the case where there are no
+ available displays
+
+It's reasonable for the firmware to return zero as the number of
+attached displays. Handle this case as otherwise drm thinks that
+the DSI panel is attached, which is nonsense.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++-----------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1303,13 +1303,13 @@ static int vc4_fkms_bind(struct device *
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
+ &num_displays, sizeof(u32));
+
+- /* If we fail to get the number of displays, or it returns 0, then
++ /* If we fail to get the number of displays, then
+ * assume old firmware that doesn't have the mailbox call, so just
+ * set one display
+ */
+- if (ret || num_displays == 0) {
++ if (ret) {
+ num_displays = 1;
+- DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
++ DRM_WARN("Unable to determine number of displays - assuming 1\n");
+ ret = 0;
+ }
+
+@@ -1338,17 +1338,21 @@ static int vc4_fkms_bind(struct device *
+ display_num);
+ }
+
+- /* Map the SMI interrupt reg */
+- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
+- if (IS_ERR(crtc_list[0]->regs))
+- DRM_ERROR("Oh dear, failed to map registers\n");
+-
+- writel(0, crtc_list[0]->regs + SMICS);
+- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
+- crtc_list);
+- if (ret)
+- DRM_ERROR("Oh dear, failed to register IRQ\n");
++ if (num_displays > 0) {
++ /* Map the SMI interrupt reg */
++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
++ if (IS_ERR(crtc_list[0]->regs))
++ DRM_ERROR("Oh dear, failed to map registers\n");
++
++ writel(0, crtc_list[0]->regs + SMICS);
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
++ vc4_crtc_irq_handler, 0,
++ "vc4 firmware kms", crtc_list);
++ if (ret)
++ DRM_ERROR("Oh dear, failed to register IRQ\n");
++ } else {
++ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
++ }
+
+ platform_set_drvdata(pdev, crtc_list);
+
+++ /dev/null
-From 0a93d1777bdd640a717a019ab53ab5c231dfa875 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 7 May 2019 12:13:34 +0100
-Subject: [PATCH] drm: vc4: Log flags in fkms mode set
-
-The flags contain info such as limited/full range RGB, aspect
-ratio, and a fwe other useful things.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -687,12 +687,13 @@ static void vc4_crtc_mode_set_nofb(struc
- return;
- }
-
-- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n",
-+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
- vc4_crtc->display_number, mode->name, mode->clock,
- mode->hdisplay, mode->hsync_start, mode->hsync_end,
- mode->htotal, mode->hskew, mode->vdisplay,
- mode->vsync_start, mode->vsync_end, mode->vtotal,
-- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio);
-+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
-+ mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
- mb.timings.video_id_code = frame.avi.video_code;
--- /dev/null
+From 11a567f1e76ca017f1963027655454b56ab81875 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 24 May 2019 17:59:01 +0100
+Subject: [PATCH] drm/vc4: Support the VEC in FKMS
+
+Extends the DPI/DSI support to also report the VEC output
+which supports interlacing too.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -128,6 +128,7 @@ struct set_timings {
+ #define TIMINGS_FLAGS_H_SYNC_NEG 0
+ #define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
+ #define TIMINGS_FLAGS_V_SYNC_NEG 0
++#define TIMINGS_FLAGS_INTERLACE BIT(2)
+
+ #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
+ #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
+@@ -1043,6 +1044,12 @@ static int vc4_fkms_lcd_connector_get_mo
+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
++ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
++ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+
+ mode = drm_mode_duplicate(connector->dev,
+ &fw_mode);
+@@ -1127,17 +1134,24 @@ vc4_fkms_connector_init(struct drm_devic
+ DRM_MODE_CONNECTOR_DSI);
+ drm_connector_helper_add(connector,
+ &vc4_fkms_lcd_conn_helper_funcs);
++ connector->interlace_allowed = 0;
++ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
++ DRM_MODE_CONNECTOR_Composite);
++ drm_connector_helper_add(connector,
++ &vc4_fkms_lcd_conn_helper_funcs);
++ connector->interlace_allowed = 1;
+ } else {
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ drm_connector_helper_add(connector,
+ &vc4_fkms_connector_helper_funcs);
++ connector->interlace_allowed = 0;
+ }
+
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+
+- connector->interlace_allowed = 0;
+ connector->doublescan_allowed = 0;
+
+ drm_connector_attach_encoder(connector, encoder);
--- /dev/null
+From 06e4e4560800232b0e6628bebc605d234ef1c237 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 7 May 2019 15:00:02 +0100
+Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio
+
+Assignment was to the wrong structure.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -718,19 +718,19 @@ static void vc4_crtc_mode_set_nofb(struc
+ switch (frame.avi.picture_aspect) {
+ default:
+ case HDMI_PICTURE_ASPECT_NONE:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
+ break;
+ case HDMI_PICTURE_ASPECT_4_3:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
+ break;
+ case HDMI_PICTURE_ASPECT_16_9:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
+ break;
+ case HDMI_PICTURE_ASPECT_64_27:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
+ break;
+ case HDMI_PICTURE_ASPECT_256_135:
+- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
+ break;
+ }
+
+++ /dev/null
-From b0f9ee06c9e611592715f9d9d31170d55d2aeded Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 16 May 2019 17:49:42 +0100
-Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support
-
-The mode was incorrectly listed as interlaced, which was then
-rejected.
-Correct this and FKMS works with the DSI display.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1005,7 +1005,7 @@ static const struct drm_display_mode lcd
- 25979400 / 1000,
- 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
- 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
-- DRM_MODE_FLAG_INTERLACE)
-+ 0)
- };
-
- static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
--- /dev/null
+From 46c612d0248ba6e0c8c236cf1839b0c2ccecee01 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 29 May 2019 15:44:11 +0100
+Subject: [PATCH] drm/vc4: Correct SAND support for FKMS.
+
+It was accepting NV21 which doesn't map through, but
+also wasn't advertising the modifier so nothing would know
+to request it.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -546,7 +546,6 @@ static bool vc4_fkms_format_mod_supporte
+ return false;
+ }
+ case DRM_FORMAT_NV12:
+- case DRM_FORMAT_NV21:
+ switch (fourcc_mod_broadcom_mod(modifier)) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+@@ -554,6 +553,7 @@ static bool vc4_fkms_format_mod_supporte
+ default:
+ return false;
+ }
++ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_YUV422:
+@@ -600,6 +600,7 @@ static struct drm_plane *vc4_fkms_plane_
+ * would prefer to scan out linear (less bus traffic).
+ */
+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
++ DRM_FORMAT_MOD_BROADCOM_SAND128,
+ DRM_FORMAT_MOD_INVALID,
+ };
+ int i;
+++ /dev/null
-From e8f126acd6da4f7d2e0df3c735fccf9971d95254 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 21 May 2019 11:50:00 +0100
-Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware
-
-For DPI and DSI displays query the firmware as to the configuration
-and add it as the only mode for DRM.
-
-In theory we can add plumbing for setting the DPI/DSI mode from
-KMS, but this is not being added at present as the support frameworks
-aren't present in the firmware.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 64 ++++++++++++++++------
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 2 files changed, 49 insertions(+), 16 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -248,7 +248,6 @@ static inline struct vc4_crtc *to_vc4_cr
- struct vc4_fkms_encoder {
- struct drm_encoder base;
- bool hdmi_monitor;
-- bool rgb_range_selectable;
- };
-
- static inline struct vc4_fkms_encoder *
-@@ -283,7 +282,7 @@ static u32 vc4_get_display_type(u32 disp
- /* The firmware display (DispmanX) IDs map to specific types in
- * a fixed manner.
- */
-- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */
-+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
- DRM_MODE_ENCODER_DSI, /* AUX_LCD */
- DRM_MODE_ENCODER_TMDS, /* HDMI0 */
- DRM_MODE_ENCODER_TVDAC, /* VEC */
-@@ -365,7 +364,6 @@ static void vc4_plane_atomic_update(stru
- vc4_get_vc_image_fmt(drm_fmt->format);
- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
- struct mailbox_set_plane *mb = &vc4_plane->mb;
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-@@ -987,11 +985,6 @@ static int vc4_fkms_connector_get_modes(
-
- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
-
-- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
-- vc4_encoder->rgb_range_selectable =
-- drm_rgb_quant_range_selectable(edid);
-- }
--
- drm_connector_update_edid_property(connector, edid);
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
-@@ -999,7 +992,9 @@ static int vc4_fkms_connector_get_modes(
- return ret;
- }
-
--/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */
-+/* This is the DSI panel resolution. Use this as a default should the firmware
-+ * not respond to our request for the timings.
-+ */
- static const struct drm_display_mode lcd_mode = {
- DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
- 25979400 / 1000,
-@@ -1010,15 +1005,52 @@ static const struct drm_display_mode lcd
-
- static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
- {
-- //struct vc4_fkms_connector *fkms_connector =
-- // to_vc4_fkms_connector(connector);
-- //struct drm_encoder *encoder = fkms_connector->encoder;
-- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
- struct drm_display_mode *mode;
-- //int ret = 0;
-+ struct mailbox_set_mode mb = {
-+ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
-+ sizeof(struct set_timings), 0},
-+ .timings = { .display = fkms_connector->display_number },
-+ };
-+ struct drm_display_mode fw_mode;
-+ int ret = 0;
-+
-+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-+ if (!ret) {
-+ /* Equivalent to DRM_MODE macro. */
-+ memset(&fw_mode, 0, sizeof(fw_mode));
-+ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
-+ fw_mode.status = 0;
-+ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-+ fw_mode.clock = mb.timings.clock;
-+ fw_mode.hdisplay = mb.timings.hdisplay;
-+ fw_mode.hsync_start = mb.timings.hsync_start;
-+ fw_mode.hsync_end = mb.timings.hsync_end;
-+ fw_mode.htotal = mb.timings.htotal;
-+ fw_mode.hskew = 0;
-+ fw_mode.vdisplay = mb.timings.vdisplay;
-+ fw_mode.vsync_start = mb.timings.vsync_start;
-+ fw_mode.vsync_end = mb.timings.vsync_end;
-+ fw_mode.vtotal = mb.timings.vtotal;
-+ fw_mode.vscan = mb.timings.vscan;
-+ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+
-+ mode = drm_mode_duplicate(connector->dev,
-+ &fw_mode);
-+ } else {
-+ mode = drm_mode_duplicate(connector->dev,
-+ &lcd_mode);
-+ }
-
-- mode = drm_mode_duplicate(connector->dev,
-- &lcd_mode);
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
- return -ENOMEM;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -150,6 +150,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
-
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
-+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
--- /dev/null
+From 1a8e3d8e883b9f9b18dff052a9294d4354994992 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 30 May 2019 13:56:15 +0100
+Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits
+
+The VPU has configured clocks for 4k (or not) via config.txt,
+and will limit the choice of video modes based on that.
+Make fkms query it for these limits too to avoid selecting modes
+that can not be handled by the current clock setup.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_drv.h | 1 +
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 1 +
+ 3 files changed, 50 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_drv.h
++++ b/drivers/gpu/drm/vc4/vc4_drv.h
+@@ -81,6 +81,7 @@ struct vc4_dev {
+ struct vc4_dsi *dsi1;
+ struct vc4_vec *vec;
+ struct vc4_txp *txp;
++ struct vc4_fkms *fkms;
+
+ struct vc4_hang_state *hang_state;
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -32,6 +32,14 @@
+ #include "vc_image_types.h"
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
++struct get_display_cfg {
++ u32 max_pixel_clock[2]; //Max pixel clock for each display
++};
++
++struct vc4_fkms {
++ struct get_display_cfg cfg;
++};
++
+ #define PLANES_PER_CRTC 3
+
+ struct set_plane {
+@@ -795,6 +803,11 @@ static void vc4_crtc_enable(struct drm_c
+ static enum drm_mode_status
+ vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
+ {
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_device *dev = crtc->dev;
++ struct vc4_dev *vc4 = to_vc4_dev(dev);
++ struct vc4_fkms *fkms = vc4->fkms;
++
+ /* Do not allow doublescan modes from user space */
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
+@@ -802,6 +815,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Limit the pixel clock based on the HDMI clock limits from the
++ * firmware
++ */
++ switch (vc4_crtc->display_number) {
++ case 2: /* HDMI0 */
++ if (fkms->cfg.max_pixel_clock[0] &&
++ mode->clock > fkms->cfg.max_pixel_clock[0])
++ return MODE_CLOCK_HIGH;
++ break;
++ case 7: /* HDMI1 */
++ if (fkms->cfg.max_pixel_clock[1] &&
++ mode->clock > fkms->cfg.max_pixel_clock[1])
++ return MODE_CLOCK_HIGH;
++ break;
++ }
++
+ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
+ * working.
+ */
+@@ -1295,11 +1324,16 @@ static int vc4_fkms_bind(struct device *
+ struct device_node *firmware_node;
+ struct vc4_crtc **crtc_list;
+ u32 num_displays, display_num;
++ struct vc4_fkms *fkms;
+ int ret;
+ u32 display_id;
+
+ vc4->firmware_kms = true;
+
++ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
++ if (!fkms)
++ return -ENOMEM;
++
+ /* firmware kms doesn't have precise a scanoutpos implementation, so
+ * we can't do the precise vblank timestamp mode.
+ */
+@@ -1328,6 +1362,18 @@ static int vc4_fkms_bind(struct device *
+ ret = 0;
+ }
+
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_GET_DISPLAY_CFG,
++ &fkms->cfg, sizeof(fkms->cfg));
++
++ if (ret)
++ return -EINVAL;
++ /* The firmware works in Hz. This will be compared against kHz, so div
++ * 1000 now rather than multiple times later.
++ */
++ fkms->cfg.max_pixel_clock[0] /= 1000;
++ fkms->cfg.max_pixel_clock[1] /= 1000;
++
+ /* Allocate a list, with space for a NULL on the end */
+ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
+ GFP_KERNEL);
+@@ -1369,6 +1415,8 @@ static int vc4_fkms_bind(struct device *
+ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
+ }
+
++ vc4->fkms = fkms;
++
+ platform_set_drvdata(pdev, crtc_list);
+
+ return 0;
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -152,6 +152,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
++ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+++ /dev/null
-From 1fbbd377bd1c6b4e3342d03091f19089ccb7fcbe Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 28 May 2019 13:56:06 +0100
-Subject: [PATCH] drm: vc4: handle the case where there are no
- available displays
-
-It's reasonable for the firmware to return zero as the number of
-attached displays. Handle this case as otherwise drm thinks that
-the DSI panel is attached, which is nonsense.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++-----------
- 1 file changed, 18 insertions(+), 14 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1303,13 +1303,13 @@ static int vc4_fkms_bind(struct device *
- RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
- &num_displays, sizeof(u32));
-
-- /* If we fail to get the number of displays, or it returns 0, then
-+ /* If we fail to get the number of displays, then
- * assume old firmware that doesn't have the mailbox call, so just
- * set one display
- */
-- if (ret || num_displays == 0) {
-+ if (ret) {
- num_displays = 1;
-- DRM_WARN("Unable to determine number of displays's. Assuming 1\n");
-+ DRM_WARN("Unable to determine number of displays - assuming 1\n");
- ret = 0;
- }
-
-@@ -1338,17 +1338,21 @@ static int vc4_fkms_bind(struct device *
- display_num);
- }
-
-- /* Map the SMI interrupt reg */
-- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-- if (IS_ERR(crtc_list[0]->regs))
-- DRM_ERROR("Oh dear, failed to map registers\n");
--
-- writel(0, crtc_list[0]->regs + SMICS);
-- ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-- vc4_crtc_irq_handler, 0, "vc4 firmware kms",
-- crtc_list);
-- if (ret)
-- DRM_ERROR("Oh dear, failed to register IRQ\n");
-+ if (num_displays > 0) {
-+ /* Map the SMI interrupt reg */
-+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
-+ if (IS_ERR(crtc_list[0]->regs))
-+ DRM_ERROR("Oh dear, failed to map registers\n");
-+
-+ writel(0, crtc_list[0]->regs + SMICS);
-+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
-+ vc4_crtc_irq_handler, 0,
-+ "vc4 firmware kms", crtc_list);
-+ if (ret)
-+ DRM_ERROR("Oh dear, failed to register IRQ\n");
-+ } else {
-+ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
-+ }
-
- platform_set_drvdata(pdev, crtc_list);
-
--- /dev/null
+From 2767f778820bd7392688512ec2996943a586db6e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 30 May 2019 15:55:15 +0100
+Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on
+ being Pi4
+
+The max resolution had been increased from 2048 to 7680 for all
+platforms. This code is common with Pi0-3 which have a max render
+target for GL of 2048, therefore the increased resolution has to
+be conditional on the platform.
+Switch based on whether the bcm2835-v3d node is found, as that is
+not present on Pi4. (There is a potential configuration on Pi0-3
+with no v3d, but this is very unlikely).
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_kms.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -18,6 +18,7 @@
+ #include <drm/drm_plane_helper.h>
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_vblank.h>
++#include <drm/drm_drv.h>
+
+ #include "vc4_drv.h"
+ #include "vc4_regs.h"
+@@ -536,8 +537,14 @@ int vc4_kms_load(struct drm_device *dev)
+ return ret;
+ }
+
+- dev->mode_config.max_width = 7680;
+- dev->mode_config.max_height = 7680;
++ if (!drm_core_check_feature(dev, DRIVER_RENDER)) {
++ /* No V3D as part of vc4. Assume this is Pi4. */
++ dev->mode_config.max_width = 7680;
++ dev->mode_config.max_height = 7680;
++ } else {
++ dev->mode_config.max_width = 2048;
++ dev->mode_config.max_height = 2048;
++ }
+ dev->mode_config.funcs = &vc4_mode_funcs;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 11a567f1e76ca017f1963027655454b56ab81875 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 24 May 2019 17:59:01 +0100
-Subject: [PATCH] drm/vc4: Support the VEC in FKMS
-
-Extends the DPI/DSI support to also report the VEC output
-which supports interlacing too.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++-
- 1 file changed, 15 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -128,6 +128,7 @@ struct set_timings {
- #define TIMINGS_FLAGS_H_SYNC_NEG 0
- #define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
- #define TIMINGS_FLAGS_V_SYNC_NEG 0
-+#define TIMINGS_FLAGS_INTERLACE BIT(2)
-
- #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
- #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
-@@ -1043,6 +1044,12 @@ static int vc4_fkms_lcd_connector_get_mo
- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
- else
- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-+ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
-+ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
-
- mode = drm_mode_duplicate(connector->dev,
- &fw_mode);
-@@ -1127,17 +1134,24 @@ vc4_fkms_connector_init(struct drm_devic
- DRM_MODE_CONNECTOR_DSI);
- drm_connector_helper_add(connector,
- &vc4_fkms_lcd_conn_helper_funcs);
-+ connector->interlace_allowed = 0;
-+ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
-+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
-+ DRM_MODE_CONNECTOR_Composite);
-+ drm_connector_helper_add(connector,
-+ &vc4_fkms_lcd_conn_helper_funcs);
-+ connector->interlace_allowed = 1;
- } else {
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
- drm_connector_helper_add(connector,
- &vc4_fkms_connector_helper_funcs);
-+ connector->interlace_allowed = 0;
- }
-
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-
-- connector->interlace_allowed = 0;
- connector->doublescan_allowed = 0;
-
- drm_connector_attach_encoder(connector, encoder);
--- /dev/null
+From 82551f68e9f9dea1f22d9cdfdf361bf054f6900c Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 7 Jun 2019 11:31:21 +0100
+Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS.
+
+The wrong vc_image formats were being checked for in the switch
+statement. Correct these.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -460,10 +460,10 @@ static void vc4_plane_atomic_update(stru
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ switch (mb->plane.vc_image_type) {
+- case VC_IMAGE_RGBX32:
++ case VC_IMAGE_XRGB8888:
+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
+ break;
+- case VC_IMAGE_RGBA32:
++ case VC_IMAGE_ARGB8888:
+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
+ break;
+ case VC_IMAGE_RGB565:
+++ /dev/null
-From 06e4e4560800232b0e6628bebc605d234ef1c237 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 7 May 2019 15:00:02 +0100
-Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio
-
-Assignment was to the wrong structure.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -718,19 +718,19 @@ static void vc4_crtc_mode_set_nofb(struc
- switch (frame.avi.picture_aspect) {
- default:
- case HDMI_PICTURE_ASPECT_NONE:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
- break;
- case HDMI_PICTURE_ASPECT_4_3:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
- break;
- case HDMI_PICTURE_ASPECT_16_9:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
- break;
- case HDMI_PICTURE_ASPECT_64_27:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
- break;
- case HDMI_PICTURE_ASPECT_256_135:
-- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135;
-+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
- break;
- }
-
+++ /dev/null
-From 46c612d0248ba6e0c8c236cf1839b0c2ccecee01 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 29 May 2019 15:44:11 +0100
-Subject: [PATCH] drm/vc4: Correct SAND support for FKMS.
-
-It was accepting NV21 which doesn't map through, but
-also wasn't advertising the modifier so nothing would know
-to request it.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -546,7 +546,6 @@ static bool vc4_fkms_format_mod_supporte
- return false;
- }
- case DRM_FORMAT_NV12:
-- case DRM_FORMAT_NV21:
- switch (fourcc_mod_broadcom_mod(modifier)) {
- case DRM_FORMAT_MOD_LINEAR:
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
-@@ -554,6 +553,7 @@ static bool vc4_fkms_format_mod_supporte
- default:
- return false;
- }
-+ case DRM_FORMAT_NV21:
- case DRM_FORMAT_RGB888:
- case DRM_FORMAT_BGR888:
- case DRM_FORMAT_YUV422:
-@@ -600,6 +600,7 @@ static struct drm_plane *vc4_fkms_plane_
- * would prefer to scan out linear (less bus traffic).
- */
- DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
-+ DRM_FORMAT_MOD_BROADCOM_SAND128,
- DRM_FORMAT_MOD_INVALID,
- };
- int i;
--- /dev/null
+From 44c7ff7864d931759efd307ef641f522c0a5bbdb Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Mon, 10 Jun 2019 16:32:51 +0100
+Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now
+ scrambling issues resolved
+
+Firmware TMDS scrambling is now being correctly configured, so
+we can use it.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -831,12 +831,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ break;
+ }
+
+- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
+- * working.
+- */
+- if (mode->clock > 340000)
+- return MODE_CLOCK_HIGH;
+-
+ return MODE_OK;
+ }
+
--- /dev/null
+From e399911ab20b650a031d883554180463804ac3f7 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 4 Jun 2019 12:14:30 +0100
+Subject: [PATCH] drm: vc4: Add status of which display is updated
+ through vblank
+
+Previously multiple displays were slaved off the same SMI
+interrupt, triggered by HVS channel 1 (HDMI0).
+This doesn't work if you only have a DPI or DSI screen (HVS channel
+0), and gives slightly erroneous results with dual HDMI as the
+events for HDMI1 are incorrect.
+
+Use SMIDSW0 and SMIDSW1 registers to denote which display has
+triggered the vblank.
+Handling should be backwards compatible with older firmware.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++----
+ 1 file changed, 36 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -233,8 +233,13 @@ static const struct vc_image_format *vc4
+ * hardware, which has only this one register.
+ */
+ #define SMICS 0x0
++#define SMIDSW0 0x14
++#define SMIDSW1 0x1C
+ #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
+
++/* Flag to denote that the firmware is giving multiple display callbacks */
++#define SMI_NEW 0xabcd0000
++
+ #define vc4_crtc vc4_kms_crtc
+ #define to_vc4_crtc to_vc4_kms_crtc
+ struct vc4_crtc {
+@@ -885,16 +890,42 @@ static irqreturn_t vc4_crtc_irq_handler(
+ int i;
+ u32 stat = readl(crtc_list[0]->regs + SMICS);
+ irqreturn_t ret = IRQ_NONE;
++ u32 chan;
+
+ if (stat & SMICS_INTERRUPTS) {
+ writel(0, crtc_list[0]->regs + SMICS);
+
+- for (i = 0; crtc_list[i]; i++) {
+- if (crtc_list[i]->vblank_enabled)
+- drm_crtc_handle_vblank(&crtc_list[i]->base);
+- vc4_crtc_handle_page_flip(crtc_list[i]);
+- ret = IRQ_HANDLED;
++ chan = readl(crtc_list[0]->regs + SMIDSW0);
++
++ if ((chan & 0xFFFF0000) != SMI_NEW) {
++ /* Older firmware. Treat the one interrupt as vblank/
++ * complete for all crtcs.
++ */
++ for (i = 0; crtc_list[i]; i++) {
++ if (crtc_list[i]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[i]->base);
++ vc4_crtc_handle_page_flip(crtc_list[i]);
++ }
++ } else {
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
++ if (crtc_list[0]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[0]->base);
++ vc4_crtc_handle_page_flip(crtc_list[0]);
++ }
++
++ /* Check for the secondary display too */
++ chan = readl(crtc_list[0]->regs + SMIDSW1);
++
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
++ if (crtc_list[1]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[1]->base);
++ vc4_crtc_handle_page_flip(crtc_list[1]);
++ }
+ }
++
++ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+++ /dev/null
-From 1a8e3d8e883b9f9b18dff052a9294d4354994992 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 30 May 2019 13:56:15 +0100
-Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits
-
-The VPU has configured clocks for 4k (or not) via config.txt,
-and will limit the choice of video modes based on that.
-Make fkms query it for these limits too to avoid selecting modes
-that can not be handled by the current clock setup.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_drv.h | 1 +
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 1 +
- 3 files changed, 50 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -81,6 +81,7 @@ struct vc4_dev {
- struct vc4_dsi *dsi1;
- struct vc4_vec *vec;
- struct vc4_txp *txp;
-+ struct vc4_fkms *fkms;
-
- struct vc4_hang_state *hang_state;
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -32,6 +32,14 @@
- #include "vc_image_types.h"
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
-+struct get_display_cfg {
-+ u32 max_pixel_clock[2]; //Max pixel clock for each display
-+};
-+
-+struct vc4_fkms {
-+ struct get_display_cfg cfg;
-+};
-+
- #define PLANES_PER_CRTC 3
-
- struct set_plane {
-@@ -795,6 +803,11 @@ static void vc4_crtc_enable(struct drm_c
- static enum drm_mode_status
- vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
- {
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_device *dev = crtc->dev;
-+ struct vc4_dev *vc4 = to_vc4_dev(dev);
-+ struct vc4_fkms *fkms = vc4->fkms;
-+
- /* Do not allow doublescan modes from user space */
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
- DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
-@@ -802,6 +815,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Limit the pixel clock based on the HDMI clock limits from the
-+ * firmware
-+ */
-+ switch (vc4_crtc->display_number) {
-+ case 2: /* HDMI0 */
-+ if (fkms->cfg.max_pixel_clock[0] &&
-+ mode->clock > fkms->cfg.max_pixel_clock[0])
-+ return MODE_CLOCK_HIGH;
-+ break;
-+ case 7: /* HDMI1 */
-+ if (fkms->cfg.max_pixel_clock[1] &&
-+ mode->clock > fkms->cfg.max_pixel_clock[1])
-+ return MODE_CLOCK_HIGH;
-+ break;
-+ }
-+
- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
- * working.
- */
-@@ -1295,11 +1324,16 @@ static int vc4_fkms_bind(struct device *
- struct device_node *firmware_node;
- struct vc4_crtc **crtc_list;
- u32 num_displays, display_num;
-+ struct vc4_fkms *fkms;
- int ret;
- u32 display_id;
-
- vc4->firmware_kms = true;
-
-+ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
-+ if (!fkms)
-+ return -ENOMEM;
-+
- /* firmware kms doesn't have precise a scanoutpos implementation, so
- * we can't do the precise vblank timestamp mode.
- */
-@@ -1328,6 +1362,18 @@ static int vc4_fkms_bind(struct device *
- ret = 0;
- }
-
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_GET_DISPLAY_CFG,
-+ &fkms->cfg, sizeof(fkms->cfg));
-+
-+ if (ret)
-+ return -EINVAL;
-+ /* The firmware works in Hz. This will be compared against kHz, so div
-+ * 1000 now rather than multiple times later.
-+ */
-+ fkms->cfg.max_pixel_clock[0] /= 1000;
-+ fkms->cfg.max_pixel_clock[1] /= 1000;
-+
- /* Allocate a list, with space for a NULL on the end */
- crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
- GFP_KERNEL);
-@@ -1369,6 +1415,8 @@ static int vc4_fkms_bind(struct device *
- DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
- }
-
-+ vc4->fkms = fkms;
-+
- platform_set_drvdata(pdev, crtc_list);
-
- return 0;
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -152,6 +152,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_SET_PLANE = 0x00048015,
- RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
-+ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
-
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
--- /dev/null
+From aa6061c2db8adbe0e75890cfc6f56b800b9995df Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 12 Jun 2019 17:13:21 +0100
+Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for
+ SAND
+
+Incorrect masking was used in the switch for the modifier,
+therefore for SAND (which puts the column pitch in the
+modifier) it didn't match.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -462,7 +462,7 @@ static void vc4_plane_atomic_update(stru
+ }
+ mb->plane.planes[3] = 0;
+
+- switch (fb->modifier) {
++ switch (fourcc_mod_broadcom_mod(fb->modifier)) {
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ switch (mb->plane.vc_image_type) {
+ case VC_IMAGE_XRGB8888:
+@@ -478,6 +478,9 @@ static void vc4_plane_atomic_update(stru
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ /* Note that the column pitch is passed across in lines, not
++ * bytes.
++ */
+ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
+ break;
+ }
+++ /dev/null
-From 2767f778820bd7392688512ec2996943a586db6e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 30 May 2019 15:55:15 +0100
-Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on
- being Pi4
-
-The max resolution had been increased from 2048 to 7680 for all
-platforms. This code is common with Pi0-3 which have a max render
-target for GL of 2048, therefore the increased resolution has to
-be conditional on the platform.
-Switch based on whether the bcm2835-v3d node is found, as that is
-not present on Pi4. (There is a potential configuration on Pi0-3
-with no v3d, but this is very unlikely).
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_kms.c | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -18,6 +18,7 @@
- #include <drm/drm_plane_helper.h>
- #include <drm/drm_probe_helper.h>
- #include <drm/drm_vblank.h>
-+#include <drm/drm_drv.h>
-
- #include "vc4_drv.h"
- #include "vc4_regs.h"
-@@ -536,8 +537,14 @@ int vc4_kms_load(struct drm_device *dev)
- return ret;
- }
-
-- dev->mode_config.max_width = 7680;
-- dev->mode_config.max_height = 7680;
-+ if (!drm_core_check_feature(dev, DRIVER_RENDER)) {
-+ /* No V3D as part of vc4. Assume this is Pi4. */
-+ dev->mode_config.max_width = 7680;
-+ dev->mode_config.max_height = 7680;
-+ } else {
-+ dev->mode_config.max_width = 2048;
-+ dev->mode_config.max_height = 2048;
-+ }
- dev->mode_config.funcs = &vc4_mode_funcs;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.async_page_flip = true;
+++ /dev/null
-From 82551f68e9f9dea1f22d9cdfdf361bf054f6900c Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 7 Jun 2019 11:31:21 +0100
-Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS.
-
-The wrong vc_image formats were being checked for in the switch
-statement. Correct these.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -460,10 +460,10 @@ static void vc4_plane_atomic_update(stru
- switch (fb->modifier) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- switch (mb->plane.vc_image_type) {
-- case VC_IMAGE_RGBX32:
-+ case VC_IMAGE_XRGB8888:
- mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
- break;
-- case VC_IMAGE_RGBA32:
-+ case VC_IMAGE_ARGB8888:
- mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
- break;
- case VC_IMAGE_RGB565:
--- /dev/null
+From 9f9d67a11cfd6318d2bd1321090c0950242cfa25 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 18 Jun 2019 21:37:45 +0100
+Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz
+
+Selecting 1080p100 and 120 has very limited gain, but don't want
+to block VGA85 and similar.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -823,6 +823,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ return MODE_NO_DBLESCAN;
+ }
+
++ /* Disable refresh rates > 85Hz as limited gain from them */
++ if (drm_mode_vrefresh(mode) > 85)
++ return MODE_BAD_VVALUE;
++
+ /* Limit the pixel clock based on the HDMI clock limits from the
+ * firmware
+ */
--- /dev/null
+From cad68ea70d649cff90102022c5d161bf84e4ed16 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 19 Jul 2019 14:29:28 +0100
+Subject: [PATCH] drm/vc4: Ignore HVS unless initialised
+
+An upstream commit to report HVS underruns causes VC4 in firmware KMS
+mode to cross into the HVS side, where it crashes due to a NULL hvs
+pointer.
+
+Make the underrun masking conditional on the hvs pointer being
+initialised.
+
+Fixes: 531a1b622da9 ("drm/vc4: Report HVS underrun errors")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++-
+ drivers/gpu/drm/vc4/vc4_kms.c | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_crtc.c
++++ b/drivers/gpu/drm/vc4/vc4_crtc.c
+@@ -801,7 +801,8 @@ static void vc4_crtc_handle_page_flip(st
+ * the CRTC and encoder already reconfigured, leading to
+ * underruns. This can be seen when reconfiguring the CRTC.
+ */
+- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
++ if (vc4->hvs)
++ vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+--- a/drivers/gpu/drm/vc4/vc4_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_kms.c
+@@ -156,7 +156,7 @@ vc4_atomic_complete_commit(struct drm_at
+ struct vc4_crtc *vc4_crtc;
+ int i;
+
+- for (i = 0; i < dev->mode_config.num_crtc; i++) {
++ for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) {
+ if (!state->crtcs[i].ptr || !state->crtcs[i].commit)
+ continue;
+
+++ /dev/null
-From 44c7ff7864d931759efd307ef641f522c0a5bbdb Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Mon, 10 Jun 2019 16:32:51 +0100
-Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now
- scrambling issues resolved
-
-Firmware TMDS scrambling is now being correctly configured, so
-we can use it.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------
- 1 file changed, 6 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -831,12 +831,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- break;
- }
-
-- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling
-- * working.
-- */
-- if (mode->clock > 340000)
-- return MODE_CLOCK_HIGH;
--
- return MODE_OK;
- }
-
+++ /dev/null
-From e399911ab20b650a031d883554180463804ac3f7 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 4 Jun 2019 12:14:30 +0100
-Subject: [PATCH] drm: vc4: Add status of which display is updated
- through vblank
-
-Previously multiple displays were slaved off the same SMI
-interrupt, triggered by HVS channel 1 (HDMI0).
-This doesn't work if you only have a DPI or DSI screen (HVS channel
-0), and gives slightly erroneous results with dual HDMI as the
-events for HDMI1 are incorrect.
-
-Use SMIDSW0 and SMIDSW1 registers to denote which display has
-triggered the vblank.
-Handling should be backwards compatible with older firmware.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++----
- 1 file changed, 36 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -233,8 +233,13 @@ static const struct vc_image_format *vc4
- * hardware, which has only this one register.
- */
- #define SMICS 0x0
-+#define SMIDSW0 0x14
-+#define SMIDSW1 0x1C
- #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
-
-+/* Flag to denote that the firmware is giving multiple display callbacks */
-+#define SMI_NEW 0xabcd0000
-+
- #define vc4_crtc vc4_kms_crtc
- #define to_vc4_crtc to_vc4_kms_crtc
- struct vc4_crtc {
-@@ -885,16 +890,42 @@ static irqreturn_t vc4_crtc_irq_handler(
- int i;
- u32 stat = readl(crtc_list[0]->regs + SMICS);
- irqreturn_t ret = IRQ_NONE;
-+ u32 chan;
-
- if (stat & SMICS_INTERRUPTS) {
- writel(0, crtc_list[0]->regs + SMICS);
-
-- for (i = 0; crtc_list[i]; i++) {
-- if (crtc_list[i]->vblank_enabled)
-- drm_crtc_handle_vblank(&crtc_list[i]->base);
-- vc4_crtc_handle_page_flip(crtc_list[i]);
-- ret = IRQ_HANDLED;
-+ chan = readl(crtc_list[0]->regs + SMIDSW0);
-+
-+ if ((chan & 0xFFFF0000) != SMI_NEW) {
-+ /* Older firmware. Treat the one interrupt as vblank/
-+ * complete for all crtcs.
-+ */
-+ for (i = 0; crtc_list[i]; i++) {
-+ if (crtc_list[i]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[i]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[i]);
-+ }
-+ } else {
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
-+ if (crtc_list[0]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[0]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[0]);
-+ }
-+
-+ /* Check for the secondary display too */
-+ chan = readl(crtc_list[0]->regs + SMIDSW1);
-+
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-+ if (crtc_list[1]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[1]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[1]);
-+ }
- }
-+
-+ ret = IRQ_HANDLED;
- }
-
- return ret;
--- /dev/null
+From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001
+From: Chris Miller <chris@mesl2.co.uk>
+Date: Wed, 26 Jun 2019 10:40:30 +0100
+Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
+ (#3012)
+
+Signed-off-by: Chris G Miller <chris@creative-electronics.net>
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
+ 1 file changed, 24 insertions(+), 11 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *d
+ /* DSI1 has a broken AXI slave that doesn't respond to writes
+ * from the ARM. It does handle writes from the DMA engine,
+ * so set up a channel for talking to it.
++ * Where possible managed resource providers are used, but the DMA channel
++ * must - if acquired - be explicitly released prior to taking an error exit path.
+ */
+ if (dsi->port == 1) {
+- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
++ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
+ &dsi->reg_dma_paddr,
+ GFP_KERNEL);
+ if (!dsi->reg_dma_mem) {
+@@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *d
+ return ret;
+ }
+
++ /* From here on, any error exits must release the dma channel */
++
+ /* Get the physical address of the device's registers. The
+ * struct resource for the regs gives us the bus address
+ * instead.
+@@ -1532,7 +1536,7 @@ static int vc4_dsi_bind(struct device *d
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get interrupt: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->escape_clock = devm_clk_get(dev, "escape");
+@@ -1540,7 +1544,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->escape_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get escape clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->pll_phy_clock = devm_clk_get(dev, "phy");
+@@ -1548,7 +1552,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->pll_phy_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get phy clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ dsi->pixel_clock = devm_clk_get(dev, "pixel");
+@@ -1556,7 +1560,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = PTR_ERR(dsi->pixel_clock);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get pixel clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+@@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *d
+ if (ret == -ENODEV)
+ return 0;
+
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ if (panel) {
+ dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
+ DRM_MODE_CONNECTOR_DSI);
+- if (IS_ERR(dsi->bridge))
+- return PTR_ERR(dsi->bridge);
++ if (IS_ERR(dsi->bridge)){
++ ret = PTR_ERR(dsi->bridge);
++ goto rel_dma_exit;
++ }
+ }
+
+ /* The esc clock rate is supposed to always be 100Mhz. */
+ ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
+ if (ret) {
+ dev_err(dev, "Failed to set esc clock: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+
+ ret = vc4_dsi_init_phy_clocks(dsi);
+ if (ret)
+- return ret;
++ goto rel_dma_exit;
+
+ if (dsi->port == 1)
+ vc4->dsi1 = dsi;
+@@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *d
+ ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
+ if (ret) {
+ dev_err(dev, "bridge attach failed: %d\n", ret);
+- return ret;
++ goto rel_dma_exit;
+ }
+ /* Disable the atomic helper calls into the bridge. We
+ * manually call the bridge pre_enable / enable / etc. calls
+@@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *d
+ pm_runtime_enable(dev);
+
+ return 0;
++
++rel_dma_exit:
++ dma_release_channel(dsi->reg_dma_chan);
++
++ return ret;
+ }
+
+ static void vc4_dsi_unbind(struct device *dev, struct device *master,
+@@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device
+
+ vc4_dsi_encoder_destroy(dsi->encoder);
+
++ dma_release_channel(dsi->reg_dma_chan);
++
+ if (dsi->port == 1)
+ vc4->dsi1 = NULL;
+ }
--- /dev/null
+From 07f4c75cfa18cedfd192010c50cd62921b5a00ed Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Mon, 24 Jun 2019 02:29:40 +0100
+Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes
+
+Adds signalling for BT601/709/2020, and limited/full range
+(on BT601).
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -69,7 +69,7 @@ struct set_plane {
+ u8 alpha;
+ u8 num_planes;
+ u8 is_vu;
+- u8 padding;
++ u8 color_encoding;
+
+ u32 planes[4]; /* DMA address of each plane */
+
+@@ -456,6 +456,28 @@ static void vc4_plane_atomic_update(stru
+ if (num_planes == 3 &&
+ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
+ mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
++
++ switch (state->color_encoding) {
++ default:
++ case DRM_COLOR_YCBCR_BT601:
++ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
++ else
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
++ break;
++ case DRM_COLOR_YCBCR_BT709:
++ /* Currently no support for a full range BT709 */
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
++ break;
++ case DRM_COLOR_YCBCR_BT2020:
++ /* Currently no support for a full range BT2020 */
++ mb->plane.color_encoding =
++ VC_IMAGE_YUVINFO_CSC_REC_2020;
++ break;
++ }
+ } else {
+ mb->plane.planes[1] = 0;
+ mb->plane.planes[2] = 0;
+@@ -644,6 +666,14 @@ static struct drm_plane *vc4_fkms_plane_
+ drm_plane_create_alpha_property(plane);
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+ SUPPORTED_ROTATIONS);
++ drm_plane_create_color_properties(plane,
++ BIT(DRM_COLOR_YCBCR_BT601) |
++ BIT(DRM_COLOR_YCBCR_BT709) |
++ BIT(DRM_COLOR_YCBCR_BT2020),
++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
++ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
++ DRM_COLOR_YCBCR_BT709,
++ DRM_COLOR_YCBCR_LIMITED_RANGE);
+
+ /*
+ * Default frame buffer setup is with FB on -127, and raspistill etc
+--- a/drivers/gpu/drm/vc4/vc_image_types.h
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -4,6 +4,8 @@
+ *
+ * Values taken from vc_image_types.h released by Broadcom at
+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
++ * and vc_image_structs.h at
++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
+ *
+ * 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
+@@ -141,3 +143,29 @@ enum {
+ VC_IMAGE_MAX, /* bounds for error checking */
+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
+ };
++
++enum {
++ /* Unknown or unset - defaults to BT601 interstitial */
++ VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
++
++ /* colour-space conversions data [4 bits] */
++
++ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
++ /* ITU-R BT.709-3 [HDTV] */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
++ /* JPEG JFIF */
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
++ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
++ VC_IMAGE_YUVINFO_CSC_FCC = 4,
++ /* Society of Motion Picture and Television Engineers 240M (1999) */
++ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
++ /* ITU-R BT.470-2 System M */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
++ /* ITU-R BT.470-2 System B,G */
++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
++ /* JPEG JFIF, but with 16..255 luma */
++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
++ /* Rec 2020 */
++ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
++};
+++ /dev/null
-From aa6061c2db8adbe0e75890cfc6f56b800b9995df Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 12 Jun 2019 17:13:21 +0100
-Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for
- SAND
-
-Incorrect masking was used in the switch for the modifier,
-therefore for SAND (which puts the column pitch in the
-modifier) it didn't match.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -462,7 +462,7 @@ static void vc4_plane_atomic_update(stru
- }
- mb->plane.planes[3] = 0;
-
-- switch (fb->modifier) {
-+ switch (fourcc_mod_broadcom_mod(fb->modifier)) {
- case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
- switch (mb->plane.vc_image_type) {
- case VC_IMAGE_XRGB8888:
-@@ -478,6 +478,9 @@ static void vc4_plane_atomic_update(stru
- break;
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
- mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
-+ /* Note that the column pitch is passed across in lines, not
-+ * bytes.
-+ */
- mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
- break;
- }
+++ /dev/null
-From 9f9d67a11cfd6318d2bd1321090c0950242cfa25 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 18 Jun 2019 21:37:45 +0100
-Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz
-
-Selecting 1080p100 and 120 has very limited gain, but don't want
-to block VGA85 and similar.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -823,6 +823,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- return MODE_NO_DBLESCAN;
- }
-
-+ /* Disable refresh rates > 85Hz as limited gain from them */
-+ if (drm_mode_vrefresh(mode) > 85)
-+ return MODE_BAD_VVALUE;
-+
- /* Limit the pixel clock based on the HDMI clock limits from the
- * firmware
- */
--- /dev/null
+From 76e24a2218069fadb28c0c2f5d813302ad5f85a3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 11 Jul 2019 13:13:39 +0100
+Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional
+
+pl011_tx_chars takes a "from_irq" parameter to reduce the number of
+register accesses. When from_irq is true the function assumes that the
+FIFO is half empty and writes up to half a FIFO's worth of bytes
+without polling the FIFO status register, the reasoning being that
+the function is being called as a result of the TX interrupt being
+raised. This logic would work were it not for the fact that
+pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases
+the spinlock before calling tty_flip_buffer_push.
+
+A user thread writing to the UART claims the spinlock and ultimately
+calls pl011_tx_chars with from_irq set to false. This reverts to the
+older logic that polls the FIFO status register before sending every
+byte. If this happen on an SMP system during the section of the IRQ
+handler where the spinlock has been released, then by the time the TX
+interrupt handler is called, the FIFO may already be full, and any
+further writes are likely to be lost.
+
+The fix involves adding a per-port flag that is true iff running from
+within the interrupt handler and the spinlock has not yet been released.
+This flag is then used as the value for the from_irq parameter of
+pl011_tx_chars, causing polling to be used in the unsafe case.
+
+Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -270,6 +270,7 @@ struct uart_amba_port {
+ unsigned int old_cr; /* state during shutdown */
+ unsigned int fixed_baud; /* vendor-set fixed baud rate */
+ char type[12];
++ bool irq_locked; /* in irq, unreleased lock */
+ #ifdef CONFIG_DMA_ENGINE
+ /* DMA stuff */
+ bool using_tx_dma;
+@@ -813,6 +814,7 @@ __acquires(&uap->port.lock)
+ if (!uap->using_tx_dma)
+ return;
+
++ uap->irq_locked = 0;
+ dmaengine_terminate_async(uap->dmatx.chan);
+
+ if (uap->dmatx.queued) {
+@@ -939,6 +941,7 @@ static void pl011_dma_rx_chars(struct ua
+ fifotaken = pl011_fifo_to_tty(uap);
+ }
+
++ uap->irq_locked = 0;
+ spin_unlock(&uap->port.lock);
+ dev_vdbg(uap->port.dev,
+ "Took %d chars from DMA buffer and %d chars from the FIFO\n",
+@@ -1347,6 +1350,7 @@ __acquires(&uap->port.lock)
+ {
+ pl011_fifo_to_tty(uap);
+
++ uap->irq_locked = 0;
+ spin_unlock(&uap->port.lock);
+ tty_flip_buffer_push(&uap->port.state->port);
+ /*
+@@ -1482,6 +1486,7 @@ static irqreturn_t pl011_int(int irq, vo
+ int handled = 0;
+
+ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->irq_locked = 1;
+ status = pl011_read(uap, REG_RIS) & uap->im;
+ if (status) {
+ do {
+@@ -1501,7 +1506,7 @@ static irqreturn_t pl011_int(int irq, vo
+ UART011_CTSMIS|UART011_RIMIS))
+ pl011_modem_status(uap);
+ if (status & UART011_TXIS)
+- pl011_tx_chars(uap, true);
++ pl011_tx_chars(uap, uap->irq_locked);
+
+ if (pass_counter-- == 0)
+ break;
+++ /dev/null
-From cad68ea70d649cff90102022c5d161bf84e4ed16 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 19 Jul 2019 14:29:28 +0100
-Subject: [PATCH] drm/vc4: Ignore HVS unless initialised
-
-An upstream commit to report HVS underruns causes VC4 in firmware KMS
-mode to cross into the HVS side, where it crashes due to a NULL hvs
-pointer.
-
-Make the underrun masking conditional on the hvs pointer being
-initialised.
-
-Fixes: 531a1b622da9 ("drm/vc4: Report HVS underrun errors")
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++-
- drivers/gpu/drm/vc4/vc4_kms.c | 2 +-
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -801,7 +801,8 @@ static void vc4_crtc_handle_page_flip(st
- * the CRTC and encoder already reconfigured, leading to
- * underruns. This can be seen when reconfiguring the CRTC.
- */
-- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
-+ if (vc4->hvs)
-+ vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
- }
- spin_unlock_irqrestore(&dev->event_lock, flags);
- }
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -156,7 +156,7 @@ vc4_atomic_complete_commit(struct drm_at
- struct vc4_crtc *vc4_crtc;
- int i;
-
-- for (i = 0; i < dev->mode_config.num_crtc; i++) {
-+ for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) {
- if (!state->crtcs[i].ptr || !state->crtcs[i].commit)
- continue;
-
--- /dev/null
+From 7bb9b7d36fa457a9fc463108d1228fd318891da4 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Thu, 11 Jul 2019 17:55:43 +0100
+Subject: [PATCH] xhci: add quirk for host controllers that don't
+ update endpoint DCS
+
+Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints
+at least, if the xHC halts on a particular TRB due to an error then
+the DCS field in the Out Endpoint Context maintained by the hardware
+is not updated with the current cycle state.
+
+Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit
+from the TRB that the xHC stopped on.
+
+See: https://github.com/raspberrypi/linux/issues/3060
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/xhci-pci.c | 4 +++-
+ drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++-
+ drivers/usb/host/xhci.h | 1 +
+ 3 files changed, 29 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -244,8 +244,10 @@ static void xhci_pci_quirks(struct devic
+ xhci->quirks |= XHCI_BROKEN_STREAMS;
+
+ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
+- pdev->device == 0x3483)
++ pdev->device == 0x3483) {
+ xhci->quirks |= XHCI_LPM_SUPPORT;
++ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
++ }
+
+ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+ pdev->device == 0x1042)
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -527,7 +527,10 @@ void xhci_find_new_dequeue_state(struct
+ struct xhci_virt_ep *ep = &dev->eps[ep_index];
+ struct xhci_ring *ep_ring;
+ struct xhci_segment *new_seg;
++ struct xhci_segment *halted_seg = NULL;
+ union xhci_trb *new_deq;
++ union xhci_trb *halted_trb;
++ int index = 0;
+ dma_addr_t addr;
+ u64 hw_dequeue;
+ bool cycle_found = false;
+@@ -548,7 +551,28 @@ void xhci_find_new_dequeue_state(struct
+ hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
+ new_seg = ep_ring->deq_seg;
+ new_deq = ep_ring->dequeue;
+- state->new_cycle_state = hw_dequeue & 0x1;
++
++ /*
++ * Quirk: xHC write-back of the DCS field in the hardware dequeue
++ * pointer is wrong - use the cycle state of the TRB pointed to by
++ * the dequeue pointer.
++ */
++ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
++ !(ep->ep_state & EP_HAS_STREAMS))
++ halted_seg = trb_in_td(xhci, cur_td->start_seg,
++ cur_td->first_trb, cur_td->last_trb,
++ hw_dequeue & ~0xf, false);
++ if (halted_seg) {
++ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
++ sizeof(*halted_trb);
++ halted_trb = &halted_seg->trbs[index];
++ state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
++ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
++ (u8)(hw_dequeue & 0x1), index,
++ state->new_cycle_state);
++ } else {
++ state->new_cycle_state = hw_dequeue & 0x1;
++ }
+ state->stream_id = stream_id;
+
+ /*
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1872,6 +1872,7 @@ struct xhci_hcd {
+ #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
+ #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
+ #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
++#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36)
+
+ unsigned int num_active_eps;
+ unsigned int limit_active_eps;
+++ /dev/null
-From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001
-From: Chris Miller <chris@mesl2.co.uk>
-Date: Wed, 26 Jun 2019 10:40:30 +0100
-Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
- (#3012)
-
-Signed-off-by: Chris G Miller <chris@creative-electronics.net>
----
- drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
- 1 file changed, 24 insertions(+), 11 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_dsi.c
-+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
-@@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *d
- /* DSI1 has a broken AXI slave that doesn't respond to writes
- * from the ARM. It does handle writes from the DMA engine,
- * so set up a channel for talking to it.
-+ * Where possible managed resource providers are used, but the DMA channel
-+ * must - if acquired - be explicitly released prior to taking an error exit path.
- */
- if (dsi->port == 1) {
-- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
-+ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
- &dsi->reg_dma_paddr,
- GFP_KERNEL);
- if (!dsi->reg_dma_mem) {
-@@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *d
- return ret;
- }
-
-+ /* From here on, any error exits must release the dma channel */
-+
- /* Get the physical address of the device's registers. The
- * struct resource for the regs gives us the bus address
- * instead.
-@@ -1532,7 +1536,7 @@ static int vc4_dsi_bind(struct device *d
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get interrupt: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->escape_clock = devm_clk_get(dev, "escape");
-@@ -1540,7 +1544,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->escape_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get escape clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->pll_phy_clock = devm_clk_get(dev, "phy");
-@@ -1548,7 +1552,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->pll_phy_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get phy clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- dsi->pixel_clock = devm_clk_get(dev, "pixel");
-@@ -1556,7 +1560,7 @@ static int vc4_dsi_bind(struct device *d
- ret = PTR_ERR(dsi->pixel_clock);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
-@@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *d
- if (ret == -ENODEV)
- return 0;
-
-- return ret;
-+ goto rel_dma_exit;
- }
-
- if (panel) {
- dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
- DRM_MODE_CONNECTOR_DSI);
-- if (IS_ERR(dsi->bridge))
-- return PTR_ERR(dsi->bridge);
-+ if (IS_ERR(dsi->bridge)){
-+ ret = PTR_ERR(dsi->bridge);
-+ goto rel_dma_exit;
-+ }
- }
-
- /* The esc clock rate is supposed to always be 100Mhz. */
- ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
- if (ret) {
- dev_err(dev, "Failed to set esc clock: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
-
- ret = vc4_dsi_init_phy_clocks(dsi);
- if (ret)
-- return ret;
-+ goto rel_dma_exit;
-
- if (dsi->port == 1)
- vc4->dsi1 = dsi;
-@@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *d
- ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
- if (ret) {
- dev_err(dev, "bridge attach failed: %d\n", ret);
-- return ret;
-+ goto rel_dma_exit;
- }
- /* Disable the atomic helper calls into the bridge. We
- * manually call the bridge pre_enable / enable / etc. calls
-@@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *d
- pm_runtime_enable(dev);
-
- return 0;
-+
-+rel_dma_exit:
-+ dma_release_channel(dsi->reg_dma_chan);
-+
-+ return ret;
- }
-
- static void vc4_dsi_unbind(struct device *dev, struct device *master,
-@@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device
-
- vc4_dsi_encoder_destroy(dsi->encoder);
-
-+ dma_release_channel(dsi->reg_dma_chan);
-+
- if (dsi->port == 1)
- vc4->dsi1 = NULL;
- }
--- /dev/null
+From 9c64858d41cc65982aaf36866ffa8e04b9792718 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 12 Jul 2019 15:38:35 +0100
+Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms
+
+The BCM2835 I2C blocks have a register to set the clock-stretch
+timeout - how long the device is allowed to hold SCL low - in bus
+cycles. The current driver doesn't write to the register, therefore
+the default value of 64 cycles is being used for all devices.
+
+Set the timeout to the value recommended for SMBus - 35ms.
+
+See: https://github.com/raspberrypi/linux/issues/3064
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -188,6 +188,7 @@ static int clk_bcm2835_i2c_set_rate(stru
+ {
+ struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
+ u32 redl, fedl;
++ u32 clk_tout;
+ u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
+
+ if (divider == -EINVAL)
+@@ -211,6 +212,17 @@ static int clk_bcm2835_i2c_set_rate(stru
+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
+ (fedl << BCM2835_I2C_FEDL_SHIFT) |
+ (redl << BCM2835_I2C_REDL_SHIFT));
++
++ /*
++ * Set the clock stretch timeout to the SMBUs-recommended 35ms.
++ */
++ if (rate > 0xffff*1000/35)
++ clk_tout = 0xffff;
++ else
++ clk_tout = 35*rate/1000;
++
++ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout);
++
+ return 0;
+ }
+
+++ /dev/null
-From 07f4c75cfa18cedfd192010c50cd62921b5a00ed Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Mon, 24 Jun 2019 02:29:40 +0100
-Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes
-
-Adds signalling for BT601/709/2020, and limited/full range
-(on BT601).
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++-
- drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++
- 2 files changed, 59 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -69,7 +69,7 @@ struct set_plane {
- u8 alpha;
- u8 num_planes;
- u8 is_vu;
-- u8 padding;
-+ u8 color_encoding;
-
- u32 planes[4]; /* DMA address of each plane */
-
-@@ -456,6 +456,28 @@ static void vc4_plane_atomic_update(stru
- if (num_planes == 3 &&
- (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
- mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
-+
-+ switch (state->color_encoding) {
-+ default:
-+ case DRM_COLOR_YCBCR_BT601:
-+ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
-+ else
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
-+ break;
-+ case DRM_COLOR_YCBCR_BT709:
-+ /* Currently no support for a full range BT709 */
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
-+ break;
-+ case DRM_COLOR_YCBCR_BT2020:
-+ /* Currently no support for a full range BT2020 */
-+ mb->plane.color_encoding =
-+ VC_IMAGE_YUVINFO_CSC_REC_2020;
-+ break;
-+ }
- } else {
- mb->plane.planes[1] = 0;
- mb->plane.planes[2] = 0;
-@@ -644,6 +666,14 @@ static struct drm_plane *vc4_fkms_plane_
- drm_plane_create_alpha_property(plane);
- drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
- SUPPORTED_ROTATIONS);
-+ drm_plane_create_color_properties(plane,
-+ BIT(DRM_COLOR_YCBCR_BT601) |
-+ BIT(DRM_COLOR_YCBCR_BT709) |
-+ BIT(DRM_COLOR_YCBCR_BT2020),
-+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-+ DRM_COLOR_YCBCR_BT709,
-+ DRM_COLOR_YCBCR_LIMITED_RANGE);
-
- /*
- * Default frame buffer setup is with FB on -127, and raspistill etc
---- a/drivers/gpu/drm/vc4/vc_image_types.h
-+++ b/drivers/gpu/drm/vc4/vc_image_types.h
-@@ -4,6 +4,8 @@
- *
- * Values taken from vc_image_types.h released by Broadcom at
- * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
-+ * and vc_image_structs.h at
-+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
- *
- * 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
-@@ -141,3 +143,29 @@ enum {
- VC_IMAGE_MAX, /* bounds for error checking */
- VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
- };
-+
-+enum {
-+ /* Unknown or unset - defaults to BT601 interstitial */
-+ VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
-+
-+ /* colour-space conversions data [4 bits] */
-+
-+ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
-+ /* ITU-R BT.709-3 [HDTV] */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
-+ /* JPEG JFIF */
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
-+ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
-+ VC_IMAGE_YUVINFO_CSC_FCC = 4,
-+ /* Society of Motion Picture and Television Engineers 240M (1999) */
-+ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
-+ /* ITU-R BT.470-2 System M */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
-+ /* ITU-R BT.470-2 System B,G */
-+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
-+ /* JPEG JFIF, but with 16..255 luma */
-+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
-+ /* Rec 2020 */
-+ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
-+};
--- /dev/null
+From 11076f57f802d2bdec3f1861ba27ce5554a710ca Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
+Date: Sat, 3 Aug 2019 14:34:59 +0200
+Subject: [PATCH] staging: vc04_services: fix compiling in separate
+ directory
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The vc04_services Makefiles do not respect the O=path argument
+correctly: include paths in CFLAGS are given relatively to object path,
+not source path. Compiling in a separate directory yields #include
+errors.
+
+Signed-off-by: Marek Behún <marek.behun@nic.cz>
+---
+ drivers/staging/vc04_services/bcm2835-codec/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/Makefile
++++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile
+@@ -4,5 +4,5 @@ bcm2835-codec-objs := bcm2835-v4l2-codec
+ obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o
+
+ ccflags-y += \
+- -Idrivers/staging/vc04_services \
++ -I$(srctree)/drivers/staging/vc04_services \
+ -D__VCCOREVER__=0x04000000
--- /dev/null
+From 7316a9e5720c2f4112a96b32c4ec78d94a44adcf Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 6 Aug 2019 15:23:14 +0100
+Subject: [PATCH] clk-bcm2835: Avoid null pointer exception
+
+clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2262,9 +2262,11 @@ static bool bcm2835_clk_is_claimed(const
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
+- const char *clk_name = *(const char **)(clk_desc_array[i].data);
+- if (!strcmp(name, clk_name))
+- return bcm2835_clk_claimed[i];
++ if (clk_desc_array[i].data) {
++ const char *clk_name = *(const char **)(clk_desc_array[i].data);
++ if (!strcmp(name, clk_name))
++ return bcm2835_clk_claimed[i];
++ }
+ }
+
+ return false;
+++ /dev/null
-From 76e24a2218069fadb28c0c2f5d813302ad5f85a3 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 11 Jul 2019 13:13:39 +0100
-Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional
-
-pl011_tx_chars takes a "from_irq" parameter to reduce the number of
-register accesses. When from_irq is true the function assumes that the
-FIFO is half empty and writes up to half a FIFO's worth of bytes
-without polling the FIFO status register, the reasoning being that
-the function is being called as a result of the TX interrupt being
-raised. This logic would work were it not for the fact that
-pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases
-the spinlock before calling tty_flip_buffer_push.
-
-A user thread writing to the UART claims the spinlock and ultimately
-calls pl011_tx_chars with from_irq set to false. This reverts to the
-older logic that polls the FIFO status register before sending every
-byte. If this happen on an SMP system during the section of the IRQ
-handler where the spinlock has been released, then by the time the TX
-interrupt handler is called, the FIFO may already be full, and any
-further writes are likely to be lost.
-
-The fix involves adding a per-port flag that is true iff running from
-within the interrupt handler and the spinlock has not yet been released.
-This flag is then used as the value for the from_irq parameter of
-pl011_tx_chars, causing polling to be used in the unsafe case.
-
-Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling")
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/tty/serial/amba-pl011.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -270,6 +270,7 @@ struct uart_amba_port {
- unsigned int old_cr; /* state during shutdown */
- unsigned int fixed_baud; /* vendor-set fixed baud rate */
- char type[12];
-+ bool irq_locked; /* in irq, unreleased lock */
- #ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- bool using_tx_dma;
-@@ -813,6 +814,7 @@ __acquires(&uap->port.lock)
- if (!uap->using_tx_dma)
- return;
-
-+ uap->irq_locked = 0;
- dmaengine_terminate_async(uap->dmatx.chan);
-
- if (uap->dmatx.queued) {
-@@ -939,6 +941,7 @@ static void pl011_dma_rx_chars(struct ua
- fifotaken = pl011_fifo_to_tty(uap);
- }
-
-+ uap->irq_locked = 0;
- spin_unlock(&uap->port.lock);
- dev_vdbg(uap->port.dev,
- "Took %d chars from DMA buffer and %d chars from the FIFO\n",
-@@ -1347,6 +1350,7 @@ __acquires(&uap->port.lock)
- {
- pl011_fifo_to_tty(uap);
-
-+ uap->irq_locked = 0;
- spin_unlock(&uap->port.lock);
- tty_flip_buffer_push(&uap->port.state->port);
- /*
-@@ -1482,6 +1486,7 @@ static irqreturn_t pl011_int(int irq, vo
- int handled = 0;
-
- spin_lock_irqsave(&uap->port.lock, flags);
-+ uap->irq_locked = 1;
- status = pl011_read(uap, REG_RIS) & uap->im;
- if (status) {
- do {
-@@ -1501,7 +1506,7 @@ static irqreturn_t pl011_int(int irq, vo
- UART011_CTSMIS|UART011_RIMIS))
- pl011_modem_status(uap);
- if (status & UART011_TXIS)
-- pl011_tx_chars(uap, true);
-+ pl011_tx_chars(uap, uap->irq_locked);
-
- if (pass_counter-- == 0)
- break;
--- /dev/null
+From 907dc84e0c7208b79ad57e0e2a7964dbc9155f50 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 15 Aug 2019 08:39:08 +0100
+Subject: [PATCH] drm/vc4: Prevent load tracking from breaking FKMS
+
+Firmware KMS uses a mixture of VC4 processing and dedicated code. The
+load tracking support in VC4 assumes it is dealing with vc4_plane_state
+objects when up-casting with container_of, but FKMS uses unadorned
+drm_plane_state structures causing the VC4 code to read off the end
+into random portions of memory. Work around the problem in a minimally-
+invasive way by over-allocating the FKMS plane state structures to be
+large enough to contain a vc4_plane_state, filling the remainder with
+zeroes.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 34 ++++++++++++++++++++++++--
+ 1 file changed, 32 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -561,6 +561,20 @@ static int vc4_plane_atomic_check(struct
+ return 0;
+ }
+
++/* Called during init to allocate the plane's atomic state. */
++static void vc4_plane_reset(struct drm_plane *plane)
++{
++ struct vc4_plane_state *vc4_state;
++
++ WARN_ON(plane->state);
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return;
++
++ __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
++}
++
+ static void vc4_plane_destroy(struct drm_plane *plane)
+ {
+ drm_plane_cleanup(plane);
+@@ -602,13 +616,29 @@ static bool vc4_fkms_format_mod_supporte
+ }
+ }
+
++static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
++{
++ struct vc4_plane_state *vc4_state;
++
++ if (WARN_ON(!plane->state))
++ return NULL;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
++
++ return &vc4_state->base;
++}
++
+ static const struct drm_plane_funcs vc4_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = vc4_plane_destroy,
+ .set_property = NULL,
+- .reset = drm_atomic_helper_plane_reset,
+- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
++ .reset = vc4_plane_reset,
++ .atomic_duplicate_state = vc4_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .format_mod_supported = vc4_fkms_format_mod_supported,
+ };
+++ /dev/null
-From 7bb9b7d36fa457a9fc463108d1228fd318891da4 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Thu, 11 Jul 2019 17:55:43 +0100
-Subject: [PATCH] xhci: add quirk for host controllers that don't
- update endpoint DCS
-
-Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints
-at least, if the xHC halts on a particular TRB due to an error then
-the DCS field in the Out Endpoint Context maintained by the hardware
-is not updated with the current cycle state.
-
-Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit
-from the TRB that the xHC stopped on.
-
-See: https://github.com/raspberrypi/linux/issues/3060
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/xhci-pci.c | 4 +++-
- drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++-
- drivers/usb/host/xhci.h | 1 +
- 3 files changed, 29 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/xhci-pci.c
-+++ b/drivers/usb/host/xhci-pci.c
-@@ -244,8 +244,10 @@ static void xhci_pci_quirks(struct devic
- xhci->quirks |= XHCI_BROKEN_STREAMS;
-
- if (pdev->vendor == PCI_VENDOR_ID_VIA &&
-- pdev->device == 0x3483)
-+ pdev->device == 0x3483) {
- xhci->quirks |= XHCI_LPM_SUPPORT;
-+ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
-+ }
-
- if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
- pdev->device == 0x1042)
---- a/drivers/usb/host/xhci-ring.c
-+++ b/drivers/usb/host/xhci-ring.c
-@@ -527,7 +527,10 @@ void xhci_find_new_dequeue_state(struct
- struct xhci_virt_ep *ep = &dev->eps[ep_index];
- struct xhci_ring *ep_ring;
- struct xhci_segment *new_seg;
-+ struct xhci_segment *halted_seg = NULL;
- union xhci_trb *new_deq;
-+ union xhci_trb *halted_trb;
-+ int index = 0;
- dma_addr_t addr;
- u64 hw_dequeue;
- bool cycle_found = false;
-@@ -548,7 +551,28 @@ void xhci_find_new_dequeue_state(struct
- hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
- new_seg = ep_ring->deq_seg;
- new_deq = ep_ring->dequeue;
-- state->new_cycle_state = hw_dequeue & 0x1;
-+
-+ /*
-+ * Quirk: xHC write-back of the DCS field in the hardware dequeue
-+ * pointer is wrong - use the cycle state of the TRB pointed to by
-+ * the dequeue pointer.
-+ */
-+ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
-+ !(ep->ep_state & EP_HAS_STREAMS))
-+ halted_seg = trb_in_td(xhci, cur_td->start_seg,
-+ cur_td->first_trb, cur_td->last_trb,
-+ hw_dequeue & ~0xf, false);
-+ if (halted_seg) {
-+ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
-+ sizeof(*halted_trb);
-+ halted_trb = &halted_seg->trbs[index];
-+ state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
-+ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
-+ (u8)(hw_dequeue & 0x1), index,
-+ state->new_cycle_state);
-+ } else {
-+ state->new_cycle_state = hw_dequeue & 0x1;
-+ }
- state->stream_id = stream_id;
-
- /*
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1872,6 +1872,7 @@ struct xhci_hcd {
- #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
- #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
- #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
-+#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36)
-
- unsigned int num_active_eps;
- unsigned int limit_active_eps;
--- /dev/null
+From ba05797f8e3578398a1ab6c835f6b100d4f46edb Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 14 Jan 2019 15:13:17 -0800
+Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now.
+
+Something is still unstable -- on starting a new glxgears from an idle
+X11, I get an MMU violation in high addresses. The CTS also failed
+quite quickly. With this, CTS progresses for an hour before OOMing
+(allocating some big buffers when my board only has 600MB available to
+Linux)
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +---------------
+ drivers/gpu/drm/v3d/v3d_drv.c | 9 ---------
+ 2 files changed, 1 insertion(+), 24 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
+@@ -4,7 +4,6 @@
+ #include <linux/circ_buf.h>
+ #include <linux/ctype.h>
+ #include <linux/debugfs.h>
+-#include <linux/pm_runtime.h>
+ #include <linux/seq_file.h>
+
+ #include <drm/drm_debugfs.h>
+@@ -130,11 +129,8 @@ static int v3d_v3d_debugfs_ident(struct
+ struct drm_device *dev = node->minor->dev;
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ u32 ident0, ident1, ident2, ident3, cores;
+- int ret, core;
++ int core;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+
+ ident0 = V3D_READ(V3D_HUB_IDENT0);
+ ident1 = V3D_READ(V3D_HUB_IDENT1);
+@@ -187,9 +183,6 @@ static int v3d_v3d_debugfs_ident(struct
+ (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
+ }
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+-
+ return 0;
+ }
+
+@@ -217,11 +210,6 @@ static int v3d_measure_clock(struct seq_
+ uint32_t cycles;
+ int core = 0;
+ int measure_ms = 1000;
+- int ret;
+-
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+
+ if (v3d->ver >= 40) {
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
+@@ -245,8 +233,6 @@ static int v3d_measure_clock(struct seq_
+ cycles / (measure_ms * 1000),
+ (cycles / (measure_ms * 100)) % 10);
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+
+ return 0;
+ }
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -78,7 +78,6 @@ static int v3d_get_param_ioctl(struct dr
+ {
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ struct drm_v3d_get_param *args = data;
+- int ret;
+ static const u32 reg_map[] = {
+ [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG,
+ [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1,
+@@ -104,17 +103,12 @@ static int v3d_get_param_ioctl(struct dr
+ if (args->value != 0)
+ return -EINVAL;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+ if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 &&
+ args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) {
+ args->value = V3D_CORE_READ(0, offset);
+ } else {
+ args->value = V3D_READ(offset);
+ }
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+ return 0;
+ }
+
+@@ -302,9 +296,6 @@ static int v3d_platform_drm_probe(struct
+ goto dev_free;
+ }
+
+- pm_runtime_use_autosuspend(dev);
+- pm_runtime_set_autosuspend_delay(dev, 50);
+- pm_runtime_enable(dev);
+
+ ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev);
+ if (ret)
+++ /dev/null
-From 9c64858d41cc65982aaf36866ffa8e04b9792718 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 12 Jul 2019 15:38:35 +0100
-Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms
-
-The BCM2835 I2C blocks have a register to set the clock-stretch
-timeout - how long the device is allowed to hold SCL low - in bus
-cycles. The current driver doesn't write to the register, therefore
-the default value of 64 cycles is being used for all devices.
-
-Set the timeout to the value recommended for SMBus - 35ms.
-
-See: https://github.com/raspberrypi/linux/issues/3064
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/i2c/busses/i2c-bcm2835.c
-+++ b/drivers/i2c/busses/i2c-bcm2835.c
-@@ -188,6 +188,7 @@ static int clk_bcm2835_i2c_set_rate(stru
- {
- struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw);
- u32 redl, fedl;
-+ u32 clk_tout;
- u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate);
-
- if (divider == -EINVAL)
-@@ -211,6 +212,17 @@ static int clk_bcm2835_i2c_set_rate(stru
- bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL,
- (fedl << BCM2835_I2C_FEDL_SHIFT) |
- (redl << BCM2835_I2C_REDL_SHIFT));
-+
-+ /*
-+ * Set the clock stretch timeout to the SMBUs-recommended 35ms.
-+ */
-+ if (rate > 0xffff*1000/35)
-+ clk_tout = 0xffff;
-+ else
-+ clk_tout = 35*rate/1000;
-+
-+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout);
-+
- return 0;
- }
-
+++ /dev/null
-From 235f775351e8f7e47cff1baa1284e0df95e3234e Mon Sep 17 00:00:00 2001
-From: Andrei Gherzan <andrei@balena.io>
-Date: Tue, 16 Jul 2019 13:28:22 +0100
-Subject: [PATCH] arm64/mm: Limit the DMA zone for arm64
-
-On RaspberryPi, only the first 1Gb can be used for DMA[1].
-
-[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2019-July/665986.html
-
-Signed-off-by: Andrei Gherzan <andrei@balena.io>
----
- arch/arm64/mm/init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm64/mm/init.c
-+++ b/arch/arm64/mm/init.c
-@@ -177,7 +177,7 @@ static void __init reserve_elfcorehdr(vo
- static phys_addr_t __init max_zone_dma_phys(void)
- {
- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
-- return min(offset + (1ULL << 32), memblock_end_of_DRAM());
-+ return min(offset + (1ULL << 30), memblock_end_of_DRAM());
- }
-
- #ifdef CONFIG_NUMA
--- /dev/null
+From ca8579839f0ebf0ffe73d1135284363b2155e712 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 2 May 2019 13:22:53 -0700
+Subject: [PATCH] drm/v3d: Clock V3D down when not in use.
+
+My various attempts at re-enabling runtime PM have failed, so just
+crank the clock down when V3D is idle to reduce power consumption.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 18 ++++++++++++
+ drivers/gpu/drm/v3d/v3d_drv.h | 6 ++++
+ drivers/gpu/drm/v3d/v3d_gem.c | 53 +++++++++++++++++++++++++++++++----
+ 3 files changed, 72 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -282,6 +282,21 @@ static int v3d_platform_drm_probe(struct
+ }
+ }
+
++ v3d->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(v3d->clk)) {
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "Failed to get clock\n");
++ goto dev_free;
++ }
++ v3d->clk_up_rate = clk_get_rate(v3d->clk);
++ /* For downclocking, drop it to the minimum frequency we can get from
++ * the CPRMAN clock generator dividing off our parent. The divider is
++ * 4 bits, but ask for just higher than that so that rounding doesn't
++ * make cprman reject our rate.
++ */
++ v3d->clk_down_rate =
++ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
++
+ if (v3d->ver < 41) {
+ ret = map_regs(v3d, &v3d->gca_regs, "gca");
+ if (ret)
+@@ -316,6 +331,9 @@ static int v3d_platform_drm_probe(struct
+ if (ret)
+ goto irq_disable;
+
++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
++ WARN_ON_ONCE(ret != 0);
++
+ return 0;
+
+ irq_disable:
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -54,6 +54,12 @@ struct v3d_dev {
+ void __iomem *bridge_regs;
+ void __iomem *gca_regs;
+ struct clk *clk;
++ struct delayed_work clk_down_work;
++ unsigned long clk_up_rate, clk_down_rate;
++ struct mutex clk_lock;
++ u32 clk_refcount;
++ bool clk_up;
++
+ struct reset_control *reset;
+
+ /* Virtual and DMA addresses of the single shared page table. */
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -4,6 +4,7 @@
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/io.h>
++#include <linux/clk.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
+@@ -19,6 +20,47 @@
+ #include "v3d_trace.h"
+
+ static void
++v3d_clock_down_work(struct work_struct *work)
++{
++ struct v3d_dev *v3d =
++ container_of(work, struct v3d_dev, clk_down_work.work);
++ int ret;
++
++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
++ v3d->clk_up = false;
++ WARN_ON_ONCE(ret != 0);
++}
++
++static void
++v3d_clock_up_get(struct v3d_dev *v3d)
++{
++ mutex_lock(&v3d->clk_lock);
++ if (v3d->clk_refcount++ == 0) {
++ cancel_delayed_work_sync(&v3d->clk_down_work);
++ if (!v3d->clk_up) {
++ int ret;
++
++ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
++ WARN_ON_ONCE(ret != 0);
++ v3d->clk_up = true;
++ }
++ }
++ mutex_unlock(&v3d->clk_lock);
++}
++
++static void
++v3d_clock_up_put(struct v3d_dev *v3d)
++{
++ mutex_lock(&v3d->clk_lock);
++ if (--v3d->clk_refcount == 0) {
++ schedule_delayed_work(&v3d->clk_down_work,
++ msecs_to_jiffies(100));
++ }
++ mutex_unlock(&v3d->clk_lock);
++}
++
++
++static void
+ v3d_init_core(struct v3d_dev *v3d, int core)
+ {
+ /* Set OVRTMUOUT, which means that the texture sampler uniform
+@@ -354,6 +396,7 @@ v3d_job_free(struct kref *ref)
+ struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
+ unsigned long index;
+ struct dma_fence *fence;
++ struct v3d_dev *v3d = job->v3d;
+ int i;
+
+ for (i = 0; i < job->bo_count; i++) {
+@@ -367,11 +410,7 @@ v3d_job_free(struct kref *ref)
+ }
+ xa_destroy(&job->deps);
+
+- dma_fence_put(job->irq_fence);
+- dma_fence_put(job->done_fence);
+-
+- pm_runtime_mark_last_busy(job->v3d->dev);
+- pm_runtime_put_autosuspend(job->v3d->dev);
++ v3d_clock_up_put(v3d);
+
+ kfree(job);
+ }
+@@ -453,6 +492,7 @@ v3d_job_init(struct v3d_dev *v3d, struct
+ if (ret)
+ goto fail;
+
++ v3d_clock_up_get(v3d);
+ kref_init(&job->refcount);
+
+ return 0;
+@@ -841,6 +881,9 @@ v3d_gem_init(struct drm_device *dev)
+ mutex_init(&v3d->sched_lock);
+ mutex_init(&v3d->cache_clean_lock);
+
++ mutex_init(&v3d->clk_lock);
++ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
++
+ /* Note: We don't allocate address 0. Various bits of HW
+ * treat 0 as special, such as the occlusion query counters
+ * where 0 means "disabled".
--- /dev/null
+From 638f29943041f9205486a03587b7bd9e64799b2a Mon Sep 17 00:00:00 2001
+From: Hermann Lauer <hlauer@seba.iwr.uni-heidelberg.de>
+Date: Thu, 8 Aug 2019 15:40:37 +0200
+Subject: [PATCH] According to 5713 pdf doc CLOCK_CTRL is a readonly
+ status register, and it behaves so. Remove useless setting
+
+---
+ sound/soc/codecs/tas5713.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/sound/soc/codecs/tas5713.c
++++ b/sound/soc/codecs/tas5713.c
+@@ -190,10 +190,6 @@ static int tas5713_probe(struct snd_soc_
+ ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
+ if (ret < 0) return ret;
+
+- // Clock mode: 44/48kHz, MCLK=64xfs
+- ret = snd_soc_component_write(component, TAS5713_CLOCK_CTRL, 0x60);
+- if (ret < 0) return ret;
+-
+ // I2S 24bit
+ ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
+ if (ret < 0) return ret;
+@@ -257,6 +253,7 @@ static bool tas5713_reg_volatile(struct
+ switch (reg) {
+ case TAS5713_DEVICE_ID:
+ case TAS5713_ERROR_STATUS:
++ case TAS5713_CLOCK_CTRL:
+ return true;
+ default:
+ return false;
+++ /dev/null
-From 11076f57f802d2bdec3f1861ba27ce5554a710ca Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
-Date: Sat, 3 Aug 2019 14:34:59 +0200
-Subject: [PATCH] staging: vc04_services: fix compiling in separate
- directory
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The vc04_services Makefiles do not respect the O=path argument
-correctly: include paths in CFLAGS are given relatively to object path,
-not source path. Compiling in a separate directory yields #include
-errors.
-
-Signed-off-by: Marek Behún <marek.behun@nic.cz>
----
- drivers/staging/vc04_services/bcm2835-codec/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/Makefile
-+++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile
-@@ -4,5 +4,5 @@ bcm2835-codec-objs := bcm2835-v4l2-codec
- obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o
-
- ccflags-y += \
-- -Idrivers/staging/vc04_services \
-+ -I$(srctree)/drivers/staging/vc04_services \
- -D__VCCOREVER__=0x04000000
+++ /dev/null
-From 773a2db89ad2785d72b215673d87c0a51d769f61 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 4 Apr 2019 13:33:47 +0100
-Subject: [PATCH] bcm2835-dma: Add proper 40-bit DMA support
-
-The 40-bit additions are not fully tested, but it should be
-capable of supporting both 40-bit memcpy on BCM2711 and regular
-Lite channels on BCM2835.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/dma/bcm2835-dma.c | 421 ++++++++++++++-----
- drivers/pci/controller/pcie-brcmstb-bounce.c | 30 +-
- drivers/pci/controller/pcie-brcmstb-bounce.h | 21 +-
- drivers/pci/controller/pcie-brcmstb.c | 23 +-
- 4 files changed, 369 insertions(+), 126 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -38,6 +38,11 @@
- #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
- #define BCM2835_DMA_CHAN_NAME_SIZE 8
- #define BCM2835_DMA_BULK_MASK BIT(0)
-+#define BCM2838_DMA_MEMCPY_CHAN 14
-+
-+struct bcm2835_dma_cfg_data {
-+ u32 chan_40bit_mask;
-+};
-
- /**
- * struct bcm2835_dmadev - BCM2835 DMA controller
-@@ -52,6 +57,7 @@ struct bcm2835_dmadev {
- void __iomem *base;
- struct device_dma_parameters dma_parms;
- dma_addr_t zero_page;
-+ const struct bcm2835_dma_cfg_data *cfg_data;
- };
-
- struct bcm2835_dma_cb {
-@@ -95,6 +101,7 @@ struct bcm2835_chan {
- unsigned int irq_flags;
-
- bool is_lite_channel;
-+ bool is_40bit_channel;
- };
-
- struct bcm2835_desc {
-@@ -184,7 +191,8 @@ struct bcm2835_desc {
- #define BCM2835_DMA_DATA_TYPE_S128 16
-
- /* Valid only for channels 0 - 14, 15 has its own base address */
--#define BCM2835_DMA_CHAN(n) ((n) << 8) /* Base address */
-+#define BCM2835_DMA_CHAN_SIZE 0x100
-+#define BCM2835_DMA_CHAN(n) ((n) * BCM2835_DMA_CHAN_SIZE) /* Base address */
- #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
-
- /* the max dma length for different channels */
-@@ -195,7 +203,7 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_CS 0x00
- #define BCM2838_DMA40_CB 0x04
- #define BCM2838_DMA40_DEBUG 0x0c
--#define BCM2858_DMA40_TI 0x10
-+#define BCM2838_DMA40_TI 0x10
- #define BCM2838_DMA40_SRC 0x14
- #define BCM2838_DMA40_SRCI 0x18
- #define BCM2838_DMA40_DEST 0x1c
-@@ -204,32 +212,97 @@ struct bcm2835_desc {
- #define BCM2838_DMA40_NEXT_CB 0x28
- #define BCM2838_DMA40_DEBUG2 0x2c
-
--#define BCM2838_DMA40_CS_ACTIVE BIT(0)
--#define BCM2838_DMA40_CS_END BIT(1)
-+#define BCM2838_DMA40_ACTIVE BIT(0)
-+#define BCM2838_DMA40_END BIT(1)
-+#define BCM2838_DMA40_INT BIT(2)
-+#define BCM2838_DMA40_DREQ BIT(3) /* DREQ state */
-+#define BCM2838_DMA40_RD_PAUSED BIT(4) /* Reading is paused */
-+#define BCM2838_DMA40_WR_PAUSED BIT(5) /* Writing is paused */
-+#define BCM2838_DMA40_DREQ_PAUSED BIT(6) /* Is paused by DREQ flow control */
-+#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7) /* Waiting for last write */
-+#define BCM2838_DMA40_ERR BIT(10)
-+#define BCM2838_DMA40_QOS(x) (((x) & 0x1f) << 16)
-+#define BCM2838_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
-+#define BCM2838_DMA40_DISDEBUG BIT(29)
-+#define BCM2838_DMA40_ABORT BIT(30)
-+#define BCM2838_DMA40_HALT BIT(31)
-+#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
-+ BCM2838_DMA40_PANIC_QOS(15) | \
-+ BCM2838_DMA40_WAIT_FOR_WRITES | \
-+ BCM2838_DMA40_DISDEBUG))
-+
-+/* Transfer information bits */
-+#define BCM2838_DMA40_INTEN BIT(0)
-+#define BCM2838_DMA40_TDMODE BIT(1) /* 2D-Mode */
-+#define BCM2838_DMA40_WAIT_RESP BIT(2) /* wait for AXI write to be acked */
-+#define BCM2838_DMA40_WAIT_RD_RESP BIT(3) /* wait for AXI read to complete */
-+#define BCM2838_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */
-+#define BCM2838_DMA40_S_DREQ BIT(14) /* enable SREQ for source */
-+#define BCM2838_DMA40_D_DREQ BIT(15) /* enable DREQ for destination */
-+#define BCM2838_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* add DMA read-wait cycles */
-+#define BCM2838_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* add DMA write-wait cycles */
-
--#define BCM2838_DMA40_CS_QOS(x) (((x) & 0x1f) << 16)
--#define BCM2838_DMA40_CS_PANIC_QOS(x) (((x) & 0x1f) << 20)
--#define BCM2838_DMA40_CS_WRITE_WAIT BIT(28)
-+/* debug register bits */
-+#define BCM2838_DMA40_DEBUG_WRITE_ERR BIT(0)
-+#define BCM2838_DMA40_DEBUG_FIFO_ERR BIT(1)
-+#define BCM2838_DMA40_DEBUG_READ_ERR BIT(2)
-+#define BCM2838_DMA40_DEBUG_READ_CB_ERR BIT(3)
-+#define BCM2838_DMA40_DEBUG_IN_ON_ERR BIT(8)
-+#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR BIT(9)
-+#define BCM2838_DMA40_DEBUG_HALT_ON_ERR BIT(10)
-+#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE BIT(11)
-+#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT 14
-+#define BCM2838_DMA40_DEBUG_RSTATE_BITS 4
-+#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT 18
-+#define BCM2838_DMA40_DEBUG_WSTATE_BITS 4
-+#define BCM2838_DMA40_DEBUG_RESET BIT(23)
-+#define BCM2838_DMA40_DEBUG_ID_SHIFT 24
-+#define BCM2838_DMA40_DEBUG_ID_BITS 4
-+#define BCM2838_DMA40_DEBUG_VERSION_SHIFT 28
-+#define BCM2838_DMA40_DEBUG_VERSION_BITS 4
-+
-+/* Valid only for channels 0 - 3 (11 - 14) */
-+#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
-+#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
-
--#define BCM2838_DMA40_BURST_LEN(x) ((((x) - 1) & 0xf) << 8)
--#define BCM2838_DMA40_INC BIT(12)
--#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+/* the max dma length for different channels */
-+#define MAX_DMA40_LEN SZ_1G
-
--#define BCM2838_DMA40_MEMCPY_QOS \
-- (BCM2838_DMA40_CS_QOS(0x0) | \
-- BCM2838_DMA40_CS_PANIC_QOS(0x0) | \
-- BCM2838_DMA40_CS_WRITE_WAIT)
-+#define BCM2838_DMA40_BURST_LEN(x) ((min(x,16) - 1) << 8)
-+#define BCM2838_DMA40_INC BIT(12)
-+#define BCM2838_DMA40_SIZE_32 (0 << 13)
-+#define BCM2838_DMA40_SIZE_64 (1 << 13)
-+#define BCM2838_DMA40_SIZE_128 (2 << 13)
-+#define BCM2838_DMA40_SIZE_256 (3 << 13)
-+#define BCM2838_DMA40_IGNORE BIT(15)
-+#define BCM2838_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */
-+
-+#define BCM2838_DMA40_MEMCPY_FLAGS \
-+ (BCM2838_DMA40_QOS(0) | \
-+ BCM2838_DMA40_PANIC_QOS(0) | \
-+ BCM2838_DMA40_WAIT_FOR_WRITES | \
-+ BCM2838_DMA40_DISDEBUG)
-
- #define BCM2838_DMA40_MEMCPY_XFER_INFO \
- (BCM2838_DMA40_SIZE_128 | \
- BCM2838_DMA40_INC | \
- BCM2838_DMA40_BURST_LEN(16))
-
-+struct bcm2835_dmadev *memcpy_parent;
- static void __iomem *memcpy_chan;
- static struct bcm2838_dma40_scb *memcpy_scb;
- static dma_addr_t memcpy_scb_dma;
- DEFINE_SPINLOCK(memcpy_lock);
-
-+static const struct bcm2835_dma_cfg_data bcm2835_dma_cfg = {
-+ .chan_40bit_mask = 0,
-+};
-+
-+static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
-+ .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
-+};
-+
- static inline size_t bcm2835_dma_max_frame_length(struct bcm2835_chan *c)
- {
- /* lite and normal channels have different max frame length */
-@@ -259,6 +332,32 @@ static inline struct bcm2835_desc *to_bc
- return container_of(t, struct bcm2835_desc, vd.tx);
- }
-
-+static inline uint32_t to_bcm2838_ti(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
-+ ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
-+ ((info & BCM2835_DMA_S_DREQ) ?
-+ (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
-+ ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
-+ BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
-+}
-+
-+static inline uint32_t to_bcm2838_srci(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_dsti(uint32_t info)
-+{
-+ return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
-+}
-+
-+static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
-+{
-+ BUG_ON(addr & 0x1f);
-+ return (addr >> 5);
-+}
-+
- static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
- {
- size_t i;
-@@ -277,45 +376,53 @@ static void bcm2835_dma_desc_free(struct
- }
-
- static void bcm2835_dma_create_cb_set_length(
-- struct bcm2835_chan *chan,
-+ struct bcm2835_chan *c,
- struct bcm2835_dma_cb *control_block,
- size_t len,
- size_t period_len,
- size_t *total_len,
- u32 finalextrainfo)
- {
-- size_t max_len = bcm2835_dma_max_frame_length(chan);
-+ size_t max_len = bcm2835_dma_max_frame_length(c);
-+ uint32_t cb_len;
-
- /* set the length taking lite-channel limitations into account */
-- control_block->length = min_t(u32, len, max_len);
-+ cb_len = min_t(u32, len, max_len);
-
-- /* finished if we have no period_length */
-- if (!period_len)
-- return;
-+ if (period_len) {
-+ /*
-+ * period_len means: that we need to generate
-+ * transfers that are terminating at every
-+ * multiple of period_len - this is typically
-+ * used to set the interrupt flag in info
-+ * which is required during cyclic transfers
-+ */
-
-- /*
-- * period_len means: that we need to generate
-- * transfers that are terminating at every
-- * multiple of period_len - this is typically
-- * used to set the interrupt flag in info
-- * which is required during cyclic transfers
-- */
-+ /* have we filled in period_length yet? */
-+ if (*total_len + cb_len < period_len) {
-+ /* update number of bytes in this period so far */
-+ *total_len += cb_len;
-+ } else {
-+ /* calculate the length that remains to reach period_len */
-+ cb_len = period_len - *total_len;
-
-- /* have we filled in period_length yet? */
-- if (*total_len + control_block->length < period_len) {
-- /* update number of bytes in this period so far */
-- *total_len += control_block->length;
-- return;
-+ /* reset total_length for next period */
-+ *total_len = 0;
-+ }
- }
-
-- /* calculate the length that remains to reach period_length */
-- control_block->length = period_len - *total_len;
--
-- /* reset total_length for next period */
-- *total_len = 0;
--
-- /* add extrainfo bits in info */
-- control_block->info |= finalextrainfo;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)control_block;
-+
-+ scb->len = cb_len;
-+ /* add extrainfo bits to ti */
-+ scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ } else {
-+ control_block->length = cb_len;
-+ /* add extrainfo bits to info */
-+ control_block->info |= finalextrainfo;
-+ }
- }
-
- static inline size_t bcm2835_dma_count_frames_for_sg(
-@@ -338,7 +445,7 @@ static inline size_t bcm2835_dma_count_f
- /**
- * bcm2835_dma_create_cb_chain - create a control block and fills data in
- *
-- * @chan: the @dma_chan for which we run this
-+ * @c: the @bcm2835_chan for which we run this
- * @direction: the direction in which we transfer
- * @cyclic: it is a cyclic transfer
- * @info: the default info bits to apply per controlblock
-@@ -356,12 +463,11 @@ static inline size_t bcm2835_dma_count_f
- * @gfp: the GFP flag to use for allocation
- */
- static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
-- struct dma_chan *chan, enum dma_transfer_direction direction,
-+ struct bcm2835_chan *c, enum dma_transfer_direction direction,
- bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
- dma_addr_t src, dma_addr_t dst, size_t buf_len,
- size_t period_len, gfp_t gfp)
- {
-- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
- size_t len = buf_len, total_len;
- size_t frame;
- struct bcm2835_desc *d;
-@@ -393,11 +499,23 @@ static struct bcm2835_desc *bcm2835_dma_
-
- /* fill in the control block */
- control_block = cb_entry->cb;
-- control_block->info = info;
-- control_block->src = src;
-- control_block->dst = dst;
-- control_block->stride = 0;
-- control_block->next = 0;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)control_block;
-+ scb->ti = to_bcm2838_ti(info);
-+ scb->src = lower_32_bits(src);
-+ scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
-+ scb->dst = lower_32_bits(dst);
-+ scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
-+ scb->next_cb = 0;
-+ } else {
-+ control_block->info = info;
-+ control_block->src = src;
-+ control_block->dst = dst;
-+ control_block->stride = 0;
-+ control_block->next = 0;
-+ }
-+
- /* set up length in control_block if requested */
- if (buf_len) {
- /* calculate length honoring period_length */
-@@ -411,7 +529,10 @@ static struct bcm2835_desc *bcm2835_dma_
- }
-
- /* link this the last controlblock */
-- if (frame)
-+ if (frame && c->is_40bit_channel)
-+ d->cb_list[frame - 1].cb->next =
-+ to_bcm2838_cbaddr(cb_entry->paddr);
-+ if (frame && !c->is_40bit_channel)
- d->cb_list[frame - 1].cb->next = cb_entry->paddr;
-
- /* update src and dst and length */
-@@ -425,7 +546,14 @@ static struct bcm2835_desc *bcm2835_dma_
- }
-
- /* the last frame requires extra flags */
-- d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
-+
-+ scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ } else {
-+ d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
-+ }
-
- /* detect a size missmatch */
- if (buf_len && (d->size != buf_len))
-@@ -439,13 +567,12 @@ error_cb:
- }
-
- static void bcm2835_dma_fill_cb_chain_with_sg(
-- struct dma_chan *chan,
-+ struct bcm2835_chan *c,
- enum dma_transfer_direction direction,
- struct bcm2835_cb_entry *cb,
- struct scatterlist *sgl,
- unsigned int sg_len)
- {
-- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
- size_t len, max_len;
- unsigned int i;
- dma_addr_t addr;
-@@ -453,14 +580,34 @@ static void bcm2835_dma_fill_cb_chain_wi
-
- max_len = bcm2835_dma_max_frame_length(c);
- for_each_sg(sgl, sgent, sg_len, i) {
-- for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
-- len > 0;
-- addr += cb->cb->length, len -= cb->cb->length, cb++) {
-- if (direction == DMA_DEV_TO_MEM)
-- cb->cb->dst = addr;
-- else
-- cb->cb->src = addr;
-- cb->cb->length = min(len, max_len);
-+ if (c->is_40bit_channel) {
-+ struct bcm2838_dma40_scb *scb =
-+ (struct bcm2838_dma40_scb *)cb->cb;
-+ for (addr = sg_dma_address(sgent),
-+ len = sg_dma_len(sgent);
-+ len > 0;
-+ addr += scb->len, len -= scb->len, scb++) {
-+ if (direction == DMA_DEV_TO_MEM) {
-+ scb->dst = lower_32_bits(addr);
-+ scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ } else {
-+ scb->src = lower_32_bits(addr);
-+ scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ }
-+ scb->len = min(len, max_len);
-+ }
-+ } else {
-+ for (addr = sg_dma_address(sgent),
-+ len = sg_dma_len(sgent);
-+ len > 0;
-+ addr += cb->cb->length, len -= cb->cb->length,
-+ cb++) {
-+ if (direction == DMA_DEV_TO_MEM)
-+ cb->cb->dst = addr;
-+ else
-+ cb->cb->src = addr;
-+ cb->cb->length = min(len, max_len);
-+ }
- }
- }
- }
-@@ -469,6 +616,10 @@ static void bcm2835_dma_abort(struct bcm
- {
- void __iomem *chan_base = c->chan_base;
- long int timeout = 10000;
-+ u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
-+
-+ if (c->is_40bit_channel)
-+ wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
-
- /*
- * A zero control block address means the channel is idle.
-@@ -481,8 +632,7 @@ static void bcm2835_dma_abort(struct bcm
- writel(0, chan_base + BCM2835_DMA_CS);
-
- /* Wait for any current AXI transfer to complete */
-- while ((readl(chan_base + BCM2835_DMA_CS) &
-- BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
-+ while ((readl(chan_base + BCM2835_DMA_CS) & wait_mask) && --timeout)
- cpu_relax();
-
- /* Peripheral might be stuck and fail to signal AXI write responses */
-@@ -507,9 +657,16 @@ static void bcm2835_dma_start_desc(struc
-
- c->desc = d = to_bcm2835_dma_desc(&vd->tx);
-
-- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-- writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-- c->chan_base + BCM2835_DMA_CS);
-+ if (c->is_40bit_channel) {
-+ writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
-+ c->chan_base + BCM2838_DMA40_CB);
-+ writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2838_DMA40_CS);
-+ } else {
-+ writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
-+ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2835_DMA_CS);
-+ }
- }
-
- static irqreturn_t bcm2835_dma_callback(int irq, void *data)
-@@ -537,7 +694,8 @@ static irqreturn_t bcm2835_dma_callback(
- * will remain idle despite the ACTIVE flag being set.
- */
- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
-- BCM2835_DMA_CS_FLAGS(c->dreq),
-+ (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
-+ BCM2835_DMA_CS_FLAGS(c->dreq)),
- c->chan_base + BCM2835_DMA_CS);
-
- d = c->desc;
-@@ -640,9 +798,17 @@ static enum dma_status bcm2835_dma_tx_st
- struct bcm2835_desc *d = c->desc;
- dma_addr_t pos;
-
-- if (d->dir == DMA_MEM_TO_DEV)
-+ if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
-+ pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
-+ ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
-+ 0xff) << 8);
-+ else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
-- else if (d->dir == DMA_DEV_TO_MEM)
-+ else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
-+ pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
-+ ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
-+ 0xff) << 8);
-+ else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
- else
- pos = 0;
-@@ -688,7 +854,7 @@ static struct dma_async_tx_descriptor *b
- frames = bcm2835_dma_frames_for_length(len, max_len);
-
- /* allocate the CB chain - this also fills in the pointers */
-- d = bcm2835_dma_create_cb_chain(chan, DMA_MEM_TO_MEM, false,
-+ d = bcm2835_dma_create_cb_chain(c, DMA_MEM_TO_MEM, false,
- info, extra, frames,
- src, dst, len, 0, GFP_KERNEL);
- if (!d)
-@@ -723,11 +889,21 @@ static struct dma_async_tx_descriptor *b
- if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
- return NULL;
- src = c->cfg.src_addr;
-+ /*
-+ * One would think it ought to be possible to get the physical
-+ * to dma address mapping information from the dma-ranges DT
-+ * property, but I've not found a way yet that doesn't involve
-+ * open-coding the whole thing.
-+ */
-+ if (c->is_40bit_channel)
-+ src |= 0x400000000ull;
- info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
- } else {
- if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
- return NULL;
- dst = c->cfg.dst_addr;
-+ if (c->is_40bit_channel)
-+ dst |= 0x400000000ull;
- info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
- }
-
-@@ -735,7 +911,7 @@ static struct dma_async_tx_descriptor *b
- frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
-
- /* allocate the CB chain */
-- d = bcm2835_dma_create_cb_chain(chan, direction, false,
-+ d = bcm2835_dma_create_cb_chain(c, direction, false,
- info, extra,
- frames, src, dst, 0, 0,
- GFP_NOWAIT);
-@@ -743,7 +919,7 @@ static struct dma_async_tx_descriptor *b
- return NULL;
-
- /* fill in frames with scatterlist pointers */
-- bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
-+ bcm2835_dma_fill_cb_chain_with_sg(c, direction, d->cb_list,
- sgl, sg_len);
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
-@@ -822,7 +998,7 @@ static struct dma_async_tx_descriptor *b
- * note that we need to use GFP_NOWAIT, as the ALSA i2s dmaengine
- * implementation calls prep_dma_cyclic with interrupts disabled.
- */
-- d = bcm2835_dma_create_cb_chain(chan, direction, true,
-+ d = bcm2835_dma_create_cb_chain(c, direction, true,
- info, extra,
- frames, src, dst, buf_len,
- period_len, GFP_NOWAIT);
-@@ -830,7 +1006,8 @@ static struct dma_async_tx_descriptor *b
- return NULL;
-
- /* wrap around into a loop */
-- d->cb_list[d->frames - 1].cb->next = d->cb_list[0].paddr;
-+ d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
-+ to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
- }
-@@ -894,9 +1071,11 @@ static int bcm2835_dma_chan_init(struct
- c->irq_number = irq;
- c->irq_flags = irq_flags;
-
-- /* check in DEBUG register if this is a LITE channel */
-- if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-- BCM2835_DMA_DEBUG_LITE)
-+ /* check for 40bit and lite channels */
-+ if (d->cfg_data->chan_40bit_mask & BIT(chan_id))
-+ c->is_40bit_channel = true;
-+ else if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
-+ BCM2835_DMA_DEBUG_LITE)
- c->is_lite_channel = true;
-
- return 0;
-@@ -916,18 +1095,16 @@ static void bcm2835_dma_free(struct bcm2
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
-
--int bcm2838_dma40_memcpy_init(struct device *dev)
-+int bcm2838_dma40_memcpy_init(void)
- {
-- if (memcpy_scb)
-- return 0;
-+ if (!memcpy_parent)
-+ return -EPROBE_DEFER;
-
-- memcpy_scb = dma_alloc_coherent(dev, sizeof(*memcpy_scb),
-- &memcpy_scb_dma, GFP_KERNEL);
-+ if (!memcpy_chan)
-+ return -EINVAL;
-
-- if (!memcpy_scb) {
-- pr_err("bcm2838_dma40_memcpy_init failed!\n");
-+ if (!memcpy_scb)
- return -ENOMEM;
-- }
-
- return 0;
- }
-@@ -954,20 +1131,22 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
- scb->next_cb = 0;
-
- writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-- writel(BCM2838_DMA40_MEMCPY_QOS + BCM2838_DMA40_CS_ACTIVE,
-+ writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
- memcpy_chan + BCM2838_DMA40_CS);
-+
- /* Poll for completion */
-- while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_CS_END))
-+ while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
- cpu_relax();
-
-- writel(BCM2838_DMA40_CS_END, memcpy_chan + BCM2838_DMA40_CS);
-+ writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
-
- spin_unlock_irqrestore(&memcpy_lock, flags);
- }
- EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-
- static const struct of_device_id bcm2835_dma_of_match[] = {
-- { .compatible = "brcm,bcm2835-dma", },
-+ { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
-+ { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
- {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-@@ -999,6 +1178,8 @@ static int bcm2835_dma_probe(struct plat
- int irq_flags;
- uint32_t chans_available;
- char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
-+ const struct of_device_id *of_id;
-+ int chan_count, chan_start, chan_end;
-
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
-@@ -1020,9 +1201,13 @@ static int bcm2835_dma_probe(struct plat
- base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-- rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
-- if (rc)
-- dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
-+
-+ /* The set of channels can be split across multiple instances. */
-+ chan_start = ((u32)(uintptr_t)base / BCM2835_DMA_CHAN_SIZE) & 0xf;
-+ base -= BCM2835_DMA_CHAN(chan_start);
-+ chan_count = resource_size(res) / BCM2835_DMA_CHAN_SIZE;
-+ chan_end = min(chan_start + chan_count,
-+ BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1);
-
- od->base = base;
-
-@@ -1059,6 +1244,14 @@ static int bcm2835_dma_probe(struct plat
- return -ENOMEM;
- }
-
-+ of_id = of_match_node(bcm2835_dma_of_match, pdev->dev.of_node);
-+ if (!of_id) {
-+ dev_err(&pdev->dev, "Failed to match compatible string\n");
-+ return -EINVAL;
-+ }
-+
-+ od->cfg_data = of_id->data;
-+
- /* Request DMA channel mask from device tree */
- if (of_property_read_u32(pdev->dev.of_node,
- "brcm,dma-channel-mask",
-@@ -1068,18 +1261,34 @@ static int bcm2835_dma_probe(struct plat
- goto err_no_dma;
- }
-
-- /* Channel 0 is used by the legacy API */
-- chans_available &= ~BCM2835_DMA_BULK_MASK;
-+ /* One channel is reserved for the legacy API */
-+ if (chans_available & BCM2835_DMA_BULK_MASK) {
-+ rc = bcm_dmaman_probe(pdev, base,
-+ chans_available & BCM2835_DMA_BULK_MASK);
-+ if (rc)
-+ dev_err(&pdev->dev,
-+ "Failed to initialize the legacy API\n");
-+
-+ chans_available &= ~BCM2835_DMA_BULK_MASK;
-+ }
-
-- /* We can't use channels 11-13 yet */
-- chans_available &= ~(BIT(11) | BIT(12) | BIT(13));
-+ /* And possibly one for the 40-bit DMA memcpy API */
-+ if (chans_available & od->cfg_data->chan_40bit_mask &
-+ BIT(BCM2838_DMA_MEMCPY_CHAN)) {
-+ memcpy_parent = od;
-+ memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
-+ memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
-+ sizeof(*memcpy_scb),
-+ &memcpy_scb_dma, GFP_KERNEL);
-+ if (!memcpy_scb)
-+ dev_warn(&pdev->dev,
-+ "Failed to allocated memcpy scb\n");
-
-- /* Grab channel 14 for the 40-bit DMA memcpy */
-- chans_available &= ~BIT(14);
-- memcpy_chan = BCM2835_DMA_CHANIO(base, 14);
-+ chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
-+ }
-
- /* get irqs for each channel that we support */
-- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+ for (i = chan_start; i < chan_end; i++) {
- /* skip masked out channels */
- if (!(chans_available & (1 << i))) {
- irq[i] = -1;
-@@ -1102,13 +1311,17 @@ static int bcm2835_dma_probe(struct plat
- irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
- }
-
-+ chan_count = 0;
-+
- /* get irqs for each channel */
-- for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
-+ for (i = chan_start; i < chan_end; i++) {
- /* skip channels without irq */
- if (irq[i] < 0)
- continue;
-
- /* check if there are other channels that also use this irq */
-+ /* FIXME: This will fail if interrupts are shared across
-+ instances */
- irq_flags = 0;
- for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
- if ((i != j) && (irq[j] == irq[i])) {
-@@ -1120,9 +1333,10 @@ static int bcm2835_dma_probe(struct plat
- rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
- if (rc)
- goto err_no_dma;
-+ chan_count++;
- }
-
-- dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
-+ dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", chan_count);
-
- /* Device-tree DMA controller registration */
- rc = of_dma_controller_register(pdev->dev.of_node,
-@@ -1154,6 +1368,13 @@ static int bcm2835_dma_remove(struct pla
-
- bcm_dmaman_remove(pdev);
- dma_async_device_unregister(&od->ddev);
-+ if (memcpy_parent == od) {
-+ dma_free_coherent(&pdev->dev, sizeof(*memcpy_scb), memcpy_scb,
-+ memcpy_scb_dma);
-+ memcpy_parent = NULL;
-+ memcpy_scb = NULL;
-+ memcpy_chan = NULL;
-+ }
- bcm2835_dma_free(od);
-
- return 0;
---- a/drivers/pci/controller/pcie-brcmstb-bounce.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -91,7 +91,7 @@ struct dmabounce_device_info {
-
- static struct dmabounce_device_info *g_dmabounce_device_info;
-
--extern int bcm2838_dma40_memcpy_init(struct device *dev);
-+extern int bcm2838_dma40_memcpy_init(void);
- extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-
- #ifdef STATS
-@@ -465,9 +465,9 @@ static const struct dma_map_ops dmabounc
- .dma_supported = dmabounce_dma_supported,
- };
-
--int brcm_pcie_bounce_register_dev(struct device *dev,
-- unsigned long buffer_size,
-- dma_addr_t threshold)
-+int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
- {
- struct dmabounce_device_info *device_info;
- int ret;
-@@ -476,9 +476,9 @@ int brcm_pcie_bounce_register_dev(struct
- if (g_dmabounce_device_info)
- return -EBUSY;
-
-- ret = bcm2838_dma40_memcpy_init(dev);
-+ ret = bcm2838_dma40_memcpy_init();
- if (ret)
-- return ret;
-+ return ret;
-
- device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
- if (!device_info) {
-@@ -509,9 +509,8 @@ int brcm_pcie_bounce_register_dev(struct
- device_create_file(dev, &dev_attr_dmabounce_stats));
-
- g_dmabounce_device_info = device_info;
-- set_dma_ops(dev, &dmabounce_ops);
-
-- dev_info(dev, "dmabounce: registered device - %ld kB, threshold %pad\n",
-+ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
- buffer_size / 1024, &threshold);
-
- return 0;
-@@ -520,14 +519,13 @@ int brcm_pcie_bounce_register_dev(struct
- kfree(device_info);
- return ret;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
-
--void brcm_pcie_bounce_unregister_dev(struct device *dev)
-+void brcm_pcie_bounce_uninit(struct device *dev)
- {
- struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-
- g_dmabounce_device_info = NULL;
-- set_dma_ops(dev, NULL);
-
- if (!device_info) {
- dev_warn(dev,
-@@ -548,10 +546,16 @@ void brcm_pcie_bounce_unregister_dev(str
- device_remove_file(dev, &dev_attr_dmabounce_stats));
-
- kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+ set_dma_ops(dev, &dmabounce_ops);
-
-- dev_info(dev, "dmabounce: device unregistered\n");
-+ return 0;
- }
--EXPORT_SYMBOL(brcm_pcie_bounce_unregister_dev);
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-
- MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
- MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -8,21 +8,26 @@
-
- #ifdef CONFIG_ARM
-
--int brcm_pcie_bounce_register_dev(struct device *dev, unsigned long buffer_size,
-- dma_addr_t threshold);
--
--int brcm_pcie_bounce_unregister_dev(struct device *dev);
-+int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
-+ dma_addr_t threshold);
-+int brcm_pcie_bounce_uninit(struct device *dev);
-+int brcm_pcie_bounce_register_dev(struct device *dev);
-
- #else
-
--static inline int brcm_pcie_bounce_register_dev(struct device *dev,
-- unsigned long buffer_size,
-- dma_addr_t threshold)
-+static inline int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ return 0;
-+}
-+
-+static inline int brcm_pcie_bounce_uninit(struct device *dev)
- {
- return 0;
- }
-
--static inline int brcm_pcie_bounce_unregister_dev(struct device *dev)
-+static inline int brcm_pcie_bounce_register_dev(struct device *dev)
- {
- return 0;
- }
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -644,6 +644,7 @@ static void brcm_set_dma_ops(struct devi
-
- static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
- unsigned int val);
-+
- static int brcmstb_platform_notifier(struct notifier_block *nb,
- unsigned long event, void *__dev)
- {
-@@ -657,12 +658,11 @@ static int brcmstb_platform_notifier(str
- strcmp(dev->kobj.name, rc_name)) {
- int ret;
-
-- ret = brcm_pcie_bounce_register_dev(dev, bounce_buffer,
-- (dma_addr_t)bounce_threshold);
-+ ret = brcm_pcie_bounce_register_dev(dev);
- if (ret) {
- dev_err(dev,
- "brcm_pcie_bounce_register_dev() failed: %d\n",
-- ret);
-+ ret);
- return ret;
- }
- }
-@@ -675,8 +675,6 @@ static int brcmstb_platform_notifier(str
- brcm_pcie_perst_set(g_pcie, 1);
- msleep(100);
- brcm_pcie_perst_set(g_pcie, 0);
-- } else if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-- brcm_pcie_bounce_unregister_dev(dev);
- }
- return NOTIFY_OK;
-
-@@ -1712,6 +1710,7 @@ static int brcm_pcie_probe(struct platfo
- void __iomem *base;
- struct pci_host_bridge *bridge;
- struct pci_bus *child;
-+ extern unsigned long max_pfn;
-
- bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
- if (!bridge)
-@@ -1747,6 +1746,20 @@ static int brcm_pcie_probe(struct platfo
- if (IS_ERR(base))
- return PTR_ERR(base);
-
-+ /* To Do: Add hardware check if this ever gets fixed */
-+ if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ int ret;
-+ ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
-+ (dma_addr_t)bounce_threshold);
-+ if (ret) {
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(&pdev->dev,
-+ "could not init bounce buffers: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ }
-+
- pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
- if (IS_ERR(pcie->clk)) {
- dev_warn(&pdev->dev, "could not get clock\n");
--- /dev/null
+From 6402d9c21c9b144d528c3248607589db94ecbce0 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 3 Jul 2019 17:44:53 +0100
+Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode
+
+Allow custom HDMI modes to be specified from config.txt,
+and these then override EDID parsing.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 130 ++++++++++++++-----------
+ 1 file changed, 75 insertions(+), 55 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1066,6 +1066,56 @@ vc4_fkms_connector_detect(struct drm_con
+ return connector_status_connected;
+ }
+
++/* Queries the firmware to populate a drm_mode structure for this display */
++static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
++ struct drm_display_mode *mode)
++{
++ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
++ struct set_timings timings = { 0 };
++ int ret;
++
++ timings.display = fkms_connector->display_number;
++
++ ret = rpi_firmware_property(vc4->firmware,
++ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
++ sizeof(timings));
++ if (ret || !timings.clock)
++ /* No mode returned - abort */
++ return -1;
++
++ /* Equivalent to DRM_MODE macro. */
++ memset(mode, 0, sizeof(*mode));
++ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
++ mode->status = 0;
++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
++ mode->clock = timings.clock;
++ mode->hdisplay = timings.hdisplay;
++ mode->hsync_start = timings.hsync_start;
++ mode->hsync_end = timings.hsync_end;
++ mode->htotal = timings.htotal;
++ mode->hskew = 0;
++ mode->vdisplay = timings.vdisplay;
++ mode->vsync_start = timings.vsync_start;
++ mode->vsync_end = timings.vsync_end;
++ mode->vtotal = timings.vtotal;
++ mode->vscan = timings.vscan;
++
++ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
++ mode->flags |= DRM_MODE_FLAG_PHSYNC;
++ else
++ mode->flags |= DRM_MODE_FLAG_NHSYNC;
++
++ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
++ mode->flags |= DRM_MODE_FLAG_PVSYNC;
++ else
++ mode->flags |= DRM_MODE_FLAG_NVSYNC;
++
++ if (timings.flags & TIMINGS_FLAGS_INTERLACE)
++ mode->flags |= DRM_MODE_FLAG_INTERLACE;
++
++ return 0;
++}
++
+ static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
+ size_t len)
+ {
+@@ -1094,25 +1144,35 @@ static int vc4_fkms_connector_get_modes(
+ to_vc4_fkms_connector(connector);
+ struct drm_encoder *encoder = fkms_connector->encoder;
+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
+- int ret = 0;
++ struct drm_display_mode fw_mode;
++ struct drm_display_mode *mode;
+ struct edid *edid;
++ int num_modes;
+
+- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
+- fkms_connector);
++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
++ drm_mode_debug_printmodeline(&fw_mode);
++ mode = drm_mode_duplicate(connector->dev,
++ &fw_mode);
++ drm_mode_probed_add(connector, mode);
++ num_modes = 1; /* 1 mode */
++ } else {
++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
++ fkms_connector);
+
+- /* FIXME: Can we do CEC?
+- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
+- * if (!edid)
+- * return -ENODEV;
+- */
+-
+- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
+-
+- drm_connector_update_edid_property(connector, edid);
+- ret = drm_add_edid_modes(connector, edid);
+- kfree(edid);
++ /* FIXME: Can we do CEC?
++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
++ * if (!edid)
++ * return -ENODEV;
++ */
++
++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
++
++ drm_connector_update_edid_property(connector, edid);
++ num_modes = drm_add_edid_modes(connector, edid);
++ kfree(edid);
++ }
+
+- return ret;
++ return num_modes;
+ }
+
+ /* This is the DSI panel resolution. Use this as a default should the firmware
+@@ -1130,55 +1190,15 @@ static int vc4_fkms_lcd_connector_get_mo
+ {
+ struct vc4_fkms_connector *fkms_connector =
+ to_vc4_fkms_connector(connector);
+- struct vc4_dev *vc4 = fkms_connector->vc4_dev;
+ struct drm_display_mode *mode;
+- struct mailbox_set_mode mb = {
+- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
+- sizeof(struct set_timings), 0},
+- .timings = { .display = fkms_connector->display_number },
+- };
+ struct drm_display_mode fw_mode;
+- int ret = 0;
+-
+- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
+- if (!ret) {
+- /* Equivalent to DRM_MODE macro. */
+- memset(&fw_mode, 0, sizeof(fw_mode));
+- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
+- fw_mode.status = 0;
+- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+- fw_mode.clock = mb.timings.clock;
+- fw_mode.hdisplay = mb.timings.hdisplay;
+- fw_mode.hsync_start = mb.timings.hsync_start;
+- fw_mode.hsync_end = mb.timings.hsync_end;
+- fw_mode.htotal = mb.timings.htotal;
+- fw_mode.hskew = 0;
+- fw_mode.vdisplay = mb.timings.vdisplay;
+- fw_mode.vsync_start = mb.timings.vsync_start;
+- fw_mode.vsync_end = mb.timings.vsync_end;
+- fw_mode.vtotal = mb.timings.vtotal;
+- fw_mode.vscan = mb.timings.vscan;
+- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
+- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
+- else
+- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
+- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+
++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
+ mode = drm_mode_duplicate(connector->dev,
+ &fw_mode);
+- } else {
++ else
+ mode = drm_mode_duplicate(connector->dev,
+ &lcd_mode);
+- }
+
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+++ /dev/null
-From 7316a9e5720c2f4112a96b32c4ec78d94a44adcf Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 6 Aug 2019 15:23:14 +0100
-Subject: [PATCH] clk-bcm2835: Avoid null pointer exception
-
-clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/clk/bcm/clk-bcm2835.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -2262,9 +2262,11 @@ static bool bcm2835_clk_is_claimed(const
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
-- const char *clk_name = *(const char **)(clk_desc_array[i].data);
-- if (!strcmp(name, clk_name))
-- return bcm2835_clk_claimed[i];
-+ if (clk_desc_array[i].data) {
-+ const char *clk_name = *(const char **)(clk_desc_array[i].data);
-+ if (!strcmp(name, clk_name))
-+ return bcm2835_clk_claimed[i];
-+ }
- }
-
- return false;
--- /dev/null
+From f146d9a60f197fbf868be7eece68ff5cc58af4ff Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 11 Jul 2019 15:12:05 +0100
+Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on
+ mode set
+
+More for completeness than need, but use drm_mode_vrefresh
+to compute the vrefresh value, and pass that down to the
+firmware on mode set.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -768,8 +768,8 @@ static void vc4_crtc_mode_set_nofb(struc
+ mode->hdisplay, mode->hsync_start, mode->hsync_end,
+ mode->htotal, mode->hskew, mode->vdisplay,
+ mode->vsync_start, mode->vsync_end, mode->vtotal,
+- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
+- mode->flags);
++ mode->vscan, drm_mode_vrefresh(mode),
++ mode->picture_aspect_ratio, mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+ mb.timings.video_id_code = frame.avi.video_code;
+@@ -785,7 +785,7 @@ static void vc4_crtc_mode_set_nofb(struc
+ mb.timings.vsync_end = mode->vsync_end;
+ mb.timings.vtotal = mode->vtotal;
+ mb.timings.vscan = mode->vscan;
+- mb.timings.vrefresh = 0;
++ mb.timings.vrefresh = drm_mode_vrefresh(mode);
+ mb.timings.flags = 0;
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
--- /dev/null
+From 8a7170d2ad05ae00733e0535b281ce2e682c6f65 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 19 Jul 2019 15:35:13 +0100
+Subject: [PATCH] drm/vc4: Add support for margins to fkms
+
+Allows for overscan to be configured under FKMS.
+NB This is rescaling the planes, not reducing the size of the
+display mode.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------
+ 1 file changed, 190 insertions(+), 51 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -259,6 +259,23 @@ static inline struct vc4_crtc *to_vc4_cr
+ return container_of(crtc, struct vc4_crtc, base);
+ }
+
++struct vc4_crtc_state {
++ struct drm_crtc_state base;
++
++ 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;
++}
++
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
+@@ -367,17 +384,127 @@ static int vc4_plane_set_blank(struct dr
+ return ret;
+ }
+
++static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
++ unsigned int *left, unsigned int *right,
++ unsigned int *top, unsigned int *bottom)
++{
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector_state *conn_state;
++ struct drm_connector *conn;
++ int i;
++
++ *left = vc4_state->margins.left;
++ *right = vc4_state->margins.right;
++ *top = vc4_state->margins.top;
++ *bottom = vc4_state->margins.bottom;
++
++ /* We have to interate over all new connector states because
++ * vc4_fkms_crtc_get_margins() might be called before
++ * vc4_fkms_crtc_atomic_check() which means margins info in
++ * vc4_crtc_state might be outdated.
++ */
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != state->crtc)
++ continue;
++
++ *left = conn_state->tv.margins.left;
++ *right = conn_state->tv.margins.right;
++ *top = conn_state->tv.margins.top;
++ *bottom = conn_state->tv.margins.bottom;
++ break;
++ }
++}
++
++static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
++ struct set_plane *plane)
++{
++ unsigned int left, right, top, bottom;
++ int adjhdisplay, adjvdisplay;
++ struct drm_crtc_state *crtc_state;
++
++ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
++ pstate->crtc);
++
++ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
++
++ if (!left && !right && !top && !bottom)
++ return 0;
++
++ if (left + right >= crtc_state->mode.hdisplay ||
++ top + bottom >= crtc_state->mode.vdisplay)
++ return -EINVAL;
++
++ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
++ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
++ (int)crtc_state->mode.hdisplay);
++ plane->dst_x += left;
++ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
++ plane->dst_x = crtc_state->mode.hdisplay - left;
++
++ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
++ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
++ (int)crtc_state->mode.vdisplay);
++ plane->dst_y += top;
++ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
++ plane->dst_y = crtc_state->mode.vdisplay - top;
++
++ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
++ crtc_state->mode.hdisplay);
++ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
++ crtc_state->mode.vdisplay);
++
++ if (!plane->dst_w || !plane->dst_h)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static void vc4_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+ {
+ struct drm_plane_state *state = plane->state;
++
++ /*
++ * Do NOT set now, as we haven't checked if the crtc is active or not.
++ * Set from vc4_plane_set_blank instead.
++ *
++ * If the CRTC is on (or going to be on) and we're enabled,
++ * then unblank. Otherwise, stay blank until CRTC enable.
++ */
++ if (state->crtc->state->active)
++ vc4_plane_set_blank(plane, false);
++}
++
++static void vc4_plane_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
++{
++ struct drm_plane_state *state = plane->state;
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
++ plane->base.id, plane->name,
++ state->crtc_w,
++ state->crtc_h,
++ vc4_plane->mb.plane.vc_image_type,
++ state->crtc_x,
++ state->crtc_y);
++ vc4_plane_set_blank(plane, true);
++}
++
++static bool plane_enabled(struct drm_plane_state *state)
++{
++ return state->fb && state->crtc;
++}
++
++static int vc4_plane_to_mb(struct drm_plane *plane,
++ struct mailbox_set_plane *mb,
++ struct drm_plane_state *state)
++{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ const struct drm_format_info *drm_fmt = fb->format;
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+- struct mailbox_set_plane *mb = &vc4_plane->mb;
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+@@ -419,25 +546,7 @@ static void vc4_plane_atomic_update(stru
+ break;
+ }
+
+- /* FIXME: If the dest rect goes off screen then clip the src rect so we
+- * don't have off-screen pixels.
+- */
+- if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+- /* There is no scaling on the cursor plane, therefore the calcs
+- * to alter the source crop as the cursor goes off the screen
+- * are simple.
+- */
+- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
+- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
+- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
+- << 16;
+- }
+- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
+- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
+- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
+- << 16;
+- }
+- }
++ vc4_fkms_margins_adj(state, &mb->plane);
+
+ if (num_planes > 1) {
+ /* Assume this must be YUV */
+@@ -527,38 +636,19 @@ static void vc4_plane_atomic_update(stru
+ state->alpha,
+ state->normalized_zpos);
+
+- /*
+- * Do NOT set now, as we haven't checked if the crtc is active or not.
+- * Set from vc4_plane_set_blank instead.
+- *
+- * If the CRTC is on (or going to be on) and we're enabled,
+- * then unblank. Otherwise, stay blank until CRTC enable.
+- */
+- if (state->crtc->state->active)
+- vc4_plane_set_blank(plane, false);
++ return 0;
+ }
+
+-static void vc4_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static int vc4_plane_atomic_check(struct drm_plane *plane,
++ struct drm_plane_state *state)
+ {
+- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct drm_plane_state *state = plane->state;
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+- plane->base.id, plane->name,
+- state->crtc_w,
+- state->crtc_h,
+- vc4_plane->mb.plane.vc_image_type,
+- state->crtc_x,
+- state->crtc_y);
+- vc4_plane_set_blank(plane, true);
+-}
++ if (!plane_enabled(state))
++ return 0;
++
++ return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
+
+-static int vc4_plane_atomic_check(struct drm_plane *plane,
+- struct drm_plane_state *state)
+-{
+- return 0;
+ }
+
+ /* Called during init to allocate the plane's atomic state. */
+@@ -909,8 +999,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
+- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
+- crtc->base.id);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector *conn;
++ struct drm_connector_state *conn_state;
++ int i;
++
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
++
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != crtc)
++ continue;
++
++ vc4_state->margins.left = conn_state->tv.margins.left;
++ vc4_state->margins.right = conn_state->tv.margins.right;
++ vc4_state->margins.top = conn_state->tv.margins.top;
++ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
++ break;
++ }
+ return 0;
+ }
+
+@@ -1011,6 +1116,33 @@ static int vc4_page_flip(struct drm_crtc
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
+ }
+
++static struct drm_crtc_state *
++vc4_crtc_duplicate_state(struct drm_crtc *crtc)
++{
++ struct vc4_crtc_state *vc4_state, *old_vc4_state;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ old_vc4_state = to_vc4_crtc_state(crtc->state);
++ vc4_state->margins = old_vc4_state->margins;
++
++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
++ return &vc4_state->base;
++}
++
++static void
++vc4_crtc_reset(struct drm_crtc *crtc)
++{
++ if (crtc->state)
++ __drm_atomic_helper_crtc_destroy_state(crtc->state);
++
++ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
++ if (crtc->state)
++ crtc->state->crtc = crtc;
++}
++
+ static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+@@ -1038,8 +1170,8 @@ static const struct drm_crtc_funcs vc4_c
+ .set_property = NULL,
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+- .reset = drm_atomic_helper_crtc_reset,
+- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
++ .reset = vc4_crtc_reset,
++ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = vc4_fkms_enable_vblank,
+ .disable_vblank = vc4_fkms_disable_vblank,
+@@ -1291,6 +1423,13 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
++ /* Create and attach TV margin props to this connector. */
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ return ERR_PTR(ret);
++
++ drm_connector_attach_tv_margin_properties(connector);
++
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+
+++ /dev/null
-From 510a127017a0aada2734dbf57d25aaa0189198ff Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 7 Aug 2019 17:19:33 +0100
-Subject: [PATCH] pcie-brcmstb: Don't set DMA ops for root complex
-
-A change to arm_get_dma_map_ops has stopped get_dma_ops from working
-on the root complex, causing an error to be logged. However, there is
-no need to override the DMA ops in that case, so skip it and
-eliminate the error message.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -665,8 +665,8 @@ static int brcmstb_platform_notifier(str
- ret);
- return ret;
- }
-+ brcm_set_dma_ops(dev);
- }
-- brcm_set_dma_ops(dev);
- return NOTIFY_OK;
-
- case BUS_NOTIFY_DEL_DEVICE:
--- /dev/null
+From 9ab46d940789f74980d18715f5715992559ea857 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 19 Jul 2019 17:49:00 +0100
+Subject: [PATCH] drm/vc4: Ensure zpos is always initialised
+
+The compiler is warning that default_zpos can be used
+uninitialised as there is no default case to catch all plane
+types.
+No other plane types should ever be presented to vc4_fkms_plane_init,
+but add a default case regardless.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -804,6 +804,7 @@ static struct drm_plane *vc4_fkms_plane_
+ * other layers as requested by KMS.
+ */
+ switch (type) {
++ default:
+ case DRM_PLANE_TYPE_PRIMARY:
+ default_zpos = 0;
+ break;
+++ /dev/null
-From 907dc84e0c7208b79ad57e0e2a7964dbc9155f50 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 15 Aug 2019 08:39:08 +0100
-Subject: [PATCH] drm/vc4: Prevent load tracking from breaking FKMS
-
-Firmware KMS uses a mixture of VC4 processing and dedicated code. The
-load tracking support in VC4 assumes it is dealing with vc4_plane_state
-objects when up-casting with container_of, but FKMS uses unadorned
-drm_plane_state structures causing the VC4 code to read off the end
-into random portions of memory. Work around the problem in a minimally-
-invasive way by over-allocating the FKMS plane state structures to be
-large enough to contain a vc4_plane_state, filling the remainder with
-zeroes.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 34 ++++++++++++++++++++++++--
- 1 file changed, 32 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -561,6 +561,20 @@ static int vc4_plane_atomic_check(struct
- return 0;
- }
-
-+/* Called during init to allocate the plane's atomic state. */
-+static void vc4_plane_reset(struct drm_plane *plane)
-+{
-+ struct vc4_plane_state *vc4_state;
-+
-+ WARN_ON(plane->state);
-+
-+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
-+ if (!vc4_state)
-+ return;
-+
-+ __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
-+}
-+
- static void vc4_plane_destroy(struct drm_plane *plane)
- {
- drm_plane_cleanup(plane);
-@@ -602,13 +616,29 @@ static bool vc4_fkms_format_mod_supporte
- }
- }
-
-+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
-+{
-+ struct vc4_plane_state *vc4_state;
-+
-+ if (WARN_ON(!plane->state))
-+ return NULL;
-+
-+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
-+ if (!vc4_state)
-+ return NULL;
-+
-+ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
-+
-+ return &vc4_state->base;
-+}
-+
- static const struct drm_plane_funcs vc4_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = vc4_plane_destroy,
- .set_property = NULL,
-- .reset = drm_atomic_helper_plane_reset,
-- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-+ .reset = vc4_plane_reset,
-+ .atomic_duplicate_state = vc4_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .format_mod_supported = vc4_fkms_format_mod_supported,
- };
--- /dev/null
+From 41c059c841d40bebc358e1c9e7f30c62b2fe3b37 Mon Sep 17 00:00:00 2001
+From: Joerg Schambacher <joscha@schambacher.com>
+Date: Tue, 23 Jul 2019 16:57:35 +0200
+Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version
+
+This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC
+Signed-off-by: Joerg Schambacher joerg@i2audio.com
+---
+ sound/soc/bcm/Kconfig | 9 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++++++++
+ 3 files changed, 549 insertions(+)
+ create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -38,6 +38,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ tristate "Support for HifiBerry DAC+"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM512x
++ select COMMON_CLK_HIFIBERRY_DACPRO
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
+@@ -50,6 +51,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+ADC.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
++ tristate "Support for HifiBerry DAC+ADC PRO"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM512x_I2C
++ select SND_SOC_PCM186X_I2C
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
++snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -39,6 +40,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -0,0 +1,538 @@
++/*
++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control)
++ *
++ * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
++ * Copyright 2014-2015
++ * based on code by Florian Meier <florian.meier@koalo.de>
++ * ADC added by Joerg Schambacher <joerg@i2audio.com>
++ * Copyright 2018-19
++ *
++ * 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 <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++#include <sound/tlv.h>
++
++#include "../codecs/pcm512x.h"
++#include "../codecs/pcm186x.h"
++
++#define HIFIBERRY_DACPRO_NOCLOCK 0
++#define HIFIBERRY_DACPRO_CLK44EN 1
++#define HIFIBERRY_DACPRO_CLK48EN 2
++
++struct pcm512x_priv {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++/* Clock rate of CLK44EN attached to GPIO6 pin */
++#define CLK_44EN_RATE 22579200UL
++/* Clock rate of CLK48EN attached to GPIO3 pin */
++#define CLK_48EN_RATE 24576000UL
++
++static bool slave;
++static bool snd_rpi_hifiberry_is_dacpro;
++static bool digital_gain_0db_limit = true;
++
++static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
++ 0x00, 0x01, 0x02, 0x03, 0x10
++};
++
++static const char * const pcm186x_adcl_input_channel_sel_text[] = {
++ "No Select",
++ "VINL1[SE]", /* Default for ADCL */
++ "VINL2[SE]",
++ "VINL2[SE] + VINL1[SE]",
++ "{VIN1P, VIN1M}[DIFF]"
++};
++
++static const char * const pcm186x_adcr_input_channel_sel_text[] = {
++ "No Select",
++ "VINR1[SE]", /* Default for ADCR */
++ "VINR2[SE]",
++ "VINR2[SE] + VINR1[SE]",
++ "{VIN2P, VIN2M}[DIFF]"
++};
++
++static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
++ PCM186X_ADC_INPUT_SEL_MASK,
++ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
++ pcm186x_adcl_input_channel_sel_text,
++ pcm186x_adc_input_channel_sel_value),
++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
++ PCM186X_ADC_INPUT_SEL_MASK,
++ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
++ pcm186x_adcr_input_channel_sel_text,
++ pcm186x_adc_input_channel_sel_value),
++};
++
++static const unsigned int pcm186x_mic_bias_sel_value[] = {
++ 0x00, 0x01, 0x11
++};
++
++static const char * const pcm186x_mic_bias_sel_text[] = {
++ "Mic Bias off",
++ "Mic Bias on",
++ "Mic Bias with Bypass Resistor"
++};
++
++static const struct soc_enum pcm186x_mic_bias_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0,
++ GENMASK(4, 0),
++ ARRAY_SIZE(pcm186x_mic_bias_sel_text),
++ pcm186x_mic_bias_sel_text,
++ pcm186x_mic_bias_sel_value),
++};
++
++static const unsigned int pcm186x_gain_sel_value[] = {
++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
++ 0x50
++};
++
++static const char * const pcm186x_gain_sel_text[] = {
++ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB",
++ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB",
++ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB",
++ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB",
++ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB",
++ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB",
++ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB",
++ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB",
++ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB",
++ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB",
++ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB",
++ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB",
++ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB",
++ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB",
++ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB",
++ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB",
++ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB",
++ "39.0dB", "39.5dB", "40.0dB"};
++
++static const struct soc_enum pcm186x_gain_sel[] = {
++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0,
++ 0xff,
++ ARRAY_SIZE(pcm186x_gain_sel_text),
++ pcm186x_gain_sel_text,
++ pcm186x_gain_sel_value),
++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0,
++ 0xff,
++ ARRAY_SIZE(pcm186x_gain_sel_text),
++ pcm186x_gain_sel_text,
++ pcm186x_gain_sel_value),
++};
++
++static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = {
++ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]),
++ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]),
++ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel),
++ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]),
++ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]),
++};
++
++static int pcm1863_add_controls(struct snd_soc_component *component)
++{
++ snd_soc_add_component_controls(component,
++ pcm1863_snd_controls_card,
++ ARRAY_SIZE(pcm1863_snd_controls_card));
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_select_clk(
++ struct snd_soc_component *component, int clk_id)
++{
++ switch (clk_id) {
++ case HIFIBERRY_DACPRO_NOCLOCK:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
++ break;
++ case HIFIBERRY_DACPRO_CLK44EN:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
++ break;
++ case HIFIBERRY_DACPRO_CLK48EN:
++ snd_soc_component_update_bits(component,
++ PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
++ break;
++ }
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component)
++{
++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component)
++{
++ unsigned int sck;
++
++ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
++ return (!(sck & 0x40));
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(
++ struct snd_soc_component *component)
++{
++ msleep(2);
++ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
++}
++
++static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component)
++{
++ bool isClk44EN, isClk48En, isNoClk;
++
++ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
++ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
++ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
++ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
++
++ return (isClk44EN && isClk48En && !isNoClk);
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate)
++{
++ int type;
++
++ switch (sample_rate) {
++ case 11025:
++ case 22050:
++ case 44100:
++ case 88200:
++ case 176400:
++ case 352800:
++ type = HIFIBERRY_DACPRO_CLK44EN;
++ break;
++ default:
++ type = HIFIBERRY_DACPRO_CLK48EN;
++ break;
++ }
++ return type;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component,
++ int sample_rate)
++{
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++
++ if (!IS_ERR(pcm512x->sclk)) {
++ int ctype;
++
++ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate);
++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
++ ? CLK_44EN_RATE : CLK_48EN_RATE);
++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype);
++ }
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver;
++ struct pcm512x_priv *priv;
++ int ret;
++
++ if (slave)
++ snd_rpi_hifiberry_is_dacpro = false;
++ else
++ snd_rpi_hifiberry_is_dacpro =
++ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac);
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++
++ dai->name = "HiFiBerry DAC+ADC Pro";
++ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
++
++ // set DAC DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM);
++ if (ret < 0)
++ return ret;
++
++ // set ADC DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1],
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ // set CPU DAI configuration
++ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
++ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03);
++ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
++ } else {
++ priv = snd_soc_component_get_drvdata(dac);
++ priv->sclk = ERR_PTR(-ENOENT);
++ }
++
++ /* disable 24bit mode as long as I2S module does not have sign extension fixed */
++ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE;
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ ret = pcm1863_add_controls(adc);
++ if (ret < 0)
++ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
++ ret);
++
++ /* set GPIO2 to output, GPIO3 input */
++ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
++ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++
++ if (digital_gain_0db_limit) {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */
++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
++ struct snd_ratnum *rats_no_pll;
++ unsigned int num = 0, den = 0;
++ int err;
++
++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
++ if (!rats_no_pll)
++ return -ENOMEM;
++
++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
++ rats_no_pll->den_min = 1;
++ rats_no_pll->den_max = 128;
++ rats_no_pll->den_step = 1;
++
++ err = snd_interval_ratnum(hw_param_interval(params,
++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
++ if (err >= 0 && den) {
++ params->rate_num = num;
++ params->rate_den = den;
++ }
++
++ devm_kfree(rtd->dev, rats_no_pll);
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ int channels = params_channels(params);
++ int width = 32;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++
++ if (snd_rpi_hifiberry_is_dacpro) {
++
++ width = snd_pcm_format_physical_width(params_format(params));
++
++ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac,
++ params_rate(params));
++
++ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
++ substream, params);
++ if (ret)
++ return ret;
++ }
++
++ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
++ channels, width);
++ if (ret)
++ return ret;
++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03,
++ channels, width);
++ if (ret)
++ return ret;
++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03,
++ channels, width);
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplusadcpro_startup(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++
++ /* switch on respective LED */
++ if (!substream->stream)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplusadcpro_shutdown(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
++ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
++
++ /* switch off respective LED */
++ if (!substream->stream)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
++}
++
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = {
++ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params,
++ .startup = snd_rpi_hifiberry_dacplusadcpro_startup,
++ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
++};
++
++static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
++ {
++ .name = "pcm512x.1-004d",
++ .dai_name = "pcm512x-hifi",
++ },
++ {
++ .name = "pcm186x.1-004a",
++ .dai_name = "pcm1863-aif",
++ },
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
++{
++ .name = "HiFiBerry DAC+ADC PRO",
++ .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .platform_name = "bcm2708-i2s.0",
++ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
++ .num_codecs = 2,
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
++ .init = snd_rpi_hifiberry_dacplusadcpro_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = {
++ .name = "snd_rpi_hifiberry_dacplusadcpro",
++ .driver_name = "HifiberryDacpAdcPro",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai),
++};
++
++static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev)
++{
++ int ret = 0, i = 0;
++ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro;
++
++ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev;
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++ if (i2s_node) {
++ for (i = 0; i < card->num_links; i++) {
++ dai->cpu_dai_name = NULL;
++ dai->cpu_of_node = i2s_node;
++ dai->platform_name = NULL;
++ dai->platform_of_node = i2s_node;
++ }
++ }
++ }
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
++ slave = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadcpro,slave");
++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
++ 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 snd_rpi_hifiberry_dacplusadcpro_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplusadcpro", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplusadcpro",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplusadcpro_probe,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver);
++
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From ba05797f8e3578398a1ab6c835f6b100d4f46edb Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Mon, 14 Jan 2019 15:13:17 -0800
-Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now.
-
-Something is still unstable -- on starting a new glxgears from an idle
-X11, I get an MMU violation in high addresses. The CTS also failed
-quite quickly. With this, CTS progresses for an hour before OOMing
-(allocating some big buffers when my board only has 600MB available to
-Linux)
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +---------------
- drivers/gpu/drm/v3d/v3d_drv.c | 9 ---------
- 2 files changed, 1 insertion(+), 24 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_debugfs.c
-+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
-@@ -4,7 +4,6 @@
- #include <linux/circ_buf.h>
- #include <linux/ctype.h>
- #include <linux/debugfs.h>
--#include <linux/pm_runtime.h>
- #include <linux/seq_file.h>
-
- #include <drm/drm_debugfs.h>
-@@ -130,11 +129,8 @@ static int v3d_v3d_debugfs_ident(struct
- struct drm_device *dev = node->minor->dev;
- struct v3d_dev *v3d = to_v3d_dev(dev);
- u32 ident0, ident1, ident2, ident3, cores;
-- int ret, core;
-+ int core;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
-
- ident0 = V3D_READ(V3D_HUB_IDENT0);
- ident1 = V3D_READ(V3D_HUB_IDENT1);
-@@ -187,9 +183,6 @@ static int v3d_v3d_debugfs_ident(struct
- (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
- }
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
--
- return 0;
- }
-
-@@ -217,11 +210,6 @@ static int v3d_measure_clock(struct seq_
- uint32_t cycles;
- int core = 0;
- int measure_ms = 1000;
-- int ret;
--
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
-
- if (v3d->ver >= 40) {
- V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
-@@ -245,8 +233,6 @@ static int v3d_measure_clock(struct seq_
- cycles / (measure_ms * 1000),
- (cycles / (measure_ms * 100)) % 10);
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
-
- return 0;
- }
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -78,7 +78,6 @@ static int v3d_get_param_ioctl(struct dr
- {
- struct v3d_dev *v3d = to_v3d_dev(dev);
- struct drm_v3d_get_param *args = data;
-- int ret;
- static const u32 reg_map[] = {
- [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG,
- [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1,
-@@ -104,17 +103,12 @@ static int v3d_get_param_ioctl(struct dr
- if (args->value != 0)
- return -EINVAL;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
- if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 &&
- args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) {
- args->value = V3D_CORE_READ(0, offset);
- } else {
- args->value = V3D_READ(offset);
- }
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
- return 0;
- }
-
-@@ -302,9 +296,6 @@ static int v3d_platform_drm_probe(struct
- goto dev_free;
- }
-
-- pm_runtime_use_autosuspend(dev);
-- pm_runtime_set_autosuspend_delay(dev, 50);
-- pm_runtime_enable(dev);
-
- ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev);
- if (ret)
+++ /dev/null
-From ca8579839f0ebf0ffe73d1135284363b2155e712 Mon Sep 17 00:00:00 2001
-From: Eric Anholt <eric@anholt.net>
-Date: Thu, 2 May 2019 13:22:53 -0700
-Subject: [PATCH] drm/v3d: Clock V3D down when not in use.
-
-My various attempts at re-enabling runtime PM have failed, so just
-crank the clock down when V3D is idle to reduce power consumption.
-
-Signed-off-by: Eric Anholt <eric@anholt.net>
----
- drivers/gpu/drm/v3d/v3d_drv.c | 18 ++++++++++++
- drivers/gpu/drm/v3d/v3d_drv.h | 6 ++++
- drivers/gpu/drm/v3d/v3d_gem.c | 53 +++++++++++++++++++++++++++++++----
- 3 files changed, 72 insertions(+), 5 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -282,6 +282,21 @@ static int v3d_platform_drm_probe(struct
- }
- }
-
-+ v3d->clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(v3d->clk)) {
-+ if (ret != -EPROBE_DEFER)
-+ dev_err(dev, "Failed to get clock\n");
-+ goto dev_free;
-+ }
-+ v3d->clk_up_rate = clk_get_rate(v3d->clk);
-+ /* For downclocking, drop it to the minimum frequency we can get from
-+ * the CPRMAN clock generator dividing off our parent. The divider is
-+ * 4 bits, but ask for just higher than that so that rounding doesn't
-+ * make cprman reject our rate.
-+ */
-+ v3d->clk_down_rate =
-+ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
-+
- if (v3d->ver < 41) {
- ret = map_regs(v3d, &v3d->gca_regs, "gca");
- if (ret)
-@@ -316,6 +331,9 @@ static int v3d_platform_drm_probe(struct
- if (ret)
- goto irq_disable;
-
-+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
-+ WARN_ON_ONCE(ret != 0);
-+
- return 0;
-
- irq_disable:
---- a/drivers/gpu/drm/v3d/v3d_drv.h
-+++ b/drivers/gpu/drm/v3d/v3d_drv.h
-@@ -54,6 +54,12 @@ struct v3d_dev {
- void __iomem *bridge_regs;
- void __iomem *gca_regs;
- struct clk *clk;
-+ struct delayed_work clk_down_work;
-+ unsigned long clk_up_rate, clk_down_rate;
-+ struct mutex clk_lock;
-+ u32 clk_refcount;
-+ bool clk_up;
-+
- struct reset_control *reset;
-
- /* Virtual and DMA addresses of the single shared page table. */
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -4,6 +4,7 @@
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
- #include <linux/io.h>
-+#include <linux/clk.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
-@@ -19,6 +20,47 @@
- #include "v3d_trace.h"
-
- static void
-+v3d_clock_down_work(struct work_struct *work)
-+{
-+ struct v3d_dev *v3d =
-+ container_of(work, struct v3d_dev, clk_down_work.work);
-+ int ret;
-+
-+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
-+ v3d->clk_up = false;
-+ WARN_ON_ONCE(ret != 0);
-+}
-+
-+static void
-+v3d_clock_up_get(struct v3d_dev *v3d)
-+{
-+ mutex_lock(&v3d->clk_lock);
-+ if (v3d->clk_refcount++ == 0) {
-+ cancel_delayed_work_sync(&v3d->clk_down_work);
-+ if (!v3d->clk_up) {
-+ int ret;
-+
-+ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
-+ WARN_ON_ONCE(ret != 0);
-+ v3d->clk_up = true;
-+ }
-+ }
-+ mutex_unlock(&v3d->clk_lock);
-+}
-+
-+static void
-+v3d_clock_up_put(struct v3d_dev *v3d)
-+{
-+ mutex_lock(&v3d->clk_lock);
-+ if (--v3d->clk_refcount == 0) {
-+ schedule_delayed_work(&v3d->clk_down_work,
-+ msecs_to_jiffies(100));
-+ }
-+ mutex_unlock(&v3d->clk_lock);
-+}
-+
-+
-+static void
- v3d_init_core(struct v3d_dev *v3d, int core)
- {
- /* Set OVRTMUOUT, which means that the texture sampler uniform
-@@ -354,6 +396,7 @@ v3d_job_free(struct kref *ref)
- struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
- unsigned long index;
- struct dma_fence *fence;
-+ struct v3d_dev *v3d = job->v3d;
- int i;
-
- for (i = 0; i < job->bo_count; i++) {
-@@ -367,11 +410,7 @@ v3d_job_free(struct kref *ref)
- }
- xa_destroy(&job->deps);
-
-- dma_fence_put(job->irq_fence);
-- dma_fence_put(job->done_fence);
--
-- pm_runtime_mark_last_busy(job->v3d->dev);
-- pm_runtime_put_autosuspend(job->v3d->dev);
-+ v3d_clock_up_put(v3d);
-
- kfree(job);
- }
-@@ -453,6 +492,7 @@ v3d_job_init(struct v3d_dev *v3d, struct
- if (ret)
- goto fail;
-
-+ v3d_clock_up_get(v3d);
- kref_init(&job->refcount);
-
- return 0;
-@@ -841,6 +881,9 @@ v3d_gem_init(struct drm_device *dev)
- mutex_init(&v3d->sched_lock);
- mutex_init(&v3d->cache_clean_lock);
-
-+ mutex_init(&v3d->clk_lock);
-+ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
-+
- /* Note: We don't allocate address 0. Various bits of HW
- * treat 0 as special, such as the occlusion query counters
- * where 0 means "disabled".
--- /dev/null
+From 88d5709082671ff2abeddc2a9b4acacbb85b9194 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 31 Jul 2019 17:36:34 +0100
+Subject: [PATCH] drm/vc4: A present but empty dmas disables audio
+
+Overlays are unable to remove properties in the base DTB, but they
+can overwrite them. Allow a present but empty 'dmas' property
+to also disable the HDMI audio interface.
+
+See: https://github.com/raspberrypi/linux/issues/2489
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ 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
+@@ -1054,10 +1054,12 @@ static int vc4_hdmi_audio_init(struct vc
+ struct device *dev = &hdmi->pdev->dev;
+ const __be32 *addr;
+ int ret;
++ int len;
+
+- if (!of_find_property(dev->of_node, "dmas", NULL)) {
++ if (!of_find_property(dev->of_node, "dmas", &len) ||
++ len == 0) {
+ dev_warn(dev,
+- "'dmas' DT property is missing, no HDMI audio\n");
++ "'dmas' DT property is missing or empty, no HDMI audio\n");
+ return 0;
+ }
+
+++ /dev/null
-From 638f29943041f9205486a03587b7bd9e64799b2a Mon Sep 17 00:00:00 2001
-From: Hermann Lauer <hlauer@seba.iwr.uni-heidelberg.de>
-Date: Thu, 8 Aug 2019 15:40:37 +0200
-Subject: [PATCH] According to 5713 pdf doc CLOCK_CTRL is a readonly
- status register, and it behaves so. Remove useless setting
-
----
- sound/soc/codecs/tas5713.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
---- a/sound/soc/codecs/tas5713.c
-+++ b/sound/soc/codecs/tas5713.c
-@@ -190,10 +190,6 @@ static int tas5713_probe(struct snd_soc_
- ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
- if (ret < 0) return ret;
-
-- // Clock mode: 44/48kHz, MCLK=64xfs
-- ret = snd_soc_component_write(component, TAS5713_CLOCK_CTRL, 0x60);
-- if (ret < 0) return ret;
--
- // I2S 24bit
- ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
- if (ret < 0) return ret;
-@@ -257,6 +253,7 @@ static bool tas5713_reg_volatile(struct
- switch (reg) {
- case TAS5713_DEVICE_ID:
- case TAS5713_ERROR_STATUS:
-+ case TAS5713_CLOCK_CTRL:
- return true;
- default:
- return false;
--- /dev/null
+From d6baa1bd90e7e68ac69d5378d70174ea67bf35dc Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Mon, 29 Jul 2019 12:02:59 +0100
+Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display
+
+If an errant interrupt flag was received from a non-existent display,
+a NULL pointer access was made. Protect against this by checking if a
+second display is present prior to checking the interrupt flags.
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1087,14 +1087,17 @@ static irqreturn_t vc4_crtc_irq_handler(
+ vc4_crtc_handle_page_flip(crtc_list[0]);
+ }
+
+- /* Check for the secondary display too */
+- chan = readl(crtc_list[0]->regs + SMIDSW1);
++ if (crtc_list[1]) {
++ /* Check for the secondary display too */
++ chan = readl(crtc_list[0]->regs + SMIDSW1);
+
+- if (chan & 1) {
+- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
+- if (crtc_list[1]->vblank_enabled)
+- drm_crtc_handle_vblank(&crtc_list[1]->base);
+- vc4_crtc_handle_page_flip(crtc_list[1]);
++ if (chan & 1) {
++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
++
++ if (crtc_list[1]->vblank_enabled)
++ drm_crtc_handle_vblank(&crtc_list[1]->base);
++ vc4_crtc_handle_page_flip(crtc_list[1]);
++ }
+ }
+ }
+
+++ /dev/null
-From 60f3db31d4cb785befed715b80c430f60f647701 Mon Sep 17 00:00:00 2001
-From: yaroslavros <yaroslavros@gmail.com>
-Date: Wed, 14 Aug 2019 15:22:55 +0100
-Subject: [PATCH] Ported pcie-brcmstb bounce buffer implementation to
- ARM64. (#3144)
-
-Ported pcie-brcmstb bounce buffer implementation to ARM64.
-This enables full 4G RAM usage on Raspberry Pi in 64-bit mode.
-
-Signed-off-by: Yaroslav Rosomakho <yaroslavros@gmail.com>
----
- arch/arm64/mm/dma-mapping.c | 29 +
- drivers/pci/controller/Makefile | 3 +
- drivers/pci/controller/pcie-brcmstb-bounce.h | 2 +-
- .../pci/controller/pcie-brcmstb-bounce64.c | 569 ++++++++++++++++++
- drivers/pci/controller/pcie-brcmstb.c | 32 +-
- 5 files changed, 610 insertions(+), 25 deletions(-)
- create mode 100644 drivers/pci/controller/pcie-brcmstb-bounce64.c
-
---- a/arch/arm64/mm/dma-mapping.c
-+++ b/arch/arm64/mm/dma-mapping.c
-@@ -31,6 +31,35 @@ void arch_dma_prep_coherent(struct page
- }
-
- #ifdef CONFIG_IOMMU_DMA
-+static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
-+ struct page *page, size_t size)
-+{
-+ int ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
-+
-+ if (!ret)
-+ sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
-+
-+ return ret;
-+}
-+
-+static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
-+ unsigned long pfn, size_t size)
-+{
-+ int ret = -ENXIO;
-+ unsigned long nr_vma_pages = vma_pages(vma);
-+ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-+ unsigned long off = vma->vm_pgoff;
-+
-+ if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
-+ ret = remap_pfn_range(vma, vma->vm_start,
-+ pfn + off,
-+ vma->vm_end - vma->vm_start,
-+ vma->vm_page_prot);
-+ }
-+
-+ return ret;
-+}
-+
- void arch_teardown_dma_ops(struct device *dev)
- {
- dev->dma_ops = NULL;
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -33,6 +33,9 @@ obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcms
- ifdef CONFIG_ARM
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce.o
- endif
-+ifdef CONFIG_ARM64
-+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb-bounce64.o
-+endif
-
- obj-$(CONFIG_VMD) += vmd.o
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
---- a/drivers/pci/controller/pcie-brcmstb-bounce.h
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.h
-@@ -6,7 +6,7 @@
- #ifndef _PCIE_BRCMSTB_BOUNCE_H
- #define _PCIE_BRCMSTB_BOUNCE_H
-
--#ifdef CONFIG_ARM
-+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-
- int brcm_pcie_bounce_init(struct device *dev, unsigned long buffer_size,
- dma_addr_t threshold);
---- /dev/null
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -0,0 +1,569 @@
-+/*
-+ * This code started out as a version of arch/arm/common/dmabounce.c,
-+ * modified to cope with highmem pages. Now it has been changed heavily -
-+ * it now preallocates a large block (currently 4MB) and carves it up
-+ * sequentially in ring fashion, and DMA is used to copy the data - to the
-+ * point where very little of the original remains.
-+ *
-+ * Copyright (C) 2019 Raspberry Pi (Trading) Ltd.
-+ *
-+ * Original version by Brad Parker (brad@heeltoe.com)
-+ * Re-written by Christopher Hoover <ch@murgatroid.com>
-+ * Made generic by Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ * Copyright (C) 2002 Hewlett Packard Company.
-+ * Copyright (C) 2004 MontaVista Software, Inc.
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/page-flags.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-direct.h>
-+#include <linux/dma-noncoherent.h>
-+#include <linux/dmapool.h>
-+#include <linux/list.h>
-+#include <linux/scatterlist.h>
-+#include <linux/bitmap.h>
-+#include <linux/swiotlb.h>
-+
-+#include <asm/cacheflush.h>
-+
-+#define STATS
-+
-+#ifdef STATS
-+#define DO_STATS(X) do { X ; } while (0)
-+#else
-+#define DO_STATS(X) do { } while (0)
-+#endif
-+
-+/* ************************************************** */
-+
-+struct safe_buffer {
-+ struct list_head node;
-+
-+ /* original request */
-+ size_t size;
-+ int direction;
-+
-+ struct dmabounce_pool *pool;
-+ void *safe;
-+ dma_addr_t unsafe_dma_addr;
-+ dma_addr_t safe_dma_addr;
-+};
-+
-+struct dmabounce_pool {
-+ unsigned long pages;
-+ void *virt_addr;
-+ dma_addr_t dma_addr;
-+ unsigned long *alloc_map;
-+ unsigned long alloc_pos;
-+ spinlock_t lock;
-+ struct device *dev;
-+ unsigned long num_pages;
-+#ifdef STATS
-+ size_t max_size;
-+ unsigned long num_bufs;
-+ unsigned long max_bufs;
-+ unsigned long max_pages;
-+#endif
-+};
-+
-+struct dmabounce_device_info {
-+ struct device *dev;
-+ dma_addr_t threshold;
-+ struct list_head safe_buffers;
-+ struct dmabounce_pool pool;
-+ rwlock_t lock;
-+#ifdef STATS
-+ unsigned long map_count;
-+ unsigned long unmap_count;
-+ unsigned long sync_dev_count;
-+ unsigned long sync_cpu_count;
-+ unsigned long fail_count;
-+ int attr_res;
-+#endif
-+};
-+
-+static struct dmabounce_device_info *g_dmabounce_device_info;
-+
-+extern int bcm2838_dma40_memcpy_init(void);
-+extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+
-+#ifdef STATS
-+static ssize_t
-+bounce_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ return sprintf(buf, "m:%lu/%lu s:%lu/%lu f:%lu s:%zu b:%lu/%lu a:%lu/%lu\n",
-+ device_info->map_count,
-+ device_info->unmap_count,
-+ device_info->sync_dev_count,
-+ device_info->sync_cpu_count,
-+ device_info->fail_count,
-+ device_info->pool.max_size,
-+ device_info->pool.num_bufs,
-+ device_info->pool.max_bufs,
-+ device_info->pool.num_pages * PAGE_SIZE,
-+ device_info->pool.max_pages * PAGE_SIZE);
-+}
-+
-+static DEVICE_ATTR(dmabounce_stats, 0444, bounce_show, NULL);
-+#endif
-+
-+static int bounce_create(struct dmabounce_pool *pool, struct device *dev,
-+ unsigned long buffer_size)
-+{
-+ int ret = -ENOMEM;
-+ pool->pages = (buffer_size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pool->alloc_map = bitmap_zalloc(pool->pages, GFP_KERNEL);
-+ if (!pool->alloc_map)
-+ goto err_bitmap;
-+ pool->virt_addr = dma_alloc_coherent(dev, pool->pages * PAGE_SIZE,
-+ &pool->dma_addr, GFP_KERNEL);
-+ if (!pool->virt_addr)
-+ goto err_dmabuf;
-+
-+ pool->alloc_pos = 0;
-+ spin_lock_init(&pool->lock);
-+ pool->dev = dev;
-+ pool->num_pages = 0;
-+
-+ DO_STATS(pool->max_size = 0);
-+ DO_STATS(pool->num_bufs = 0);
-+ DO_STATS(pool->max_bufs = 0);
-+ DO_STATS(pool->max_pages = 0);
-+
-+ return 0;
-+
-+err_dmabuf:
-+ bitmap_free(pool->alloc_map);
-+err_bitmap:
-+ return ret;
-+}
-+
-+static void bounce_destroy(struct dmabounce_pool *pool)
-+{
-+ dma_free_coherent(pool->dev, pool->pages * PAGE_SIZE, pool->virt_addr,
-+ pool->dma_addr);
-+
-+ bitmap_free(pool->alloc_map);
-+}
-+
-+static void *bounce_alloc(struct dmabounce_pool *pool, size_t size,
-+ dma_addr_t *dmaaddrp)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+
-+ DO_STATS(pool->max_size = max(size, pool->max_size));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ pool->alloc_pos, pages, 0);
-+ /* If not found, try from the start */
-+ if (pos >= pool->pages && pool->alloc_pos)
-+ pos = bitmap_find_next_zero_area(pool->alloc_map, pool->pages,
-+ 0, pages, 0);
-+
-+ if (pos >= pool->pages) {
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+ return NULL;
-+ }
-+
-+ bitmap_set(pool->alloc_map, pos, pages);
-+ pool->alloc_pos = (pos + pages) % pool->pages;
-+ pool->num_pages += pages;
-+
-+ DO_STATS(pool->num_bufs++);
-+ DO_STATS(pool->max_bufs = max(pool->num_bufs, pool->max_bufs));
-+ DO_STATS(pool->max_pages = max(pool->num_pages, pool->max_pages));
-+
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+
-+ *dmaaddrp = pool->dma_addr + pos * PAGE_SIZE;
-+
-+ return pool->virt_addr + pos * PAGE_SIZE;
-+}
-+
-+static void
-+bounce_free(struct dmabounce_pool *pool, void *buf, size_t size)
-+{
-+ unsigned long pages;
-+ unsigned long flags;
-+ unsigned long pos;
-+
-+ pages = (size + PAGE_SIZE - 1)/PAGE_SIZE;
-+ pos = (buf - pool->virt_addr)/PAGE_SIZE;
-+
-+ BUG_ON((buf - pool->virt_addr) & (PAGE_SIZE - 1));
-+
-+ spin_lock_irqsave(&pool->lock, flags);
-+ bitmap_clear(pool->alloc_map, pos, pages);
-+ pool->num_pages -= pages;
-+ if (pool->num_pages == 0)
-+ pool->alloc_pos = 0;
-+ DO_STATS(pool->num_bufs--);
-+ spin_unlock_irqrestore(&pool->lock, flags);
-+}
-+
-+/* allocate a 'safe' buffer and keep track of it */
-+static struct safe_buffer *
-+alloc_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t dma_addr, size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+ struct dmabounce_pool *pool = &device_info->pool;
-+ struct device *dev = device_info->dev;
-+ unsigned long flags;
-+
-+ /*
-+ * Although one might expect this to be called in thread context,
-+ * using GFP_KERNEL here leads to hard-to-debug lockups. in_atomic()
-+ * was previously used to select the appropriate allocation mode,
-+ * but this is unsafe.
-+ */
-+ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
-+ if (!buf) {
-+ dev_warn(dev, "%s: kmalloc failed\n", __func__);
-+ return NULL;
-+ }
-+
-+ buf->unsafe_dma_addr = dma_addr;
-+ buf->size = size;
-+ buf->direction = dir;
-+ buf->pool = pool;
-+
-+ buf->safe = bounce_alloc(pool, size, &buf->safe_dma_addr);
-+
-+ if (!buf->safe) {
-+ dev_warn(dev,
-+ "%s: could not alloc dma memory (size=%zu)\n",
-+ __func__, size);
-+ kfree(buf);
-+ return NULL;
-+ }
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_add(&buf->node, &device_info->safe_buffers);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ return buf;
-+}
-+
-+/* determine if a buffer is from our "safe" pool */
-+static struct safe_buffer *
-+find_safe_buffer(struct dmabounce_device_info *device_info,
-+ dma_addr_t safe_dma_addr)
-+{
-+ struct safe_buffer *b, *rb = NULL;
-+ unsigned long flags;
-+
-+ read_lock_irqsave(&device_info->lock, flags);
-+
-+ list_for_each_entry(b, &device_info->safe_buffers, node)
-+ if (b->safe_dma_addr <= safe_dma_addr &&
-+ b->safe_dma_addr + b->size > safe_dma_addr) {
-+ rb = b;
-+ break;
-+ }
-+
-+ read_unlock_irqrestore(&device_info->lock, flags);
-+ return rb;
-+}
-+
-+static void
-+free_safe_buffer(struct dmabounce_device_info *device_info,
-+ struct safe_buffer *buf)
-+{
-+ unsigned long flags;
-+
-+ write_lock_irqsave(&device_info->lock, flags);
-+ list_del(&buf->node);
-+ write_unlock_irqrestore(&device_info->lock, flags);
-+
-+ bounce_free(buf->pool, buf->safe, buf->size);
-+
-+ kfree(buf);
-+}
-+
-+/* ************************************************** */
-+
-+static struct safe_buffer *
-+find_safe_buffer_dev(struct device *dev, dma_addr_t dma_addr, const char *where)
-+{
-+ if (!dev || !g_dmabounce_device_info)
-+ return NULL;
-+ if (dma_mapping_error(dev, dma_addr)) {
-+ dev_err(dev, "Trying to %s invalid mapping\n", where);
-+ return NULL;
-+ }
-+ return find_safe_buffer(g_dmabounce_device_info, dma_addr);
-+}
-+
-+static dma_addr_t
-+map_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ dev_dbg(dev, "map: %llx->%llx\n", (u64)buf->unsafe_dma_addr,
-+ (u64)buf->safe_dma_addr);
-+
-+ if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-+ bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ size);
-+
-+ return buf->safe_dma_addr;
-+}
-+
-+static dma_addr_t
-+unmap_single(struct device *dev, struct safe_buffer *buf, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ BUG_ON(buf->size != size);
-+ BUG_ON(buf->direction != dir);
-+
-+ if ((dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) &&
-+ !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
-+ dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
-+ (u64)buf->unsafe_dma_addr);
-+
-+ bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ size);
-+ }
-+ return buf->unsafe_dma_addr;
-+}
-+
-+/* ************************************************** */
-+
-+/*
-+ * see if a buffer address is in an 'unsafe' range. if it is
-+ * allocate a 'safe' buffer and copy the unsafe buffer into it.
-+ * substitute the safe buffer for the unsafe one.
-+ * (basically move the buffer from an unsafe area to a safe one)
-+ */
-+static dma_addr_t
-+dmabounce_map_page(struct device *dev, struct page *page, unsigned long offset,
-+ size_t size, enum dma_data_direction dir,
-+ unsigned long attrs)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+ dma_addr_t dma_addr;
-+
-+ dma_addr = phys_to_dma(dev, page_to_phys(page)) + offset;
-+
-+ dma_direct_sync_single_for_device(dev, dma_addr, size, dir);
-+ if (!dev_is_dma_coherent(dev))
-+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+ if (device_info && (dma_addr + size) > device_info->threshold) {
-+ struct safe_buffer *buf;
-+
-+ buf = alloc_safe_buffer(device_info, dma_addr, size, dir);
-+ if (!buf) {
-+ DO_STATS(device_info->fail_count++);
-+ return (~(dma_addr_t)0x0);
-+ }
-+
-+ DO_STATS(device_info->map_count++);
-+
-+ dma_addr = map_single(dev, buf, size, dir, attrs);
-+ }
-+ return dma_addr;
-+}
-+
-+/*
-+ * see if a mapped address was really a "safe" buffer and if so, copy
-+ * the data from the safe buffer back to the unsafe buffer and free up
-+ * the safe buffer. (basically return things back to the way they
-+ * should be)
-+ */
-+static void
-+dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir, unsigned long attrs)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->unmap_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, attrs);
-+ free_safe_buffer(g_dmabounce_device_info, buf);
-+ }
-+
-+ if (!dev_is_dma_coherent(dev))
-+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+ dma_direct_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+/*
-+ * A version of dmabounce_map_page that assumes the mapping has already
-+ * been created - intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_device(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ dma_direct_sync_single_for_device(dev, dma_addr, size, dir);
-+ if (!dev_is_dma_coherent(dev))
-+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_dev_count++);
-+ map_single(dev, buf, size, dir, 0);
-+ }
-+}
-+
-+/*
-+ * A version of dmabounce_unmap_page that doesn't destroy the mapping -
-+ * intended for streaming operation.
-+ */
-+static void
-+dmabounce_sync_for_cpu(struct device *dev, dma_addr_t dma_addr,
-+ size_t size, enum dma_data_direction dir)
-+{
-+ struct safe_buffer *buf;
-+
-+ buf = find_safe_buffer_dev(dev, dma_addr, __func__);
-+ if (buf) {
-+ DO_STATS(g_dmabounce_device_info->sync_cpu_count++);
-+ dma_addr = unmap_single(dev, buf, size, dir, 0);
-+ }
-+
-+ if (!dev_is_dma_coherent(dev))
-+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dma_addr)), size, dir);
-+ dma_direct_sync_single_for_cpu(dev, dma_addr, size, dir);
-+}
-+
-+static int dmabounce_dma_supported(struct device *dev, u64 dma_mask)
-+{
-+ if (g_dmabounce_device_info)
-+ return 0;
-+
-+ return dma_direct_supported(dev, dma_mask);
-+}
-+
-+static const struct dma_map_ops dmabounce_ops = {
-+ .alloc = dma_direct_alloc,
-+ .free = dma_direct_free,
-+ .map_page = dmabounce_map_page,
-+ .unmap_page = dmabounce_unmap_page,
-+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
-+ .sync_single_for_device = dmabounce_sync_for_device,
-+ .map_sg = dma_direct_map_sg,
-+ .unmap_sg = dma_direct_unmap_sg,
-+ .sync_sg_for_cpu = dma_direct_sync_sg_for_cpu,
-+ .sync_sg_for_device = dma_direct_sync_sg_for_device,
-+ .dma_supported = dmabounce_dma_supported,
-+};
-+
-+int brcm_pcie_bounce_init(struct device *dev,
-+ unsigned long buffer_size,
-+ dma_addr_t threshold)
-+{
-+ struct dmabounce_device_info *device_info;
-+ int ret;
-+
-+ /* Only support a single client */
-+ if (g_dmabounce_device_info)
-+ return -EBUSY;
-+
-+ ret = bcm2838_dma40_memcpy_init();
-+ if (ret)
-+ return ret;
-+
-+ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC);
-+ if (!device_info) {
-+ dev_err(dev,
-+ "Could not allocated dmabounce_device_info\n");
-+ return -ENOMEM;
-+ }
-+
-+ ret = bounce_create(&device_info->pool, dev, buffer_size);
-+ if (ret) {
-+ dev_err(dev,
-+ "dmabounce: could not allocate %ld byte DMA pool\n",
-+ buffer_size);
-+ goto err_bounce;
-+ }
-+
-+ device_info->dev = dev;
-+ device_info->threshold = threshold;
-+ INIT_LIST_HEAD(&device_info->safe_buffers);
-+ rwlock_init(&device_info->lock);
-+
-+ DO_STATS(device_info->map_count = 0);
-+ DO_STATS(device_info->unmap_count = 0);
-+ DO_STATS(device_info->sync_dev_count = 0);
-+ DO_STATS(device_info->sync_cpu_count = 0);
-+ DO_STATS(device_info->fail_count = 0);
-+ DO_STATS(device_info->attr_res =
-+ device_create_file(dev, &dev_attr_dmabounce_stats));
-+
-+ g_dmabounce_device_info = device_info;
-+
-+ dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+ buffer_size / 1024, &threshold);
-+
-+ return 0;
-+
-+ err_bounce:
-+ kfree(device_info);
-+ return ret;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_init);
-+
-+void brcm_pcie_bounce_uninit(struct device *dev)
-+{
-+ struct dmabounce_device_info *device_info = g_dmabounce_device_info;
-+
-+ g_dmabounce_device_info = NULL;
-+
-+ if (!device_info) {
-+ dev_warn(dev,
-+ "Never registered with dmabounce but attempting"
-+ "to unregister!\n");
-+ return;
-+ }
-+
-+ if (!list_empty(&device_info->safe_buffers)) {
-+ dev_err(dev,
-+ "Removing from dmabounce with pending buffers!\n");
-+ BUG();
-+ }
-+
-+ bounce_destroy(&device_info->pool);
-+
-+ DO_STATS(if (device_info->attr_res == 0)
-+ device_remove_file(dev, &dev_attr_dmabounce_stats));
-+
-+ kfree(device_info);
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_uninit);
-+
-+int brcm_pcie_bounce_register_dev(struct device *dev)
-+{
-+ set_dma_ops(dev, &dmabounce_ops);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(brcm_pcie_bounce_register_dev);
-+
-+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
-+MODULE_DESCRIPTION("Dedicate DMA bounce support for pcie-brcmstb");
-+MODULE_LICENSE("GPL");
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -611,28 +611,6 @@ static const struct dma_map_ops brcm_dma
-
- static void brcm_set_dma_ops(struct device *dev)
- {
-- int ret;
--
-- if (IS_ENABLED(CONFIG_ARM64)) {
-- /*
-- * We are going to invoke get_dma_ops(). That
-- * function, at this point in time, invokes
-- * get_arch_dma_ops(), and for ARM64 that function
-- * returns a pointer to dummy_dma_ops. So then we'd
-- * like to call arch_setup_dma_ops(), but that isn't
-- * exported. Instead, we call of_dma_configure(),
-- * which is exported, and this calls
-- * arch_setup_dma_ops(). Once we do this the call to
-- * get_dma_ops() will work properly because
-- * dev->dma_ops will be set.
-- */
-- ret = of_dma_configure(dev, dev->of_node, true);
-- if (ret) {
-- dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-- return;
-- }
-- }
--
- arch_dma_ops = get_dma_ops(dev);
- if (!arch_dma_ops) {
- dev_err(dev, "failed to get arch_dma_ops\n");
-@@ -651,12 +629,12 @@ static int brcmstb_platform_notifier(str
- extern unsigned long max_pfn;
- struct device *dev = __dev;
- const char *rc_name = "0000:00:00.0";
-+ int ret;
-
- switch (event) {
- case BUS_NOTIFY_ADD_DEVICE:
- if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
- strcmp(dev->kobj.name, rc_name)) {
-- int ret;
-
- ret = brcm_pcie_bounce_register_dev(dev);
- if (ret) {
-@@ -665,8 +643,14 @@ static int brcmstb_platform_notifier(str
- ret);
- return ret;
- }
-- brcm_set_dma_ops(dev);
-+ } else if (IS_ENABLED(CONFIG_ARM64)) {
-+ ret = of_dma_configure(dev, dev->of_node, true);
-+ if (ret) {
-+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
-+ return ret;
-+ }
- }
-+ brcm_set_dma_ops(dev);
- return NOTIFY_OK;
-
- case BUS_NOTIFY_DEL_DEVICE:
--- /dev/null
+From dcf515d36ce574edd773c9c6321b6bbf9724e209 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Thu, 9 May 2019 14:30:37 +0100
+Subject: [PATCH] drivers: char: add chardev for mmap'ing the RPiVid
+ control registers
+
+Based on the gpiomem driver, allow mapping of the decoder register
+spaces such that userspace can access control/status registers.
+This driver is intended for use with a custom ffmpeg backend accelerator
+prior to a v4l2 driver being written.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/char/broadcom/Kconfig | 8 +
+ drivers/char/broadcom/Makefile | 1 +
+ drivers/char/broadcom/rpivid-mem.c | 286 +++++++++++++++++++++++++++++
+ drivers/mfd/bcm2835-pm.c | 12 +-
+ drivers/soc/bcm/bcm2835-power.c | 6 +-
+ include/linux/mfd/bcm2835-pm.h | 2 +-
+ 6 files changed, 305 insertions(+), 10 deletions(-)
+ create mode 100644 drivers/char/broadcom/rpivid-mem.c
+
+--- a/drivers/char/broadcom/Kconfig
++++ b/drivers/char/broadcom/Kconfig
+@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV
+ This driver provides a character device interface (ioctl + read/write) to
+ Broadcom's Secondary Memory interface. The low-level functionality is provided
+ by the SMI driver itself.
++
++config RPIVID_MEM
++ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
++ default n
++ help
++ This driver provides a character device interface for memory-map operations
++ so userspace tools can access the control and status registers of the
++ Raspberry Pi RPiVid video decoder hardware.
+--- a/drivers/char/broadcom/Makefile
++++ b/drivers/char/broadcom/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
+
+ obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
+ obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
++obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o
+--- /dev/null
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -0,0 +1,286 @@
++/**
++ * rpivid-mem.c - character device access to the RPiVid decoder registers
++ *
++ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
++ * register blocks such that ffmpeg plugins can access the hardware.
++ *
++ * Jonathan Bell <jonathan@raspberrypi.org>
++ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/cdev.h>
++#include <linux/pagemap.h>
++#include <linux/io.h>
++
++#define DRIVER_NAME "rpivid-mem"
++#define DEVICE_MINOR 0
++
++struct rpivid_mem_priv {
++ dev_t devid;
++ struct class *class;
++ struct cdev rpivid_mem_cdev;
++ unsigned long regs_phys;
++ unsigned long mem_window_len;
++ struct device *dev;
++ const char *name;
++};
++
++static int rpivid_mem_open(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++ struct rpivid_mem_priv *priv;
++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
++ ret = -ENXIO;
++
++ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
++ rpivid_mem_cdev);
++ if (!priv)
++ return -EINVAL;
++ file->private_data = priv;
++ return ret;
++}
++
++static int rpivid_mem_release(struct inode *inode, struct file *file)
++{
++ int dev = iminor(inode);
++ int ret = 0;
++
++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
++ ret = -ENXIO;
++
++ return ret;
++}
++
++static const struct vm_operations_struct rpivid_mem_vm_ops = {
++#ifdef CONFIG_HAVE_IOREMAP_PROT
++ .access = generic_access_phys
++#endif
++};
++
++static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct rpivid_mem_priv *priv;
++ unsigned long pages;
++
++ priv = file->private_data;
++ pages = priv->regs_phys >> PAGE_SHIFT;
++ /*
++ * The address decode is far larger than the actual number of registers.
++ * Just map the whole lot in.
++ */
++ vma->vm_page_prot = phys_mem_access_prot(file, pages,
++ priv->mem_window_len,
++ vma->vm_page_prot);
++ vma->vm_ops = &rpivid_mem_vm_ops;
++ if (remap_pfn_range(vma, vma->vm_start,
++ pages,
++ priv->mem_window_len,
++ vma->vm_page_prot)) {
++ return -EAGAIN;
++ }
++ return 0;
++}
++
++static const struct file_operations
++rpivid_mem_fops = {
++ .owner = THIS_MODULE,
++ .open = rpivid_mem_open,
++ .release = rpivid_mem_release,
++ .mmap = rpivid_mem_mmap,
++};
++
++static const struct of_device_id rpivid_mem_of_match[];
++static int rpivid_mem_probe(struct platform_device *pdev)
++{
++ int err;
++ void *ptr_err;
++ const struct of_device_id *id;
++ struct device *dev = &pdev->dev;
++ struct device *rpivid_mem_dev;
++ struct resource *ioresource;
++ struct rpivid_mem_priv *priv;
++
++
++ /* Allocate buffers and instance data */
++
++ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
++
++ if (!priv) {
++ err = -ENOMEM;
++ goto failed_inst_alloc;
++ }
++ platform_set_drvdata(pdev, priv);
++
++ priv->dev = dev;
++ id = of_match_device(rpivid_mem_of_match, dev);
++ if (!id)
++ return -EINVAL;
++ priv->name = id->data;
++
++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (ioresource) {
++ priv->regs_phys = ioresource->start;
++ priv->mem_window_len = ioresource->end - ioresource->start;
++ } else {
++ dev_err(priv->dev, "failed to get IO resource");
++ err = -ENOENT;
++ goto failed_get_resource;
++ }
++
++ /* Create character device entries */
++
++ err = alloc_chrdev_region(&priv->devid,
++ DEVICE_MINOR, 2, priv->name);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to allocate device number");
++ goto failed_alloc_chrdev;
++ }
++ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
++ priv->rpivid_mem_cdev.owner = THIS_MODULE;
++ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
++ if (err != 0) {
++ dev_err(priv->dev, "unable to register device");
++ goto failed_cdev_add;
++ }
++
++ /* Create sysfs entries */
++
++ priv->class = class_create(THIS_MODULE, priv->name);
++ ptr_err = priv->class;
++ if (IS_ERR(ptr_err))
++ goto failed_class_create;
++
++ rpivid_mem_dev = device_create(priv->class, NULL,
++ priv->devid, NULL,
++ priv->name);
++ ptr_err = rpivid_mem_dev;
++ if (IS_ERR(ptr_err))
++ goto failed_device_create;
++
++ /* Legacy alias */
++ {
++ char *oldname = kstrdup(priv->name, GFP_KERNEL);
++
++ oldname[1] = 'a';
++ oldname[2] = 'r';
++ oldname[3] = 'g';
++ oldname[4] = 'o';
++ oldname[5] = 'n';
++ (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
++ oldname + 1);
++ kfree(oldname);
++ }
++
++ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
++ priv->name, priv->regs_phys, priv->mem_window_len);
++
++ return 0;
++
++failed_device_create:
++ class_destroy(priv->class);
++failed_class_create:
++ cdev_del(&priv->rpivid_mem_cdev);
++ err = PTR_ERR(ptr_err);
++failed_cdev_add:
++ unregister_chrdev_region(priv->devid, 1);
++failed_alloc_chrdev:
++failed_get_resource:
++ kfree(priv);
++failed_inst_alloc:
++ dev_err(priv->dev, "could not load rpivid_mem");
++ return err;
++}
++
++static int rpivid_mem_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
++
++ device_destroy(priv->class, priv->devid);
++ class_destroy(priv->class);
++ cdev_del(&priv->rpivid_mem_cdev);
++ unregister_chrdev_region(priv->devid, 1);
++ kfree(priv);
++
++ dev_info(dev, "%s driver removed - OK", priv->name);
++ return 0;
++}
++
++static const struct of_device_id rpivid_mem_of_match[] = {
++ {
++ .compatible = "raspberrypi,rpivid-hevc-decoder",
++ .data = "rpivid-hevcmem",
++ },
++ {
++ .compatible = "raspberrypi,rpivid-h264-decoder",
++ .data = "rpivid-h264mem",
++ },
++ {
++ .compatible = "raspberrypi,rpivid-vp9-decoder",
++ .data = "rpivid-vp9mem",
++ },
++ /* The "intc" is included as this block of hardware contains the
++ * "frame done" status flags.
++ */
++ {
++ .compatible = "raspberrypi,rpivid-local-intc",
++ .data = "rpivid-intcmem",
++ },
++ { /* sentinel */ },
++};
++
++MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
++
++static struct platform_driver rpivid_mem_driver = {
++ .probe = rpivid_mem_probe,
++ .remove = rpivid_mem_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = rpivid_mem_of_match,
++ },
++};
++
++module_platform_driver(rpivid_mem_driver);
++
++MODULE_ALIAS("platform:rpivid-mem");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
++MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.org>");
+--- a/drivers/mfd/bcm2835-pm.c
++++ b/drivers/mfd/bcm2835-pm.c
+@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf
+ if (ret)
+ return ret;
+
+- /* Map the ARGON ASB regs if present. */
++ /* Map the RPiVid ASB regs if present. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res) {
+- pm->arg_asb = devm_ioremap_resource(dev, res);
+- if (IS_ERR(pm->arg_asb)) {
+- dev_err(dev, "Failed to map ARGON ASB: %ld\n",
+- PTR_ERR(pm->arg_asb));
+- return PTR_ERR(pm->arg_asb);
++ pm->rpivid_asb = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pm->rpivid_asb)) {
++ dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
++ PTR_ERR(pm->rpivid_asb));
++ return PTR_ERR(pm->rpivid_asb);
+ }
+ }
+
+--- a/drivers/soc/bcm/bcm2835-power.c
++++ b/drivers/soc/bcm/bcm2835-power.c
+@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl
+ power->base = pm->base;
+ power->asb = pm->asb;
+
+- /* 2711 hack: the new ARGON ASB took over V3D, which is our
++ /* 2711 hack: the new RPiVid ASB took over V3D, which is our
+ * only consumer of this driver so far. The old ASB seems to
+ * still be present with ISP and H264 bits but no V3D, but I
+ * don't know if that's real or not. The V3D is in the same
+ * place in the new ASB as the old one, so just poke the new
+ * one for now.
+ */
+- if (pm->arg_asb) {
+- power->asb = pm->arg_asb;
++ if (pm->rpivid_asb) {
++ power->asb = pm->rpivid_asb;
+ power->is_2711 = true;
+ }
+
+--- a/include/linux/mfd/bcm2835-pm.h
++++ b/include/linux/mfd/bcm2835-pm.h
+@@ -9,7 +9,7 @@ struct bcm2835_pm {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *asb;
+- void __iomem *arg_asb;
++ void __iomem *rpivid_asb;
+ };
+
+ #endif /* BCM2835_MFD_PM_H */
+++ /dev/null
-From 6402d9c21c9b144d528c3248607589db94ecbce0 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 3 Jul 2019 17:44:53 +0100
-Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode
-
-Allow custom HDMI modes to be specified from config.txt,
-and these then override EDID parsing.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 130 ++++++++++++++-----------
- 1 file changed, 75 insertions(+), 55 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1066,6 +1066,56 @@ vc4_fkms_connector_detect(struct drm_con
- return connector_status_connected;
- }
-
-+/* Queries the firmware to populate a drm_mode structure for this display */
-+static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
-+ struct drm_display_mode *mode)
-+{
-+ struct vc4_dev *vc4 = fkms_connector->vc4_dev;
-+ struct set_timings timings = { 0 };
-+ int ret;
-+
-+ timings.display = fkms_connector->display_number;
-+
-+ ret = rpi_firmware_property(vc4->firmware,
-+ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
-+ sizeof(timings));
-+ if (ret || !timings.clock)
-+ /* No mode returned - abort */
-+ return -1;
-+
-+ /* Equivalent to DRM_MODE macro. */
-+ memset(mode, 0, sizeof(*mode));
-+ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
-+ mode->status = 0;
-+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-+ mode->clock = timings.clock;
-+ mode->hdisplay = timings.hdisplay;
-+ mode->hsync_start = timings.hsync_start;
-+ mode->hsync_end = timings.hsync_end;
-+ mode->htotal = timings.htotal;
-+ mode->hskew = 0;
-+ mode->vdisplay = timings.vdisplay;
-+ mode->vsync_start = timings.vsync_start;
-+ mode->vsync_end = timings.vsync_end;
-+ mode->vtotal = timings.vtotal;
-+ mode->vscan = timings.vscan;
-+
-+ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
-+ else
-+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
-+
-+ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
-+ else
-+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
-+
-+ if (timings.flags & TIMINGS_FLAGS_INTERLACE)
-+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
-+
-+ return 0;
-+}
-+
- static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
- size_t len)
- {
-@@ -1094,25 +1144,35 @@ static int vc4_fkms_connector_get_modes(
- to_vc4_fkms_connector(connector);
- struct drm_encoder *encoder = fkms_connector->encoder;
- struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-- int ret = 0;
-+ struct drm_display_mode fw_mode;
-+ struct drm_display_mode *mode;
- struct edid *edid;
-+ int num_modes;
-
-- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-- fkms_connector);
-+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
-+ drm_mode_debug_printmodeline(&fw_mode);
-+ mode = drm_mode_duplicate(connector->dev,
-+ &fw_mode);
-+ drm_mode_probed_add(connector, mode);
-+ num_modes = 1; /* 1 mode */
-+ } else {
-+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
-+ fkms_connector);
-
-- /* FIXME: Can we do CEC?
-- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-- * if (!edid)
-- * return -ENODEV;
-- */
--
-- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
--
-- drm_connector_update_edid_property(connector, edid);
-- ret = drm_add_edid_modes(connector, edid);
-- kfree(edid);
-+ /* FIXME: Can we do CEC?
-+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
-+ * if (!edid)
-+ * return -ENODEV;
-+ */
-+
-+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
-+
-+ drm_connector_update_edid_property(connector, edid);
-+ num_modes = drm_add_edid_modes(connector, edid);
-+ kfree(edid);
-+ }
-
-- return ret;
-+ return num_modes;
- }
-
- /* This is the DSI panel resolution. Use this as a default should the firmware
-@@ -1130,55 +1190,15 @@ static int vc4_fkms_lcd_connector_get_mo
- {
- struct vc4_fkms_connector *fkms_connector =
- to_vc4_fkms_connector(connector);
-- struct vc4_dev *vc4 = fkms_connector->vc4_dev;
- struct drm_display_mode *mode;
-- struct mailbox_set_mode mb = {
-- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING,
-- sizeof(struct set_timings), 0},
-- .timings = { .display = fkms_connector->display_number },
-- };
- struct drm_display_mode fw_mode;
-- int ret = 0;
--
-- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
-- if (!ret) {
-- /* Equivalent to DRM_MODE macro. */
-- memset(&fw_mode, 0, sizeof(fw_mode));
-- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name));
-- fw_mode.status = 0;
-- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-- fw_mode.clock = mb.timings.clock;
-- fw_mode.hdisplay = mb.timings.hdisplay;
-- fw_mode.hsync_start = mb.timings.hsync_start;
-- fw_mode.hsync_end = mb.timings.hsync_end;
-- fw_mode.htotal = mb.timings.htotal;
-- fw_mode.hskew = 0;
-- fw_mode.vdisplay = mb.timings.vdisplay;
-- fw_mode.vsync_start = mb.timings.vsync_start;
-- fw_mode.vsync_end = mb.timings.vsync_end;
-- fw_mode.vtotal = mb.timings.vtotal;
-- fw_mode.vscan = mb.timings.vscan;
-- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
-- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC;
-- else
-- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC;
-- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE)
-- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE;
-
-+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
- mode = drm_mode_duplicate(connector->dev,
- &fw_mode);
-- } else {
-+ else
- mode = drm_mode_duplicate(connector->dev,
- &lcd_mode);
-- }
-
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
--- /dev/null
+From 8f4720ca2ed61fbaf2a3039b510e276d06d6a2fb Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Thu, 1 Aug 2019 16:41:20 +0100
+Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3
+ and MX3
+
+These wireless mouse/keyboard combo remote control devices specify
+multiple "wheel" events in their report descriptors. The wheel events
+are incorrectly defined and apparently map to accelerometer data, leading
+to spurious mouse scroll events being generated at an extreme rate when
+the device is moved.
+
+As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask
+feeding the extra wheel events to the input subsystem.
+
+See: https://github.com/raspberrypi/firmware/issues/1189
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/hid/hid-ids.h | 6 ++++++
+ drivers/hid/hid-quirks.c | 2 ++
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -223,6 +223,9 @@
+ #define USB_VENDOR_ID_BAANTO 0x2453
+ #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+
++#define USB_VENDOR_ID_BEKEN 0x25a7
++#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402
++
+ #define USB_VENDOR_ID_BELKIN 0x050d
+ #define USB_DEVICE_ID_FLIP_KVM 0x3201
+
+@@ -1224,6 +1227,9 @@
+ #define USB_VENDOR_ID_XAT 0x2505
+ #define USB_DEVICE_ID_XAT_CSR 0x0220
+
++#define USB_VENDOR_ID_XENTA 0x1d57
++#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03
++
+ #define USB_VENDOR_ID_XIN_MO 0x16c0
+ #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
+ #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1
+--- a/drivers/hid/hid-quirks.c
++++ b/drivers/hid/hid-quirks.c
+@@ -41,6 +41,7 @@ static const struct hid_device_id hid_qu
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
++ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
+@@ -175,6 +176,7 @@ static const struct hid_device_id hid_qu
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
++ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+
+ { 0 }
+ };
--- /dev/null
+From 661cefed28f420f7ca6e52882d83a7a321d60256 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 14 Jun 2019 10:12:07 +0100
+Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property
+
+Some HDMI monitors do not abide by the full or limited
+(16-235) range RGB flags in the AVI infoframe. This can
+result in images looking washed out (if given limited and
+interpreting as full), or detail disappearing at the extremes
+(given full and interpreting as limited).
+
+Copy the Intel i915 driver's approach of adding an override
+property ("Broadcast RGB") to force one mode or the other.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++--
+ 1 file changed, 177 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -287,6 +287,13 @@ to_vc4_fkms_encoder(struct drm_encoder *
+ return container_of(encoder, struct vc4_fkms_encoder, base);
+ }
+
++/* "Broadcast RGB" property.
++ * Allows overriding of HDMI full or limited range RGB
++ */
++#define VC4_BROADCAST_RGB_AUTO 0
++#define VC4_BROADCAST_RGB_FULL 1
++#define VC4_BROADCAST_RGB_LIMITED 2
++
+ /* VC4 FKMS connector KMS struct */
+ struct vc4_fkms_connector {
+ struct drm_connector base;
+@@ -299,6 +306,8 @@ struct vc4_fkms_connector {
+ struct vc4_dev *vc4_dev;
+ u32 display_number;
+ u32 display_type;
++
++ struct drm_property *broadcast_rgb_property;
+ };
+
+ static inline struct vc4_fkms_connector *
+@@ -307,6 +316,16 @@ to_vc4_fkms_connector(struct drm_connect
+ return container_of(connector, struct vc4_fkms_connector, base);
+ }
+
++/* VC4 FKMS connector state */
++struct vc4_fkms_connector_state {
++ struct drm_connector_state base;
++
++ int broadcast_rgb;
++};
++
++#define to_vc4_fkms_connector_state(x) \
++ container_of(x, struct vc4_fkms_connector_state, base)
++
+ static u32 vc4_get_display_type(u32 display_number)
+ {
+ const u32 display_types[] = {
+@@ -863,8 +882,6 @@ static void vc4_crtc_mode_set_nofb(struc
+ mode->picture_aspect_ratio, mode->flags);
+ mb.timings.display = vc4_crtc->display_number;
+
+- mb.timings.video_id_code = frame.avi.video_code;
+-
+ mb.timings.clock = mode->clock;
+ mb.timings.hdisplay = mode->hdisplay;
+ mb.timings.hsync_start = mode->hsync_start;
+@@ -902,11 +919,30 @@ static void vc4_crtc_mode_set_nofb(struc
+ break;
+ }
+
+- if (!vc4_encoder->hdmi_monitor)
++ if (!vc4_encoder->hdmi_monitor) {
+ mb.timings.flags |= TIMINGS_FLAGS_DVI;
+- else if (drm_default_rgb_quant_range(mode) ==
++ mb.timings.video_id_code = frame.avi.video_code;
++ } else {
++ struct vc4_fkms_connector_state *conn_state =
++ to_vc4_fkms_connector_state(vc4_crtc->connector->state);
++
++ /* Do not provide a VIC as the HDMI spec requires that we do not
++ * signal the opposite of the defined range in the AVI
++ * infoframe.
++ */
++ mb.timings.video_id_code = 0;
++
++ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
++ /* See CEA-861-E - 5.1 Default Encoding Parameters */
++ if (drm_default_rgb_quant_range(mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED)
+- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ } else {
++ if (conn_state->broadcast_rgb ==
++ VC4_BROADCAST_RGB_LIMITED)
++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
++ }
++ }
+
+ /*
+ FIXME: To implement
+@@ -1364,13 +1400,95 @@ static void vc4_fkms_connector_destroy(s
+ drm_connector_cleanup(connector);
+ }
+
++/**
++ * vc4_connector_duplicate_state - duplicate connector state
++ * @connector: digital connector
++ *
++ * Allocates and returns a copy of the connector state (both common and
++ * digital connector specific) for the specified connector.
++ *
++ * Returns: The newly allocated connector state, or NULL on failure.
++ */
++struct drm_connector_state *
++vc4_connector_duplicate_state(struct drm_connector *connector)
++{
++ struct vc4_fkms_connector_state *state;
++
++ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
++ if (!state)
++ return NULL;
++
++ __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
++ return &state->base;
++}
++
++/**
++ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
++ * @connector: Connector to get the property for.
++ * @state: Connector state to retrieve the property from.
++ * @property: Property to retrieve.
++ * @val: Return value for the property.
++ *
++ * Returns the atomic property value for a digital connector.
++ */
++int vc4_connector_atomic_get_property(struct drm_connector *connector,
++ const struct drm_connector_state *state,
++ struct drm_property *property,
++ uint64_t *val)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_fkms_connector_state *vc4_conn_state =
++ to_vc4_fkms_connector_state(state);
++
++ if (property == fkms_connector->broadcast_rgb_property) {
++ *val = vc4_conn_state->broadcast_rgb;
++ } else {
++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
++ property->base.id, property->name);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/**
++ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
++ * @connector: Connector to set the property for.
++ * @state: Connector state to set the property on.
++ * @property: Property to set.
++ * @val: New value for the property.
++ *
++ * Sets the atomic property value for a digital connector.
++ */
++int vc4_connector_atomic_set_property(struct drm_connector *connector,
++ struct drm_connector_state *state,
++ struct drm_property *property,
++ uint64_t val)
++{
++ struct vc4_fkms_connector *fkms_connector =
++ to_vc4_fkms_connector(connector);
++ struct vc4_fkms_connector_state *vc4_conn_state =
++ to_vc4_fkms_connector_state(state);
++
++ if (property == fkms_connector->broadcast_rgb_property) {
++ vc4_conn_state->broadcast_rgb = val;
++ return 0;
++ }
++
++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
++ property->base.id, property->name);
++ return -EINVAL;
++}
++
+ static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
+ .detect = vc4_fkms_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = vc4_fkms_connector_destroy,
+- .reset = drm_atomic_helper_connector_reset,
+- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++ .atomic_duplicate_state = vc4_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++ .atomic_get_property = vc4_connector_atomic_get_property,
++ .atomic_set_property = vc4_connector_atomic_set_property,
+ };
+
+ static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
+@@ -1383,12 +1501,40 @@ static const struct drm_connector_helper
+ .best_encoder = vc4_fkms_connector_best_encoder,
+ };
+
++static const struct drm_prop_enum_list broadcast_rgb_names[] = {
++ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
++ { VC4_BROADCAST_RGB_FULL, "Full" },
++ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
++};
++
++static void
++vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
++{
++ struct drm_device *dev = fkms_connector->base.dev;
++ struct drm_property *prop;
++
++ prop = fkms_connector->broadcast_rgb_property;
++ if (!prop) {
++ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
++ "Broadcast RGB",
++ broadcast_rgb_names,
++ ARRAY_SIZE(broadcast_rgb_names));
++ if (!prop)
++ return;
++
++ fkms_connector->broadcast_rgb_property = prop;
++ }
++
++ drm_object_attach_property(&fkms_connector->base.base, prop, 0);
++}
++
+ static struct drm_connector *
+ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
+ u32 display_num)
+ {
+ struct drm_connector *connector = NULL;
+ struct vc4_fkms_connector *fkms_connector;
++ struct vc4_fkms_connector_state *conn_state = NULL;
+ struct vc4_dev *vc4_dev = to_vc4_dev(dev);
+ int ret = 0;
+
+@@ -1397,9 +1543,18 @@ vc4_fkms_connector_init(struct drm_devic
+ fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
+ GFP_KERNEL);
+ if (!fkms_connector) {
+- ret = -ENOMEM;
+- goto fail;
++ return ERR_PTR(-ENOMEM);
++ }
++
++ /*
++ * Allocate enough memory to hold vc4_fkms_connector_state,
++ */
++ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
++ if (!conn_state) {
++ kfree(fkms_connector);
++ return ERR_PTR(-ENOMEM);
+ }
++
+ connector = &fkms_connector->base;
+
+ fkms_connector->encoder = encoder;
+@@ -1407,6 +1562,9 @@ vc4_fkms_connector_init(struct drm_devic
+ fkms_connector->display_type = vc4_get_display_type(display_num);
+ fkms_connector->vc4_dev = vc4_dev;
+
++ __drm_atomic_helper_connector_reset(connector,
++ &conn_state->base);
++
+ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+@@ -1427,10 +1585,14 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
+- /* Create and attach TV margin props to this connector. */
+- ret = drm_mode_create_tv_margin_properties(dev);
+- if (ret)
+- return ERR_PTR(ret);
++ /* Create and attach TV margin props to this connector.
++ * Already done for SDTV outputs.
++ */
++ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ goto fail;
++ }
+
+ drm_connector_attach_tv_margin_properties(connector);
+
+@@ -1439,6 +1601,8 @@ vc4_fkms_connector_init(struct drm_devic
+
+ connector->doublescan_allowed = 0;
+
++ vc4_attach_broadcast_rgb_property(fkms_connector);
++
+ drm_connector_attach_encoder(connector, encoder);
+
+ return connector;
+++ /dev/null
-From f146d9a60f197fbf868be7eece68ff5cc58af4ff Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 11 Jul 2019 15:12:05 +0100
-Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on
- mode set
-
-More for completeness than need, but use drm_mode_vrefresh
-to compute the vrefresh value, and pass that down to the
-firmware on mode set.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -768,8 +768,8 @@ static void vc4_crtc_mode_set_nofb(struc
- mode->hdisplay, mode->hsync_start, mode->hsync_end,
- mode->htotal, mode->hskew, mode->vdisplay,
- mode->vsync_start, mode->vsync_end, mode->vtotal,
-- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio,
-- mode->flags);
-+ mode->vscan, drm_mode_vrefresh(mode),
-+ mode->picture_aspect_ratio, mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
- mb.timings.video_id_code = frame.avi.video_code;
-@@ -785,7 +785,7 @@ static void vc4_crtc_mode_set_nofb(struc
- mb.timings.vsync_end = mode->vsync_end;
- mb.timings.vtotal = mode->vtotal;
- mb.timings.vscan = mode->vscan;
-- mb.timings.vrefresh = 0;
-+ mb.timings.vrefresh = drm_mode_vrefresh(mode);
- mb.timings.flags = 0;
- if (mode->flags & DRM_MODE_FLAG_PHSYNC)
- mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
+++ /dev/null
-From 8a7170d2ad05ae00733e0535b281ce2e682c6f65 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 19 Jul 2019 15:35:13 +0100
-Subject: [PATCH] drm/vc4: Add support for margins to fkms
-
-Allows for overscan to be configured under FKMS.
-NB This is rescaling the planes, not reducing the size of the
-display mode.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------
- 1 file changed, 190 insertions(+), 51 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -259,6 +259,23 @@ static inline struct vc4_crtc *to_vc4_cr
- return container_of(crtc, struct vc4_crtc, base);
- }
-
-+struct vc4_crtc_state {
-+ struct drm_crtc_state base;
-+
-+ 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;
-+}
-+
- struct vc4_fkms_encoder {
- struct drm_encoder base;
- bool hdmi_monitor;
-@@ -367,17 +384,127 @@ static int vc4_plane_set_blank(struct dr
- return ret;
- }
-
-+static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
-+ unsigned int *left, unsigned int *right,
-+ unsigned int *top, unsigned int *bottom)
-+{
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
-+ struct drm_connector_state *conn_state;
-+ struct drm_connector *conn;
-+ int i;
-+
-+ *left = vc4_state->margins.left;
-+ *right = vc4_state->margins.right;
-+ *top = vc4_state->margins.top;
-+ *bottom = vc4_state->margins.bottom;
-+
-+ /* We have to interate over all new connector states because
-+ * vc4_fkms_crtc_get_margins() might be called before
-+ * vc4_fkms_crtc_atomic_check() which means margins info in
-+ * vc4_crtc_state might be outdated.
-+ */
-+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
-+ if (conn_state->crtc != state->crtc)
-+ continue;
-+
-+ *left = conn_state->tv.margins.left;
-+ *right = conn_state->tv.margins.right;
-+ *top = conn_state->tv.margins.top;
-+ *bottom = conn_state->tv.margins.bottom;
-+ break;
-+ }
-+}
-+
-+static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
-+ struct set_plane *plane)
-+{
-+ unsigned int left, right, top, bottom;
-+ int adjhdisplay, adjvdisplay;
-+ struct drm_crtc_state *crtc_state;
-+
-+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
-+ pstate->crtc);
-+
-+ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
-+
-+ if (!left && !right && !top && !bottom)
-+ return 0;
-+
-+ if (left + right >= crtc_state->mode.hdisplay ||
-+ top + bottom >= crtc_state->mode.vdisplay)
-+ return -EINVAL;
-+
-+ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
-+ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
-+ (int)crtc_state->mode.hdisplay);
-+ plane->dst_x += left;
-+ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
-+ plane->dst_x = crtc_state->mode.hdisplay - left;
-+
-+ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
-+ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
-+ (int)crtc_state->mode.vdisplay);
-+ plane->dst_y += top;
-+ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
-+ plane->dst_y = crtc_state->mode.vdisplay - top;
-+
-+ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
-+ crtc_state->mode.hdisplay);
-+ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
-+ crtc_state->mode.vdisplay);
-+
-+ if (!plane->dst_w || !plane->dst_h)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
- static void vc4_plane_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
- {
- struct drm_plane_state *state = plane->state;
-+
-+ /*
-+ * Do NOT set now, as we haven't checked if the crtc is active or not.
-+ * Set from vc4_plane_set_blank instead.
-+ *
-+ * If the CRTC is on (or going to be on) and we're enabled,
-+ * then unblank. Otherwise, stay blank until CRTC enable.
-+ */
-+ if (state->crtc->state->active)
-+ vc4_plane_set_blank(plane, false);
-+}
-+
-+static void vc4_plane_atomic_disable(struct drm_plane *plane,
-+ struct drm_plane_state *old_state)
-+{
-+ struct drm_plane_state *state = plane->state;
-+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-+
-+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
-+ plane->base.id, plane->name,
-+ state->crtc_w,
-+ state->crtc_h,
-+ vc4_plane->mb.plane.vc_image_type,
-+ state->crtc_x,
-+ state->crtc_y);
-+ vc4_plane_set_blank(plane, true);
-+}
-+
-+static bool plane_enabled(struct drm_plane_state *state)
-+{
-+ return state->fb && state->crtc;
-+}
-+
-+static int vc4_plane_to_mb(struct drm_plane *plane,
-+ struct mailbox_set_plane *mb,
-+ struct drm_plane_state *state)
-+{
- struct drm_framebuffer *fb = state->fb;
- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
- const struct drm_format_info *drm_fmt = fb->format;
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
-- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-- struct mailbox_set_plane *mb = &vc4_plane->mb;
- int num_planes = fb->format->num_planes;
- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-@@ -419,25 +546,7 @@ static void vc4_plane_atomic_update(stru
- break;
- }
-
-- /* FIXME: If the dest rect goes off screen then clip the src rect so we
-- * don't have off-screen pixels.
-- */
-- if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-- /* There is no scaling on the cursor plane, therefore the calcs
-- * to alter the source crop as the cursor goes off the screen
-- * are simple.
-- */
-- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
-- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
-- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
-- << 16;
-- }
-- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
-- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
-- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
-- << 16;
-- }
-- }
-+ vc4_fkms_margins_adj(state, &mb->plane);
-
- if (num_planes > 1) {
- /* Assume this must be YUV */
-@@ -527,38 +636,19 @@ static void vc4_plane_atomic_update(stru
- state->alpha,
- state->normalized_zpos);
-
-- /*
-- * Do NOT set now, as we haven't checked if the crtc is active or not.
-- * Set from vc4_plane_set_blank instead.
-- *
-- * If the CRTC is on (or going to be on) and we're enabled,
-- * then unblank. Otherwise, stay blank until CRTC enable.
-- */
-- if (state->crtc->state->active)
-- vc4_plane_set_blank(plane, false);
-+ return 0;
- }
-
--static void vc4_plane_atomic_disable(struct drm_plane *plane,
-- struct drm_plane_state *old_state)
-+static int vc4_plane_atomic_check(struct drm_plane *plane,
-+ struct drm_plane_state *state)
- {
-- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
-- struct drm_plane_state *state = plane->state;
- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
-
-- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
-- plane->base.id, plane->name,
-- state->crtc_w,
-- state->crtc_h,
-- vc4_plane->mb.plane.vc_image_type,
-- state->crtc_x,
-- state->crtc_y);
-- vc4_plane_set_blank(plane, true);
--}
-+ if (!plane_enabled(state))
-+ return 0;
-+
-+ return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
-
--static int vc4_plane_atomic_check(struct drm_plane *plane,
-- struct drm_plane_state *state)
--{
-- return 0;
- }
-
- /* Called during init to allocate the plane's atomic state. */
-@@ -909,8 +999,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
- static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
- {
-- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
-- crtc->base.id);
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
-+ struct drm_connector *conn;
-+ struct drm_connector_state *conn_state;
-+ int i;
-+
-+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
-+
-+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
-+ if (conn_state->crtc != crtc)
-+ continue;
-+
-+ vc4_state->margins.left = conn_state->tv.margins.left;
-+ vc4_state->margins.right = conn_state->tv.margins.right;
-+ vc4_state->margins.top = conn_state->tv.margins.top;
-+ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
-+ break;
-+ }
- return 0;
- }
-
-@@ -1011,6 +1116,33 @@ static int vc4_page_flip(struct drm_crtc
- return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
- }
-
-+static struct drm_crtc_state *
-+vc4_crtc_duplicate_state(struct drm_crtc *crtc)
-+{
-+ struct vc4_crtc_state *vc4_state, *old_vc4_state;
-+
-+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
-+ if (!vc4_state)
-+ return NULL;
-+
-+ old_vc4_state = to_vc4_crtc_state(crtc->state);
-+ vc4_state->margins = old_vc4_state->margins;
-+
-+ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
-+ return &vc4_state->base;
-+}
-+
-+static void
-+vc4_crtc_reset(struct drm_crtc *crtc)
-+{
-+ if (crtc->state)
-+ __drm_atomic_helper_crtc_destroy_state(crtc->state);
-+
-+ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
-+ if (crtc->state)
-+ crtc->state->crtc = crtc;
-+}
-+
- static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
- {
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-@@ -1038,8 +1170,8 @@ static const struct drm_crtc_funcs vc4_c
- .set_property = NULL,
- .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
- .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
-- .reset = drm_atomic_helper_crtc_reset,
-- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
-+ .reset = vc4_crtc_reset,
-+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
- .enable_vblank = vc4_fkms_enable_vblank,
- .disable_vblank = vc4_fkms_disable_vblank,
-@@ -1291,6 +1423,13 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-+ /* Create and attach TV margin props to this connector. */
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ return ERR_PTR(ret);
-+
-+ drm_connector_attach_tv_margin_properties(connector);
-+
- connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT);
-
--- /dev/null
+From 651d4137cc20de6b64edd2302ebd82d8e88121df Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 23 Jul 2019 11:09:26 +0100
+Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset
+
+Now that the TV margins are properly parsed and filled into
+drm_cmdline_mode, we just need to initialise the first state at reset to
+get those values and start using them.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1481,10 +1481,17 @@ int vc4_connector_atomic_set_property(st
+ return -EINVAL;
+ }
+
++static void vc4_hdmi_connector_reset(struct drm_connector *connector)
++{
++ drm_atomic_helper_connector_reset(connector);
++ drm_atomic_helper_connector_tv_reset(connector);
++}
++
+ static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
+ .detect = vc4_fkms_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = vc4_fkms_connector_destroy,
++ .reset = vc4_hdmi_connector_reset,
+ .atomic_duplicate_state = vc4_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = vc4_connector_atomic_get_property,
+++ /dev/null
-From 9ab46d940789f74980d18715f5715992559ea857 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 19 Jul 2019 17:49:00 +0100
-Subject: [PATCH] drm/vc4: Ensure zpos is always initialised
-
-The compiler is warning that default_zpos can be used
-uninitialised as there is no default case to catch all plane
-types.
-No other plane types should ever be presented to vc4_fkms_plane_init,
-but add a default case regardless.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -804,6 +804,7 @@ static struct drm_plane *vc4_fkms_plane_
- * other layers as requested by KMS.
- */
- switch (type) {
-+ default:
- case DRM_PLANE_TYPE_PRIMARY:
- default_zpos = 0;
- break;
--- /dev/null
+From 9495e07dac5cb6230838763572f73b863cd72019 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Thu, 18 Jul 2019 17:07:05 +0800
+Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API
+
+There are two APIs for mem2mem devices, the older single-planar API and
+the newer multi-planar one. Without making things overly complex, the
+driver can only support one or the other. However the userspace libv4l2
+library has a plugin that allows multi-planar API devices to service
+single-planar consumers.
+
+Chromium supports the multi-planar API exclusively, though this is
+currently limited to ChromiumOS. It would be possible to add support
+for generic Linux.
+
+Switching to the multi-planar API would allow usage of both APIs from
+userspace.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 141 +++++++++---------
+ 1 file changed, 74 insertions(+), 67 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo
+
+ for (k = 0; k < fmts->num_entries; k++) {
+ fmt = &fmts->list[k];
+- if (fmt->fourcc == f->fmt.pix.pixelformat)
++ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+ if (k == fmts->num_entries)
+@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_
+ enum v4l2_buf_type type)
+ {
+ switch (type) {
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &ctx->q_data[V4L2_M2M_SRC];
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return &ctx->q_data[V4L2_M2M_DST];
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
+@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_
+ return NULL;
+
+ switch (type) {
+- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &ctx->component->input[0];
+- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return &ctx->component->output[0];
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
+@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc
+ format->es.video.crop.width, format->es.video.crop.height,
+ format->es.video.color_space);
+
+- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
++ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+ q_data->bytesperline = format->es.video.crop.width;
+@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *
+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
++ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+ }
+@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c
+
+ q_data = get_q_data(ctx, f->type);
+
+- f->fmt.pix.width = q_data->crop_width;
+- f->fmt.pix.height = q_data->height;
+- f->fmt.pix.field = V4L2_FIELD_NONE;
+- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+- f->fmt.pix.bytesperline = q_data->bytesperline;
+- f->fmt.pix.sizeimage = q_data->sizeimage;
+- f->fmt.pix.colorspace = ctx->colorspace;
+- f->fmt.pix.xfer_func = ctx->xfer_func;
+- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+- f->fmt.pix.quantization = ctx->quant;
++ f->fmt.pix_mp.width = q_data->crop_width;
++ f->fmt.pix_mp.height = q_data->height;
++ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
++ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
++ f->fmt.pix_mp.colorspace = ctx->colorspace;
++ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
++ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
++ f->fmt.pix_mp.num_planes = 1;
++ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
++ f->fmt.pix_mp.quantization = ctx->quant;
++ f->fmt.pix_mp.xfer_func = ctx->xfer_func;
++
++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
+
+ return 0;
+ }
+@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835
+ * The V4L2 specification requires the driver to correct the format
+ * struct if any of the dimensions is unsupported
+ */
+- if (f->fmt.pix.width > MAX_W)
+- f->fmt.pix.width = MAX_W;
+- if (f->fmt.pix.height > MAX_H)
+- f->fmt.pix.height = MAX_H;
++ if (f->fmt.pix_mp.width > MAX_W)
++ f->fmt.pix_mp.width = MAX_W;
++ if (f->fmt.pix_mp.height > MAX_H)
++ f->fmt.pix_mp.height = MAX_H;
+
+ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+ /* Only clip min w/h on capture. Treat 0x0 as unknown. */
+- if (f->fmt.pix.width < MIN_W)
+- f->fmt.pix.width = MIN_W;
+- if (f->fmt.pix.height < MIN_H)
+- f->fmt.pix.height = MIN_H;
++ if (f->fmt.pix_mp.width < MIN_W)
++ f->fmt.pix_mp.width = MIN_W;
++ if (f->fmt.pix_mp.height < MIN_H)
++ f->fmt.pix_mp.height = MIN_H;
+
+ /*
+ * For codecs the buffer must have a vertical alignment of 16
+@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835
+ * some of the pixels are active.
+ */
+ if (ctx->dev->role != ISP)
+- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
++ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
+ }
+- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
+- fmt);
+- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
+- f->fmt.pix.width,
+- f->fmt.pix.height,
+- fmt);
++ f->fmt.pix_mp.num_planes = 1;
++ f->fmt.pix_mp.plane_fmt[0].bytesperline =
++ get_bytesperline(f->fmt.pix_mp.width, fmt);
++ f->fmt.pix_mp.plane_fmt[0].sizeimage =
++ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
++ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
+
+- f->fmt.pix.field = V4L2_FIELD_NONE;
++ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+
+ return 0;
+ }
+@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct
+
+ fmt = find_format(f, ctx->dev, true);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+- true)->fourcc;
++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
++ true)->fourcc;
+ fmt = find_format(f, ctx->dev, true);
+ }
+
+@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct
+
+ fmt = find_format(f, ctx->dev, false);
+ if (!fmt) {
+- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
+- false)->fourcc;
++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
++ false)->fourcc;
+ fmt = find_format(f, ctx->dev, false);
+ }
+
+- if (!f->fmt.pix.colorspace)
+- f->fmt.pix.colorspace = ctx->colorspace;
++ if (!f->fmt.pix_mp.colorspace)
++ f->fmt.pix_mp.colorspace = ctx->colorspace;
+
+ return vidioc_try_fmt(ctx, f, fmt);
+ }
+@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c
+ bool update_capture_port = false;
+ int ret;
+
+- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
+- f->type, f->fmt.pix.width, f->fmt.pix.height,
+- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
++ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
++
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c
+ }
+
+ q_data->fmt = find_format(f, ctx->dev,
+- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+- q_data->crop_width = f->fmt.pix.width;
+- q_data->height = f->fmt.pix.height;
++ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
++ q_data->crop_width = f->fmt.pix_mp.width;
++ q_data->height = f->fmt.pix_mp.height;
+ if (!q_data->selection_set)
+ q_data->crop_height = requested_height;
+
+@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c
+ * Copying the behaviour of vicodec which retains a single set of
+ * colorspace parameters for both input and output.
+ */
+- ctx->colorspace = f->fmt.pix.colorspace;
+- ctx->xfer_func = f->fmt.pix.xfer_func;
+- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+- ctx->quant = f->fmt.pix.quantization;
++ ctx->colorspace = f->fmt.pix_mp.colorspace;
++ ctx->xfer_func = f->fmt.pix_mp.xfer_func;
++ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
++ ctx->quant = f->fmt.pix_mp.quantization;
+
+ /* All parameters should have been set correctly by try_fmt */
+- q_data->bytesperline = f->fmt.pix.bytesperline;
+- q_data->sizeimage = f->fmt.pix.sizeimage;
++ q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
++ q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
+ q_data->bytesperline, q_data->sizeimage);
+
+ if (ctx->dev->role == DECODE &&
+ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
+- f->fmt.pix.width && f->fmt.pix.height) {
++ q_data->crop_width && q_data->height) {
+ /*
+ * On the decoder, if provided with a resolution on the input
+ * side, then replicate that to the output side.
+@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ q_data_dst->height = ALIGN(q_data->crop_height, 16);
+
+ q_data_dst->bytesperline =
+- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
++ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
+ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
+ q_data_dst->crop_width,
+ q_data_dst->height,
+@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c
+ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+- unsigned int height = f->fmt.pix.height;
++ unsigned int height = f->fmt.pix_mp.height;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f
+ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+ {
+- unsigned int height = f->fmt.pix.height;
++ unsigned int height = f->fmt.pix_mp.height;
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+ true : false;
+
+ if ((ctx->dev->role == DECODE && !capture_queue) ||
+@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data = NULL;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+ true : false;
+
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
+@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ ctx->framerate_num =
+@@ -1739,14 +1746,14 @@ static const struct v4l2_ioctl_ops bcm28
+ .vidioc_querycap = vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
+- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming
+ ctx->component_enabled = true;
+ }
+
+- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /*
+ * Create the EOS buffer.
+ * We only need the MMAL part, and want to NOT attach a memory
+@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct
+ struct bcm2835_codec_ctx *ctx = priv;
+ int ret;
+
+- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
+@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct
+ if (ret)
+ return ret;
+
+- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
+++ /dev/null
-From 41c059c841d40bebc358e1c9e7f30c62b2fe3b37 Mon Sep 17 00:00:00 2001
-From: Joerg Schambacher <joscha@schambacher.com>
-Date: Tue, 23 Jul 2019 16:57:35 +0200
-Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version
-
-This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC
-Signed-off-by: Joerg Schambacher joerg@i2audio.com
----
- sound/soc/bcm/Kconfig | 9 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++++++++
- 3 files changed, 549 insertions(+)
- create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -38,6 +38,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- tristate "Support for HifiBerry DAC+"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
- select SND_SOC_PCM512x
-+ select COMMON_CLK_HIFIBERRY_DACPRO
- help
- Say Y or M if you want to add support for HifiBerry DAC+.
-
-@@ -50,6 +51,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+ADC.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
-+ tristate "Support for HifiBerry DAC+ADC PRO"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM512x_I2C
-+ select SND_SOC_PCM186X_I2C
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo
- # BCM2708 Machine Support
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
-+snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -39,6 +40,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
-@@ -0,0 +1,538 @@
-+/*
-+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control)
-+ *
-+ * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
-+ * Copyright 2014-2015
-+ * based on code by Florian Meier <florian.meier@koalo.de>
-+ * ADC added by Joerg Schambacher <joerg@i2audio.com>
-+ * Copyright 2018-19
-+ *
-+ * 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 <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+#include <sound/tlv.h>
-+
-+#include "../codecs/pcm512x.h"
-+#include "../codecs/pcm186x.h"
-+
-+#define HIFIBERRY_DACPRO_NOCLOCK 0
-+#define HIFIBERRY_DACPRO_CLK44EN 1
-+#define HIFIBERRY_DACPRO_CLK48EN 2
-+
-+struct pcm512x_priv {
-+ struct regmap *regmap;
-+ struct clk *sclk;
-+};
-+
-+/* Clock rate of CLK44EN attached to GPIO6 pin */
-+#define CLK_44EN_RATE 22579200UL
-+/* Clock rate of CLK48EN attached to GPIO3 pin */
-+#define CLK_48EN_RATE 24576000UL
-+
-+static bool slave;
-+static bool snd_rpi_hifiberry_is_dacpro;
-+static bool digital_gain_0db_limit = true;
-+
-+static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
-+ 0x00, 0x01, 0x02, 0x03, 0x10
-+};
-+
-+static const char * const pcm186x_adcl_input_channel_sel_text[] = {
-+ "No Select",
-+ "VINL1[SE]", /* Default for ADCL */
-+ "VINL2[SE]",
-+ "VINL2[SE] + VINL1[SE]",
-+ "{VIN1P, VIN1M}[DIFF]"
-+};
-+
-+static const char * const pcm186x_adcr_input_channel_sel_text[] = {
-+ "No Select",
-+ "VINR1[SE]", /* Default for ADCR */
-+ "VINR2[SE]",
-+ "VINR2[SE] + VINR1[SE]",
-+ "{VIN2P, VIN2M}[DIFF]"
-+};
-+
-+static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
-+ PCM186X_ADC_INPUT_SEL_MASK,
-+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
-+ pcm186x_adcl_input_channel_sel_text,
-+ pcm186x_adc_input_channel_sel_value),
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
-+ PCM186X_ADC_INPUT_SEL_MASK,
-+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
-+ pcm186x_adcr_input_channel_sel_text,
-+ pcm186x_adc_input_channel_sel_value),
-+};
-+
-+static const unsigned int pcm186x_mic_bias_sel_value[] = {
-+ 0x00, 0x01, 0x11
-+};
-+
-+static const char * const pcm186x_mic_bias_sel_text[] = {
-+ "Mic Bias off",
-+ "Mic Bias on",
-+ "Mic Bias with Bypass Resistor"
-+};
-+
-+static const struct soc_enum pcm186x_mic_bias_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0,
-+ GENMASK(4, 0),
-+ ARRAY_SIZE(pcm186x_mic_bias_sel_text),
-+ pcm186x_mic_bias_sel_text,
-+ pcm186x_mic_bias_sel_value),
-+};
-+
-+static const unsigned int pcm186x_gain_sel_value[] = {
-+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
-+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
-+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
-+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
-+ 0x50
-+};
-+
-+static const char * const pcm186x_gain_sel_text[] = {
-+ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB",
-+ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB",
-+ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB",
-+ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB",
-+ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB",
-+ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB",
-+ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB",
-+ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB",
-+ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB",
-+ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB",
-+ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB",
-+ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB",
-+ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB",
-+ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB",
-+ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB",
-+ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB",
-+ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB",
-+ "39.0dB", "39.5dB", "40.0dB"};
-+
-+static const struct soc_enum pcm186x_gain_sel[] = {
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0,
-+ 0xff,
-+ ARRAY_SIZE(pcm186x_gain_sel_text),
-+ pcm186x_gain_sel_text,
-+ pcm186x_gain_sel_value),
-+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0,
-+ 0xff,
-+ ARRAY_SIZE(pcm186x_gain_sel_text),
-+ pcm186x_gain_sel_text,
-+ pcm186x_gain_sel_value),
-+};
-+
-+static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = {
-+ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]),
-+ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]),
-+ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel),
-+ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]),
-+ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]),
-+};
-+
-+static int pcm1863_add_controls(struct snd_soc_component *component)
-+{
-+ snd_soc_add_component_controls(component,
-+ pcm1863_snd_controls_card,
-+ ARRAY_SIZE(pcm1863_snd_controls_card));
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_select_clk(
-+ struct snd_soc_component *component, int clk_id)
-+{
-+ switch (clk_id) {
-+ case HIFIBERRY_DACPRO_NOCLOCK:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK44EN:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
-+ break;
-+ case HIFIBERRY_DACPRO_CLK48EN:
-+ snd_soc_component_update_bits(component,
-+ PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
-+ break;
-+ }
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component)
-+{
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component)
-+{
-+ unsigned int sck;
-+
-+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
-+ return (!(sck & 0x40));
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(
-+ struct snd_soc_component *component)
-+{
-+ msleep(2);
-+ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component);
-+}
-+
-+static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component)
-+{
-+ bool isClk44EN, isClk48En, isNoClk;
-+
-+ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
-+ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
-+ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
-+ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component);
-+
-+ return (isClk44EN && isClk48En && !isNoClk);
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate)
-+{
-+ int type;
-+
-+ switch (sample_rate) {
-+ case 11025:
-+ case 22050:
-+ case 44100:
-+ case 88200:
-+ case 176400:
-+ case 352800:
-+ type = HIFIBERRY_DACPRO_CLK44EN;
-+ break;
-+ default:
-+ type = HIFIBERRY_DACPRO_CLK48EN;
-+ break;
-+ }
-+ return type;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component,
-+ int sample_rate)
-+{
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+
-+ if (!IS_ERR(pcm512x->sclk)) {
-+ int ctype;
-+
-+ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate);
-+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
-+ ? CLK_44EN_RATE : CLK_48EN_RATE);
-+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype);
-+ }
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver;
-+ struct pcm512x_priv *priv;
-+ int ret;
-+
-+ if (slave)
-+ snd_rpi_hifiberry_is_dacpro = false;
-+ else
-+ snd_rpi_hifiberry_is_dacpro =
-+ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac);
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+ struct snd_soc_dai_link *dai = rtd->dai_link;
-+
-+ dai->name = "HiFiBerry DAC+ADC Pro";
-+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
-+
-+ // set DAC DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM);
-+ if (ret < 0)
-+ return ret;
-+
-+ // set ADC DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1],
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBS_CFS);
-+ if (ret < 0)
-+ return ret;
-+
-+ // set CPU DAI configuration
-+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
-+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-+ if (ret < 0)
-+ return ret;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
-+ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03);
-+ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
-+ } else {
-+ priv = snd_soc_component_get_drvdata(dac);
-+ priv->sclk = ERR_PTR(-ENOENT);
-+ }
-+
-+ /* disable 24bit mode as long as I2S module does not have sign extension fixed */
-+ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ ret = pcm1863_add_controls(adc);
-+ if (ret < 0)
-+ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
-+ ret);
-+
-+ /* set GPIO2 to output, GPIO3 input */
-+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
-+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-+
-+ if (digital_gain_0db_limit) {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */
-+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
-+ struct snd_ratnum *rats_no_pll;
-+ unsigned int num = 0, den = 0;
-+ int err;
-+
-+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
-+ if (!rats_no_pll)
-+ return -ENOMEM;
-+
-+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
-+ rats_no_pll->den_min = 1;
-+ rats_no_pll->den_max = 128;
-+ rats_no_pll->den_step = 1;
-+
-+ err = snd_interval_ratnum(hw_param_interval(params,
-+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
-+ if (err >= 0 && den) {
-+ params->rate_num = num;
-+ params->rate_den = den;
-+ }
-+
-+ devm_kfree(rtd->dev, rats_no_pll);
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ int ret = 0;
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ int channels = params_channels(params);
-+ int width = 32;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+
-+ if (snd_rpi_hifiberry_is_dacpro) {
-+
-+ width = snd_pcm_format_physical_width(params_format(params));
-+
-+ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac,
-+ params_rate(params));
-+
-+ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den(
-+ substream, params);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03,
-+ channels, width);
-+ if (ret)
-+ return ret;
-+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03,
-+ channels, width);
-+ if (ret)
-+ return ret;
-+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03,
-+ channels, width);
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_startup(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+
-+ /* switch on respective LED */
-+ if (!substream->stream)
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+ else
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplusadcpro_shutdown(
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-+
-+ /* switch off respective LED */
-+ if (!substream->stream)
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+ else
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
-+}
-+
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = {
-+ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params,
-+ .startup = snd_rpi_hifiberry_dacplusadcpro_startup,
-+ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
-+};
-+
-+static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
-+ {
-+ .name = "pcm512x.1-004d",
-+ .dai_name = "pcm512x-hifi",
-+ },
-+ {
-+ .name = "pcm186x.1-004a",
-+ .dai_name = "pcm1863-aif",
-+ },
-+};
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
-+{
-+ .name = "HiFiBerry DAC+ADC PRO",
-+ .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
-+ .cpu_dai_name = "bcm2708-i2s.0",
-+ .platform_name = "bcm2708-i2s.0",
-+ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
-+ .num_codecs = 2,
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
-+ .init = snd_rpi_hifiberry_dacplusadcpro_init,
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = {
-+ .name = "snd_rpi_hifiberry_dacplusadcpro",
-+ .driver_name = "HifiberryDacpAdcPro",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai),
-+};
-+
-+static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev)
-+{
-+ int ret = 0, i = 0;
-+ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro;
-+
-+ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev;
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+ if (i2s_node) {
-+ for (i = 0; i < card->num_links; i++) {
-+ dai->cpu_dai_name = NULL;
-+ dai->cpu_of_node = i2s_node;
-+ dai->platform_name = NULL;
-+ dai->platform_of_node = i2s_node;
-+ }
-+ }
-+ }
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
-+ slave = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplusadcpro,slave");
-+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
-+ 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 snd_rpi_hifiberry_dacplusadcpro_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dacplusadcpro", },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = {
-+ .driver = {
-+ .name = "snd-rpi-hifiberry-dacplusadcpro",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dacplusadcpro_probe,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver);
-+
-+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
-+MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 8ffc08d336326d576b84d59135402f08cf2cf41c Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 22 Jul 2019 22:13:30 +0800
+Subject: [PATCH] staging: bcm2835-codec: implement
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+
+The stateful decoder specification shows an optional step for retrieving
+the miminum number of capture buffers required for the decoder to
+proceed. While not a required parameter, having it makes some
+applications happy.
+
+bcm2835-codec is a little different from other decoder implementations
+in that there is an intermediate format conversion between the hardware
+and V4L2 buffers. The number of capture buffers required is therefore
+independent of the stream and DPB etc.
+
+There are plans to remove the conversion, but it requires a fair amount
+of rework within the firmware. Until that is done, simply return a value
+of 1.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
++ } else if (dev->role == DECODE) {
++ v4l2_ctrl_handler_init(hdl, 1);
++
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
++ 1, 1, 1, 1);
++ if (hdl->error) {
++ rc = hdl->error;
++ goto free_ctrl_handler;
++ }
++ ctx->fh.ctrl_handler = hdl;
++ v4l2_ctrl_handler_setup(hdl);
+ }
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+++ /dev/null
-From 88d5709082671ff2abeddc2a9b4acacbb85b9194 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 31 Jul 2019 17:36:34 +0100
-Subject: [PATCH] drm/vc4: A present but empty dmas disables audio
-
-Overlays are unable to remove properties in the base DTB, but they
-can overwrite them. Allow a present but empty 'dmas' property
-to also disable the HDMI audio interface.
-
-See: https://github.com/raspberrypi/linux/issues/2489
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- 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
-@@ -1054,10 +1054,12 @@ static int vc4_hdmi_audio_init(struct vc
- struct device *dev = &hdmi->pdev->dev;
- const __be32 *addr;
- int ret;
-+ int len;
-
-- if (!of_find_property(dev->of_node, "dmas", NULL)) {
-+ if (!of_find_property(dev->of_node, "dmas", &len) ||
-+ len == 0) {
- dev_warn(dev,
-- "'dmas' DT property is missing, no HDMI audio\n");
-+ "'dmas' DT property is missing or empty, no HDMI audio\n");
- return 0;
- }
-
--- /dev/null
+From d06677b96fc10122363028dea9ca06e5f9899865 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 22 Jul 2019 22:20:55 +0800
+Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct
+ video_device
+
+Instead of filling in the struct v4l2_capability device_caps
+field, fill in the struct video_device device_caps field.
+
+That way the V4L2 core knows what the capabilities of the
+video device are.
+
+This is similar to a cleanup series by Hans Verkuil [1].
+
+[1] https://www.spinics.net/lists/linux-media/msg153313.html
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file *
+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+ }
+
+@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
++ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+
+ switch (role) {
+ case DECODE:
--- /dev/null
+From fb8e73c19c2e153444b34e8d9804371095e92fe0 Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Tue, 16 Jul 2019 12:18:21 +0100
+Subject: [PATCH] Add HDMI1 facility to the driver.
+
+For generic ALSA, all you need is the bcm2835.h change, but
+have also added structures for IEC958 HDMI. Not sure how to
+test those.
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++---
+ .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++-
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str
+ if (err)
+ return err;
+
+- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
++ if (err)
++ return err;
++
++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
+ if (err)
+ return err;
+
+@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28
+ .newctl = snd_bcm2835_new_ctl,
+ };
+
+-static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
++static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
+ .driver = {
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+- .route = AUDIO_DEST_HDMI
++ .route = AUDIO_DEST_HDMI0
++};
++
++static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
++ .driver = {
++ .name = "bcm2835_hdmi",
++ .owner = THIS_MODULE,
++ },
++ .shortname = "bcm2835 HDMI 1",
++ .longname = "bcm2835 HDMI 1",
++ .minchannels = 1,
++ .newpcm = bcm2835_audio_simple_newpcm,
++ .newctl = snd_bcm2835_new_hdmi_ctl,
++ .route = AUDIO_DEST_HDMI1
+ };
+
+ static struct bcm2835_audio_driver bcm2835_audio_headphones = {
+@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil
+ .is_enabled = &enable_compat_alsa,
+ },
+ {
+- .audio_driver = &bcm2835_audio_hdmi,
++ .audio_driver = &bcm2835_audio_hdmi0,
++ .is_enabled = &enable_hdmi,
++ },
++ {
++ .audio_driver = &bcm2835_audio_hdmi1,
+ .is_enabled = &enable_hdmi,
+ },
+ {
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+@@ -33,7 +33,9 @@ enum {
+ enum snd_bcm2835_route {
+ AUDIO_DEST_AUTO = 0,
+ AUDIO_DEST_HEADPHONES = 1,
+- AUDIO_DEST_HDMI = 2,
++ AUDIO_DEST_HDMI = 2, // for backwards compatibility.
++ AUDIO_DEST_HDMI0 = 2,
++ AUDIO_DEST_HDMI1 = 3,
+ AUDIO_DEST_MAX,
+ };
+
+++ /dev/null
-From d6baa1bd90e7e68ac69d5378d70174ea67bf35dc Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Mon, 29 Jul 2019 12:02:59 +0100
-Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display
-
-If an errant interrupt flag was received from a non-existent display,
-a NULL pointer access was made. Protect against this by checking if a
-second display is present prior to checking the interrupt flags.
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++-------
- 1 file changed, 10 insertions(+), 7 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1087,14 +1087,17 @@ static irqreturn_t vc4_crtc_irq_handler(
- vc4_crtc_handle_page_flip(crtc_list[0]);
- }
-
-- /* Check for the secondary display too */
-- chan = readl(crtc_list[0]->regs + SMIDSW1);
-+ if (crtc_list[1]) {
-+ /* Check for the secondary display too */
-+ chan = readl(crtc_list[0]->regs + SMIDSW1);
-
-- if (chan & 1) {
-- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-- if (crtc_list[1]->vblank_enabled)
-- drm_crtc_handle_vblank(&crtc_list[1]->base);
-- vc4_crtc_handle_page_flip(crtc_list[1]);
-+ if (chan & 1) {
-+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
-+
-+ if (crtc_list[1]->vblank_enabled)
-+ drm_crtc_handle_vblank(&crtc_list[1]->base);
-+ vc4_crtc_handle_page_flip(crtc_list[1]);
-+ }
- }
- }
-
+++ /dev/null
-From dcf515d36ce574edd773c9c6321b6bbf9724e209 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Thu, 9 May 2019 14:30:37 +0100
-Subject: [PATCH] drivers: char: add chardev for mmap'ing the RPiVid
- control registers
-
-Based on the gpiomem driver, allow mapping of the decoder register
-spaces such that userspace can access control/status registers.
-This driver is intended for use with a custom ffmpeg backend accelerator
-prior to a v4l2 driver being written.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/char/broadcom/Kconfig | 8 +
- drivers/char/broadcom/Makefile | 1 +
- drivers/char/broadcom/rpivid-mem.c | 286 +++++++++++++++++++++++++++++
- drivers/mfd/bcm2835-pm.c | 12 +-
- drivers/soc/bcm/bcm2835-power.c | 6 +-
- include/linux/mfd/bcm2835-pm.h | 2 +-
- 6 files changed, 305 insertions(+), 10 deletions(-)
- create mode 100644 drivers/char/broadcom/rpivid-mem.c
-
---- a/drivers/char/broadcom/Kconfig
-+++ b/drivers/char/broadcom/Kconfig
-@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV
- This driver provides a character device interface (ioctl + read/write) to
- Broadcom's Secondary Memory interface. The low-level functionality is provided
- by the SMI driver itself.
-+
-+config RPIVID_MEM
-+ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware"
-+ default n
-+ help
-+ This driver provides a character device interface for memory-map operations
-+ so userspace tools can access the control and status registers of the
-+ Raspberry Pi RPiVid video decoder hardware.
---- a/drivers/char/broadcom/Makefile
-+++ b/drivers/char/broadcom/Makefile
-@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm
-
- obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
- obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
-+obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o
---- /dev/null
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -0,0 +1,286 @@
-+/**
-+ * rpivid-mem.c - character device access to the RPiVid decoder registers
-+ *
-+ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder
-+ * register blocks such that ffmpeg plugins can access the hardware.
-+ *
-+ * Jonathan Bell <jonathan@raspberrypi.org>
-+ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions, and the following disclaimer,
-+ * without modification.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. The names of the above-listed copyright holders may not be used
-+ * to endorse or promote products derived from this software without
-+ * specific prior written permission.
-+ *
-+ * ALTERNATIVELY, this software may be distributed under the terms of the
-+ * GNU General Public License ("GPL") version 2, as published by the Free
-+ * Software Foundation.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/cdev.h>
-+#include <linux/pagemap.h>
-+#include <linux/io.h>
-+
-+#define DRIVER_NAME "rpivid-mem"
-+#define DEVICE_MINOR 0
-+
-+struct rpivid_mem_priv {
-+ dev_t devid;
-+ struct class *class;
-+ struct cdev rpivid_mem_cdev;
-+ unsigned long regs_phys;
-+ unsigned long mem_window_len;
-+ struct device *dev;
-+ const char *name;
-+};
-+
-+static int rpivid_mem_open(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+ struct rpivid_mem_priv *priv;
-+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
-+ ret = -ENXIO;
-+
-+ priv = container_of(inode->i_cdev, struct rpivid_mem_priv,
-+ rpivid_mem_cdev);
-+ if (!priv)
-+ return -EINVAL;
-+ file->private_data = priv;
-+ return ret;
-+}
-+
-+static int rpivid_mem_release(struct inode *inode, struct file *file)
-+{
-+ int dev = iminor(inode);
-+ int ret = 0;
-+
-+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
-+ ret = -ENXIO;
-+
-+ return ret;
-+}
-+
-+static const struct vm_operations_struct rpivid_mem_vm_ops = {
-+#ifdef CONFIG_HAVE_IOREMAP_PROT
-+ .access = generic_access_phys
-+#endif
-+};
-+
-+static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ struct rpivid_mem_priv *priv;
-+ unsigned long pages;
-+
-+ priv = file->private_data;
-+ pages = priv->regs_phys >> PAGE_SHIFT;
-+ /*
-+ * The address decode is far larger than the actual number of registers.
-+ * Just map the whole lot in.
-+ */
-+ vma->vm_page_prot = phys_mem_access_prot(file, pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot);
-+ vma->vm_ops = &rpivid_mem_vm_ops;
-+ if (remap_pfn_range(vma, vma->vm_start,
-+ pages,
-+ priv->mem_window_len,
-+ vma->vm_page_prot)) {
-+ return -EAGAIN;
-+ }
-+ return 0;
-+}
-+
-+static const struct file_operations
-+rpivid_mem_fops = {
-+ .owner = THIS_MODULE,
-+ .open = rpivid_mem_open,
-+ .release = rpivid_mem_release,
-+ .mmap = rpivid_mem_mmap,
-+};
-+
-+static const struct of_device_id rpivid_mem_of_match[];
-+static int rpivid_mem_probe(struct platform_device *pdev)
-+{
-+ int err;
-+ void *ptr_err;
-+ const struct of_device_id *id;
-+ struct device *dev = &pdev->dev;
-+ struct device *rpivid_mem_dev;
-+ struct resource *ioresource;
-+ struct rpivid_mem_priv *priv;
-+
-+
-+ /* Allocate buffers and instance data */
-+
-+ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
-+
-+ if (!priv) {
-+ err = -ENOMEM;
-+ goto failed_inst_alloc;
-+ }
-+ platform_set_drvdata(pdev, priv);
-+
-+ priv->dev = dev;
-+ id = of_match_device(rpivid_mem_of_match, dev);
-+ if (!id)
-+ return -EINVAL;
-+ priv->name = id->data;
-+
-+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (ioresource) {
-+ priv->regs_phys = ioresource->start;
-+ priv->mem_window_len = ioresource->end - ioresource->start;
-+ } else {
-+ dev_err(priv->dev, "failed to get IO resource");
-+ err = -ENOENT;
-+ goto failed_get_resource;
-+ }
-+
-+ /* Create character device entries */
-+
-+ err = alloc_chrdev_region(&priv->devid,
-+ DEVICE_MINOR, 2, priv->name);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to allocate device number");
-+ goto failed_alloc_chrdev;
-+ }
-+ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops);
-+ priv->rpivid_mem_cdev.owner = THIS_MODULE;
-+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2);
-+ if (err != 0) {
-+ dev_err(priv->dev, "unable to register device");
-+ goto failed_cdev_add;
-+ }
-+
-+ /* Create sysfs entries */
-+
-+ priv->class = class_create(THIS_MODULE, priv->name);
-+ ptr_err = priv->class;
-+ if (IS_ERR(ptr_err))
-+ goto failed_class_create;
-+
-+ rpivid_mem_dev = device_create(priv->class, NULL,
-+ priv->devid, NULL,
-+ priv->name);
-+ ptr_err = rpivid_mem_dev;
-+ if (IS_ERR(ptr_err))
-+ goto failed_device_create;
-+
-+ /* Legacy alias */
-+ {
-+ char *oldname = kstrdup(priv->name, GFP_KERNEL);
-+
-+ oldname[1] = 'a';
-+ oldname[2] = 'r';
-+ oldname[3] = 'g';
-+ oldname[4] = 'o';
-+ oldname[5] = 'n';
-+ (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
-+ oldname + 1);
-+ kfree(oldname);
-+ }
-+
-+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
-+ priv->name, priv->regs_phys, priv->mem_window_len);
-+
-+ return 0;
-+
-+failed_device_create:
-+ class_destroy(priv->class);
-+failed_class_create:
-+ cdev_del(&priv->rpivid_mem_cdev);
-+ err = PTR_ERR(ptr_err);
-+failed_cdev_add:
-+ unregister_chrdev_region(priv->devid, 1);
-+failed_alloc_chrdev:
-+failed_get_resource:
-+ kfree(priv);
-+failed_inst_alloc:
-+ dev_err(priv->dev, "could not load rpivid_mem");
-+ return err;
-+}
-+
-+static int rpivid_mem_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
-+
-+ device_destroy(priv->class, priv->devid);
-+ class_destroy(priv->class);
-+ cdev_del(&priv->rpivid_mem_cdev);
-+ unregister_chrdev_region(priv->devid, 1);
-+ kfree(priv);
-+
-+ dev_info(dev, "%s driver removed - OK", priv->name);
-+ return 0;
-+}
-+
-+static const struct of_device_id rpivid_mem_of_match[] = {
-+ {
-+ .compatible = "raspberrypi,rpivid-hevc-decoder",
-+ .data = "rpivid-hevcmem",
-+ },
-+ {
-+ .compatible = "raspberrypi,rpivid-h264-decoder",
-+ .data = "rpivid-h264mem",
-+ },
-+ {
-+ .compatible = "raspberrypi,rpivid-vp9-decoder",
-+ .data = "rpivid-vp9mem",
-+ },
-+ /* The "intc" is included as this block of hardware contains the
-+ * "frame done" status flags.
-+ */
-+ {
-+ .compatible = "raspberrypi,rpivid-local-intc",
-+ .data = "rpivid-intcmem",
-+ },
-+ { /* sentinel */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, rpivid_mem_of_match);
-+
-+static struct platform_driver rpivid_mem_driver = {
-+ .probe = rpivid_mem_probe,
-+ .remove = rpivid_mem_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = rpivid_mem_of_match,
-+ },
-+};
-+
-+module_platform_driver(rpivid_mem_driver);
-+
-+MODULE_ALIAS("platform:rpivid-mem");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace");
-+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.org>");
---- a/drivers/mfd/bcm2835-pm.c
-+++ b/drivers/mfd/bcm2835-pm.c
-@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf
- if (ret)
- return ret;
-
-- /* Map the ARGON ASB regs if present. */
-+ /* Map the RPiVid ASB regs if present. */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- if (res) {
-- pm->arg_asb = devm_ioremap_resource(dev, res);
-- if (IS_ERR(pm->arg_asb)) {
-- dev_err(dev, "Failed to map ARGON ASB: %ld\n",
-- PTR_ERR(pm->arg_asb));
-- return PTR_ERR(pm->arg_asb);
-+ pm->rpivid_asb = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pm->rpivid_asb)) {
-+ dev_err(dev, "Failed to map RPiVid ASB: %ld\n",
-+ PTR_ERR(pm->rpivid_asb));
-+ return PTR_ERR(pm->rpivid_asb);
- }
- }
-
---- a/drivers/soc/bcm/bcm2835-power.c
-+++ b/drivers/soc/bcm/bcm2835-power.c
-@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl
- power->base = pm->base;
- power->asb = pm->asb;
-
-- /* 2711 hack: the new ARGON ASB took over V3D, which is our
-+ /* 2711 hack: the new RPiVid ASB took over V3D, which is our
- * only consumer of this driver so far. The old ASB seems to
- * still be present with ISP and H264 bits but no V3D, but I
- * don't know if that's real or not. The V3D is in the same
- * place in the new ASB as the old one, so just poke the new
- * one for now.
- */
-- if (pm->arg_asb) {
-- power->asb = pm->arg_asb;
-+ if (pm->rpivid_asb) {
-+ power->asb = pm->rpivid_asb;
- power->is_2711 = true;
- }
-
---- a/include/linux/mfd/bcm2835-pm.h
-+++ b/include/linux/mfd/bcm2835-pm.h
-@@ -9,7 +9,7 @@ struct bcm2835_pm {
- struct device *dev;
- void __iomem *base;
- void __iomem *asb;
-- void __iomem *arg_asb;
-+ void __iomem *rpivid_asb;
- };
-
- #endif /* BCM2835_MFD_PM_H */
--- /dev/null
+From a82d716ab4c2ab5f198f3461e32614defb52c724 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 25 Jul 2019 17:27:44 +0100
+Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode
+ switching
+
+The details over when and how a driver is to service the
+vblank events are sketchy, and the fkms driver was triggering
+a kernel warning every time the crtc was enabled or disabled.
+
+Copy the event handling as used by the vc4-kms driver slightly
+more closely, and we avoid the warnings.
+
+https://github.com/raspberrypi/linux/issues/3020
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++--------
+ 1 file changed, 33 insertions(+), 15 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -964,6 +964,7 @@ static void vc4_crtc_mode_set_nofb(struc
+
+ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+ {
++ struct drm_device *dev = crtc->dev;
+ struct drm_plane *plane;
+
+ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
+@@ -979,6 +980,35 @@ static void vc4_crtc_disable(struct drm_
+
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+ vc4_plane_atomic_disable(plane, plane->state);
++
++ /*
++ * Make sure we issue a vblank event after disabling the CRTC if
++ * someone was waiting it.
++ */
++ if (crtc->state->event) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev->event_lock, flags);
++ drm_crtc_send_vblank_event(crtc, crtc->state->event);
++ crtc->state->event = NULL;
++ spin_unlock_irqrestore(&dev->event_lock, flags);
++ }
++}
++
++static void vc4_crtc_consume_event(struct drm_crtc *crtc)
++{
++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
++ struct drm_device *dev = crtc->dev;
++ unsigned long flags;
++
++ crtc->state->event->pipe = drm_crtc_index(crtc);
++
++ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
++
++ spin_lock_irqsave(&dev->event_lock, flags);
++ vc4_crtc->event = crtc->state->event;
++ crtc->state->event = NULL;
++ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
+ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
+@@ -988,6 +1018,7 @@ static void vc4_crtc_enable(struct drm_c
+ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
+ crtc->base.id);
+ drm_crtc_vblank_on(crtc);
++ vc4_crtc_consume_event(crtc);
+
+ /* Unblank the planes (if they're supposed to be displayed). */
+ drm_atomic_crtc_for_each_plane(plane, crtc)
+@@ -1059,23 +1090,10 @@ static int vc4_crtc_atomic_check(struct
+ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+ {
+- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+- struct drm_device *dev = crtc->dev;
+-
+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
+ crtc->base.id);
+- if (crtc->state->event) {
+- unsigned long flags;
+-
+- crtc->state->event->pipe = drm_crtc_index(crtc);
+-
+- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+-
+- spin_lock_irqsave(&dev->event_lock, flags);
+- vc4_crtc->event = crtc->state->event;
+- crtc->state->event = NULL;
+- spin_unlock_irqrestore(&dev->event_lock, flags);
+- }
++ if (crtc->state->active && old_state->active && crtc->state->event)
++ vc4_crtc_consume_event(crtc);
+ }
+
+ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
--- /dev/null
+From 71402ae2a97b18f0c03b763a2e1e2800f360d50a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 25 Jul 2019 17:34:29 +0100
+Subject: [PATCH] drm/vc4: Remove unused mode variable
+
+"89d1376 drm/vc4: Add support for margins to fkms" removed
+the requirement for having the mode structure from vc4_plane_to_mb,
+but didn't remove it as a local to the function, causing a
+compiler warning.
+
+Remove the unused variable.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -525,7 +525,6 @@ static int vc4_plane_to_mb(struct drm_pl
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ int num_planes = fb->format->num_planes;
+- struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+++ /dev/null
-From 8f4720ca2ed61fbaf2a3039b510e276d06d6a2fb Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Thu, 1 Aug 2019 16:41:20 +0100
-Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3
- and MX3
-
-These wireless mouse/keyboard combo remote control devices specify
-multiple "wheel" events in their report descriptors. The wheel events
-are incorrectly defined and apparently map to accelerometer data, leading
-to spurious mouse scroll events being generated at an extreme rate when
-the device is moved.
-
-As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask
-feeding the extra wheel events to the input subsystem.
-
-See: https://github.com/raspberrypi/firmware/issues/1189
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/hid/hid-ids.h | 6 ++++++
- drivers/hid/hid-quirks.c | 2 ++
- 2 files changed, 8 insertions(+)
-
---- a/drivers/hid/hid-ids.h
-+++ b/drivers/hid/hid-ids.h
-@@ -223,6 +223,9 @@
- #define USB_VENDOR_ID_BAANTO 0x2453
- #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
-
-+#define USB_VENDOR_ID_BEKEN 0x25a7
-+#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402
-+
- #define USB_VENDOR_ID_BELKIN 0x050d
- #define USB_DEVICE_ID_FLIP_KVM 0x3201
-
-@@ -1224,6 +1227,9 @@
- #define USB_VENDOR_ID_XAT 0x2505
- #define USB_DEVICE_ID_XAT_CSR 0x0220
-
-+#define USB_VENDOR_ID_XENTA 0x1d57
-+#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03
-+
- #define USB_VENDOR_ID_XIN_MO 0x16c0
- #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
- #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1
---- a/drivers/hid/hid-quirks.c
-+++ b/drivers/hid/hid-quirks.c
-@@ -41,6 +41,7 @@ static const struct hid_device_id hid_qu
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
- { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
-@@ -175,6 +176,7 @@ static const struct hid_device_id hid_qu
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
-
- { 0 }
- };
+++ /dev/null
-From 661cefed28f420f7ca6e52882d83a7a321d60256 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 14 Jun 2019 10:12:07 +0100
-Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property
-
-Some HDMI monitors do not abide by the full or limited
-(16-235) range RGB flags in the AVI infoframe. This can
-result in images looking washed out (if given limited and
-interpreting as full), or detail disappearing at the extremes
-(given full and interpreting as limited).
-
-Copy the Intel i915 driver's approach of adding an override
-property ("Broadcast RGB") to force one mode or the other.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++--
- 1 file changed, 177 insertions(+), 13 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -287,6 +287,13 @@ to_vc4_fkms_encoder(struct drm_encoder *
- return container_of(encoder, struct vc4_fkms_encoder, base);
- }
-
-+/* "Broadcast RGB" property.
-+ * Allows overriding of HDMI full or limited range RGB
-+ */
-+#define VC4_BROADCAST_RGB_AUTO 0
-+#define VC4_BROADCAST_RGB_FULL 1
-+#define VC4_BROADCAST_RGB_LIMITED 2
-+
- /* VC4 FKMS connector KMS struct */
- struct vc4_fkms_connector {
- struct drm_connector base;
-@@ -299,6 +306,8 @@ struct vc4_fkms_connector {
- struct vc4_dev *vc4_dev;
- u32 display_number;
- u32 display_type;
-+
-+ struct drm_property *broadcast_rgb_property;
- };
-
- static inline struct vc4_fkms_connector *
-@@ -307,6 +316,16 @@ to_vc4_fkms_connector(struct drm_connect
- return container_of(connector, struct vc4_fkms_connector, base);
- }
-
-+/* VC4 FKMS connector state */
-+struct vc4_fkms_connector_state {
-+ struct drm_connector_state base;
-+
-+ int broadcast_rgb;
-+};
-+
-+#define to_vc4_fkms_connector_state(x) \
-+ container_of(x, struct vc4_fkms_connector_state, base)
-+
- static u32 vc4_get_display_type(u32 display_number)
- {
- const u32 display_types[] = {
-@@ -863,8 +882,6 @@ static void vc4_crtc_mode_set_nofb(struc
- mode->picture_aspect_ratio, mode->flags);
- mb.timings.display = vc4_crtc->display_number;
-
-- mb.timings.video_id_code = frame.avi.video_code;
--
- mb.timings.clock = mode->clock;
- mb.timings.hdisplay = mode->hdisplay;
- mb.timings.hsync_start = mode->hsync_start;
-@@ -902,11 +919,30 @@ static void vc4_crtc_mode_set_nofb(struc
- break;
- }
-
-- if (!vc4_encoder->hdmi_monitor)
-+ if (!vc4_encoder->hdmi_monitor) {
- mb.timings.flags |= TIMINGS_FLAGS_DVI;
-- else if (drm_default_rgb_quant_range(mode) ==
-+ mb.timings.video_id_code = frame.avi.video_code;
-+ } else {
-+ struct vc4_fkms_connector_state *conn_state =
-+ to_vc4_fkms_connector_state(vc4_crtc->connector->state);
-+
-+ /* Do not provide a VIC as the HDMI spec requires that we do not
-+ * signal the opposite of the defined range in the AVI
-+ * infoframe.
-+ */
-+ mb.timings.video_id_code = 0;
-+
-+ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
-+ /* See CEA-861-E - 5.1 Default Encoding Parameters */
-+ if (drm_default_rgb_quant_range(mode) ==
- HDMI_QUANTIZATION_RANGE_LIMITED)
-- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ } else {
-+ if (conn_state->broadcast_rgb ==
-+ VC4_BROADCAST_RGB_LIMITED)
-+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
-+ }
-+ }
-
- /*
- FIXME: To implement
-@@ -1364,13 +1400,95 @@ static void vc4_fkms_connector_destroy(s
- drm_connector_cleanup(connector);
- }
-
-+/**
-+ * vc4_connector_duplicate_state - duplicate connector state
-+ * @connector: digital connector
-+ *
-+ * Allocates and returns a copy of the connector state (both common and
-+ * digital connector specific) for the specified connector.
-+ *
-+ * Returns: The newly allocated connector state, or NULL on failure.
-+ */
-+struct drm_connector_state *
-+vc4_connector_duplicate_state(struct drm_connector *connector)
-+{
-+ struct vc4_fkms_connector_state *state;
-+
-+ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
-+ if (!state)
-+ return NULL;
-+
-+ __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
-+ return &state->base;
-+}
-+
-+/**
-+ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
-+ * @connector: Connector to get the property for.
-+ * @state: Connector state to retrieve the property from.
-+ * @property: Property to retrieve.
-+ * @val: Return value for the property.
-+ *
-+ * Returns the atomic property value for a digital connector.
-+ */
-+int vc4_connector_atomic_get_property(struct drm_connector *connector,
-+ const struct drm_connector_state *state,
-+ struct drm_property *property,
-+ uint64_t *val)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_fkms_connector_state *vc4_conn_state =
-+ to_vc4_fkms_connector_state(state);
-+
-+ if (property == fkms_connector->broadcast_rgb_property) {
-+ *val = vc4_conn_state->broadcast_rgb;
-+ } else {
-+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
-+ property->base.id, property->name);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
-+ * @connector: Connector to set the property for.
-+ * @state: Connector state to set the property on.
-+ * @property: Property to set.
-+ * @val: New value for the property.
-+ *
-+ * Sets the atomic property value for a digital connector.
-+ */
-+int vc4_connector_atomic_set_property(struct drm_connector *connector,
-+ struct drm_connector_state *state,
-+ struct drm_property *property,
-+ uint64_t val)
-+{
-+ struct vc4_fkms_connector *fkms_connector =
-+ to_vc4_fkms_connector(connector);
-+ struct vc4_fkms_connector_state *vc4_conn_state =
-+ to_vc4_fkms_connector_state(state);
-+
-+ if (property == fkms_connector->broadcast_rgb_property) {
-+ vc4_conn_state->broadcast_rgb = val;
-+ return 0;
-+ }
-+
-+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
-+ property->base.id, property->name);
-+ return -EINVAL;
-+}
-+
- static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
- .detect = vc4_fkms_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = vc4_fkms_connector_destroy,
-- .reset = drm_atomic_helper_connector_reset,
-- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+ .atomic_duplicate_state = vc4_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+ .atomic_get_property = vc4_connector_atomic_get_property,
-+ .atomic_set_property = vc4_connector_atomic_set_property,
- };
-
- static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
-@@ -1383,12 +1501,40 @@ static const struct drm_connector_helper
- .best_encoder = vc4_fkms_connector_best_encoder,
- };
-
-+static const struct drm_prop_enum_list broadcast_rgb_names[] = {
-+ { VC4_BROADCAST_RGB_AUTO, "Automatic" },
-+ { VC4_BROADCAST_RGB_FULL, "Full" },
-+ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
-+};
-+
-+static void
-+vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
-+{
-+ struct drm_device *dev = fkms_connector->base.dev;
-+ struct drm_property *prop;
-+
-+ prop = fkms_connector->broadcast_rgb_property;
-+ if (!prop) {
-+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
-+ "Broadcast RGB",
-+ broadcast_rgb_names,
-+ ARRAY_SIZE(broadcast_rgb_names));
-+ if (!prop)
-+ return;
-+
-+ fkms_connector->broadcast_rgb_property = prop;
-+ }
-+
-+ drm_object_attach_property(&fkms_connector->base.base, prop, 0);
-+}
-+
- static struct drm_connector *
- vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
- u32 display_num)
- {
- struct drm_connector *connector = NULL;
- struct vc4_fkms_connector *fkms_connector;
-+ struct vc4_fkms_connector_state *conn_state = NULL;
- struct vc4_dev *vc4_dev = to_vc4_dev(dev);
- int ret = 0;
-
-@@ -1397,9 +1543,18 @@ vc4_fkms_connector_init(struct drm_devic
- fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
- GFP_KERNEL);
- if (!fkms_connector) {
-- ret = -ENOMEM;
-- goto fail;
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ /*
-+ * Allocate enough memory to hold vc4_fkms_connector_state,
-+ */
-+ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
-+ if (!conn_state) {
-+ kfree(fkms_connector);
-+ return ERR_PTR(-ENOMEM);
- }
-+
- connector = &fkms_connector->base;
-
- fkms_connector->encoder = encoder;
-@@ -1407,6 +1562,9 @@ vc4_fkms_connector_init(struct drm_devic
- fkms_connector->display_type = vc4_get_display_type(display_num);
- fkms_connector->vc4_dev = vc4_dev;
-
-+ __drm_atomic_helper_connector_reset(connector,
-+ &conn_state->base);
-+
- if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
-@@ -1427,10 +1585,14 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-- /* Create and attach TV margin props to this connector. */
-- ret = drm_mode_create_tv_margin_properties(dev);
-- if (ret)
-- return ERR_PTR(ret);
-+ /* Create and attach TV margin props to this connector.
-+ * Already done for SDTV outputs.
-+ */
-+ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ goto fail;
-+ }
-
- drm_connector_attach_tv_margin_properties(connector);
-
-@@ -1439,6 +1601,8 @@ vc4_fkms_connector_init(struct drm_devic
-
- connector->doublescan_allowed = 0;
-
-+ vc4_attach_broadcast_rgb_property(fkms_connector);
-+
- drm_connector_attach_encoder(connector, encoder);
-
- return connector;
--- /dev/null
+From cedd3e7ee97213d0d3d0ada2a7df58ad0059372e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 11 Jul 2019 14:57:09 +0100
+Subject: [PATCH] staging:bcm2835-codec: Expand logging on format
+ setting
+
+Adds some more useful logging during format changed events and
+s_fmt.
+
+Reported by: zillevdr <zillevdr@gmx.de>
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc
+ format->es.video.color_space);
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n",
++ __func__, q_data->bytesperline, q_data->height,
++ q_data->crop_width, q_data->crop_height);
++
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+ q_data->bytesperline = format->es.video.crop.width;
+@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c
+ bool update_capture_port = false;
+ int ret;
+
+- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n",
+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+-
++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat),
++ f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+++ /dev/null
-From 651d4137cc20de6b64edd2302ebd82d8e88121df Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 23 Jul 2019 11:09:26 +0100
-Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset
-
-Now that the TV margins are properly parsed and filled into
-drm_cmdline_mode, we just need to initialise the first state at reset to
-get those values and start using them.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1481,10 +1481,17 @@ int vc4_connector_atomic_set_property(st
- return -EINVAL;
- }
-
-+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
-+{
-+ drm_atomic_helper_connector_reset(connector);
-+ drm_atomic_helper_connector_tv_reset(connector);
-+}
-+
- static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
- .detect = vc4_fkms_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = vc4_fkms_connector_destroy,
-+ .reset = vc4_hdmi_connector_reset,
- .atomic_duplicate_state = vc4_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- .atomic_get_property = vc4_connector_atomic_get_property,
--- /dev/null
+From eb4cbf0e6893397f00aff0f90dc9d3df75e98b52 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Thu, 11 Jul 2019 14:58:35 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on
+ format changed
+
+The handling of format changed events incorrectly set bytesperline
+to the cropped width, which ignored padding and formats with
+more than 8bpp.
+Fix these.
+
+Reported by: zillevdr <zillevdr@gmx.de>
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc
+
+ q_data->crop_width = format->es.video.crop.width;
+ q_data->crop_height = format->es.video.crop.height;
+- q_data->bytesperline = format->es.video.crop.width;
++ q_data->bytesperline = get_bytesperline(format->es.video.width,
++ q_data->fmt);
++
+ q_data->height = format->es.video.height;
+ q_data->sizeimage = format->buffer_size_min;
+ if (format->es.video.color_space)
--- /dev/null
+From e2e9da35d4a598490b73da41eea1db27540339fd Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 7 Aug 2019 11:31:08 +0100
+Subject: [PATCH] drm/vc4: Add missing NULL check to
+ vc4_crtc_consume_event
+
+vc4_crtc_consume_event wasn't checking crtc->state->event was
+set before dereferencing it, leading to an OOPS.
+
+Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching"
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1000,6 +1000,9 @@ static void vc4_crtc_consume_event(struc
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+
++ if (!crtc->state->event)
++ return;
++
+ crtc->state->event->pipe = drm_crtc_index(crtc);
+
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+++ /dev/null
-From 9495e07dac5cb6230838763572f73b863cd72019 Mon Sep 17 00:00:00 2001
-From: Chen-Yu Tsai <wens@csie.org>
-Date: Thu, 18 Jul 2019 17:07:05 +0800
-Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API
-
-There are two APIs for mem2mem devices, the older single-planar API and
-the newer multi-planar one. Without making things overly complex, the
-driver can only support one or the other. However the userspace libv4l2
-library has a plugin that allows multi-planar API devices to service
-single-planar consumers.
-
-Chromium supports the multi-planar API exclusively, though this is
-currently limited to ChromiumOS. It would be possible to add support
-for generic Linux.
-
-Switching to the multi-planar API would allow usage of both APIs from
-userspace.
-
-Signed-off-by: Chen-Yu Tsai <wens@csie.org>
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 141 +++++++++---------
- 1 file changed, 74 insertions(+), 67 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo
-
- for (k = 0; k < fmts->num_entries; k++) {
- fmt = &fmts->list[k];
-- if (fmt->fourcc == f->fmt.pix.pixelformat)
-+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
- break;
- }
- if (k == fmts->num_entries)
-@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_
- enum v4l2_buf_type type)
- {
- switch (type) {
-- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return &ctx->q_data[V4L2_M2M_SRC];
-- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- return &ctx->q_data[V4L2_M2M_DST];
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_
- return NULL;
-
- switch (type) {
-- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return &ctx->component->input[0];
-- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- return &ctx->component->output[0];
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n",
-@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc
- format->es.video.crop.width, format->es.video.crop.height,
- format->es.video.color_space);
-
-- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
- q_data->bytesperline = format->es.video.crop.width;
-@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file *
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
-- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
- }
-@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c
-
- q_data = get_q_data(ctx, f->type);
-
-- f->fmt.pix.width = q_data->crop_width;
-- f->fmt.pix.height = q_data->height;
-- f->fmt.pix.field = V4L2_FIELD_NONE;
-- f->fmt.pix.pixelformat = q_data->fmt->fourcc;
-- f->fmt.pix.bytesperline = q_data->bytesperline;
-- f->fmt.pix.sizeimage = q_data->sizeimage;
-- f->fmt.pix.colorspace = ctx->colorspace;
-- f->fmt.pix.xfer_func = ctx->xfer_func;
-- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
-- f->fmt.pix.quantization = ctx->quant;
-+ f->fmt.pix_mp.width = q_data->crop_width;
-+ f->fmt.pix_mp.height = q_data->height;
-+ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
-+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-+ f->fmt.pix_mp.colorspace = ctx->colorspace;
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
-+ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
-+ f->fmt.pix_mp.num_planes = 1;
-+ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
-+ f->fmt.pix_mp.quantization = ctx->quant;
-+ f->fmt.pix_mp.xfer_func = ctx->xfer_func;
-+
-+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
-+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
-
- return 0;
- }
-@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835
- * The V4L2 specification requires the driver to correct the format
- * struct if any of the dimensions is unsupported
- */
-- if (f->fmt.pix.width > MAX_W)
-- f->fmt.pix.width = MAX_W;
-- if (f->fmt.pix.height > MAX_H)
-- f->fmt.pix.height = MAX_H;
-+ if (f->fmt.pix_mp.width > MAX_W)
-+ f->fmt.pix_mp.width = MAX_W;
-+ if (f->fmt.pix_mp.height > MAX_H)
-+ f->fmt.pix_mp.height = MAX_H;
-
- if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
- /* Only clip min w/h on capture. Treat 0x0 as unknown. */
-- if (f->fmt.pix.width < MIN_W)
-- f->fmt.pix.width = MIN_W;
-- if (f->fmt.pix.height < MIN_H)
-- f->fmt.pix.height = MIN_H;
-+ if (f->fmt.pix_mp.width < MIN_W)
-+ f->fmt.pix_mp.width = MIN_W;
-+ if (f->fmt.pix_mp.height < MIN_H)
-+ f->fmt.pix_mp.height = MIN_H;
-
- /*
- * For codecs the buffer must have a vertical alignment of 16
-@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835
- * some of the pixels are active.
- */
- if (ctx->dev->role != ISP)
-- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16);
-+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
- }
-- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width,
-- fmt);
-- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline,
-- f->fmt.pix.width,
-- f->fmt.pix.height,
-- fmt);
-+ f->fmt.pix_mp.num_planes = 1;
-+ f->fmt.pix_mp.plane_fmt[0].bytesperline =
-+ get_bytesperline(f->fmt.pix_mp.width, fmt);
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
-+ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline,
-+ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt);
-+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
-+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
-
-- f->fmt.pix.field = V4L2_FIELD_NONE;
-+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-
- return 0;
- }
-@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct
-
- fmt = find_format(f, ctx->dev, true);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-- true)->fourcc;
-+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
-+ true)->fourcc;
- fmt = find_format(f, ctx->dev, true);
- }
-
-@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct
-
- fmt = find_format(f, ctx->dev, false);
- if (!fmt) {
-- f->fmt.pix.pixelformat = get_default_format(ctx->dev,
-- false)->fourcc;
-+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev,
-+ false)->fourcc;
- fmt = find_format(f, ctx->dev, false);
- }
-
-- if (!f->fmt.pix.colorspace)
-- f->fmt.pix.colorspace = ctx->colorspace;
-+ if (!f->fmt.pix_mp.colorspace)
-+ f->fmt.pix_mp.colorspace = ctx->colorspace;
-
- return vidioc_try_fmt(ctx, f, fmt);
- }
-@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c
- bool update_capture_port = false;
- int ret;
-
-- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-- f->type, f->fmt.pix.width, f->fmt.pix.height,
-- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
-+ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
-+
-
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (!vq)
-@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c
- }
-
- q_data->fmt = find_format(f, ctx->dev,
-- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-- q_data->crop_width = f->fmt.pix.width;
-- q_data->height = f->fmt.pix.height;
-+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-+ q_data->crop_width = f->fmt.pix_mp.width;
-+ q_data->height = f->fmt.pix_mp.height;
- if (!q_data->selection_set)
- q_data->crop_height = requested_height;
-
-@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c
- * Copying the behaviour of vicodec which retains a single set of
- * colorspace parameters for both input and output.
- */
-- ctx->colorspace = f->fmt.pix.colorspace;
-- ctx->xfer_func = f->fmt.pix.xfer_func;
-- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
-- ctx->quant = f->fmt.pix.quantization;
-+ ctx->colorspace = f->fmt.pix_mp.colorspace;
-+ ctx->xfer_func = f->fmt.pix_mp.xfer_func;
-+ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
-+ ctx->quant = f->fmt.pix_mp.quantization;
-
- /* All parameters should have been set correctly by try_fmt */
-- q_data->bytesperline = f->fmt.pix.bytesperline;
-- q_data->sizeimage = f->fmt.pix.sizeimage;
-+ q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
-+ q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
-
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n",
- q_data->bytesperline, q_data->sizeimage);
-
- if (ctx->dev->role == DECODE &&
- q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED &&
-- f->fmt.pix.width && f->fmt.pix.height) {
-+ q_data->crop_width && q_data->height) {
- /*
- * On the decoder, if provided with a resolution on the input
- * side, then replicate that to the output side.
-@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- q_data_dst->height = ALIGN(q_data->crop_height, 16);
-
- q_data_dst->bytesperline =
-- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt);
-+ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt);
- q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline,
- q_data_dst->crop_width,
- q_data_dst->height,
-@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c
- static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
- {
-- unsigned int height = f->fmt.pix.height;
-+ unsigned int height = f->fmt.pix_mp.height;
- int ret;
-
- ret = vidioc_try_fmt_vid_cap(file, priv, f);
-@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f
- static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
- struct v4l2_format *f)
- {
-- unsigned int height = f->fmt.pix.height;
-+ unsigned int height = f->fmt.pix_mp.height;
- int ret;
-
- ret = vidioc_try_fmt_vid_out(file, priv, f);
-@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
- true : false;
-
- if ((ctx->dev->role == DECODE && !capture_queue) ||
-@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data = NULL;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
- true : false;
-
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
-@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
- ctx->framerate_num =
-@@ -1739,14 +1746,14 @@ static const struct v4l2_ioctl_ops bcm28
- .vidioc_querycap = vidioc_querycap,
-
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
-- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
-- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
-- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap,
-+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap,
-+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap,
-
- .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
-- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
-- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
-- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
-+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out,
-+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out,
-+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out,
-
- .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
- .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
-@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming
- ctx->component_enabled = true;
- }
-
-- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /*
- * Create the EOS buffer.
- * We only need the MMAL part, and want to NOT attach a memory
-@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct
- struct bcm2835_codec_ctx *ctx = priv;
- int ret;
-
-- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- src_vq->drv_priv = ctx;
- src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
-@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct
- if (ret)
- return ret;
-
-- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
- dst_vq->drv_priv = ctx;
- dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer);
--- /dev/null
+From 128e363e406841fbbd9800199cb093b4737d7cba Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 9 Aug 2019 08:51:43 +0100
+Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail
+
+Some combinations of Pi 4Bs and Ethernet switches don't reliably get a
+DCHP-assigned IP address, leaving the unit with a self=assigned 169.254
+address. In the failure case, the Pi is left able to receive packets
+but not send them, suggesting that the MAC<->PHY link is getting into
+a bad state.
+
+It has been found empirically that skipping a reset step by the genet
+driver prevents the failures. No downsides have been discovered yet,
+and unlike the forced renegotiation it doesn't increase the time to
+get an IP address, so the workaround is enabled by default; add
+
+ genet.skip_umac_reset=n
+
+to the command line to disable it.
+
+See: https://github.com/raspberrypi/linux/issues/3108
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -69,6 +69,10 @@
+ #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
+ TOTAL_DESC * DMA_DESC_SIZE)
+
++static bool skip_umac_reset = true;
++module_param(skip_umac_reset, bool, 0444);
++MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
++
+ static inline void bcmgenet_writel(u32 value, void __iomem *offset)
+ {
+ /* MIPS chips strapped for BE will automagically configure the
+@@ -1991,6 +1995,11 @@ static void reset_umac(struct bcmgenet_p
+ bcmgenet_rbuf_ctrl_set(priv, 0);
+ udelay(10);
+
++ if (skip_umac_reset) {
++ pr_warn("Skipping UMAC reset\n");
++ return;
++ }
++
+ /* disable MAC while updating its registers */
+ bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+
+++ /dev/null
-From 8ffc08d336326d576b84d59135402f08cf2cf41c Mon Sep 17 00:00:00 2001
-From: Chen-Yu Tsai <wens@csie.org>
-Date: Mon, 22 Jul 2019 22:13:30 +0800
-Subject: [PATCH] staging: bcm2835-codec: implement
- V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
-
-The stateful decoder specification shows an optional step for retrieving
-the miminum number of capture buffers required for the decoder to
-proceed. While not a required parameter, having it makes some
-applications happy.
-
-bcm2835-codec is a little different from other decoder implementations
-in that there is an intermediate format conversion between the hardware
-and V4L2 buffers. The number of capture buffers required is therefore
-independent of the stream and DPB etc.
-
-There are plans to remove the conversion, but it requires a fair amount
-of rework within the firmware. Until that is done, simply return a value
-of 1.
-
-Signed-off-by: Chen-Yu Tsai <wens@csie.org>
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil
- }
- ctx->fh.ctrl_handler = hdl;
- v4l2_ctrl_handler_setup(hdl);
-+ } else if (dev->role == DECODE) {
-+ v4l2_ctrl_handler_init(hdl, 1);
-+
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
-+ 1, 1, 1, 1);
-+ if (hdl->error) {
-+ rc = hdl->error;
-+ goto free_ctrl_handler;
-+ }
-+ ctx->fh.ctrl_handler = hdl;
-+ v4l2_ctrl_handler_setup(hdl);
- }
-
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+++ /dev/null
-From d06677b96fc10122363028dea9ca06e5f9899865 Mon Sep 17 00:00:00 2001
-From: Chen-Yu Tsai <wens@csie.org>
-Date: Mon, 22 Jul 2019 22:20:55 +0800
-Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct
- video_device
-
-Instead of filling in the struct v4l2_capability device_caps
-field, fill in the struct video_device device_caps field.
-
-That way the V4L2 core knows what the capabilities of the
-video device are.
-
-This is similar to a cleanup series by Hans Verkuil [1].
-
-[1] https://www.spinics.net/lists/linux-media/msg153313.html
-
-Signed-off-by: Chen-Yu Tsai <wens@csie.org>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file *
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
-- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
- }
-
-@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p
- vfd = &dev->vfd;
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
-+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-
- switch (role) {
- case DECODE:
--- /dev/null
+From 90c56c8f52c912aa6e990e63d953b6dbccea7250 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 13 Aug 2019 15:53:29 +0100
+Subject: [PATCH] xhci: Use more event ring segment table entries
+
+Users have reported log spam created by "Event Ring Full" xHC event
+TRBs. These are caused by interrupt latency in conjunction with a very
+busy set of devices on the bus. The errors are benign, but throughput
+will suffer as the xHC will pause processing of transfers until the
+event ring is drained by the kernel. Expand the number of event TRB slots
+available by increasing the number of event ring segments in the ERST.
+
+Controllers have a hardware-defined limit as to the number of ERST
+entries they can process, so make the actual number in use
+min(ERST_MAX_SEGS, hw_max).
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/xhci-mem.c | 8 +++++---
+ drivers/usb/host/xhci.h | 4 ++--
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2503,9 +2503,11 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ * Event ring setup: Allocate a normal ring, but also setup
+ * the event ring segment table (ERST). Section 4.9.3.
+ */
++ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2);
++ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
+- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+- 0, flags);
++ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT,
++ 0, flags);
+ if (!xhci->event_ring)
+ goto fail;
+ if (xhci_check_trb_in_td_math(xhci) < 0)
+@@ -2518,7 +2520,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ /* set ERST count with the number of entries in the segment table */
+ val = readl(&xhci->ir_set->erst_size);
+ val &= ERST_SIZE_MASK;
+- val |= ERST_NUM_SEGS;
++ val |= val2;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Write ERST size = %i to ir_set 0 (some bits preserved)",
+ val);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1649,8 +1649,8 @@ struct urb_priv {
+ * Each segment table entry is 4*32bits long. 1K seems like an ok size:
+ * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+ * meaning 64 ring segments.
+- * Initial allocated size of the ERST, in number of entries */
+-#define ERST_NUM_SEGS 1
++ * Maximum number of segments in the ERST */
++#define ERST_MAX_SEGS 8
+ /* Initial allocated size of the ERST, in number of entries */
+ #define ERST_SIZE 64
+ /* Initial number of event segment rings allocated */
+++ /dev/null
-From fb8e73c19c2e153444b34e8d9804371095e92fe0 Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Tue, 16 Jul 2019 12:18:21 +0100
-Subject: [PATCH] Add HDMI1 facility to the driver.
-
-For generic ALSA, all you need is the bcm2835.h change, but
-have also added structures for IEC958 HDMI. Not sure how to
-test those.
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++---
- .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++-
- 2 files changed, 28 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str
- if (err)
- return err;
-
-- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
-+ if (err)
-+ return err;
-+
-+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
- if (err)
- return err;
-
-@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28
- .newctl = snd_bcm2835_new_ctl,
- };
-
--static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
-+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
- .driver = {
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
-@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-- .route = AUDIO_DEST_HDMI
-+ .route = AUDIO_DEST_HDMI0
-+};
-+
-+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
-+ .driver = {
-+ .name = "bcm2835_hdmi",
-+ .owner = THIS_MODULE,
-+ },
-+ .shortname = "bcm2835 HDMI 1",
-+ .longname = "bcm2835 HDMI 1",
-+ .minchannels = 1,
-+ .newpcm = bcm2835_audio_simple_newpcm,
-+ .newctl = snd_bcm2835_new_hdmi_ctl,
-+ .route = AUDIO_DEST_HDMI1
- };
-
- static struct bcm2835_audio_driver bcm2835_audio_headphones = {
-@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil
- .is_enabled = &enable_compat_alsa,
- },
- {
-- .audio_driver = &bcm2835_audio_hdmi,
-+ .audio_driver = &bcm2835_audio_hdmi0,
-+ .is_enabled = &enable_hdmi,
-+ },
-+ {
-+ .audio_driver = &bcm2835_audio_hdmi1,
- .is_enabled = &enable_hdmi,
- },
- {
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -33,7 +33,9 @@ enum {
- enum snd_bcm2835_route {
- AUDIO_DEST_AUTO = 0,
- AUDIO_DEST_HEADPHONES = 1,
-- AUDIO_DEST_HDMI = 2,
-+ AUDIO_DEST_HDMI = 2, // for backwards compatibility.
-+ AUDIO_DEST_HDMI0 = 2,
-+ AUDIO_DEST_HDMI1 = 3,
- AUDIO_DEST_MAX,
- };
-
--- /dev/null
+From 4896c33bf9fe61ab62d5f6f93762d7c951a64a49 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 15 Aug 2019 12:02:34 +0100
+Subject: [PATCH] configs: arm64/bcm2711: Enable V3D
+
+Enable the V3D driver, which depends on BCM2835_POWER.
+
+Originally submitted by GitHub user 'phire' in a slightly different
+form.
+
+See: https://github.com/raspberrypi/linux/pull/3063
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/Kconfig | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/Kconfig
++++ b/drivers/gpu/drm/v3d/Kconfig
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ config DRM_V3D
+ tristate "Broadcom V3D 3.x and newer"
+- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
++ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
+ depends on DRM
+ depends on COMMON_CLK
+ depends on MMU
+++ /dev/null
-From a82d716ab4c2ab5f198f3461e32614defb52c724 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 25 Jul 2019 17:27:44 +0100
-Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode
- switching
-
-The details over when and how a driver is to service the
-vblank events are sketchy, and the fkms driver was triggering
-a kernel warning every time the crtc was enabled or disabled.
-
-Copy the event handling as used by the vc4-kms driver slightly
-more closely, and we avoid the warnings.
-
-https://github.com/raspberrypi/linux/issues/3020
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++--------
- 1 file changed, 33 insertions(+), 15 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -964,6 +964,7 @@ static void vc4_crtc_mode_set_nofb(struc
-
- static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
- {
-+ struct drm_device *dev = crtc->dev;
- struct drm_plane *plane;
-
- DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
-@@ -979,6 +980,35 @@ static void vc4_crtc_disable(struct drm_
-
- drm_atomic_crtc_for_each_plane(plane, crtc)
- vc4_plane_atomic_disable(plane, plane->state);
-+
-+ /*
-+ * Make sure we issue a vblank event after disabling the CRTC if
-+ * someone was waiting it.
-+ */
-+ if (crtc->state->event) {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&dev->event_lock, flags);
-+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
-+ crtc->state->event = NULL;
-+ spin_unlock_irqrestore(&dev->event_lock, flags);
-+ }
-+}
-+
-+static void vc4_crtc_consume_event(struct drm_crtc *crtc)
-+{
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct drm_device *dev = crtc->dev;
-+ unsigned long flags;
-+
-+ crtc->state->event->pipe = drm_crtc_index(crtc);
-+
-+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
-+
-+ spin_lock_irqsave(&dev->event_lock, flags);
-+ vc4_crtc->event = crtc->state->event;
-+ crtc->state->event = NULL;
-+ spin_unlock_irqrestore(&dev->event_lock, flags);
- }
-
- static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
-@@ -988,6 +1018,7 @@ static void vc4_crtc_enable(struct drm_c
- DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
- crtc->base.id);
- drm_crtc_vblank_on(crtc);
-+ vc4_crtc_consume_event(crtc);
-
- /* Unblank the planes (if they're supposed to be displayed). */
- drm_atomic_crtc_for_each_plane(plane, crtc)
-@@ -1059,23 +1090,10 @@ static int vc4_crtc_atomic_check(struct
- static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
- {
-- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-- struct drm_device *dev = crtc->dev;
--
- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
- crtc->base.id);
-- if (crtc->state->event) {
-- unsigned long flags;
--
-- crtc->state->event->pipe = drm_crtc_index(crtc);
--
-- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
--
-- spin_lock_irqsave(&dev->event_lock, flags);
-- vc4_crtc->event = crtc->state->event;
-- crtc->state->event = NULL;
-- spin_unlock_irqrestore(&dev->event_lock, flags);
-- }
-+ if (crtc->state->active && old_state->active && crtc->state->event)
-+ vc4_crtc_consume_event(crtc);
- }
-
- static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
--- /dev/null
+From f80d87ce56916edf52dce4a311f3d512443ca7f7 Mon Sep 17 00:00:00 2001
+From: Aman Gupta <aman@tmm1.net>
+Date: Thu, 22 Aug 2019 22:31:37 +0000
+Subject: [PATCH] staging: bcm2835-codec: add support for
+ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME
+
+fixes #3171
+
+Signed-off-by: Aman Gupta <aman@tmm1.net>
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v
+ ret = bcm2835_codec_set_level_profile(ctx, ctrl);
+ break;
+
++ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: {
++ u32 mmal_bool = 1;
++
++ if (!ctx->component)
++ break;
++
++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
++ &ctx->component->output[0],
++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
++ &mmal_bool,
++ sizeof(mmal_bool));
++ break;
++ }
++
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil
+ hdl = &ctx->hdl;
+ if (dev->role == ENCODE) {
+ /* Encode controls */
+- v4l2_ctrl_handler_init(hdl, 6);
++ v4l2_ctrl_handler_init(hdl, 7);
+
+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
++ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
++ 0, 0, 0, 0);
+ if (hdl->error) {
+ rc = hdl->error;
+ goto free_ctrl_handler;
+++ /dev/null
-From 71402ae2a97b18f0c03b763a2e1e2800f360d50a Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 25 Jul 2019 17:34:29 +0100
-Subject: [PATCH] drm/vc4: Remove unused mode variable
-
-"89d1376 drm/vc4: Add support for margins to fkms" removed
-the requirement for having the mode structure from vc4_plane_to_mb,
-but didn't remove it as a local to the function, causing a
-compiler warning.
-
-Remove the unused variable.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -525,7 +525,6 @@ static int vc4_plane_to_mb(struct drm_pl
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
- int num_planes = fb->format->num_planes;
-- struct drm_display_mode *mode = &state->crtc->mode;
- unsigned int rotation = SUPPORTED_ROTATIONS;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
--- /dev/null
+From aa8519dd50cf310e8760fbc11f5fa3ff672683e1 Mon Sep 17 00:00:00 2001
+From: Aman Gupta <aman@tmm1.net>
+Date: Fri, 23 Aug 2019 16:29:07 -0700
+Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on
+ encoder input
+
+The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment.
+
+Signed-off-by: Aman Gupta <aman@tmm1.net>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835
+ f->fmt.pix_mp.height = MIN_H;
+
+ /*
+- * For codecs the buffer must have a vertical alignment of 16
++ * For decoders the buffer must have a vertical alignment of 16
+ * lines.
+ * The selection will reflect any cropping rectangle when only
+ * some of the pixels are active.
+ */
+- if (ctx->dev->role != ISP)
++ if (ctx->dev->role == DECODE)
+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
+ }
+ f->fmt.pix_mp.num_planes = 1;
--- /dev/null
+From 4964bc1608844cb58c8ee96f315867e8142706a1 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 3 Sep 2019 18:16:56 +0100
+Subject: [PATCH] arch/arm: Add model string to cpuinfo
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/kernel/setup.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -1240,6 +1240,8 @@ static int c_show(struct seq_file *m, vo
+ {
+ int i, j;
+ u32 cpuid;
++ struct device_node *np;
++ const char *model;
+
+ for_each_online_cpu(i) {
+ /*
+@@ -1299,6 +1301,14 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
+ seq_printf(m, "Serial\t\t: %s\n", system_serial);
+
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (!of_property_read_string(np, "model",
++ &model))
++ seq_printf(m, "Model\t\t: %s\n", model);
++ of_node_put(np);
++ }
++
+ return 0;
+ }
+
+++ /dev/null
-From cedd3e7ee97213d0d3d0ada2a7df58ad0059372e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 11 Jul 2019 14:57:09 +0100
-Subject: [PATCH] staging:bcm2835-codec: Expand logging on format
- setting
-
-Adds some more useful logging during format changed events and
-s_fmt.
-
-Reported by: zillevdr <zillevdr@gmx.de>
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc
- format->es.video.color_space);
-
- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n",
-+ __func__, q_data->bytesperline, q_data->height,
-+ q_data->crop_width, q_data->crop_height);
-+
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
- q_data->bytesperline = format->es.video.crop.width;
-@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c
- bool update_capture_port = false;
- int ret;
-
-- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
-+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n",
- f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
-- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage);
--
-+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat),
-+ f->fmt.pix_mp.plane_fmt[0].sizeimage);
-
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
- if (!vq)
--- /dev/null
+From 6ce4c2034f11fe1ba270637ebd5ba459c69e2b27 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 3 Sep 2019 18:17:25 +0100
+Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/arch/arm64/kernel/cpuinfo.c
++++ b/arch/arm64/kernel/cpuinfo.c
+@@ -17,6 +17,7 @@
+ #include <linux/elf.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
++#include <linux/of_platform.h>
+ #include <linux/personality.h>
+ #include <linux/preempt.h>
+ #include <linux/printk.h>
+@@ -128,6 +129,10 @@ static int c_show(struct seq_file *m, vo
+ {
+ int i, j;
+ bool compat = personality(current->personality) == PER_LINUX32;
++ struct device_node *np;
++ const char *model;
++ const char *serial;
++ u32 revision;
+
+ for_each_online_cpu(i) {
+ struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
+@@ -179,6 +184,26 @@ static int c_show(struct seq_file *m, vo
+ seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
+ }
+
++ seq_printf(m, "Hardware\t: BCM2835\n");
++
++ np = of_find_node_by_path("/system");
++ if (np) {
++ if (!of_property_read_u32(np, "linux,revision", &revision))
++ seq_printf(m, "Revision\t: %04x\n", revision);
++ of_node_put(np);
++ }
++
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (!of_property_read_string(np, "serial-number",
++ &serial))
++ seq_printf(m, "Serial\t\t: %s\n", serial);
++ if (!of_property_read_string(np, "model",
++ &model))
++ seq_printf(m, "Model\t\t: %s\n", model);
++ of_node_put(np);
++ }
++
+ return 0;
+ }
+
+++ /dev/null
-From eb4cbf0e6893397f00aff0f90dc9d3df75e98b52 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Thu, 11 Jul 2019 14:58:35 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on
- format changed
-
-The handling of format changed events incorrectly set bytesperline
-to the cropped width, which ignored padding and formats with
-more than 8bpp.
-Fix these.
-
-Reported by: zillevdr <zillevdr@gmx.de>
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc
-
- q_data->crop_width = format->es.video.crop.width;
- q_data->crop_height = format->es.video.crop.height;
-- q_data->bytesperline = format->es.video.crop.width;
-+ q_data->bytesperline = get_bytesperline(format->es.video.width,
-+ q_data->fmt);
-+
- q_data->height = format->es.video.height;
- q_data->sizeimage = format->buffer_size_min;
- if (format->es.video.color_space)
+++ /dev/null
-From e2e9da35d4a598490b73da41eea1db27540339fd Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 7 Aug 2019 11:31:08 +0100
-Subject: [PATCH] drm/vc4: Add missing NULL check to
- vc4_crtc_consume_event
-
-vc4_crtc_consume_event wasn't checking crtc->state->event was
-set before dereferencing it, leading to an OOPS.
-
-Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching"
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1000,6 +1000,9 @@ static void vc4_crtc_consume_event(struc
- struct drm_device *dev = crtc->dev;
- unsigned long flags;
-
-+ if (!crtc->state->event)
-+ return;
-+
- crtc->state->event->pipe = drm_crtc_index(crtc);
-
- WARN_ON(drm_crtc_vblank_get(crtc) != 0);
--- /dev/null
+From 8c9e3687480d787750a7cc09016ac551a9009e87 Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Sun, 28 Apr 2019 12:15:35 +0200
+Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment
+ block
+
+The job_ready comment is incorrectly using the documentation prefix
+(/**) which causes a warning at build time.
+
+Simplify it.
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_
+ * mem2mem callbacks
+ */
+
+-/**
++/*
+ * job_ready() - check whether an instance is ready to be scheduled to run
+ */
+ static int job_ready(void *priv)
+++ /dev/null
-From 128e363e406841fbbd9800199cb093b4737d7cba Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 9 Aug 2019 08:51:43 +0100
-Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail
-
-Some combinations of Pi 4Bs and Ethernet switches don't reliably get a
-DCHP-assigned IP address, leaving the unit with a self=assigned 169.254
-address. In the failure case, the Pi is left able to receive packets
-but not send them, suggesting that the MAC<->PHY link is getting into
-a bad state.
-
-It has been found empirically that skipping a reset step by the genet
-driver prevents the failures. No downsides have been discovered yet,
-and unlike the forced renegotiation it doesn't increase the time to
-get an IP address, so the workaround is enabled by default; add
-
- genet.skip_umac_reset=n
-
-to the command line to disable it.
-
-See: https://github.com/raspberrypi/linux/issues/3108
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++
- 1 file changed, 9 insertions(+)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -69,6 +69,10 @@
- #define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \
- TOTAL_DESC * DMA_DESC_SIZE)
-
-+static bool skip_umac_reset = true;
-+module_param(skip_umac_reset, bool, 0444);
-+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
-+
- static inline void bcmgenet_writel(u32 value, void __iomem *offset)
- {
- /* MIPS chips strapped for BE will automagically configure the
-@@ -1991,6 +1995,11 @@ static void reset_umac(struct bcmgenet_p
- bcmgenet_rbuf_ctrl_set(priv, 0);
- udelay(10);
-
-+ if (skip_umac_reset) {
-+ pr_warn("Skipping UMAC reset\n");
-+ return;
-+ }
-+
- /* disable MAC while updating its registers */
- bcmgenet_umac_writel(priv, 0, UMAC_CMD);
-
--- /dev/null
+From 1efb26ffda4c95103a91eb51505ef1bb30553b08 Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Wed, 20 Mar 2019 11:42:39 +0000
+Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles
+
+The static role text is declared incorrectly. The static should be
+first, and the roles should also be constified.
+
+Convert from "const static char *" to "static const char * const".
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -77,7 +77,7 @@ enum bcm2835_codec_role {
+ ISP,
+ };
+
+-const static char *roles[] = {
++static const char * const roles[] = {
+ "decode",
+ "encode",
+ "isp"
--- /dev/null
+From 434803a4828aed99d5328dd41b4600ef7b0be0ff Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Wed, 20 Mar 2019 11:55:43 +0000
+Subject: [PATCH] staging: bcm2835-codec: Add role to device name
+
+Three entities are created, Decode, Encode and ISP but all of the video
+nodes use the same video name string "bcm2835-codec" which makes it
+difficult to identify each role.
+
+Append the role-name to the video name to facilitate identifying a
+specific instance from userspace.
+
+The Card-Type is also extended with the role name to support identifying
+the device context from within QUERY_CAP operations.
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -947,8 +947,10 @@ static void device_run(void *priv)
+ static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+ {
++ struct bcm2835_codec_dev *dev = video_drvdata(file);
++
+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
++ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ MEM2MEM_NAME);
+ return 0;
+@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p
+ }
+
+ video_set_drvdata(vfd, dev);
+- snprintf(vfd->name, sizeof(vfd->name), "%s",
+- bcm2835_codec_videodev.name);
++ snprintf(vfd->name, sizeof(vfd->name), "%s-%s",
++ bcm2835_codec_videodev.name, roles[role]);
+ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
+ vfd->num);
+
+++ /dev/null
-From 90c56c8f52c912aa6e990e63d953b6dbccea7250 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 13 Aug 2019 15:53:29 +0100
-Subject: [PATCH] xhci: Use more event ring segment table entries
-
-Users have reported log spam created by "Event Ring Full" xHC event
-TRBs. These are caused by interrupt latency in conjunction with a very
-busy set of devices on the bus. The errors are benign, but throughput
-will suffer as the xHC will pause processing of transfers until the
-event ring is drained by the kernel. Expand the number of event TRB slots
-available by increasing the number of event ring segments in the ERST.
-
-Controllers have a hardware-defined limit as to the number of ERST
-entries they can process, so make the actual number in use
-min(ERST_MAX_SEGS, hw_max).
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/xhci-mem.c | 8 +++++---
- drivers/usb/host/xhci.h | 4 ++--
- 2 files changed, 7 insertions(+), 5 deletions(-)
-
---- a/drivers/usb/host/xhci-mem.c
-+++ b/drivers/usb/host/xhci-mem.c
-@@ -2503,9 +2503,11 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- * Event ring setup: Allocate a normal ring, but also setup
- * the event ring segment table (ERST). Section 4.9.3.
- */
-+ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2);
-+ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
-- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
-- 0, flags);
-+ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT,
-+ 0, flags);
- if (!xhci->event_ring)
- goto fail;
- if (xhci_check_trb_in_td_math(xhci) < 0)
-@@ -2518,7 +2520,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- /* set ERST count with the number of entries in the segment table */
- val = readl(&xhci->ir_set->erst_size);
- val &= ERST_SIZE_MASK;
-- val |= ERST_NUM_SEGS;
-+ val |= val2;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Write ERST size = %i to ir_set 0 (some bits preserved)",
- val);
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1649,8 +1649,8 @@ struct urb_priv {
- * Each segment table entry is 4*32bits long. 1K seems like an ok size:
- * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
- * meaning 64 ring segments.
-- * Initial allocated size of the ERST, in number of entries */
--#define ERST_NUM_SEGS 1
-+ * Maximum number of segments in the ERST */
-+#define ERST_MAX_SEGS 8
- /* Initial allocated size of the ERST, in number of entries */
- #define ERST_SIZE 64
- /* Initial number of event segment rings allocated */
+++ /dev/null
-From 4896c33bf9fe61ab62d5f6f93762d7c951a64a49 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 15 Aug 2019 12:02:34 +0100
-Subject: [PATCH] configs: arm64/bcm2711: Enable V3D
-
-Enable the V3D driver, which depends on BCM2835_POWER.
-
-Originally submitted by GitHub user 'phire' in a slightly different
-form.
-
-See: https://github.com/raspberrypi/linux/pull/3063
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/Kconfig | 2 +-
- 2 files changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/Kconfig
-+++ b/drivers/gpu/drm/v3d/Kconfig
-@@ -1,7 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0-only
- config DRM_V3D
- tristate "Broadcom V3D 3.x and newer"
-- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST
-+ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST
- depends on DRM
- depends on COMMON_CLK
- depends on MMU
--- /dev/null
+From aebdaf3bf7931e42b6787d1f1554de03e84422c7 Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Wed, 20 Mar 2019 11:35:26 +0000
+Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create
+ entities
+
+Pass the bcm2835_codec_driver driver context directly into the
+bcm2835_codec_create() so that it can be used to store driver global
+state. Pass the struct platform_device *pdev by adding it to the driver
+global state.
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx {
+ };
+
+ struct bcm2835_codec_driver {
++ struct platform_device *pdev;
++
+ struct bcm2835_codec_dev *encode;
+ struct bcm2835_codec_dev *decode;
+ struct bcm2835_codec_dev *isp;
+@@ -2587,10 +2589,11 @@ destroy_component:
+ return ret;
+ }
+
+-static int bcm2835_codec_create(struct platform_device *pdev,
++static int bcm2835_codec_create(struct bcm2835_codec_driver *drv,
+ struct bcm2835_codec_dev **new_dev,
+ enum bcm2835_codec_role role)
+ {
++ struct platform_device *pdev = drv->pdev;
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
+ int video_nr;
+@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl
+ if (!drv)
+ return -ENOMEM;
+
+- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
++ drv->pdev = pdev;
++
++ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
+ if (ret)
+ goto out;
+
+- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
++ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE);
+ if (ret)
+ goto out;
+
+- ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
++ ret = bcm2835_codec_create(drv, &drv->isp, ISP);
+ if (ret)
+ goto out;
+
--- /dev/null
+From 4d066da23979b8de03b5915388136be6e293600f Mon Sep 17 00:00:00 2001
+From: Kieran Bingham <kieran.bingham@ideasonboard.com>
+Date: Wed, 20 Mar 2019 12:54:15 +0000
+Subject: [PATCH] staging: bcm2835-codec: add media controller support
+
+Provide a single media device to contain all of the bcm2835_codec
+devices created.
+
+Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
+---
+ .../vc04_services/bcm2835-codec/Kconfig | 2 +-
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++--
+ 2 files changed, 38 insertions(+), 5 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig
++++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
+@@ -1,6 +1,6 @@
+ config VIDEO_CODEC_BCM2835
+ tristate "BCM2835 Video codec support"
+- depends on MEDIA_SUPPORT
++ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER
+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
+ select BCM2835_VCHIQ_MMAL
+ select VIDEOBUF2_DMA_CONTIG
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx {
+
+ struct bcm2835_codec_driver {
+ struct platform_device *pdev;
++ struct media_device mdev;
+
+ struct bcm2835_codec_dev *encode;
+ struct bcm2835_codec_dev *decode;
+@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b
+ struct platform_device *pdev = drv->pdev;
+ struct bcm2835_codec_dev *dev;
+ struct video_device *vfd;
++ int function;
+ int video_nr;
+ int ret;
+
+@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b
+ if (ret)
+ goto vchiq_finalise;
+
+- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+- if (ret)
+- goto vchiq_finalise;
+-
+ atomic_set(&dev->num_inst, 0);
+ mutex_init(&dev->dev_mutex);
+
++ /* Initialise the video device */
+ dev->vfd = bcm2835_codec_videodev;
++
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
++ vfd->v4l2_dev->mdev = &drv->mdev;
++
++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
++ if (ret)
++ goto vchiq_finalise;
+
+ switch (role) {
+ case DECODE:
+@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
++ function = MEDIA_ENT_F_PROC_VIDEO_DECODER;
+ video_nr = decode_video_nr;
+ break;
+ case ENCODE:
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
++ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
+ video_nr = encode_video_nr;
+ break;
+ case ISP:
+@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
++ function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ video_nr = isp_video_nr;
+ break;
+ default:
+@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b
+ goto err_m2m;
+ }
+
++ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function);
++ if (ret)
++ goto err_m2m;
++
+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
+ roles[role]);
+ return 0;
+@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct
+
+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
+ roles[dev->role]);
++ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct
+ static int bcm2835_codec_probe(struct platform_device *pdev)
+ {
+ struct bcm2835_codec_driver *drv;
++ struct media_device *mdev;
+ int ret = 0;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl
+ return -ENOMEM;
+
+ drv->pdev = pdev;
++ mdev = &drv->mdev;
++ mdev->dev = &pdev->dev;
++
++ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model));
++ strscpy(mdev->serial, "0000", sizeof(mdev->serial));
++ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
++ pdev->name);
++
++ /* This should return the vgencmd version information or such .. */
++ mdev->hw_revision = 1;
++ media_device_init(mdev);
+
+ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
+ if (ret)
+@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl
+ if (ret)
+ goto out;
+
++ /* Register the media device node */
++ if (media_device_register(mdev) < 0)
++ goto out;
++
+ platform_set_drvdata(pdev, drv);
+
+ return 0;
+@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p
+ {
+ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
+
++ media_device_unregister(&drv->mdev);
++
+ bcm2835_codec_destroy(drv->isp);
+
+ bcm2835_codec_destroy(drv->encode);
+
+ bcm2835_codec_destroy(drv->decode);
+
++ media_device_cleanup(&drv->mdev);
++
+ return 0;
+ }
+
+++ /dev/null
-From f80d87ce56916edf52dce4a311f3d512443ca7f7 Mon Sep 17 00:00:00 2001
-From: Aman Gupta <aman@tmm1.net>
-Date: Thu, 22 Aug 2019 22:31:37 +0000
-Subject: [PATCH] staging: bcm2835-codec: add support for
- V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME
-
-fixes #3171
-
-Signed-off-by: Aman Gupta <aman@tmm1.net>
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v
- ret = bcm2835_codec_set_level_profile(ctx, ctrl);
- break;
-
-+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: {
-+ u32 mmal_bool = 1;
-+
-+ if (!ctx->component)
-+ break;
-+
-+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance,
-+ &ctx->component->output[0],
-+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
-+ &mmal_bool,
-+ sizeof(mmal_bool));
-+ break;
-+ }
-+
- default:
- v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
- return -EINVAL;
-@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil
- hdl = &ctx->hdl;
- if (dev->role == ENCODE) {
- /* Encode controls */
-- v4l2_ctrl_handler_init(hdl, 6);
-+ v4l2_ctrl_handler_init(hdl, 7);
-
- v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil
- BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
- BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
- V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
-+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops,
-+ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
-+ 0, 0, 0, 0);
- if (hdl->error) {
- rc = hdl->error;
- goto free_ctrl_handler;
+++ /dev/null
-From aa8519dd50cf310e8760fbc11f5fa3ff672683e1 Mon Sep 17 00:00:00 2001
-From: Aman Gupta <aman@tmm1.net>
-Date: Fri, 23 Aug 2019 16:29:07 -0700
-Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on
- encoder input
-
-The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment.
-
-Signed-off-by: Aman Gupta <aman@tmm1.net>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835
- f->fmt.pix_mp.height = MIN_H;
-
- /*
-- * For codecs the buffer must have a vertical alignment of 16
-+ * For decoders the buffer must have a vertical alignment of 16
- * lines.
- * The selection will reflect any cropping rectangle when only
- * some of the pixels are active.
- */
-- if (ctx->dev->role != ISP)
-+ if (ctx->dev->role == DECODE)
- f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16);
- }
- f->fmt.pix_mp.num_planes = 1;
--- /dev/null
+From 1b14387d6b699c4cfc8218867997b1508a67167a Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 6 Sep 2019 15:04:51 +0100
+Subject: [PATCH] v4l2: Add a Greyworld AWB mode.
+
+Adds a simple greyworld white balance preset, mainly for use
+with cameras without an IR filter (eg Raspberry Pi NoIR)
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/media/v4l2-core/v4l2-ctrls.c | 1 +
+ include/uapi/linux/v4l2-controls.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/media/v4l2-core/v4l2-ctrls.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls.c
+@@ -271,6 +271,7 @@ const char * const *v4l2_ctrl_get_menu(u
+ "Flash",
+ "Cloudy",
+ "Shade",
++ "Greyworld",
+ NULL,
+ };
+ static const char * const camera_iso_sensitivity_auto[] = {
+--- a/include/uapi/linux/v4l2-controls.h
++++ b/include/uapi/linux/v4l2-controls.h
+@@ -850,6 +850,7 @@ enum v4l2_auto_n_preset_white_balance {
+ V4L2_WHITE_BALANCE_FLASH = 7,
+ V4L2_WHITE_BALANCE_CLOUDY = 8,
+ V4L2_WHITE_BALANCE_SHADE = 9,
++ V4L2_WHITE_BALANCE_GREYWORLD = 10,
+ };
+
+ #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21)
+++ /dev/null
-From 4964bc1608844cb58c8ee96f315867e8142706a1 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 3 Sep 2019 18:16:56 +0100
-Subject: [PATCH] arch/arm: Add model string to cpuinfo
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/kernel/setup.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/arch/arm/kernel/setup.c
-+++ b/arch/arm/kernel/setup.c
-@@ -1240,6 +1240,8 @@ static int c_show(struct seq_file *m, vo
- {
- int i, j;
- u32 cpuid;
-+ struct device_node *np;
-+ const char *model;
-
- for_each_online_cpu(i) {
- /*
-@@ -1299,6 +1301,14 @@ static int c_show(struct seq_file *m, vo
- seq_printf(m, "Revision\t: %04x\n", system_rev);
- seq_printf(m, "Serial\t\t: %s\n", system_serial);
-
-+ np = of_find_node_by_path("/");
-+ if (np) {
-+ if (!of_property_read_string(np, "model",
-+ &model))
-+ seq_printf(m, "Model\t\t: %s\n", model);
-+ of_node_put(np);
-+ }
-+
- return 0;
- }
-
--- /dev/null
+From a1504ea7c24e74fe4d10b024d8105dc66115b01e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 6 Sep 2019 15:13:06 +0100
+Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode
+
+This is mainly used for the NoIR camera which has no IR
+filter and can completely confuse normal AWB presets.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++--
+ .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 +
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
+@@ -477,6 +477,10 @@ static int ctrl_set_awb_mode(struct bm28
+ case V4L2_WHITE_BALANCE_SHADE:
+ u32_value = MMAL_PARAM_AWBMODE_SHADE;
+ break;
++
++ case V4L2_WHITE_BALANCE_GREYWORLD:
++ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD;
++ break;
+ }
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+@@ -1014,8 +1018,8 @@ static const struct bm2835_mmal_v4l2_ctr
+ {
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
+- NULL,
++ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO,
++ 0, NULL,
+ MMAL_PARAMETER_AWB_MODE,
+ ctrl_set_awb_mode,
+ false
+--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
+@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode {
+ MMAL_PARAM_AWBMODE_INCANDESCENT,
+ MMAL_PARAM_AWBMODE_FLASH,
+ MMAL_PARAM_AWBMODE_HORIZON,
++ MMAL_PARAM_AWBMODE_GREYWORLD,
+ };
+
+ enum mmal_parameter_imagefx {
+++ /dev/null
-From 6ce4c2034f11fe1ba270637ebd5ba459c69e2b27 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 3 Sep 2019 18:17:25 +0100
-Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++
- 1 file changed, 25 insertions(+)
-
---- a/arch/arm64/kernel/cpuinfo.c
-+++ b/arch/arm64/kernel/cpuinfo.c
-@@ -17,6 +17,7 @@
- #include <linux/elf.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
-+#include <linux/of_platform.h>
- #include <linux/personality.h>
- #include <linux/preempt.h>
- #include <linux/printk.h>
-@@ -128,6 +129,10 @@ static int c_show(struct seq_file *m, vo
- {
- int i, j;
- bool compat = personality(current->personality) == PER_LINUX32;
-+ struct device_node *np;
-+ const char *model;
-+ const char *serial;
-+ u32 revision;
-
- for_each_online_cpu(i) {
- struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
-@@ -179,6 +184,26 @@ static int c_show(struct seq_file *m, vo
- seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
- }
-
-+ seq_printf(m, "Hardware\t: BCM2835\n");
-+
-+ np = of_find_node_by_path("/system");
-+ if (np) {
-+ if (!of_property_read_u32(np, "linux,revision", &revision))
-+ seq_printf(m, "Revision\t: %04x\n", revision);
-+ of_node_put(np);
-+ }
-+
-+ np = of_find_node_by_path("/");
-+ if (np) {
-+ if (!of_property_read_string(np, "serial-number",
-+ &serial))
-+ seq_printf(m, "Serial\t\t: %s\n", serial);
-+ if (!of_property_read_string(np, "model",
-+ &model))
-+ seq_printf(m, "Model\t\t: %s\n", model);
-+ of_node_put(np);
-+ }
-+
- return 0;
- }
-
--- /dev/null
+From ae66baa23455df9f7593b98c5c2f02818dbaf41b Mon Sep 17 00:00:00 2001
+From: James Hughes <JamesH65@users.noreply.github.com>
+Date: Wed, 11 Sep 2019 14:57:18 +0100
+Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode
+ (#3223)
+
+Margins were incorrectly assumed to be setup in SDTV mode, but were
+not actually done, so this make the setup non-conditional on mode.
+
+Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++--------
+ 1 file changed, 3 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -1612,14 +1612,9 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
+- /* Create and attach TV margin props to this connector.
+- * Already done for SDTV outputs.
+- */
+- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
+- ret = drm_mode_create_tv_margin_properties(dev);
+- if (ret)
+- goto fail;
+- }
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ goto fail;
+
+ drm_connector_attach_tv_margin_properties(connector);
+
--- /dev/null
+From 59c54c8b3b5afe051ca627fb42a685909b58d631 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+ <j-schambacher@users.noreply.github.com>
+Date: Thu, 12 Sep 2019 14:57:32 +0200
+Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224)
+
+Adds the driver for the Hifiberry DAC+DSP. It supports capture and
+playback depending on the DSP firmware.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ sound/soc/bcm/Kconfig | 7 ++
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 28 +++-----
+ sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++++++++
+ sound/soc/bcm/rpi-simple-soundcard.c | 23 +++++++
+ 5 files changed, 132 insertions(+), 18 deletions(-)
+ create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c
+
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -59,6 +59,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
++ tristate "Support for HifiBerry DAC+DSP"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_RPI_SIMPLE_SOUNDCARD
++ help
++ Say Y or M if you want to add support for HifiBerry DSP-DAC.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -16,6 +16,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
++snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -445,29 +445,21 @@ static struct snd_soc_ops snd_rpi_hifibe
+ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
+ };
+
+-static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
+- {
+- .name = "pcm512x.1-004d",
+- .dai_name = "pcm512x-hifi",
+- },
+- {
+- .name = "pcm186x.1-004a",
+- .dai_name = "pcm1863-aif",
+- },
+-};
++SND_SOC_DAILINK_DEFS(hifi,
++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
++ COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")),
++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
+
+ static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
+ {
+ .name = "HiFiBerry DAC+ADC PRO",
+ .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
+- .cpu_dai_name = "bcm2708-i2s.0",
+- .platform_name = "bcm2708-i2s.0",
+- .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
+- .num_codecs = 2,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
+ .init = snd_rpi_hifiberry_dacplusadcpro_init,
++ SND_SOC_DAILINK_REG(hifi),
+ },
+ };
+
+@@ -495,10 +487,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+ "i2s-controller", 0);
+ if (i2s_node) {
+ for (i = 0; i < card->num_links; i++) {
+- dai->cpu_dai_name = NULL;
+- dai->cpu_of_node = i2s_node;
+- dai->platform_name = NULL;
+- dai->platform_of_node = i2s_node;
++ dai->cpus->dai_name = NULL;
++ dai->cpus->of_node = i2s_node;
++ dai->platforms->name = NULL;
++ dai->platforms->of_node = i2s_node;
+ }
+ }
+ }
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplusdsp.c
+@@ -0,0 +1,90 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ASoC Driver for HiFiBerry DAC + DSP
++ *
++ * Author: Joerg Schambacher <joscha@schambacher.com>
++ * Copyright 2018
++ *
++ * 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 <linux/init.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <sound/soc.h>
++
++static struct snd_soc_component_driver dacplusdsp_component_driver;
++
++static struct snd_soc_dai_driver dacplusdsp_dai = {
++ .name = "dacplusdsp-hifi",
++ .capture = {
++ .stream_name = "DAC+DSP Capture",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE,
++ },
++ .playback = {
++ .stream_name = "DACP+DSP Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE |
++ SNDRV_PCM_FMTBIT_S24_LE |
++ SNDRV_PCM_FMTBIT_S32_LE,
++ },
++ .symmetric_rates = 1};
++
++#ifdef CONFIG_OF
++static const struct of_device_id dacplusdsp_ids[] = {
++ {
++ .compatible = "hifiberry,dacplusdsp",
++ },
++ {} };
++MODULE_DEVICE_TABLE(of, dacplusdsp_ids);
++#endif
++
++static int dacplusdsp_platform_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ ret = snd_soc_register_component(&pdev->dev,
++ &dacplusdsp_component_driver, &dacplusdsp_dai, 1);
++ if (ret) {
++ pr_alert("snd_soc_register_component failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int dacplusdsp_platform_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_component(&pdev->dev);
++ return 0;
++}
++
++static struct platform_driver dacplusdsp_driver = {
++ .driver = {
++ .name = "hifiberry-dacplusdsp-codec",
++ .of_match_table = of_match_ptr(dacplusdsp_ids),
++ },
++ .probe = dacplusdsp_platform_probe,
++ .remove = dacplusdsp_platform_remove,
++};
++
++module_platform_driver(dacplusdsp_driver);
++
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP");
++MODULE_LICENSE("GPL v2");
+--- a/sound/soc/bcm/rpi-simple-soundcard.c
++++ b/sound/soc/bcm/rpi-simple-soundcard.c
+@@ -144,6 +144,27 @@ static struct snd_rpi_simple_drvdata drv
+ .dai = snd_googlevoicehat_soundcard_dai,
+ };
+
++SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp,
++ DAILINK_COMP_ARRAY(COMP_EMPTY()),
++ DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")),
++ DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
++{
++ .name = "Hifiberry DAC+DSP SoundCard",
++ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi",
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ SND_SOC_DAILINK_REG(hifiberry_dacplusdsp),
++},
++};
++
++static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
++ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
++ .dai = snd_hifiberrydacplusdsp_soundcard_dai,
++};
++
+ SND_SOC_DAILINK_DEFS(hifiberry_amp,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")),
+@@ -213,6 +234,8 @@ static const struct of_device_id snd_rpi
+ .data = (void *) &drvdata_adau1977 },
+ { .compatible = "googlevoicehat,googlevoicehat-soundcard",
+ .data = (void *) &drvdata_googlevoicehat },
++ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
++ .data = (void *) &drvdata_hifiberrydacplusdsp },
+ { .compatible = "hifiberry,hifiberry-amp",
+ .data = (void *) &drvdata_hifiberry_amp },
+ { .compatible = "hifiberry,hifiberry-dac",
+++ /dev/null
-From 7bd5937663a13ad17a04d8ca8ba1503d492cf42b Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 28 Aug 2019 13:34:30 +0100
-Subject: [PATCH] media: dt-bindings: Add binding for the Sony IMX219
- sensor
-
-The IMX219 is an 8MPix CSI2 sensor, supporting 2 or 4 data lanes.
-Document the binding for this device.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../devicetree/bindings/media/i2c/imx219.txt | 59 +++++++++++++++++++
- 1 file changed, 59 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/imx219.txt
-@@ -0,0 +1,59 @@
-+* Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
-+
-+The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor with
-+an active array size of 3280H x 2464V. It is programmable through I2C
-+interface. The I2C address is fixed to 0x10 as per sensor data sheet.
-+Image data is sent through MIPI CSI-2, which is configured as either 2 or 4
-+data lanes.
-+
-+Required Properties:
-+- compatible: value should be "sony,imx219" for imx219 sensor
-+- reg: I2C bus address of the device
-+- clocks: reference to the xclk input clock.
-+- clock-names: should be "xclk".
-+- DOVDD-supply: Digital I/O voltage supply, 1.8 volts
-+- AVDD-supply: Analog voltage supply, 2.8 volts
-+- DVDD-supply: Digital core voltage supply, 1.2 volts
-+
-+Optional Properties:
-+- xclr-gpios: reference to the GPIO connected to the xclr pin, if any. Must be
-+ released after all supplies are applied.
-+ This is an active high signal to the imx219.
-+
-+The imx219 device node should contain one 'port' child node with
-+an 'endpoint' subnode. For further reading on port node refer to
-+Documentation/devicetree/bindings/media/video-interfaces.txt.
-+
-+Endpoint node required properties for CSI-2 connection are:
-+- remote-endpoint: a phandle to the bus receiver's endpoint node.
-+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
-+- data-lanes: should be set to <1 2>, or <1 2 3 4> (two or four lane CSI-2
-+ supported)
-+
-+Example:
-+ sensor@10 {
-+ compatible = "sony,imx219";
-+ reg = <0x10>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ clocks = <&imx219_clk>;
-+ clock-names = "xclk";
-+ xclr-gpios = <&gpio_sensor 0 0>;
-+ DOVDD-supply = <&vgen4_reg>; /* 1.8v */
-+ AVDD-supply = <&vgen3_reg>; /* 2.8v */
-+ DVDD-supply = <&vgen2_reg>; /* 1.2v */
-+
-+ imx219_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ port {
-+ sensor_out: endpoint {
-+ remote-endpoint = <&csiss_in>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ };
-+ };
-+ };
+++ /dev/null
-From 8436bbdd722445870c514d889eb082155f88dde1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 28 Aug 2019 13:34:49 +0100
-Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor
-
-Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
-Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
-currently only supports 2 lanes.
-8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
-@ 30fps are currently supported.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- drivers/media/i2c/Kconfig | 11 +
- drivers/media/i2c/Makefile | 1 +
- drivers/media/i2c/imx219.c | 1093 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 1105 insertions(+)
- create mode 100644 drivers/media/i2c/imx219.c
-
---- a/drivers/media/i2c/Kconfig
-+++ b/drivers/media/i2c/Kconfig
-@@ -578,6 +578,17 @@ config VIDEO_IMX214
- To compile this driver as a module, choose M here: the
- module will be called imx214.
-
-+config VIDEO_IMX219
-+ tristate "Sony IMX219 sensor support"
-+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+ depends on MEDIA_CAMERA_SUPPORT
-+ help
-+ This is a Video4Linux2 sensor driver for the Sony
-+ IMX219 camera.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called imx219.
-+
- config VIDEO_IMX258
- tristate "Sony IMX258 sensor support"
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---- a/drivers/media/i2c/Makefile
-+++ b/drivers/media/i2c/Makefile
-@@ -110,6 +110,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v76
- obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
- obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
- obj-$(CONFIG_VIDEO_IMX214) += imx214.o
-+obj-$(CONFIG_VIDEO_IMX219) += imx219.o
- obj-$(CONFIG_VIDEO_IMX258) += imx258.o
- obj-$(CONFIG_VIDEO_IMX274) += imx274.o
- obj-$(CONFIG_VIDEO_IMX319) += imx319.o
---- /dev/null
-+++ b/drivers/media/i2c/imx219.c
-@@ -0,0 +1,1093 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Sony IMX219 cameras.
-+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on Sony imx258 camera driver
-+ * Copyright (C) 2018 Intel Corporation
-+ *
-+ * DT / fwnode changes, and regulator / GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regulator/consumer.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-mediabus.h>
-+#include <asm/unaligned.h>
-+
-+#define IMX219_REG_VALUE_08BIT 1
-+#define IMX219_REG_VALUE_16BIT 2
-+
-+#define IMX219_REG_MODE_SELECT 0x0100
-+#define IMX219_MODE_STANDBY 0x00
-+#define IMX219_MODE_STREAMING 0x01
-+
-+/* Chip ID */
-+#define IMX219_REG_CHIP_ID 0x0000
-+#define IMX219_CHIP_ID 0x0219
-+
-+/* V_TIMING internal */
-+#define IMX219_REG_VTS 0x0160
-+#define IMX219_VTS_15FPS 0x0dc6
-+#define IMX219_VTS_30FPS_1080P 0x06e3
-+#define IMX219_VTS_30FPS_BINNED 0x06e3
-+#define IMX219_VTS_MAX 0xffff
-+
-+/*Frame Length Line*/
-+#define IMX219_FLL_MIN 0x08a6
-+#define IMX219_FLL_MAX 0xffff
-+#define IMX219_FLL_STEP 1
-+#define IMX219_FLL_DEFAULT 0x0c98
-+
-+/* HBLANK control - read only */
-+#define IMX219_PPL_DEFAULT 5352
-+
-+/* Exposure control */
-+#define IMX219_REG_EXPOSURE 0x015a
-+#define IMX219_EXPOSURE_MIN 4
-+#define IMX219_EXPOSURE_STEP 1
-+#define IMX219_EXPOSURE_DEFAULT 0x640
-+#define IMX219_EXPOSURE_MAX 65535
-+
-+/* Analog gain control */
-+#define IMX219_REG_ANALOG_GAIN 0x0157
-+#define IMX219_ANA_GAIN_MIN 0
-+#define IMX219_ANA_GAIN_MAX 232
-+#define IMX219_ANA_GAIN_STEP 1
-+#define IMX219_ANA_GAIN_DEFAULT 0x0
-+
-+/* Digital gain control */
-+#define IMX219_REG_DIGITAL_GAIN 0x0158
-+#define IMX219_DGTL_GAIN_MIN 0x0100
-+#define IMX219_DGTL_GAIN_MAX 0x0fff
-+#define IMX219_DGTL_GAIN_DEFAULT 0x0100
-+#define IMX219_DGTL_GAIN_STEP 1
-+
-+/* Test Pattern Control */
-+#define IMX219_REG_TEST_PATTERN 0x0600
-+#define IMX219_TEST_PATTERN_DISABLE 0
-+#define IMX219_TEST_PATTERN_SOLID_COLOR 1
-+#define IMX219_TEST_PATTERN_COLOR_BARS 2
-+#define IMX219_TEST_PATTERN_GREY_COLOR 3
-+#define IMX219_TEST_PATTERN_PN9 4
-+
-+struct imx219_reg {
-+ u16 address;
-+ u8 val;
-+};
-+
-+struct imx219_reg_list {
-+ u32 num_of_regs;
-+ const struct imx219_reg *regs;
-+};
-+
-+/* Mode : resolution and related config&values */
-+struct imx219_mode {
-+ /* Frame width */
-+ u32 width;
-+ /* Frame height */
-+ u32 height;
-+
-+ /* V-timing */
-+ u32 vts_def;
-+
-+ /* Default register values */
-+ struct imx219_reg_list reg_list;
-+};
-+
-+/*
-+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
-+ * driver.
-+ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
-+ */
-+static const struct imx219_reg mode_3280x2464_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x0c},
-+ {0x30eb, 0x05},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0164, 0x00},
-+ {0x0165, 0x00},
-+ {0x0166, 0x0c},
-+ {0x0167, 0xcf},
-+ {0x0168, 0x00},
-+ {0x0169, 0x00},
-+ {0x016a, 0x09},
-+ {0x016b, 0x9f},
-+ {0x016c, 0x0c},
-+ {0x016d, 0xd0},
-+ {0x016e, 0x09},
-+ {0x016f, 0xa0},
-+ {0x0170, 0x01},
-+ {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},
-+ {0x0624, 0x0c},
-+ {0x0625, 0xd0},
-+ {0x0626, 0x09},
-+ {0x0627, 0xa0},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const struct imx219_reg mode_1920_1080_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x0c},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+ {0x0164, 0x02},
-+ {0x0165, 0xa8},
-+ {0x0166, 0x0a},
-+ {0x0167, 0x27},
-+ {0x0168, 0x02},
-+ {0x0169, 0xb4},
-+ {0x016a, 0x06},
-+ {0x016b, 0xeb},
-+ {0x016c, 0x07},
-+ {0x016d, 0x80},
-+ {0x016e, 0x04},
-+ {0x016f, 0x38},
-+ {0x0170, 0x01},
-+ {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},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const struct imx219_reg mode_1640_1232_regs[] = {
-+ {0x30eb, 0x0c},
-+ {0x30eb, 0x05},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0164, 0x00},
-+ {0x0165, 0x00},
-+ {0x0166, 0x0c},
-+ {0x0167, 0xcf},
-+ {0x0168, 0x00},
-+ {0x0169, 0x00},
-+ {0x016a, 0x09},
-+ {0x016b, 0x9f},
-+ {0x016c, 0x06},
-+ {0x016d, 0x68},
-+ {0x016e, 0x04},
-+ {0x016f, 0xd0},
-+ {0x0170, 0x01},
-+ {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},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+
-+ {0x0172, 0x03},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+};
-+
-+static const char * const imx219_test_pattern_menu[] = {
-+ "Disabled",
-+ "Color Bars",
-+ "Solid Color",
-+ "Grey Color Bars",
-+ "PN9"
-+};
-+
-+static const int imx219_test_pattern_val[] = {
-+ IMX219_TEST_PATTERN_DISABLE,
-+ IMX219_TEST_PATTERN_COLOR_BARS,
-+ IMX219_TEST_PATTERN_SOLID_COLOR,
-+ IMX219_TEST_PATTERN_GREY_COLOR,
-+ IMX219_TEST_PATTERN_PN9,
-+};
-+
-+/* regulator supplies */
-+static const char * const imx219_supply_name[] = {
-+ /* Supplies can be enabled in any order */
-+ "VANA", /* Analog (2.8V) supply */
-+ "VDIG", /* Digital Core (1.8V) supply */
-+ "VDDL", /* IF (1.2V) supply */
-+};
-+
-+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
-+
-+#define IMX219_XCLR_DELAY_MS 10 /* Initialisation delay after XCLR low->high */
-+
-+/* Mode configs */
-+static const struct imx219_mode supported_modes[] = {
-+ {
-+ /* 8MPix 15fps mode */
-+ .width = 3280,
-+ .height = 2464,
-+ .vts_def = IMX219_VTS_15FPS,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
-+ .regs = mode_3280x2464_regs,
-+ },
-+ },
-+ {
-+ /* 1080P 30fps cropped */
-+ .width = 1920,
-+ .height = 1080,
-+ .vts_def = IMX219_VTS_30FPS_1080P,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
-+ .regs = mode_1920_1080_regs,
-+ },
-+ },
-+ {
-+ /* 2x2 binned 30fps mode */
-+ .width = 1640,
-+ .height = 1232,
-+ .vts_def = IMX219_VTS_30FPS_BINNED,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
-+ .regs = mode_1640_1232_regs,
-+ },
-+ },
-+};
-+
-+struct imx219 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to IMX219 */
-+ u32 xclk_freq;
-+
-+ struct gpio_desc *xclr_gpio;
-+ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
-+
-+ struct v4l2_ctrl_handler ctrl_handler;
-+ /* V4L2 Controls */
-+ struct v4l2_ctrl *pixel_rate;
-+ struct v4l2_ctrl *exposure;
-+
-+ /* Current mode */
-+ const struct imx219_mode *mode;
-+
-+ /*
-+ * Mutex for serialized access:
-+ * Protect sensor module set pad format and start/stop streaming safely.
-+ */
-+ struct mutex mutex;
-+
-+ int power_count;
-+ /* Streaming on/off */
-+ bool streaming;
-+};
-+
-+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
-+{
-+ return container_of(_sd, struct imx219, sd);
-+}
-+
-+/* Read registers up to 2 at a time */
-+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct i2c_msg msgs[2];
-+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
-+ u8 data_buf[4] = { 0, };
-+ int ret;
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ /* Write register address */
-+ msgs[0].addr = client->addr;
-+ msgs[0].flags = 0;
-+ msgs[0].len = ARRAY_SIZE(addr_buf);
-+ msgs[0].buf = addr_buf;
-+
-+ /* Read data from register */
-+ msgs[1].addr = client->addr;
-+ msgs[1].flags = I2C_M_RD;
-+ msgs[1].len = len;
-+ msgs[1].buf = &data_buf[4 - len];
-+
-+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+ if (ret != ARRAY_SIZE(msgs))
-+ return -EIO;
-+
-+ *val = get_unaligned_be32(data_buf);
-+
-+ return 0;
-+}
-+
-+/* Write registers up to 2 at a time */
-+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ u8 buf[6];
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ put_unaligned_be16(reg, buf);
-+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
-+ if (i2c_master_send(client, buf, len + 2) != len + 2)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+/* Write a list of registers */
-+static int imx219_write_regs(struct imx219 *imx219,
-+ const struct imx219_reg *regs, u32 len)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ unsigned int i;
-+ int ret;
-+
-+ for (i = 0; i < len; i++) {
-+ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
-+ if (ret) {
-+ dev_err_ratelimited(&client->dev,
-+ "Failed to write reg 0x%4.4x. error = %d\n",
-+ regs[i].address, ret);
-+
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* Power/clock management functions */
-+static void imx219_power(struct imx219 *imx219, bool enable)
-+{
-+ gpiod_set_value_cansleep(imx219->xclr_gpio, enable ? 1 : 0);
-+}
-+
-+static int imx219_set_power_on(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ ret = clk_prepare_enable(imx219->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
-+ imx219->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ imx219_power(imx219, true);
-+ msleep(IMX219_XCLR_DELAY_MS);
-+
-+ return 0;
-+xclk_off:
-+ clk_disable_unprepare(imx219->xclk);
-+ return ret;
-+}
-+
-+static void imx219_set_power_off(struct imx219 *imx219)
-+{
-+ imx219_power(imx219, false);
-+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+ clk_disable_unprepare(imx219->xclk);
-+}
-+
-+static int imx219_set_power(struct imx219 *imx219, bool on)
-+{
-+ int ret = 0;
-+
-+ if (on) {
-+ ret = imx219_set_power_on(imx219);
-+ if (ret)
-+ return ret;
-+ } else {
-+ imx219_set_power_off(imx219);
-+ }
-+
-+ return 0;
-+}
-+
-+/* Open sub-device */
-+static int imx219_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ /*
-+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
-+ * update the power state.
-+ */
-+ if (imx219->power_count == !on) {
-+ ret = imx219_set_power(imx219, !!on);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ /* Update the power count. */
-+ imx219->power_count += on ? 1 : -1;
-+ WARN_ON(imx219->power_count < 0);
-+out:
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_mbus_framefmt *try_fmt =
-+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
-+
-+ /* Initialize try_fmt */
-+ try_fmt->width = supported_modes[0].width;
-+ try_fmt->height = supported_modes[0].height;
-+ try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ try_fmt->field = V4L2_FIELD_NONE;
-+
-+ return 0;
-+}
-+
-+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct imx219 *imx219 =
-+ container_of(ctrl->handler, struct imx219, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret = 0;
-+
-+ /*
-+ * Applying V4L2 control value only happens
-+ * when power is up for streaming
-+ */
-+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
-+ IMX219_REG_VALUE_08BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_DIGITAL_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
-+ IMX219_REG_VALUE_16BIT,
-+ imx219_test_pattern_val[ctrl->val]);
-+ break;
-+ default:
-+ dev_info(&client->dev,
-+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
-+ ctrl->id, ctrl->val);
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_put(&client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
-+ .s_ctrl = imx219_set_ctrl,
-+};
-+
-+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ /* Only one bayer order(GRBG) is supported */
-+ if (code->index > 0)
-+ return -EINVAL;
-+
-+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+
-+ return 0;
-+}
-+
-+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->index >= ARRAY_SIZE(supported_modes))
-+ return -EINVAL;
-+
-+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
-+ return -EINVAL;
-+
-+ fse->min_width = supported_modes[fse->index].width;
-+ fse->max_width = fse->min_width;
-+ fse->min_height = supported_modes[fse->index].height;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static void imx219_update_pad_format(const struct imx219_mode *mode,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ fmt->format.width = mode->width;
-+ fmt->format.height = mode->height;
-+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ fmt->format.field = V4L2_FIELD_NONE;
-+}
-+
-+static int __imx219_get_pad_format(struct imx219 *imx219,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt->format = *v4l2_subdev_get_try_format(&imx219->sd, cfg,
-+ fmt->pad);
-+ else
-+ imx219_update_pad_format(imx219->mode, fmt);
-+
-+ return 0;
-+}
-+
-+static int imx219_get_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ mutex_lock(&imx219->mutex);
-+ ret = __imx219_get_pad_format(imx219, cfg, fmt);
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int imx219_set_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ const struct imx219_mode *mode;
-+ struct v4l2_mbus_framefmt *framefmt;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ /* Only one raw bayer(BGGR) order is supported */
-+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+
-+ mode = v4l2_find_nearest_size(supported_modes,
-+ ARRAY_SIZE(supported_modes),
-+ width, height,
-+ fmt->format.width, fmt->format.height);
-+ imx219_update_pad_format(mode, fmt);
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
-+ *framefmt = fmt->format;
-+ } else {
-+ imx219->mode = mode;
-+ }
-+
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+/* Start streaming */
-+static int imx219_start_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ const struct imx219_reg_list *reg_list;
-+ int ret;
-+
-+ /* Apply default values of current mode */
-+ reg_list = &imx219->mode->reg_list;
-+ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
-+ return ret;
-+ }
-+
-+ /*
-+ * Set VTS appropriately for frame rate control.
-+ * Currently fixed per mode.
-+ */
-+ ret = imx219_write_reg(imx219, IMX219_REG_VTS,
-+ IMX219_REG_VALUE_16BIT, imx219->mode->vts_def);
-+ if (ret)
-+ return ret;
-+
-+ /* Apply customized values from user */
-+ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
-+ if (ret)
-+ return ret;
-+
-+ /* set stream on register */
-+ return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
-+}
-+
-+/* Stop streaming */
-+static int imx219_stop_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ /* set stream off register */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
-+ if (ret)
-+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
-+
-+ /*
-+ * Return success even if it was an error, as there is nothing the
-+ * caller can do about it.
-+ */
-+ return 0;
-+}
-+
-+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx219->mutex);
-+ if (imx219->streaming == enable) {
-+ mutex_unlock(&imx219->mutex);
-+ return 0;
-+ }
-+
-+ if (enable) {
-+ ret = pm_runtime_get_sync(&client->dev);
-+ if (ret < 0) {
-+ pm_runtime_put_noidle(&client->dev);
-+ goto err_unlock;
-+ }
-+
-+ /*
-+ * Apply default & customized values
-+ * and then start streaming.
-+ */
-+ ret = imx219_start_streaming(imx219);
-+ if (ret) {
-+ pm_runtime_put(&client->dev);
-+ goto err_unlock;
-+ }
-+ } else {
-+ imx219_stop_streaming(imx219);
-+ pm_runtime_put(&client->dev);
-+ }
-+
-+ imx219->streaming = enable;
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+
-+err_unlock:
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int __maybe_unused imx219_suspend(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ if (imx219->streaming)
-+ imx219_stop_streaming(imx219);
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused imx219_resume(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ if (imx219->streaming) {
-+ ret = imx219_start_streaming(imx219);
-+ if (ret)
-+ goto error;
-+ }
-+
-+ return 0;
-+
-+error:
-+ imx219_stop_streaming(imx219);
-+ imx219->streaming = 0;
-+ return ret;
-+}
-+
-+static int imx219_get_regulators(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int i;
-+
-+ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
-+ imx219->supplies[i].supply = imx219_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&client->dev,
-+ IMX219_NUM_SUPPLIES,
-+ imx219->supplies);
-+}
-+
-+/* Verify chip ID */
-+static int imx219_identify_module(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+ u32 val;
-+
-+ ret = imx219_set_power_on(imx219);
-+ if (ret)
-+ return ret;
-+
-+ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
-+ IMX219_REG_VALUE_16BIT, &val);
-+ if (ret) {
-+ dev_err(&client->dev, "failed to read chip id %x\n",
-+ IMX219_CHIP_ID);
-+ goto power_off;
-+ }
-+
-+ if (val != IMX219_CHIP_ID) {
-+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
-+ IMX219_CHIP_ID, val);
-+ ret = -EIO;
-+ }
-+
-+power_off:
-+ imx219_set_power_off(imx219);
-+ return ret;
-+}
-+
-+static const struct v4l2_subdev_core_ops imx219_core_ops = {
-+ .s_power = imx219_s_power,
-+};
-+
-+static const struct v4l2_subdev_video_ops imx219_video_ops = {
-+ .s_stream = imx219_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
-+ .enum_mbus_code = imx219_enum_mbus_code,
-+ .get_fmt = imx219_get_pad_format,
-+ .set_fmt = imx219_set_pad_format,
-+ .enum_frame_size = imx219_enum_frame_size,
-+};
-+
-+static const struct v4l2_subdev_ops imx219_subdev_ops = {
-+ .core = &imx219_core_ops,
-+ .video = &imx219_video_ops,
-+ .pad = &imx219_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
-+ .open = imx219_open,
-+};
-+
-+/* Initialize control handlers */
-+static int imx219_init_controls(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct v4l2_ctrl_handler *ctrl_hdlr;
-+ int ret;
-+
-+ ctrl_hdlr = &imx219->ctrl_handler;
-+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&imx219->mutex);
-+ ctrl_hdlr->lock = &imx219->mutex;
-+
-+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_EXPOSURE,
-+ IMX219_EXPOSURE_MIN,
-+ IMX219_EXPOSURE_MAX,
-+ IMX219_EXPOSURE_STEP,
-+ IMX219_EXPOSURE_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
-+ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
-+ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
-+ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
-+ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
-+ 0, 0, imx219_test_pattern_menu);
-+
-+ if (ctrl_hdlr->error) {
-+ ret = ctrl_hdlr->error;
-+ dev_err(&client->dev, "%s control init failed (%d)\n",
-+ __func__, ret);
-+ goto error;
-+ }
-+
-+ imx219->sd.ctrl_handler = ctrl_hdlr;
-+
-+ return 0;
-+
-+error:
-+ v4l2_ctrl_handler_free(ctrl_hdlr);
-+ mutex_destroy(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static void imx219_free_controls(struct imx219 *imx219)
-+{
-+ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
-+ mutex_destroy(&imx219->mutex);
-+}
-+
-+static int imx219_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct imx219 *imx219;
-+ int ret;
-+
-+ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
-+ if (!imx219)
-+ return -ENOMEM;
-+
-+ /* Initialize subdev */
-+ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
-+
-+ /* Get CSI2 bus config */
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &imx219->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ /* Get system clock (xclk) */
-+ imx219->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(imx219->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(imx219->xclk);
-+ }
-+
-+ imx219->xclk_freq = clk_get_rate(imx219->xclk);
-+ if (imx219->xclk_freq != 24000000) {
-+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
-+ imx219->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ ret = imx219_get_regulators(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* request optional power down pin */
-+ imx219->xclr_gpio = devm_gpiod_get_optional(dev, "xclr",
-+ GPIOD_OUT_HIGH);
-+
-+ /* Check module identity */
-+ ret = imx219_identify_module(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* Set default mode to max resolution */
-+ imx219->mode = &supported_modes[0];
-+
-+ ret = imx219_init_controls(imx219);
-+ if (ret)
-+ return ret;
-+
-+ /* Initialize subdev */
-+ imx219->sd.internal_ops = &imx219_internal_ops;
-+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+
-+ /* Initialize source pad */
-+ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
-+
-+ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
-+ if (ret)
-+ goto error_handler_free;
-+
-+ ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
-+ if (ret < 0)
-+ goto error_media_entity;
-+
-+ pm_runtime_set_active(&client->dev);
-+ pm_runtime_enable(&client->dev);
-+ pm_runtime_idle(&client->dev);
-+
-+ return 0;
-+
-+error_media_entity:
-+ media_entity_cleanup(&imx219->sd.entity);
-+
-+error_handler_free:
-+ imx219_free_controls(imx219);
-+
-+ return ret;
-+}
-+
-+static int imx219_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ v4l2_async_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ imx219_free_controls(imx219);
-+
-+ pm_runtime_disable(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id imx219_dt_ids[] = {
-+ { .compatible = "sony,imx219" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
-+
-+static struct i2c_driver imx219_i2c_driver = {
-+ .driver = {
-+ .name = "imx219",
-+ .of_match_table = imx219_dt_ids,
-+ },
-+ .probe = imx219_probe,
-+ .remove = imx219_remove,
-+};
-+
-+module_i2c_driver(imx219_i2c_driver);
-+
-+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org");
-+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 59c8c7740d6f236431fa792957fefe9f67611b27 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 6 Sep 2019 17:24:55 +0100
+Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920.
+
+The codec is happy with video up to 1920 high if the width
+is suitably reduced to stay within level limits. eg 1080x1920
+is OK to decode.
+
+Increase the height limit accordingly.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -92,7 +92,7 @@ static const char * const components[] =
+ #define MIN_W 32
+ #define MIN_H 32
+ #define MAX_W 1920
+-#define MAX_H 1088
++#define MAX_H 1920
+ #define BPL_ALIGN 32
+ #define DEFAULT_WIDTH 640
+ #define DEFAULT_HEIGHT 480
--- /dev/null
+From c8a466aecf6b7d0bdc1fea9e32f80327b641cd03 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 13 Sep 2019 15:11:47 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API
+ MPLANE support
+
+The g_selection and s_selection API is messed up and requires
+the driver to expect the non-MPLANE buffer types, not the MPLANE
+ones even if they are supported. The V4L2 core will convert the
+MPLANE ones to non-MPLANE should they be passed in
+
+Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------
+ 1 file changed, 47 insertions(+), 20 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+- true : false;
+
+- if ((ctx->dev->role == DECODE && !capture_queue) ||
+- (ctx->dev->role == ENCODE && capture_queue))
+- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+- return -EINVAL;
+-
+- q_data = get_q_data(ctx, s->type);
+- if (!q_data)
++ /*
++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
++ * API. The V4L2 core will have converted the MPLANE variants to
++ * non-MPLANE.
++ * Open code this instead of using get_q_data in this case.
++ */
++ switch (s->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ /* CAPTURE on encoder is not valid. */
++ if (ctx->dev->role == ENCODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_DST];
++ break;
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ /* OUTPUT on deoder is not valid. */
++ if (ctx->dev->role == DECODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_SRC];
++ break;
++ default:
+ return -EINVAL;
++ }
+
+ switch (ctx->dev->role) {
+ case DECODE:
+@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+ struct bcm2835_codec_q_data *q_data = NULL;
+- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+- true : false;
++
++ /*
++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
++ * API. The V4L2 core will have converted the MPLANE variants to
++ * non-MPLANE.
++ *
++ * Open code this instead of using get_q_data in this case.
++ */
++ switch (s->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ /* CAPTURE on encoder is not valid. */
++ if (ctx->dev->role == ENCODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_DST];
++ break;
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ /* OUTPUT on deoder is not valid. */
++ if (ctx->dev->role == DECODE)
++ return -EINVAL;
++ q_data = &ctx->q_data[V4L2_M2M_SRC];
++ break;
++ default:
++ return -EINVAL;
++ }
+
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
+ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
+ s->r.width, s->r.height);
+
+- if ((ctx->dev->role == DECODE && !capture_queue) ||
+- (ctx->dev->role == ENCODE && capture_queue))
+- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
+- return -EINVAL;
+-
+- q_data = get_q_data(ctx, s->type);
+- if (!q_data)
+- return -EINVAL;
+-
+ switch (ctx->dev->role) {
+ case DECODE:
+ switch (s->target) {
+++ /dev/null
-From 8c9e3687480d787750a7cc09016ac551a9009e87 Mon Sep 17 00:00:00 2001
-From: Kieran Bingham <kieran.bingham@ideasonboard.com>
-Date: Sun, 28 Apr 2019 12:15:35 +0200
-Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment
- block
-
-The job_ready comment is incorrectly using the documentation prefix
-(/**) which causes a warning at build time.
-
-Simplify it.
-
-Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_
- * mem2mem callbacks
- */
-
--/**
-+/*
- * job_ready() - check whether an instance is ready to be scheduled to run
- */
- static int job_ready(void *priv)
--- /dev/null
+From 4fad98821e9ccd74b9b828d98cbe9df8c7437605 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 18 Sep 2019 17:22:36 +0100
+Subject: [PATCH] drm/v3d: Delete pm_runtime support
+
+The pm_runtime was blocking changelist submission, so delete it as a
+temporary workaround.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 5 -----
+ drivers/gpu/drm/v3d/v3d_mmu.c | 11 -----------
+ 2 files changed, 16 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -478,10 +478,6 @@ v3d_job_init(struct v3d_dev *v3d, struct
+ job->v3d = v3d;
+ job->free = free;
+
+- ret = pm_runtime_get_sync(v3d->dev);
+- if (ret < 0)
+- return ret;
+-
+ xa_init_flags(&job->deps, XA_FLAGS_ALLOC);
+
+ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence);
+@@ -498,7 +494,6 @@ v3d_job_init(struct v3d_dev *v3d, struct
+ return 0;
+ fail:
+ xa_destroy(&job->deps);
+- pm_runtime_put_autosuspend(v3d->dev);
+ return ret;
+ }
+
+--- a/drivers/gpu/drm/v3d/v3d_mmu.c
++++ b/drivers/gpu/drm/v3d/v3d_mmu.c
+@@ -36,14 +36,6 @@ static int v3d_mmu_flush_all(struct v3d_
+ {
+ int ret;
+
+- /* Keep power on the device on until we're done with this
+- * call, but skip the flush if the device is off and will be
+- * reset when powered back on.
+- */
+- ret = pm_runtime_get_if_in_use(v3d->dev);
+- if (ret == 0)
+- return 0;
+-
+ /* Make sure that another flush isn't already running when we
+ * start this one.
+ */
+@@ -71,9 +63,6 @@ static int v3d_mmu_flush_all(struct v3d_
+ if (ret)
+ dev_err(v3d->dev, "MMUC flush wait idle failed\n");
+
+- pm_runtime_mark_last_busy(v3d->dev);
+- pm_runtime_put_autosuspend(v3d->dev);
+-
+ return ret;
+ }
+
+++ /dev/null
-From 1efb26ffda4c95103a91eb51505ef1bb30553b08 Mon Sep 17 00:00:00 2001
-From: Kieran Bingham <kieran.bingham@ideasonboard.com>
-Date: Wed, 20 Mar 2019 11:42:39 +0000
-Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles
-
-The static role text is declared incorrectly. The static should be
-first, and the roles should also be constified.
-
-Convert from "const static char *" to "static const char * const".
-
-Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -77,7 +77,7 @@ enum bcm2835_codec_role {
- ISP,
- };
-
--const static char *roles[] = {
-+static const char * const roles[] = {
- "decode",
- "encode",
- "isp"
--- /dev/null
+From 849dc86116416161d0f13bf929ab712ea2bade7e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <pelwell@users.noreply.github.com>
+Date: Wed, 18 Sep 2019 09:02:10 +0100
+Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235)
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm64/boot/dts/broadcom/Makefile | 2 ++
+ arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +++
+ 2 files changed, 5 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
+
+--- a/arch/arm64/boot/dts/broadcom/Makefile
++++ b/arch/arm64/boot/dts/broadcom/Makefile
+@@ -3,7 +3,9 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
+ bcm2837-rpi-cm3-io3.dtb
++dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
++dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
+ dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
+--- /dev/null
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
+@@ -0,0 +1,3 @@
++#define RPI364
++
++#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
+++ /dev/null
-From 434803a4828aed99d5328dd41b4600ef7b0be0ff Mon Sep 17 00:00:00 2001
-From: Kieran Bingham <kieran.bingham@ideasonboard.com>
-Date: Wed, 20 Mar 2019 11:55:43 +0000
-Subject: [PATCH] staging: bcm2835-codec: Add role to device name
-
-Three entities are created, Decode, Encode and ISP but all of the video
-nodes use the same video name string "bcm2835-codec" which makes it
-difficult to identify each role.
-
-Append the role-name to the video name to facilitate identifying a
-specific instance from userspace.
-
-The Card-Type is also extended with the role name to support identifying
-the device context from within QUERY_CAP operations.
-
-Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -947,8 +947,10 @@ static void device_run(void *priv)
- static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
- {
-+ struct bcm2835_codec_dev *dev = video_drvdata(file);
-+
- strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
-- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
-+ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
- MEM2MEM_NAME);
- return 0;
-@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p
- }
-
- video_set_drvdata(vfd, dev);
-- snprintf(vfd->name, sizeof(vfd->name), "%s",
-- bcm2835_codec_videodev.name);
-+ snprintf(vfd->name, sizeof(vfd->name), "%s-%s",
-+ bcm2835_codec_videodev.name, roles[role]);
- v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n",
- vfd->num);
-
--- /dev/null
+From 141da39c2ce8dbf77773c54182244c14d96b301d Mon Sep 17 00:00:00 2001
+From: Iago Toral Quiroga <itoral@igalia.com>
+Date: Tue, 3 Sep 2019 08:45:24 +0200
+Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on
+ request from user space
+
+Extends the user space ioctl for CL submissions so it can include a request
+to flush the cache once the CL execution has completed. Fixes memory
+write violation messages reported by the kernel in workloads involving
+shader memory writes (SSBOs, shader images, scratch, etc) which sometimes
+also lead to GPU resets during Piglit and CTS workloads.
+
+v2: if v3d_job_init() fails we need to kfree() the job instead of
+ v3d_job_put() it (Eric Anholt).
+
+v3 (Eric Anholt):
+ - Drop _FLAG suffix from the new flag name.
+ - Add a new param so userspace can tell whether cache flushing is
+ implemented in the kernel.
+
+Signed-off-by: Iago Toral Quiroga <itoral@igalia.com>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 3 +++
+ drivers/gpu/drm/v3d/v3d_gem.c | 48 ++++++++++++++++++++++++++++++-----
+ include/uapi/drm/v3d_drm.h | 6 +++--
+ 3 files changed, 49 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -120,6 +120,9 @@ static int v3d_get_param_ioctl(struct dr
+ case DRM_V3D_PARAM_SUPPORTS_CSD:
+ args->value = v3d_has_csd(v3d);
+ return 0;
++ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH:
++ args->value = 1;
++ return 0;
+ default:
+ DRM_DEBUG("Unknown parameter %d\n", args->param);
+ return -EINVAL;
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -565,13 +565,16 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ struct drm_v3d_submit_cl *args = data;
+ struct v3d_bin_job *bin = NULL;
+ struct v3d_render_job *render;
++ struct v3d_job *clean_job = NULL;
++ struct v3d_job *last_job;
+ struct ww_acquire_ctx acquire_ctx;
+ int ret = 0;
+
+ trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
+
+- if (args->pad != 0) {
+- DRM_INFO("pad must be zero: %d\n", args->pad);
++ if (args->flags != 0 &&
++ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
++ DRM_INFO("invalid flags: %d\n", args->flags);
+ return -EINVAL;
+ }
+
+@@ -613,12 +616,31 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ bin->render = render;
+ }
+
+- ret = v3d_lookup_bos(dev, file_priv, &render->base,
++ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
++ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
++ if (!clean_job) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++
++ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
++ if (ret) {
++ kfree(clean_job);
++ clean_job = NULL;
++ goto fail;
++ }
++
++ last_job = clean_job;
++ } else {
++ last_job = &render->base;
++ }
++
++ ret = v3d_lookup_bos(dev, file_priv, last_job,
+ args->bo_handles, args->bo_handle_count);
+ if (ret)
+ goto fail;
+
+- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
++ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx);
+ if (ret)
+ goto fail;
+
+@@ -637,17 +659,29 @@ v3d_submit_cl_ioctl(struct drm_device *d
+ ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
+ if (ret)
+ goto fail_unreserve;
++
++ if (clean_job) {
++ ret = drm_gem_fence_array_add(&clean_job->deps,
++ dma_fence_get(render->base.done_fence));
++ if (ret)
++ goto fail_unreserve;
++ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
++ if (ret)
++ goto fail_unreserve;
++ }
+ mutex_unlock(&v3d->sched_lock);
+
+ v3d_attach_fences_and_unlock_reservation(file_priv,
+- &render->base,
++ last_job,
+ &acquire_ctx,
+ args->out_sync,
+- render->base.done_fence);
++ last_job->done_fence);
+
+ if (bin)
+ v3d_job_put(&bin->base);
+ v3d_job_put(&render->base);
++ if (clean_job)
++ v3d_job_put(clean_job);
+
+ return 0;
+
+@@ -659,6 +693,8 @@ fail:
+ if (bin)
+ v3d_job_put(&bin->base);
+ v3d_job_put(&render->base);
++ if (clean_job)
++ v3d_job_put(clean_job);
+
+ return ret;
+ }
+--- a/include/uapi/drm/v3d_drm.h
++++ b/include/uapi/drm/v3d_drm.h
+@@ -48,6 +48,8 @@ extern "C" {
+ #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
+ #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
+
++#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
++
+ /**
+ * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
+ * engine.
+@@ -124,8 +126,7 @@ struct drm_v3d_submit_cl {
+ /* Number of BO handles passed in (size is that times 4). */
+ __u32 bo_handle_count;
+
+- /* Pad, must be zero-filled. */
+- __u32 pad;
++ __u32 flags;
+ };
+
+ /**
+@@ -193,6 +194,7 @@ enum drm_v3d_param {
+ DRM_V3D_PARAM_V3D_CORE0_IDENT2,
+ DRM_V3D_PARAM_SUPPORTS_TFU,
+ DRM_V3D_PARAM_SUPPORTS_CSD,
++ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH,
+ };
+
+ struct drm_v3d_get_param {
+++ /dev/null
-From aebdaf3bf7931e42b6787d1f1554de03e84422c7 Mon Sep 17 00:00:00 2001
-From: Kieran Bingham <kieran.bingham@ideasonboard.com>
-Date: Wed, 20 Mar 2019 11:35:26 +0000
-Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create
- entities
-
-Pass the bcm2835_codec_driver driver context directly into the
-bcm2835_codec_create() so that it can be used to store driver global
-state. Pass the struct platform_device *pdev by adding it to the driver
-global state.
-
-Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++----
- 1 file changed, 9 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx {
- };
-
- struct bcm2835_codec_driver {
-+ struct platform_device *pdev;
-+
- struct bcm2835_codec_dev *encode;
- struct bcm2835_codec_dev *decode;
- struct bcm2835_codec_dev *isp;
-@@ -2587,10 +2589,11 @@ destroy_component:
- return ret;
- }
-
--static int bcm2835_codec_create(struct platform_device *pdev,
-+static int bcm2835_codec_create(struct bcm2835_codec_driver *drv,
- struct bcm2835_codec_dev **new_dev,
- enum bcm2835_codec_role role)
- {
-+ struct platform_device *pdev = drv->pdev;
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
- int video_nr;
-@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl
- if (!drv)
- return -ENOMEM;
-
-- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE);
-+ drv->pdev = pdev;
-+
-+ ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
- if (ret)
- goto out;
-
-- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE);
-+ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE);
- if (ret)
- goto out;
-
-- ret = bcm2835_codec_create(pdev, &drv->isp, ISP);
-+ ret = bcm2835_codec_create(drv, &drv->isp, ISP);
- if (ret)
- goto out;
-
--- /dev/null
+From 7542fb08d2726606057c4283b3a454abb195a0f5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 23 Sep 2019 09:26:41 +0100
+Subject: [PATCH] kbuild: Allow .dtbo overlays to be built piecemeal
+
+Before 4.20, it was possible to build an arbitrary overlay by copying
+it to arm/boot/dts/overlays/mytest-overlay.dts and running:
+
+ make ARCH=arm overlays/mytest.dtbo
+
+In 4.20 the .dtb build rules were centralised, requiring the dowstream
+.dtbo build rules to be changed. They were, enough to support "make ...
+dtbs", but not sufficiently to allow this ad-hoc, one-off building of
+individual files.
+
+Add the missing makefile rule to support this way of building.
+
+See: https://github.com/raspberrypi/linux/issues/3250
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ Makefile | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/Makefile
++++ b/Makefile
+@@ -1238,6 +1238,9 @@ ifneq ($(dtstree),)
+ %.dtb: include/config/kernel.release scripts_dtc
+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
+
++%.dtbo: prepare3 scripts_dtc
++ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
++
+ PHONY += dtbs dtbs_install dt_binding_check
+ dtbs dtbs_check: include/config/kernel.release scripts_dtc
+ $(Q)$(MAKE) $(build)=$(dtstree)
+++ /dev/null
-From 4d066da23979b8de03b5915388136be6e293600f Mon Sep 17 00:00:00 2001
-From: Kieran Bingham <kieran.bingham@ideasonboard.com>
-Date: Wed, 20 Mar 2019 12:54:15 +0000
-Subject: [PATCH] staging: bcm2835-codec: add media controller support
-
-Provide a single media device to contain all of the bcm2835_codec
-devices created.
-
-Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
----
- .../vc04_services/bcm2835-codec/Kconfig | 2 +-
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++--
- 2 files changed, 38 insertions(+), 5 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig
-+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
-@@ -1,6 +1,6 @@
- config VIDEO_CODEC_BCM2835
- tristate "BCM2835 Video codec support"
-- depends on MEDIA_SUPPORT
-+ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER
- depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
- select BCM2835_VCHIQ_MMAL
- select VIDEOBUF2_DMA_CONTIG
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx {
-
- struct bcm2835_codec_driver {
- struct platform_device *pdev;
-+ struct media_device mdev;
-
- struct bcm2835_codec_dev *encode;
- struct bcm2835_codec_dev *decode;
-@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b
- struct platform_device *pdev = drv->pdev;
- struct bcm2835_codec_dev *dev;
- struct video_device *vfd;
-+ int function;
- int video_nr;
- int ret;
-
-@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b
- if (ret)
- goto vchiq_finalise;
-
-- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-- if (ret)
-- goto vchiq_finalise;
--
- atomic_set(&dev->num_inst, 0);
- mutex_init(&dev->dev_mutex);
-
-+ /* Initialise the video device */
- dev->vfd = bcm2835_codec_videodev;
-+
- vfd = &dev->vfd;
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-+ vfd->v4l2_dev->mdev = &drv->mdev;
-+
-+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-+ if (ret)
-+ goto vchiq_finalise;
-
- switch (role) {
- case DECODE:
-@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
- v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
-+ function = MEDIA_ENT_F_PROC_VIDEO_DECODER;
- video_nr = decode_video_nr;
- break;
- case ENCODE:
- v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
-+ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
- video_nr = encode_video_nr;
- break;
- case ISP:
-@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
- v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
-+ function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
- video_nr = isp_video_nr;
- break;
- default:
-@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b
- goto err_m2m;
- }
-
-+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function);
-+ if (ret)
-+ goto err_m2m;
-+
- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
- roles[role]);
- return 0;
-@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct
-
- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
- roles[dev->role]);
-+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
- v4l2_m2m_release(dev->m2m_dev);
- video_unregister_device(&dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
-@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct
- static int bcm2835_codec_probe(struct platform_device *pdev)
- {
- struct bcm2835_codec_driver *drv;
-+ struct media_device *mdev;
- int ret = 0;
-
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
-@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl
- return -ENOMEM;
-
- drv->pdev = pdev;
-+ mdev = &drv->mdev;
-+ mdev->dev = &pdev->dev;
-+
-+ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model));
-+ strscpy(mdev->serial, "0000", sizeof(mdev->serial));
-+ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
-+ pdev->name);
-+
-+ /* This should return the vgencmd version information or such .. */
-+ mdev->hw_revision = 1;
-+ media_device_init(mdev);
-
- ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
- if (ret)
-@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl
- if (ret)
- goto out;
-
-+ /* Register the media device node */
-+ if (media_device_register(mdev) < 0)
-+ goto out;
-+
- platform_set_drvdata(pdev, drv);
-
- return 0;
-@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p
- {
- struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
-
-+ media_device_unregister(&drv->mdev);
-+
- bcm2835_codec_destroy(drv->isp);
-
- bcm2835_codec_destroy(drv->encode);
-
- bcm2835_codec_destroy(drv->decode);
-
-+ media_device_cleanup(&drv->mdev);
-+
- return 0;
- }
-
--- /dev/null
+From afde0ffa449eef528deb2fe455a512acd0569be4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 25 Sep 2019 09:49:58 +0100
+Subject: [PATCH] dma-direct: Temporary DMA fix on arm64
+
+See: https://github.com/raspberrypi/linux/issues/3251
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ kernel/dma/direct.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -397,7 +397,7 @@ int dma_direct_supported(struct device *
+ if (IS_ENABLED(CONFIG_ZONE_DMA))
+ min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS);
+ else
+- min_mask = DMA_BIT_MASK(32);
++ min_mask = DMA_BIT_MASK(30);
+
+ min_mask = min_t(u64, min_mask, (max_pfn - 1) << PAGE_SHIFT);
+
+++ /dev/null
-From 1b14387d6b699c4cfc8218867997b1508a67167a Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 6 Sep 2019 15:04:51 +0100
-Subject: [PATCH] v4l2: Add a Greyworld AWB mode.
-
-Adds a simple greyworld white balance preset, mainly for use
-with cameras without an IR filter (eg Raspberry Pi NoIR)
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/media/v4l2-core/v4l2-ctrls.c | 1 +
- include/uapi/linux/v4l2-controls.h | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/media/v4l2-core/v4l2-ctrls.c
-+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
-@@ -271,6 +271,7 @@ const char * const *v4l2_ctrl_get_menu(u
- "Flash",
- "Cloudy",
- "Shade",
-+ "Greyworld",
- NULL,
- };
- static const char * const camera_iso_sensitivity_auto[] = {
---- a/include/uapi/linux/v4l2-controls.h
-+++ b/include/uapi/linux/v4l2-controls.h
-@@ -850,6 +850,7 @@ enum v4l2_auto_n_preset_white_balance {
- V4L2_WHITE_BALANCE_FLASH = 7,
- V4L2_WHITE_BALANCE_CLOUDY = 8,
- V4L2_WHITE_BALANCE_SHADE = 9,
-+ V4L2_WHITE_BALANCE_GREYWORLD = 10,
- };
-
- #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21)
--- /dev/null
+From 7a226e4533daa54a2ca625005b06ddeffe5de994 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Thu, 19 Sep 2019 20:45:30 +0200
+Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711
+ compatible
+
+After the decision to use bcm2711 compatible for upstream, we should
+switch all accepted compatibles to bcm2711. So we can boot with
+one DTB the down- and the upstream kernel.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -109,7 +109,7 @@ static const char * const bcm2835_compat
+ #ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+ "brcm,bcm2837",
+- "brcm,bcm2838",
++ "brcm,bcm2711",
+ #endif
+ NULL
+ };
+++ /dev/null
-From a1504ea7c24e74fe4d10b024d8105dc66115b01e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 6 Sep 2019 15:13:06 +0100
-Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode
-
-This is mainly used for the NoIR camera which has no IR
-filter and can completely confuse normal AWB presets.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++--
- .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 +
- 2 files changed, 7 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
-+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
-@@ -477,6 +477,10 @@ static int ctrl_set_awb_mode(struct bm28
- case V4L2_WHITE_BALANCE_SHADE:
- u32_value = MMAL_PARAM_AWBMODE_SHADE;
- break;
-+
-+ case V4L2_WHITE_BALANCE_GREYWORLD:
-+ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD;
-+ break;
- }
-
- return vchiq_mmal_port_parameter_set(dev->instance, control,
-@@ -1014,8 +1018,8 @@ static const struct bm2835_mmal_v4l2_ctr
- {
- V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
- MMAL_CONTROL_TYPE_STD_MENU,
-- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
-- NULL,
-+ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO,
-+ 0, NULL,
- MMAL_PARAMETER_AWB_MODE,
- ctrl_set_awb_mode,
- false
---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h
-@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode {
- MMAL_PARAM_AWBMODE_INCANDESCENT,
- MMAL_PARAM_AWBMODE_FLASH,
- MMAL_PARAM_AWBMODE_HORIZON,
-+ MMAL_PARAM_AWBMODE_GREYWORLD,
- };
-
- enum mmal_parameter_imagefx {
+++ /dev/null
-From ae66baa23455df9f7593b98c5c2f02818dbaf41b Mon Sep 17 00:00:00 2001
-From: James Hughes <JamesH65@users.noreply.github.com>
-Date: Wed, 11 Sep 2019 14:57:18 +0100
-Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode
- (#3223)
-
-Margins were incorrectly assumed to be setup in SDTV mode, but were
-not actually done, so this make the setup non-conditional on mode.
-
-Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++--------
- 1 file changed, 3 insertions(+), 8 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -1612,14 +1612,9 @@ vc4_fkms_connector_init(struct drm_devic
- connector->interlace_allowed = 0;
- }
-
-- /* Create and attach TV margin props to this connector.
-- * Already done for SDTV outputs.
-- */
-- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) {
-- ret = drm_mode_create_tv_margin_properties(dev);
-- if (ret)
-- goto fail;
-- }
-+ ret = drm_mode_create_tv_margin_properties(dev);
-+ if (ret)
-+ goto fail;
-
- drm_connector_attach_tv_margin_properties(connector);
-
--- /dev/null
+From cf658ebc86b3e22c0b77e136fbbf19b580c7c256 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Sun, 21 Jul 2019 16:01:36 +0200
+Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up
+ functionality
+
+commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream.
+
+The BCM2711 has a new way of selecting the pull-up/pull-down setting
+for a GPIO pin. The registers used for the BCM2835, GP_PUD and
+GP_PUDCLKn0, are no longer connected. A new set of registers,
+GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add
+a new compatible string "brcm,bcm2711-gpio" and the kernel
+driver will use it to select which method is used to select
+pull-up/pull-down.
+
+This patch based on a patch by Al Cooper which was intended for the
+BCM7211. This is a bugfixed and improved version.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Acked-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1168,6 +1168,12 @@ static int bcm2835_pinctrl_probe(struct
+ (const struct pinconf_ops *)match->data;
+ }
+
++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
++ if (match) {
++ bcm2835_pinctrl_desc.confops =
++ (const struct pinconf_ops *)match->data;
++ }
++
+ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
+ if (IS_ERR(pc->pctl_dev)) {
+ gpiochip_remove(&pc->gpio_chip);
+++ /dev/null
-From 59c54c8b3b5afe051ca627fb42a685909b58d631 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
- <j-schambacher@users.noreply.github.com>
-Date: Thu, 12 Sep 2019 14:57:32 +0200
-Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224)
-
-Adds the driver for the Hifiberry DAC+DSP. It supports capture and
-playback depending on the DSP firmware.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- sound/soc/bcm/Kconfig | 7 ++
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplusadcpro.c | 28 +++-----
- sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++++++++
- sound/soc/bcm/rpi-simple-soundcard.c | 23 +++++++
- 5 files changed, 132 insertions(+), 18 deletions(-)
- create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c
-
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -59,6 +59,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
-+ tristate "Support for HifiBerry DAC+DSP"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_RPI_SIMPLE_SOUNDCARD
-+ help
-+ Say Y or M if you want to add support for HifiBerry DSP-DAC.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DIGI
- tristate "Support for HifiBerry Digi"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -16,6 +16,7 @@ snd-soc-googlevoicehat-codec-objs := goo
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
-+snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
-+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
-@@ -445,29 +445,21 @@ static struct snd_soc_ops snd_rpi_hifibe
- .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown,
- };
-
--static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = {
-- {
-- .name = "pcm512x.1-004d",
-- .dai_name = "pcm512x-hifi",
-- },
-- {
-- .name = "pcm186x.1-004a",
-- .dai_name = "pcm1863-aif",
-- },
--};
-+SND_SOC_DAILINK_DEFS(hifi,
-+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
-+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
-+ COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")),
-+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
-
- static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = {
- {
- .name = "HiFiBerry DAC+ADC PRO",
- .stream_name = "HiFiBerry DAC+ADC PRO HiFi",
-- .cpu_dai_name = "bcm2708-i2s.0",
-- .platform_name = "bcm2708-i2s.0",
-- .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs,
-- .num_codecs = 2,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
- .ops = &snd_rpi_hifiberry_dacplusadcpro_ops,
- .init = snd_rpi_hifiberry_dacplusadcpro_init,
-+ SND_SOC_DAILINK_REG(hifi),
- },
- };
-
-@@ -495,10 +487,10 @@ static int snd_rpi_hifiberry_dacplusadcp
- "i2s-controller", 0);
- if (i2s_node) {
- for (i = 0; i < card->num_links; i++) {
-- dai->cpu_dai_name = NULL;
-- dai->cpu_of_node = i2s_node;
-- dai->platform_name = NULL;
-- dai->platform_of_node = i2s_node;
-+ dai->cpus->dai_name = NULL;
-+ dai->cpus->of_node = i2s_node;
-+ dai->platforms->name = NULL;
-+ dai->platforms->of_node = i2s_node;
- }
- }
- }
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplusdsp.c
-@@ -0,0 +1,90 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * ASoC Driver for HiFiBerry DAC + DSP
-+ *
-+ * Author: Joerg Schambacher <joscha@schambacher.com>
-+ * Copyright 2018
-+ *
-+ * 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 <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <sound/soc.h>
-+
-+static struct snd_soc_component_driver dacplusdsp_component_driver;
-+
-+static struct snd_soc_dai_driver dacplusdsp_dai = {
-+ .name = "dacplusdsp-hifi",
-+ .capture = {
-+ .stream_name = "DAC+DSP Capture",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .playback = {
-+ .stream_name = "DACP+DSP Playback",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .symmetric_rates = 1};
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id dacplusdsp_ids[] = {
-+ {
-+ .compatible = "hifiberry,dacplusdsp",
-+ },
-+ {} };
-+MODULE_DEVICE_TABLE(of, dacplusdsp_ids);
-+#endif
-+
-+static int dacplusdsp_platform_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+
-+ ret = snd_soc_register_component(&pdev->dev,
-+ &dacplusdsp_component_driver, &dacplusdsp_dai, 1);
-+ if (ret) {
-+ pr_alert("snd_soc_register_component failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int dacplusdsp_platform_remove(struct platform_device *pdev)
-+{
-+ snd_soc_unregister_component(&pdev->dev);
-+ return 0;
-+}
-+
-+static struct platform_driver dacplusdsp_driver = {
-+ .driver = {
-+ .name = "hifiberry-dacplusdsp-codec",
-+ .of_match_table = of_match_ptr(dacplusdsp_ids),
-+ },
-+ .probe = dacplusdsp_platform_probe,
-+ .remove = dacplusdsp_platform_remove,
-+};
-+
-+module_platform_driver(dacplusdsp_driver);
-+
-+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP");
-+MODULE_LICENSE("GPL v2");
---- a/sound/soc/bcm/rpi-simple-soundcard.c
-+++ b/sound/soc/bcm/rpi-simple-soundcard.c
-@@ -144,6 +144,27 @@ static struct snd_rpi_simple_drvdata drv
- .dai = snd_googlevoicehat_soundcard_dai,
- };
-
-+SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp,
-+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
-+ DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")),
-+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
-+
-+static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
-+{
-+ .name = "Hifiberry DAC+DSP SoundCard",
-+ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S |
-+ SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ SND_SOC_DAILINK_REG(hifiberry_dacplusdsp),
-+},
-+};
-+
-+static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
-+ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
-+ .dai = snd_hifiberrydacplusdsp_soundcard_dai,
-+};
-+
- SND_SOC_DAILINK_DEFS(hifiberry_amp,
- DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")),
-@@ -213,6 +234,8 @@ static const struct of_device_id snd_rpi
- .data = (void *) &drvdata_adau1977 },
- { .compatible = "googlevoicehat,googlevoicehat-soundcard",
- .data = (void *) &drvdata_googlevoicehat },
-+ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
-+ .data = (void *) &drvdata_hifiberrydacplusdsp },
- { .compatible = "hifiberry,hifiberry-amp",
- .data = (void *) &drvdata_hifiberry_amp },
- { .compatible = "hifiberry,hifiberry-dac",
--- /dev/null
+From a822f97a094991b08a50352355b0a376086b46c4 Mon Sep 17 00:00:00 2001
+From: Matteo Croce <mcroce@redhat.com>
+Date: Sun, 6 Oct 2019 03:23:15 +0200
+Subject: [PATCH] vchiq_2835_arm: suppress warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Suppress the following warning by casting the pointer to and uintptr_t
+before void*:
+
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c: In function ‘vchiq_prepare_bulk_data’:
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c:260:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
+ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
+ ^
+
+Signed-off-by: Matteo Croce <mcroce@redhat.com>
+---
+ .../staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+@@ -255,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul
+ if (!pagelistinfo)
+ return VCHIQ_ERROR;
+
+- bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
++ bulk->data = (void *)(uintptr_t)VC_SAFE(pagelistinfo->dma_addr);
+
+ /*
+ * Store the pagelistinfo address in remote_data,
--- /dev/null
+From 95709d5c58c57f31a70e96fe9ebb8d34c046f877 Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Tue, 24 Sep 2019 18:26:55 +0100
+Subject: [PATCH] Rename HDMI ALSA device names, check for enable state
+
+HDMI Alsa devices renamed to match names used by DRM, to
+HDMI 1 and HDMI 2
+
+Check for which HDMI devices are connected and only create
+devices for those that are present.
+
+The rename of the devices might cause some backwards compatibility
+issues, but since this particular part of the driver needs to be
+specifically enabled, I suspect the number of people who will see
+the problem will be very small.
+
+Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
+---
+ .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++--
+ 1 file changed, 63 insertions(+), 7 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+@@ -9,8 +9,9 @@
+ #include <linux/of.h>
+
+ #include "bcm2835.h"
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+-static bool enable_hdmi;
++static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
+ static bool enable_headphones;
+ static bool enable_compat_alsa = true;
+
+@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+- .shortname = "bcm2835 HDMI",
+- .longname = "bcm2835 HDMI",
++ .shortname = "bcm2835 HDMI 1",
++ .longname = "bcm2835 HDMI 1",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+- .shortname = "bcm2835 HDMI 1",
+- .longname = "bcm2835 HDMI 1",
++ .shortname = "bcm2835 HDMI 2",
++ .longname = "bcm2835 HDMI 2",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi0,
+- .is_enabled = &enable_hdmi,
++ .is_enabled = &enable_hdmi0,
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi1,
+- .is_enabled = &enable_hdmi,
++ .is_enabled = &enable_hdmi1,
+ },
+ {
+ .audio_driver = &bcm2835_audio_headphones,
+@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct
+ return 0;
+ }
+
++static void set_hdmi_enables(struct device *dev)
++{
++ struct device_node *firmware_node;
++ struct rpi_firmware *firmware;
++ u32 num_displays, i, display_id;
++ int ret;
++
++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
++ firmware = rpi_firmware_get(firmware_node);
++
++ if (!firmware)
++ return;
++
++ of_node_put(firmware_node);
++
++ ret = rpi_firmware_property(firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
++ &num_displays, sizeof(u32));
++
++ if (ret)
++ return;
++
++ for (i = 0; i < num_displays; i++) {
++ display_id = i;
++ ret = rpi_firmware_property(firmware,
++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
++ &display_id, sizeof(display_id));
++ if (!ret) {
++ if (display_id == 2)
++ enable_hdmi0 = true;
++ if (display_id == 7)
++ enable_hdmi1 = true;
++ }
++ }
++
++ if (!enable_hdmi0 && enable_hdmi1) {
++ /* Swap them over and reassign route. This means
++ * that if we only have one connected, it is always named
++ * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
++ * This should match with the naming of HDMI ports in DRM
++ */
++ enable_hdmi0 = true;
++ enable_hdmi1 = false;
++ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
++ }
++}
++
+ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct
+ numchans);
+ }
+
++ if (!enable_compat_alsa) {
++ set_hdmi_enables(dev);
++ // In this mode, always enable analog output
++ enable_headphones = true;
++ } else {
++ enable_hdmi0 = enable_hdmi;
++ }
++
+ err = bcm2835_devm_add_vchi_ctx(dev);
+ if (err)
+ return err;
+++ /dev/null
-From 59c8c7740d6f236431fa792957fefe9f67611b27 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 6 Sep 2019 17:24:55 +0100
-Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920.
-
-The codec is happy with video up to 1920 high if the width
-is suitably reduced to stay within level limits. eg 1080x1920
-is OK to decode.
-
-Increase the height limit accordingly.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -92,7 +92,7 @@ static const char * const components[] =
- #define MIN_W 32
- #define MIN_H 32
- #define MAX_W 1920
--#define MAX_H 1088
-+#define MAX_H 1920
- #define BPL_ALIGN 32
- #define DEFAULT_WIDTH 640
- #define DEFAULT_HEIGHT 480
--- /dev/null
+From fb76c3ded8c771e8b9287d62b5e13666037f890e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 17 Sep 2019 18:28:17 +0100
+Subject: [PATCH] drm/vc4: Add support for YUV color encodings and
+ ranges
+
+The BT601/BT709 color encoding and limited vs full
+range properties were not being exposed, defaulting
+always to BT601 limited range.
+
+Expose the parameters and set the registers appropriately.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++--
+ drivers/gpu/drm/vc4/vc4_regs.h | 3 ++
+ 2 files changed, 72 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_plane.c
++++ b/drivers/gpu/drm/vc4/vc4_plane.c
+@@ -577,6 +577,53 @@ static int vc4_plane_allocate_lbm(struct
+ return 0;
+ }
+
++/* The colorspace conversion matrices are held in 3 entries in the dlist.
++ * Create an array of them, with entries for each full and limited mode, and
++ * each supported colorspace.
++ */
++#define VC4_LIMITED_RANGE 0
++#define VC4_FULL_RANGE 1
++
++static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
++ {
++ /* Limited range */
++ {
++ /* BT601 */
++ SCALER_CSC0_ITR_R_601_5,
++ SCALER_CSC1_ITR_R_601_5,
++ SCALER_CSC2_ITR_R_601_5,
++ }, {
++ /* BT709 */
++ SCALER_CSC0_ITR_R_709_3,
++ SCALER_CSC1_ITR_R_709_3,
++ SCALER_CSC2_ITR_R_709_3,
++ }, {
++ /* BT2020. Not supported yet - copy 601 */
++ SCALER_CSC0_ITR_R_601_5,
++ SCALER_CSC1_ITR_R_601_5,
++ SCALER_CSC2_ITR_R_601_5,
++ }
++ }, {
++ /* Full range */
++ {
++ /* JFIF */
++ SCALER_CSC0_JPEG_JFIF,
++ SCALER_CSC1_JPEG_JFIF,
++ SCALER_CSC2_JPEG_JFIF,
++ }, {
++ /* BT709 */
++ SCALER_CSC0_ITR_R_709_3_FR,
++ SCALER_CSC1_ITR_R_709_3_FR,
++ SCALER_CSC2_ITR_R_709_3_FR,
++ }, {
++ /* BT2020. Not supported yet - copy JFIF */
++ SCALER_CSC0_JPEG_JFIF,
++ SCALER_CSC1_JPEG_JFIF,
++ SCALER_CSC2_JPEG_JFIF,
++ }
++ }
++};
++
+ /* Writes out a full display list for an active plane to the plane's
+ * private dlist state.
+ */
+@@ -856,9 +903,20 @@ static int vc4_plane_mode_set(struct drm
+
+ /* Colorspace conversion words */
+ if (vc4_state->is_yuv) {
+- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
+- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
+- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
++ enum drm_color_encoding color_encoding = state->color_encoding;
++ enum drm_color_range color_range = state->color_range;
++ const u32 *ccm;
++
++ if (color_encoding >= DRM_COLOR_ENCODING_MAX)
++ color_encoding = DRM_COLOR_YCBCR_BT601;
++ if (color_range >= DRM_COLOR_RANGE_MAX)
++ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
++
++ ccm = colorspace_coeffs[color_range][color_encoding];
++
++ vc4_dlist_write(vc4_state, ccm[0]);
++ vc4_dlist_write(vc4_state, ccm[1]);
++ vc4_dlist_write(vc4_state, ccm[2]);
+ }
+
+ vc4_state->lbm_offset = 0;
+@@ -1265,5 +1323,13 @@ struct drm_plane *vc4_plane_init(struct
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y);
+
++ drm_plane_create_color_properties(plane,
++ BIT(DRM_COLOR_YCBCR_BT601) |
++ BIT(DRM_COLOR_YCBCR_BT709),
++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
++ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
++ DRM_COLOR_YCBCR_BT709,
++ DRM_COLOR_YCBCR_LIMITED_RANGE);
++
+ return plane;
+ }
+--- a/drivers/gpu/drm/vc4/vc4_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_regs.h
+@@ -950,6 +950,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC0_ITR_R_601_5 0x00f00000
+ #define SCALER_CSC0_ITR_R_709_3 0x00f00000
+ #define SCALER_CSC0_JPEG_JFIF 0x00000000
++#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
+
+ /* S2.8 contribution of Cb to Green */
+ #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
+@@ -966,6 +967,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC1_ITR_R_601_5 0xe73304a8
+ #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
+ #define SCALER_CSC1_JPEG_JFIF 0xea34a400
++#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
+
+ /* S2.8 contribution of Cb to Red */
+ #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
+@@ -979,6 +981,7 @@ enum hvs_pixel_format {
+ #define SCALER_CSC2_ITR_R_601_5 0x00066204
+ #define SCALER_CSC2_ITR_R_709_3 0x00072a1c
+ #define SCALER_CSC2_JPEG_JFIF 0x000599c5
++#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
+
+ #define SCALER_TPZ0_VERT_RECALC BIT(31)
+ #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
+++ /dev/null
-From c8a466aecf6b7d0bdc1fea9e32f80327b641cd03 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 13 Sep 2019 15:11:47 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API
- MPLANE support
-
-The g_selection and s_selection API is messed up and requires
-the driver to expect the non-MPLANE buffer types, not the MPLANE
-ones even if they are supported. The V4L2 core will convert the
-MPLANE ones to non-MPLANE should they be passed in
-
-Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------
- 1 file changed, 47 insertions(+), 20 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
-- true : false;
-
-- if ((ctx->dev->role == DECODE && !capture_queue) ||
-- (ctx->dev->role == ENCODE && capture_queue))
-- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-- return -EINVAL;
--
-- q_data = get_q_data(ctx, s->type);
-- if (!q_data)
-+ /*
-+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
-+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
-+ * API. The V4L2 core will have converted the MPLANE variants to
-+ * non-MPLANE.
-+ * Open code this instead of using get_q_data in this case.
-+ */
-+ switch (s->type) {
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ /* CAPTURE on encoder is not valid. */
-+ if (ctx->dev->role == ENCODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_DST];
-+ break;
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ /* OUTPUT on deoder is not valid. */
-+ if (ctx->dev->role == DECODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ break;
-+ default:
- return -EINVAL;
-+ }
-
- switch (ctx->dev->role) {
- case DECODE:
-@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
- struct bcm2835_codec_q_data *q_data = NULL;
-- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
-- true : false;
-+
-+ /*
-+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and
-+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE
-+ * API. The V4L2 core will have converted the MPLANE variants to
-+ * non-MPLANE.
-+ *
-+ * Open code this instead of using get_q_data in this case.
-+ */
-+ switch (s->type) {
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-+ /* CAPTURE on encoder is not valid. */
-+ if (ctx->dev->role == ENCODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_DST];
-+ break;
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-+ /* OUTPUT on deoder is not valid. */
-+ if (ctx->dev->role == DECODE)
-+ return -EINVAL;
-+ q_data = &ctx->q_data[V4L2_M2M_SRC];
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-
- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n",
- __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top,
- s->r.width, s->r.height);
-
-- if ((ctx->dev->role == DECODE && !capture_queue) ||
-- (ctx->dev->role == ENCODE && capture_queue))
-- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */
-- return -EINVAL;
--
-- q_data = get_q_data(ctx, s->type);
-- if (!q_data)
-- return -EINVAL;
--
- switch (ctx->dev->role) {
- case DECODE:
- switch (s->target) {
+++ /dev/null
-From 4fad98821e9ccd74b9b828d98cbe9df8c7437605 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 18 Sep 2019 17:22:36 +0100
-Subject: [PATCH] drm/v3d: Delete pm_runtime support
-
-The pm_runtime was blocking changelist submission, so delete it as a
-temporary workaround.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_gem.c | 5 -----
- drivers/gpu/drm/v3d/v3d_mmu.c | 11 -----------
- 2 files changed, 16 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -478,10 +478,6 @@ v3d_job_init(struct v3d_dev *v3d, struct
- job->v3d = v3d;
- job->free = free;
-
-- ret = pm_runtime_get_sync(v3d->dev);
-- if (ret < 0)
-- return ret;
--
- xa_init_flags(&job->deps, XA_FLAGS_ALLOC);
-
- ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence);
-@@ -498,7 +494,6 @@ v3d_job_init(struct v3d_dev *v3d, struct
- return 0;
- fail:
- xa_destroy(&job->deps);
-- pm_runtime_put_autosuspend(v3d->dev);
- return ret;
- }
-
---- a/drivers/gpu/drm/v3d/v3d_mmu.c
-+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
-@@ -36,14 +36,6 @@ static int v3d_mmu_flush_all(struct v3d_
- {
- int ret;
-
-- /* Keep power on the device on until we're done with this
-- * call, but skip the flush if the device is off and will be
-- * reset when powered back on.
-- */
-- ret = pm_runtime_get_if_in_use(v3d->dev);
-- if (ret == 0)
-- return 0;
--
- /* Make sure that another flush isn't already running when we
- * start this one.
- */
-@@ -71,9 +63,6 @@ static int v3d_mmu_flush_all(struct v3d_
- if (ret)
- dev_err(v3d->dev, "MMUC flush wait idle failed\n");
-
-- pm_runtime_mark_last_busy(v3d->dev);
-- pm_runtime_put_autosuspend(v3d->dev);
--
- return ret;
- }
-
--- /dev/null
+From 23ed834712dfc0d25451f16b46ae9c19abb675b5 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Wed, 18 Sep 2019 15:49:13 +0100
+Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in
+ fkms
+
+One bit within DRM_MODE_ROTATE_MASK will always be set to
+determine the base rotation 0/90/180/270, and then REFLECT_X
+and REFLECT_Y are on top.
+
+Correct the handling which was assuming that REFLECT_[X|Y]
+was instead of ROTATE_x.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++----------------
+ 1 file changed, 14 insertions(+), 23 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -82,11 +82,6 @@ struct set_plane {
+ #define TRANSFORM_FLIP_HRIZ BIT(16)
+ #define TRANSFORM_FLIP_VERT BIT(17)
+
+-#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
+- DRM_MODE_ROTATE_180 | \
+- DRM_MODE_REFLECT_X | \
+- DRM_MODE_REFLECT_Y)
+-
+ struct mailbox_set_plane {
+ struct rpi_firmware_property_tag_header tag;
+ struct set_plane plane;
+@@ -525,7 +520,7 @@ static int vc4_plane_to_mb(struct drm_pl
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+ int num_planes = fb->format->num_planes;
+- unsigned int rotation = SUPPORTED_ROTATIONS;
++ unsigned int rotation;
+
+ mb->plane.vc_image_type = vc_fmt->vc_image;
+ mb->plane.width = fb->width;
+@@ -546,23 +541,16 @@ static int vc4_plane_to_mb(struct drm_pl
+ mb->plane.is_vu = vc_fmt->is_vu;
+ mb->plane.planes[0] = bo->paddr + fb->offsets[0];
+
+- rotation = drm_rotation_simplify(state->rotation, rotation);
+-
+- switch (rotation) {
+- default:
+- case DRM_MODE_ROTATE_0:
+- mb->plane.transform = TRANSFORM_NO_ROTATE;
+- break;
+- case DRM_MODE_ROTATE_180:
+- mb->plane.transform = TRANSFORM_ROTATE_180;
+- break;
+- case DRM_MODE_REFLECT_X:
+- mb->plane.transform = TRANSFORM_FLIP_HRIZ;
+- break;
+- case DRM_MODE_REFLECT_Y:
+- mb->plane.transform = TRANSFORM_FLIP_VERT;
+- break;
+- }
++ rotation = drm_rotation_simplify(state->rotation,
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
++
++ mb->plane.transform = TRANSFORM_NO_ROTATE;
++ if (rotation & DRM_MODE_REFLECT_X)
++ mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
++ if (rotation & DRM_MODE_REFLECT_Y)
++ mb->plane.transform |= TRANSFORM_FLIP_VERT;
+
+ vc4_fkms_margins_adj(state, &mb->plane);
+
+@@ -803,7 +791,10 @@ static struct drm_plane *vc4_fkms_plane_
+
+ drm_plane_create_alpha_property(plane);
+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+- SUPPORTED_ROTATIONS);
++ DRM_MODE_ROTATE_0 |
++ DRM_MODE_ROTATE_180 |
++ DRM_MODE_REFLECT_X |
++ DRM_MODE_REFLECT_Y);
+ drm_plane_create_color_properties(plane,
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
--- /dev/null
+From 5db0abcd74512cf7013c2ea87d347cd158726be3 Mon Sep 17 00:00:00 2001
+From: Markus Proeller <markus.proeller@pieye.org>
+Date: Thu, 10 Oct 2019 19:12:08 +0200
+Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125
+ sensor
+
+Adds a binding for the Infineon IRS1125 time-of-flight depth
+sensor.
+
+Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
+---
+ .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt
+@@ -0,0 +1,48 @@
++* Infineon irs1125 time of flight sensor
++
++The Infineon irs1125 is a time of flight digital image sensor with
++an active array size of 352H x 286V. It is programmable through I2C
++interface. The I2C address defaults to 0x3D, but can be reconfigured
++to address 0x3C or 0x41 via I2C commands. Image data is sent through
++MIPI CSI-2, which is configured as either 1 or 2 data lanes.
++
++Required Properties:
++- compatible: value should be "infineon,irs1125" for irs1125 sensor
++- reg: I2C bus address of the device
++- clocks: reference to the xclk input clock.
++- pwdn-gpios: reference to the GPIO connected to the reset pin.
++ This is an active low signal to the iirs1125.
++
++The irs1125 device node should contain one 'port' child node with
++an 'endpoint' subnode. For further reading on port node refer to
++Documentation/devicetree/bindings/media/video-interfaces.txt.
++
++Endpoint node required properties for CSI-2 connection are:
++- remote-endpoint: a phandle to the bus receiver's endpoint node.
++- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
++- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2
++ supported)
++
++Example:
++ sensor@10 {
++ compatible = "infineon,irs1125";
++ reg = <0x3D>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&irs1125_clk>;
++ pwdn-gpios = <&gpio 5 0>;
++
++ irs1125_clk: camera-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <26000000>;
++ };
++
++ port {
++ sensor_out: endpoint {
++ remote-endpoint = <&csiss_in>;
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ };
++ };
++ };
+++ /dev/null
-From 849dc86116416161d0f13bf929ab712ea2bade7e Mon Sep 17 00:00:00 2001
-From: Phil Elwell <pelwell@users.noreply.github.com>
-Date: Wed, 18 Sep 2019 09:02:10 +0100
-Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235)
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm64/boot/dts/broadcom/Makefile | 2 ++
- arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +++
- 2 files changed, 5 insertions(+)
- create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
-
---- a/arch/arm64/boot/dts/broadcom/Makefile
-+++ b/arch/arm64/boot/dts/broadcom/Makefile
-@@ -3,7 +3,9 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp
- bcm2837-rpi-3-b.dtb \
- bcm2837-rpi-3-b-plus.dtb \
- bcm2837-rpi-cm3-io3.dtb
-+dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb
- dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb
-+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb
- dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb
---- /dev/null
-+++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
-@@ -0,0 +1,3 @@
-+#define RPI364
-+
-+#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
+++ /dev/null
-From 141da39c2ce8dbf77773c54182244c14d96b301d Mon Sep 17 00:00:00 2001
-From: Iago Toral Quiroga <itoral@igalia.com>
-Date: Tue, 3 Sep 2019 08:45:24 +0200
-Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on
- request from user space
-
-Extends the user space ioctl for CL submissions so it can include a request
-to flush the cache once the CL execution has completed. Fixes memory
-write violation messages reported by the kernel in workloads involving
-shader memory writes (SSBOs, shader images, scratch, etc) which sometimes
-also lead to GPU resets during Piglit and CTS workloads.
-
-v2: if v3d_job_init() fails we need to kfree() the job instead of
- v3d_job_put() it (Eric Anholt).
-
-v3 (Eric Anholt):
- - Drop _FLAG suffix from the new flag name.
- - Add a new param so userspace can tell whether cache flushing is
- implemented in the kernel.
-
-Signed-off-by: Iago Toral Quiroga <itoral@igalia.com>
----
- drivers/gpu/drm/v3d/v3d_drv.c | 3 +++
- drivers/gpu/drm/v3d/v3d_gem.c | 48 ++++++++++++++++++++++++++++++-----
- include/uapi/drm/v3d_drm.h | 6 +++--
- 3 files changed, 49 insertions(+), 8 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -120,6 +120,9 @@ static int v3d_get_param_ioctl(struct dr
- case DRM_V3D_PARAM_SUPPORTS_CSD:
- args->value = v3d_has_csd(v3d);
- return 0;
-+ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH:
-+ args->value = 1;
-+ return 0;
- default:
- DRM_DEBUG("Unknown parameter %d\n", args->param);
- return -EINVAL;
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -565,13 +565,16 @@ v3d_submit_cl_ioctl(struct drm_device *d
- struct drm_v3d_submit_cl *args = data;
- struct v3d_bin_job *bin = NULL;
- struct v3d_render_job *render;
-+ struct v3d_job *clean_job = NULL;
-+ struct v3d_job *last_job;
- struct ww_acquire_ctx acquire_ctx;
- int ret = 0;
-
- trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
-
-- if (args->pad != 0) {
-- DRM_INFO("pad must be zero: %d\n", args->pad);
-+ if (args->flags != 0 &&
-+ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
-+ DRM_INFO("invalid flags: %d\n", args->flags);
- return -EINVAL;
- }
-
-@@ -613,12 +616,31 @@ v3d_submit_cl_ioctl(struct drm_device *d
- bin->render = render;
- }
-
-- ret = v3d_lookup_bos(dev, file_priv, &render->base,
-+ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
-+ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
-+ if (!clean_job) {
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
-+ if (ret) {
-+ kfree(clean_job);
-+ clean_job = NULL;
-+ goto fail;
-+ }
-+
-+ last_job = clean_job;
-+ } else {
-+ last_job = &render->base;
-+ }
-+
-+ ret = v3d_lookup_bos(dev, file_priv, last_job,
- args->bo_handles, args->bo_handle_count);
- if (ret)
- goto fail;
-
-- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
-+ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx);
- if (ret)
- goto fail;
-
-@@ -637,17 +659,29 @@ v3d_submit_cl_ioctl(struct drm_device *d
- ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
- if (ret)
- goto fail_unreserve;
-+
-+ if (clean_job) {
-+ ret = drm_gem_fence_array_add(&clean_job->deps,
-+ dma_fence_get(render->base.done_fence));
-+ if (ret)
-+ goto fail_unreserve;
-+ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
-+ if (ret)
-+ goto fail_unreserve;
-+ }
- mutex_unlock(&v3d->sched_lock);
-
- v3d_attach_fences_and_unlock_reservation(file_priv,
-- &render->base,
-+ last_job,
- &acquire_ctx,
- args->out_sync,
-- render->base.done_fence);
-+ last_job->done_fence);
-
- if (bin)
- v3d_job_put(&bin->base);
- v3d_job_put(&render->base);
-+ if (clean_job)
-+ v3d_job_put(clean_job);
-
- return 0;
-
-@@ -659,6 +693,8 @@ fail:
- if (bin)
- v3d_job_put(&bin->base);
- v3d_job_put(&render->base);
-+ if (clean_job)
-+ v3d_job_put(clean_job);
-
- return ret;
- }
---- a/include/uapi/drm/v3d_drm.h
-+++ b/include/uapi/drm/v3d_drm.h
-@@ -48,6 +48,8 @@ extern "C" {
- #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
- #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
-
-+#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
-+
- /**
- * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
- * engine.
-@@ -124,8 +126,7 @@ struct drm_v3d_submit_cl {
- /* Number of BO handles passed in (size is that times 4). */
- __u32 bo_handle_count;
-
-- /* Pad, must be zero-filled. */
-- __u32 pad;
-+ __u32 flags;
- };
-
- /**
-@@ -193,6 +194,7 @@ enum drm_v3d_param {
- DRM_V3D_PARAM_V3D_CORE0_IDENT2,
- DRM_V3D_PARAM_SUPPORTS_TFU,
- DRM_V3D_PARAM_SUPPORTS_CSD,
-+ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH,
- };
-
- struct drm_v3d_get_param {
--- /dev/null
+From 54e4ff9b3cae743ca90b86a8fef72810d431e143 Mon Sep 17 00:00:00 2001
+From: Markus Proeller <markus.proeller@pieye.org>
+Date: Thu, 10 Oct 2019 19:12:36 +0200
+Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125
+ depth sensor
+
+The Infineon IRS1125 is a time of flight depth sensor that
+has a CSI-2 interface.
+
+Add a V4L2 subdevice driver for this device.
+
+Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
+---
+ drivers/media/i2c/Kconfig | 12 +
+ drivers/media/i2c/Makefile | 1 +
+ drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++
+ drivers/media/i2c/irs1125.h | 61 ++
+ 4 files changed, 1186 insertions(+)
+ create mode 100644 drivers/media/i2c/irs1125.c
+ create mode 100644 drivers/media/i2c/irs1125.h
+
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -839,6 +839,18 @@ config VIDEO_OV13858
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OV13858 camera.
+
++config VIDEO_IRS1125
++ tristate "Infineon IRS1125 sensor support"
++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
++ depends on MEDIA_CAMERA_SUPPORT
++ select V4L2_FWNODE
++ help
++ This is a Video4Linux2 sensor-level driver for the Infineon
++ IRS1125 camera.
++
++ To compile this driver as a module, choose M here: the
++ module will be called irs1125.
++
+ config VIDEO_VS6624
+ tristate "ST VS6624 sensor support"
+ depends on VIDEO_V4L2 && I2C
+--- a/drivers/media/i2c/Makefile
++++ b/drivers/media/i2c/Makefile
+@@ -82,6 +82,7 @@ obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
+ obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
+ obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
+ obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
++obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
+ obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
+ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
+ obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
+--- /dev/null
++++ b/drivers/media/i2c/irs1125.c
+@@ -0,0 +1,1112 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * A V4L2 driver for Infineon IRS1125 TOF cameras.
++ * Copyright (C) 2018, pieye GmbH
++ *
++ * Based on V4L2 OmniVision OV5647 Image Sensor driver
++ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
++ *
++ * DT / fwnode changes, and GPIO control taken from ov5640.c
++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ *
++ */
++
++#include "irs1125.h"
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/slab.h>
++#include <linux/videodev2.h>
++#include <linux/firmware.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-fwnode.h>
++#include <media/v4l2-image-sizes.h>
++#include <media/v4l2-mediabus.h>
++#include <media/v4l2-ctrls.h>
++
++#define CHECK_BIT(val, pos) ((val) & BIT(pos))
++
++#define SENSOR_NAME "irs1125"
++
++#define RESET_ACTIVE_DELAY_MS 20
++
++#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
++
++#define IRS1125_REG_CSICFG 0xA882
++#define IRS1125_REG_DESIGN_STEP 0xB0AD
++#define IRS1125_REG_EFUSEVAL2 0xB09F
++#define IRS1125_REG_EFUSEVAL3 0xB0A0
++#define IRS1125_REG_EFUSEVAL4 0xB0A1
++#define IRS1125_REG_DMEM_SHADOW 0xC320
++
++#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12
++
++#define IRS1125_ROW_START_DEF 0
++#define IRS1125_COLUMN_START_DEF 0
++#define IRS1125_WINDOW_HEIGHT_DEF 288
++#define IRS1125_WINDOW_WIDTH_DEF 352
++
++struct regval_list {
++ u16 addr;
++ u16 data;
++};
++
++struct irs1125 {
++ struct v4l2_subdev sd;
++ struct media_pad pad;
++ /* the parsed DT endpoint info */
++ struct v4l2_fwnode_endpoint ep;
++
++ struct clk *xclk;
++ struct v4l2_ctrl_handler ctrl_handler;
++
++ /* To serialize asynchronus callbacks */
++ struct mutex lock;
++
++ /* image data layout */
++ unsigned int num_seq;
++
++ /* reset pin */
++ struct gpio_desc *reset;
++
++ /* V4l2 Controls to grab */
++ struct v4l2_ctrl *ctrl_modplls;
++ struct v4l2_ctrl *ctrl_numseq;
++
++ int power_count;
++};
++
++static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
++{
++ return container_of(sd, struct irs1125, sd);
++}
++
++static struct regval_list irs1125_26MHz[] = {
++ {0xB017, 0x0413},
++ {0xB086, 0x3535},
++ {0xB0AE, 0xEF02},
++ {0xA000, 0x0004},
++ {0xFFFF, 100},
++
++ {0xB062, 0x6383},
++ {0xB063, 0x55A8},
++ {0xB068, 0x7628},
++ {0xB069, 0x03E2},
++
++ {0xFFFF, 100},
++ {0xB05A, 0x01C5},
++ {0xB05C, 0x0206},
++ {0xB05D, 0x01C5},
++ {0xB05F, 0x0206},
++ {0xB016, 0x1335},
++ {0xFFFF, 100},
++ {0xA893, 0x8261},
++ {0xA894, 0x89d8},
++ {0xA895, 0x131d},
++ {0xA896, 0x4251},
++ {0xA897, 0x9D8A},
++ {0xA898, 0x0BD8},
++ {0xA899, 0x2245},
++ {0xA89A, 0xAB9B},
++ {0xA89B, 0x03B9},
++ {0xA89C, 0x8041},
++ {0xA89D, 0xE07E},
++ {0xA89E, 0x0307},
++ {0xFFFF, 100},
++ {0xA88D, 0x0004},
++ {0xA800, 0x0E68},
++ {0xA801, 0x0000},
++ {0xA802, 0x000C},
++ {0xA803, 0x0000},
++ {0xA804, 0x0E68},
++ {0xA805, 0x0000},
++ {0xA806, 0x0440},
++ {0xA807, 0x0000},
++ {0xA808, 0x0E68},
++ {0xA809, 0x0000},
++ {0xA80A, 0x0884},
++ {0xA80B, 0x0000},
++ {0xA80C, 0x0E68},
++ {0xA80D, 0x0000},
++ {0xA80E, 0x0CC8},
++ {0xA80F, 0x0000},
++ {0xA810, 0x0E68},
++ {0xA811, 0x0000},
++ {0xA812, 0x2000},
++ {0xA813, 0x0000},
++ {0xA882, 0x0081},
++ {0xA88C, 0x403A},
++ {0xA88F, 0x031E},
++ {0xA892, 0x0351},
++ {0x9813, 0x13FF},
++ {0x981B, 0x7608},
++
++ {0xB008, 0x0000},
++ {0xB015, 0x1513},
++
++ {0xFFFF, 100}
++};
++
++static struct regval_list irs1125_seq_cfg[] = {
++ {0xC3A0, 0x823D},
++ {0xC3A1, 0xB13B},
++ {0xC3A2, 0x0313},
++ {0xC3A3, 0x4659},
++ {0xC3A4, 0xC4EC},
++ {0xC3A5, 0x03CE},
++ {0xC3A6, 0x4259},
++ {0xC3A7, 0xC4EC},
++ {0xC3A8, 0x03CE},
++ {0xC3A9, 0x8839},
++ {0xC3AA, 0x89D8},
++ {0xC3AB, 0x031D},
++
++ {0xC24C, 0x5529},
++ {0xC24D, 0x0000},
++ {0xC24E, 0x1200},
++ {0xC24F, 0x6CB2},
++ {0xC250, 0x0000},
++ {0xC251, 0x5529},
++ {0xC252, 0x42F4},
++ {0xC253, 0xD1AF},
++ {0xC254, 0x8A18},
++ {0xC255, 0x0002},
++ {0xC256, 0x5529},
++ {0xC257, 0x6276},
++ {0xC258, 0x11A7},
++ {0xC259, 0xD907},
++ {0xC25A, 0x0000},
++ {0xC25B, 0x5529},
++ {0xC25C, 0x07E0},
++ {0xC25D, 0x7BFE},
++ {0xC25E, 0x6402},
++ {0xC25F, 0x0019},
++
++ {0xC3AC, 0x0007},
++ {0xC3AD, 0xED88},
++ {0xC320, 0x003E},
++ {0xC321, 0x0000},
++ {0xC322, 0x2000},
++ {0xC323, 0x0000},
++ {0xC324, 0x0271},
++ {0xC325, 0x0000},
++ {0xC326, 0x000C},
++ {0xC327, 0x0000},
++ {0xC328, 0x0271},
++ {0xC329, 0x0000},
++ {0xC32A, 0x0440},
++ {0xC32B, 0x0000},
++ {0xC32C, 0x0271},
++ {0xC32D, 0x0000},
++ {0xC32E, 0x0884},
++ {0xC32F, 0x0000},
++ {0xC330, 0x0271},
++ {0xC331, 0x0000},
++ {0xC332, 0x0CC8},
++ {0xC333, 0x0000},
++ {0xA88D, 0x0004},
++
++ {0xA890, 0x0000},
++ {0xC219, 0x0002},
++ {0xC21A, 0x0000},
++ {0xC21B, 0x0000},
++ {0xC21C, 0x00CD},
++ {0xC21D, 0x0009},
++ {0xC21E, 0x00CD},
++ {0xC21F, 0x0009},
++
++ {0xA87C, 0x0000},
++ {0xC032, 0x0001},
++ {0xC034, 0x0000},
++ {0xC035, 0x0001},
++ {0xC039, 0x0000},
++ {0xC401, 0x0002},
++
++ {0xFFFF, 1},
++ {0xA87C, 0x0001}
++};
++
++static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
++{
++ int ret;
++ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = i2c_master_send(client, data, 4);
++ if (ret < 0)
++ dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
++ __func__, reg);
++
++ return ret;
++}
++
++static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
++{
++ int ret;
++ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
++ char rdval[2];
++
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = i2c_master_send(client, data_w, 2);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
++ __func__, reg);
++ return ret;
++ }
++
++ ret = i2c_master_recv(client, rdval, 2);
++ if (ret < 0)
++ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
++ __func__, reg);
++
++ *val = rdval[1] | (rdval[0] << 8);
++
++ return ret;
++}
++
++static int irs1125_write_array(struct v4l2_subdev *sd,
++ struct regval_list *regs, int array_size)
++{
++ int i, ret;
++
++ for (i = 0; i < array_size; i++) {
++ if (regs[i].addr == 0xFFFF) {
++ msleep(regs[i].data);
++ } else {
++ ret = irs1125_write(sd, regs[i].addr, regs[i].data);
++ if (ret < 0)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int irs1125_stream_on(struct v4l2_subdev *sd)
++{
++ int ret;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
++
++ ret = irs1125_write(sd, 0xC400, 0x0001);
++ if (ret < 0) {
++ dev_err(&client->dev, "error enabling firmware: %d", ret);
++ return ret;
++ }
++
++ msleep(100);
++
++ return irs1125_write(sd, 0xA87C, 0x0001);
++}
++
++static int irs1125_stream_off(struct v4l2_subdev *sd)
++{
++ int ret;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
++
++ ret = irs1125_write(sd, 0xA87C, 0x0000);
++ if (ret < 0) {
++ dev_err(&client->dev, "error disabling trigger: %d", ret);
++ return ret;
++ }
++
++ msleep(100);
++
++ return irs1125_write(sd, 0xC400, 0x0002);
++}
++
++static int __sensor_init(struct v4l2_subdev *sd)
++{
++ unsigned int cnt, idx;
++ int ret;
++ u16 val;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct irs1125 *irs1125 = to_state(sd);
++ const struct firmware *fw;
++ struct regval_list *reg_data;
++
++ cnt = 0;
++ while (1) {
++ ret = irs1125_read(sd, 0xC40F, &val);
++ if (ret < 0) {
++ dev_err(&client->dev, "read register 0xC40F failed\n");
++ return ret;
++ }
++ if (CHECK_BIT(val, 14) == 0)
++ break;
++
++ if (cnt >= 5) {
++ dev_err(&client->dev, "timeout waiting for 0xC40F\n");
++ return -EAGAIN;
++ }
++
++ cnt++;
++ }
++
++ ret = irs1125_write_array(sd, irs1125_26MHz,
++ ARRAY_SIZE(irs1125_26MHz));
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor default regs error\n");
++ return ret;
++ }
++
++ /* set CSI-2 number of data lanes */
++ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
++ val = 0x0001;
++ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
++ val = 0x0081;
++ } else {
++ dev_err(&client->dev, "invalid number of data lanes %d\n",
++ irs1125->ep.bus.mipi_csi2.num_data_lanes);
++ return -EINVAL;
++ }
++
++ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor csi2 config error\n");
++ return ret;
++ }
++
++ /* request the firmware, this will block and timeout */
++ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
++ if (ret) {
++ dev_err(&client->dev,
++ "did not find the firmware file '%s' (status %d)\n",
++ IRS1125_ALTERNATE_FW, ret);
++ return ret;
++ }
++
++ if (fw->size % 4) {
++ dev_err(&client->dev, "firmware file '%s' invalid\n",
++ IRS1125_ALTERNATE_FW);
++ release_firmware(fw);
++ return -EINVAL;
++ }
++
++ for (idx = 0; idx < fw->size; idx += 4) {
++ reg_data = (struct regval_list *)&fw->data[idx];
++ ret = irs1125_write(sd, reg_data->addr, reg_data->data);
++ if (ret < 0) {
++ dev_err(&client->dev, "firmware write error\n");
++ release_firmware(fw);
++ return ret;
++ }
++ }
++ release_firmware(fw);
++
++ ret = irs1125_write_array(sd, irs1125_seq_cfg,
++ ARRAY_SIZE(irs1125_seq_cfg));
++ if (ret < 0) {
++ dev_err(&client->dev, "write default sequence failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
++{
++ int ret = 0;
++ struct irs1125 *irs1125 = to_state(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ mutex_lock(&irs1125->lock);
++
++ if (on && !irs1125->power_count) {
++ gpiod_set_value_cansleep(irs1125->reset, 1);
++ msleep(RESET_ACTIVE_DELAY_MS);
++
++ ret = clk_prepare_enable(irs1125->xclk);
++ if (ret < 0) {
++ dev_err(&client->dev, "clk prepare enable failed\n");
++ goto out;
++ }
++
++ ret = __sensor_init(sd);
++ if (ret < 0) {
++ clk_disable_unprepare(irs1125->xclk);
++ dev_err(&client->dev,
++ "Camera not available, check Power\n");
++ goto out;
++ }
++ } else if (!on && irs1125->power_count == 1) {
++ gpiod_set_value_cansleep(irs1125->reset, 0);
++ }
++
++ /* Update the power count. */
++ irs1125->power_count += on ? 1 : -1;
++ WARN_ON(irs1125->power_count < 0);
++
++out:
++ mutex_unlock(&irs1125->lock);
++
++ return ret;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ u16 val;
++ int ret;
++
++ ret = irs1125_read(sd, reg->reg & 0xffff, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = 1;
++
++ return 0;
++}
++
++static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
++}
++#endif
++
++static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
++ .s_power = irs1125_sensor_power,
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = irs1125_sensor_get_register,
++ .s_register = irs1125_sensor_set_register,
++#endif
++};
++
++static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ if (enable)
++ return irs1125_stream_on(sd);
++ else
++ return irs1125_stream_off(sd);
++}
++
++static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
++ .s_stream = irs1125_s_stream,
++};
++
++static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->index > 0)
++ return -EINVAL;
++
++ code->code = MEDIA_BUS_FMT_Y12_1X12;
++
++ return 0;
++}
++
++static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *fmt = &format->format;
++ struct irs1125 *irs1125 = to_state(sd);
++
++ if (format->pad != 0)
++ return -EINVAL;
++
++ /* Only one format is supported, so return that */
++ memset(fmt, 0, sizeof(*fmt));
++ fmt->code = MEDIA_BUS_FMT_Y12_1X12;
++ fmt->colorspace = V4L2_COLORSPACE_RAW;
++ fmt->field = V4L2_FIELD_NONE;
++ fmt->width = IRS1125_WINDOW_WIDTH_DEF;
++ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
++
++ return 0;
++}
++
++static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
++ .enum_mbus_code = irs1125_enum_mbus_code,
++ .set_fmt = irs1125_set_get_fmt,
++ .get_fmt = irs1125_set_get_fmt,
++};
++
++static const struct v4l2_subdev_ops irs1125_subdev_ops = {
++ .core = &irs1125_subdev_core_ops,
++ .video = &irs1125_subdev_video_ops,
++ .pad = &irs1125_subdev_pad_ops,
++};
++
++static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct irs1125 *dev = container_of(ctrl->handler,
++ struct irs1125, ctrl_handler);
++ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
++ int err, i;
++ struct irs1125_mod_pll *mod_cur, *mod_new;
++ struct irs1125_seq_cfg *cfg_cur, *cfg_new;
++ u16 addr, val;
++
++ err = 0;
++
++ switch (ctrl->id) {
++ case IRS1125_CID_SAFE_RECONFIG:
++ {
++ struct irs1125_illu *illu_cur, *illu_new;
++
++ illu_new = (struct irs1125_illu *)ctrl->p_new.p;
++ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
++ if (illu_cur[i].exposure != illu_new[i].exposure) {
++ addr = 0xA850 + i * 2;
++ val = illu_new[i].exposure;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (illu_cur[i].framerate != illu_new[i].framerate) {
++ addr = 0xA851 + i * 2;
++ val = illu_new[i].framerate;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ }
++ case IRS1125_CID_MOD_PLL:
++ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
++ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
++ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
++ addr = 0xC3A0 + i * 3;
++ val = mod_new[i].pllcfg1;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
++ addr = 0xC3A1 + i * 3;
++ val = mod_new[i].pllcfg2;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
++ addr = 0xC3A2 + i * 3;
++ val = mod_new[i].pllcfg3;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
++ addr = 0xC24C + i * 5;
++ val = mod_new[i].pllcfg4;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
++ addr = 0xC24D + i * 5;
++ val = mod_new[i].pllcfg5;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
++ addr = 0xC24E + i * 5;
++ val = mod_new[i].pllcfg6;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
++ addr = 0xC24F + i * 5;
++ val = mod_new[i].pllcfg7;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
++ addr = 0xC250 + i * 5;
++ val = mod_new[i].pllcfg8;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ case IRS1125_CID_SEQ_CONFIG:
++ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
++ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p;
++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
++ if (cfg_cur[i].exposure != cfg_new[i].exposure) {
++ addr = IRS1125_REG_DMEM_SHADOW + i * 4;
++ val = cfg_new[i].exposure;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].framerate != cfg_new[i].framerate) {
++ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4;
++ val = cfg_new[i].framerate;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].ps != cfg_new[i].ps) {
++ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4;
++ val = cfg_new[i].ps;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ if (cfg_cur[i].pll != cfg_new[i].pll) {
++ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4;
++ val = cfg_new[i].pll;
++ err = irs1125_write(&dev->sd, addr, val);
++ if (err < 0)
++ break;
++ }
++ }
++ break;
++ case IRS1125_CID_NUM_SEQS:
++ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
++ if (err >= 0)
++ dev->num_seq = ctrl->val;
++ break;
++ case IRS1125_CID_CONTINUOUS_TRIG:
++ if (ctrl->val == 0)
++ err = irs1125_write(&dev->sd, 0xA87C, 0);
++ else
++ err = irs1125_write(&dev->sd, 0xA87C, 1);
++ break;
++ case IRS1125_CID_TRIGGER:
++ if (ctrl->val != 0) {
++ err = irs1125_write(&dev->sd, 0xA87C, 1);
++ if (err >= 0)
++ err = irs1125_write(&dev->sd, 0xA87C, 0);
++ }
++ break;
++ case IRS1125_CID_RECONFIG:
++ if (ctrl->val != 0)
++ err = irs1125_write(&dev->sd, 0xA87A, 1);
++ break;
++ case IRS1125_CID_ILLU_ON:
++ if (ctrl->val == 0)
++ err = irs1125_write(&dev->sd, 0xA892, 0x377);
++ else
++ err = irs1125_write(&dev->sd, 0xA892, 0x355);
++ break;
++ default:
++ break;
++ }
++
++ if (err < 0)
++ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
++ ctrl->id, ctrl->val, err);
++ else
++ err = 0;
++
++ return err;
++}
++
++static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
++ .s_ctrl = irs1125_s_ctrl,
++};
++
++static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
++ {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_NUM_SEQS,
++ .name = "Change number of sequences",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
++ .min = 1,
++ .max = 20,
++ .step = 1,
++ .def = 5,
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_MOD_PLL,
++ .name = "Reconfigure modulation PLLs",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
++ IRS1125_NUM_MOD_PLLS}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_SAFE_RECONFIG,
++ .name = "Change exposure and pause of single seq",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_illu) / sizeof(u16),
++ IRS1125_NUM_SEQ_ENTRIES}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_SEQ_CONFIG,
++ .name = "Change sequence settings",
++ .type = V4L2_CTRL_TYPE_U16,
++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
++ .min = 0,
++ .max = U16_MAX,
++ .step = 1,
++ .def = 0,
++ .elem_size = sizeof(u16),
++ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
++ IRS1125_NUM_SEQ_ENTRIES}
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_CONTINUOUS_TRIG,
++ .name = "Enable/disable continuous trigger",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_TRIGGER,
++ .name = "Capture a single sequence",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_RECONFIG,
++ .name = "Trigger imager reconfiguration",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_ILLU_ON,
++ .name = "Turn illu on or off",
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
++ .min = 0,
++ .max = 1,
++ .step = 1,
++ .def = 1
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT0,
++ .name = "Get ident 0 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT1,
++ .name = "Get ident 1 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }, {
++ .ops = &irs1125_ctrl_ops,
++ .id = IRS1125_CID_IDENT2,
++ .name = "Get ident 2 information",
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ .flags = V4L2_CTRL_FLAG_READ_ONLY,
++ .min = S32_MIN,
++ .max = S32_MAX,
++ .step = 1,
++ .def = 0
++ }
++};
++
++static int irs1125_detect(struct v4l2_subdev *sd)
++{
++ u16 read;
++ int ret;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
++ if (ret < 0) {
++ dev_err(&client->dev, "error reading from i2c\n");
++ return ret;
++ }
++
++ if (read != IRS1125_DESIGN_STEP_EXPECTED) {
++ dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
++ IRS1125_DESIGN_STEP_EXPECTED, read);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_mbus_framefmt *format =
++ v4l2_subdev_get_try_format(sd, fh->pad, 0);
++
++ format->code = MEDIA_BUS_FMT_Y12_1X12;
++ format->width = IRS1125_WINDOW_WIDTH_DEF;
++ format->height = IRS1125_WINDOW_HEIGHT_DEF;
++ format->field = V4L2_FIELD_NONE;
++ format->colorspace = V4L2_COLORSPACE_RAW;
++
++ return 0;
++}
++
++static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
++ .open = irs1125_open,
++};
++
++static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
++{
++ struct v4l2_ctrl *ctrl;
++ int err, i;
++ struct v4l2_ctrl_handler *hdl;
++
++ hdl = &sensor->ctrl_handler;
++ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
++
++ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) {
++ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
++ NULL);
++ if (!ctrl)
++ dev_err(dev, "Failed to init custom control %s\n",
++ irs1125_custom_ctrls[i].name);
++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
++ sensor->ctrl_numseq = ctrl;
++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
++ sensor->ctrl_modplls = ctrl;
++ }
++
++ if (hdl->error) {
++ dev_err(dev, "Error %d adding controls\n", hdl->error);
++ err = hdl->error;
++ goto error_ctrls;
++ }
++
++ sensor->sd.ctrl_handler = hdl;
++ return 0;
++
++error_ctrls:
++ v4l2_ctrl_handler_free(&sensor->ctrl_handler);
++ return -err;
++}
++
++static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
++{
++ int ret;
++ struct v4l2_ctrl *ctrl;
++ struct v4l2_subdev *sd;
++ u16 read;
++
++ sd = &sensor->sd;
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++
++ v4l2_ctrl_s_ctrl(ctrl, read);
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++
++ v4l2_ctrl_s_ctrl(ctrl, read);
++
++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
++ if (!ctrl) {
++ dev_err(dev, "could not find device ctrl.\n");
++ return -EINVAL;
++ }
++
++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
++ if (ret < 0) {
++ dev_err(dev, "error reading from i2c\n");
++ return -EIO;
++ }
++ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
++
++ return 0;
++}
++
++static int irs1125_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct device *dev = &client->dev;
++ struct irs1125 *sensor;
++ int ret;
++ struct fwnode_handle *endpoint;
++ u32 xclk_freq;
++ int gpio_num;
++
++ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
++ if (!sensor)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
++
++ /* Get CSI2 bus config */
++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
++ NULL);
++ if (!endpoint) {
++ dev_err(dev, "endpoint node not found\n");
++ return -EINVAL;
++ }
++
++ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
++ fwnode_handle_put(endpoint);
++ if (ret) {
++ dev_err(dev, "Could not parse endpoint\n");
++ return ret;
++ }
++
++ /* get system clock (xclk) */
++ sensor->xclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(sensor->xclk)) {
++ dev_err(dev, "could not get xclk");
++ return PTR_ERR(sensor->xclk);
++ }
++
++ xclk_freq = clk_get_rate(sensor->xclk);
++ if (xclk_freq != 26000000) {
++ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
++ return -EINVAL;
++ }
++
++ sensor->num_seq = 5;
++
++ /* Request the power down GPIO */
++ sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
++ GPIOD_OUT_LOW);
++
++ if (IS_ERR(sensor->reset)) {
++ dev_err(dev, "could not get reset");
++ return PTR_ERR(sensor->reset);
++ }
++
++ gpio_num = desc_to_gpio(sensor->reset);
++
++ mutex_init(&sensor->lock);
++
++ ret = irs1125_ctrls_init(sensor, dev);
++ if (ret < 0)
++ goto mutex_remove;
++
++ sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
++ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
++ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
++ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
++ if (ret < 0)
++ goto mutex_remove;
++
++ gpiod_set_value_cansleep(sensor->reset, 1);
++ msleep(RESET_ACTIVE_DELAY_MS);
++
++ ret = irs1125_detect(&sensor->sd);
++ if (ret < 0)
++ goto error;
++
++ ret = irs1125_ident_setup(sensor, dev);
++ if (ret < 0)
++ goto error;
++
++ gpiod_set_value_cansleep(sensor->reset, 0);
++
++ ret = v4l2_async_register_subdev(&sensor->sd);
++ if (ret < 0)
++ goto error;
++
++ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
++
++ return 0;
++
++error:
++ media_entity_cleanup(&sensor->sd.entity);
++mutex_remove:
++ mutex_destroy(&sensor->lock);
++ return ret;
++}
++
++static int irs1125_remove(struct i2c_client *client)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct irs1125 *irs1125 = to_state(sd);
++
++ v4l2_async_unregister_subdev(&irs1125->sd);
++ media_entity_cleanup(&irs1125->sd.entity);
++ v4l2_device_unregister_subdev(sd);
++ mutex_destroy(&irs1125->lock);
++ v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
++
++ return 0;
++}
++
++#if IS_ENABLED(CONFIG_OF)
++static const struct of_device_id irs1125_of_match[] = {
++ { .compatible = "infineon,irs1125" },
++ { /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, irs1125_of_match);
++#endif
++
++static struct i2c_driver irs1125_driver = {
++ .driver = {
++ .of_match_table = of_match_ptr(irs1125_of_match),
++ .name = SENSOR_NAME,
++ },
++ .probe = irs1125_probe,
++ .remove = irs1125_remove,
++};
++
++module_i2c_driver(irs1125_driver);
++
++MODULE_AUTHOR("Markus Proeller <markus.proeller@pieye.org>");
++MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
++MODULE_LICENSE("GPL v2");
++
+--- /dev/null
++++ b/drivers/media/i2c/irs1125.h
+@@ -0,0 +1,61 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * A V4L2 driver for Infineon IRS1125 TOF cameras.
++ * Copyright (C) 2018, pieye GmbH
++ *
++ * Based on V4L2 OmniVision OV5647 Image Sensor driver
++ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
++ *
++ * DT / fwnode changes, and GPIO control taken from ov5640.c
++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2014-2017 Mentor Graphics Inc.
++ *
++ */
++
++#ifndef IRS1125_H
++#define IRS1125_H
++
++#include <linux/v4l2-controls.h>
++#include <linux/types.h>
++
++#define IRS1125_NUM_SEQ_ENTRIES 20
++#define IRS1125_NUM_MOD_PLLS 4
++
++#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
++#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0)
++#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1)
++#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2)
++#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3)
++#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4)
++#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5)
++#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6)
++#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7)
++#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8)
++#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9)
++#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10)
++
++struct irs1125_seq_cfg {
++ __u16 exposure;
++ __u16 framerate;
++ __u16 ps;
++ __u16 pll;
++};
++
++struct irs1125_illu {
++ __u16 exposure;
++ __u16 framerate;
++};
++
++struct irs1125_mod_pll {
++ __u16 pllcfg1;
++ __u16 pllcfg2;
++ __u16 pllcfg3;
++ __u16 pllcfg4;
++ __u16 pllcfg5;
++ __u16 pllcfg6;
++ __u16 pllcfg7;
++ __u16 pllcfg8;
++};
++
++#endif /* IRS1125 */
++
+++ /dev/null
-From 7542fb08d2726606057c4283b3a454abb195a0f5 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 23 Sep 2019 09:26:41 +0100
-Subject: [PATCH] kbuild: Allow .dtbo overlays to be built piecemeal
-
-Before 4.20, it was possible to build an arbitrary overlay by copying
-it to arm/boot/dts/overlays/mytest-overlay.dts and running:
-
- make ARCH=arm overlays/mytest.dtbo
-
-In 4.20 the .dtb build rules were centralised, requiring the dowstream
-.dtbo build rules to be changed. They were, enough to support "make ...
-dtbs", but not sufficiently to allow this ad-hoc, one-off building of
-individual files.
-
-Add the missing makefile rule to support this way of building.
-
-See: https://github.com/raspberrypi/linux/issues/3250
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- Makefile | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/Makefile
-+++ b/Makefile
-@@ -1238,6 +1238,9 @@ ifneq ($(dtstree),)
- %.dtb: include/config/kernel.release scripts_dtc
- $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
-
-+%.dtbo: prepare3 scripts_dtc
-+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
-+
- PHONY += dtbs dtbs_install dt_binding_check
- dtbs dtbs_check: include/config/kernel.release scripts_dtc
- $(Q)$(MAKE) $(build)=$(dtstree)
--- /dev/null
+From 3d9d9ae68a1fb5451d12b46b65289e67cca2a340 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 13 Sep 2019 17:19:33 +0100
+Subject: [PATCH] staging:bcm2835-codec: Add support for
+ ENUM_FRAMESIZES
+
+Required for compliance testing for the encoder.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++--
+ 1 file changed, 44 insertions(+), 4 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo
+ return &dev->supported_fmts[capture ? 1 : 0].list[0];
+ }
+
+-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
+- struct bcm2835_codec_dev *dev,
+- bool capture)
++static
++struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt,
++ struct bcm2835_codec_dev *dev,
++ bool capture)
+ {
+ struct bcm2835_codec_fmt *fmt;
+ unsigned int k;
+@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo
+
+ for (k = 0; k < fmts->num_entries; k++) {
+ fmt = &fmts->list[k];
+- if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
++ if (fmt->fourcc == pix_fmt)
+ break;
+ }
+ if (k == fmts->num_entries)
+@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo
+ return &fmts->list[k];
+ }
+
++static inline
++struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
++ struct bcm2835_codec_dev *dev,
++ bool capture)
++{
++ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture);
++}
++
+ static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
+ {
+ return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
+@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil
+ return 0;
+ }
+
++static int vidioc_enum_framesizes(struct file *file, void *fh,
++ struct v4l2_frmsizeenum *fsize)
++{
++ struct bcm2835_codec_fmt *fmt;
++
++ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev,
++ true);
++ if (!fmt)
++ fmt = find_format_pix_fmt(fsize->pixel_format,
++ file2ctx(file)->dev,
++ false);
++
++ if (!fmt)
++ return -EINVAL;
++
++ if (fsize->index)
++ return -EINVAL;
++
++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
++
++ fsize->stepwise.min_width = MIN_W;
++ fsize->stepwise.max_width = MAX_W;
++ fsize->stepwise.step_width = 1;
++ fsize->stepwise.min_height = MIN_H;
++ fsize->stepwise.max_height = MAX_H;
++ fsize->stepwise.step_height = 1;
++
++ return 0;
++}
++
+ static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+
+@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28
+ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
+ .vidioc_encoder_cmd = vidioc_encoder_cmd,
+ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
++ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+ };
+
+ static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
+++ /dev/null
-From afde0ffa449eef528deb2fe455a512acd0569be4 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 25 Sep 2019 09:49:58 +0100
-Subject: [PATCH] dma-direct: Temporary DMA fix on arm64
-
-See: https://github.com/raspberrypi/linux/issues/3251
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- kernel/dma/direct.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/kernel/dma/direct.c
-+++ b/kernel/dma/direct.c
-@@ -397,7 +397,7 @@ int dma_direct_supported(struct device *
- if (IS_ENABLED(CONFIG_ZONE_DMA))
- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS);
- else
-- min_mask = DMA_BIT_MASK(32);
-+ min_mask = DMA_BIT_MASK(30);
-
- min_mask = min_t(u64, min_mask, (max_pfn - 1) << PAGE_SHIFT);
-
--- /dev/null
+From 0ff5cd805e7db4003ad5a0d783b4d029b23b7ece Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 13 Sep 2019 17:22:08 +0100
+Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on
+ G_PARM
+
+The output queue buffer type is now OUTPUT_MPLANE.
+
+Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi
+ {
+ struct bcm2835_codec_ctx *ctx = file2ctx(file);
+
+- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+++ /dev/null
-From 7a226e4533daa54a2ca625005b06ddeffe5de994 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Thu, 19 Sep 2019 20:45:30 +0200
-Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711
- compatible
-
-After the decision to use bcm2711 compatible for upstream, we should
-switch all accepted compatibles to bcm2711. So we can boot with
-one DTB the down- and the upstream kernel.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/mach-bcm/board_bcm2835.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -109,7 +109,7 @@ static const char * const bcm2835_compat
- #ifdef CONFIG_ARCH_MULTI_V7
- "brcm,bcm2836",
- "brcm,bcm2837",
-- "brcm,bcm2838",
-+ "brcm,bcm2711",
- #endif
- NULL
- };
--- /dev/null
+From 6680d139ee23cf655c0aa43581604a7c5de31803 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 13 Sep 2019 17:23:26 +0100
+Subject: [PATCH] staging: bcm2835-codec: Set default and error check
+ timeperframe
+
+G_PARM default was invalid as 0/0, and the driver didn't check
+the value set in S_PARM wasn't 0/0.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
++ if (!parm->parm.output.timeperframe.denominator ||
++ !parm->parm.output.timeperframe.numerator)
++ return -EINVAL;
++
+ ctx->framerate_num =
+ parm->parm.output.timeperframe.denominator;
+ ctx->framerate_denom =
+@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->bitrate = 10 * 1000 * 1000;
+
++ ctx->framerate_num = 30;
++ ctx->framerate_denom = 1;
++
+ /* Initialise V4L2 contexts */
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+++ /dev/null
-From cf658ebc86b3e22c0b77e136fbbf19b580c7c256 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Sun, 21 Jul 2019 16:01:36 +0200
-Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up
- functionality
-
-commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream.
-
-The BCM2711 has a new way of selecting the pull-up/pull-down setting
-for a GPIO pin. The registers used for the BCM2835, GP_PUD and
-GP_PUDCLKn0, are no longer connected. A new set of registers,
-GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add
-a new compatible string "brcm,bcm2711-gpio" and the kernel
-driver will use it to select which method is used to select
-pull-up/pull-down.
-
-This patch based on a patch by Al Cooper which was intended for the
-BCM7211. This is a bugfixed and improved version.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
-Acked-by: Eric Anholt <eric@anholt.net>
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -1168,6 +1168,12 @@ static int bcm2835_pinctrl_probe(struct
- (const struct pinconf_ops *)match->data;
- }
-
-+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
-+ if (match) {
-+ bcm2835_pinctrl_desc.confops =
-+ (const struct pinconf_ops *)match->data;
-+ }
-+
- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
- if (IS_ERR(pc->pctl_dev)) {
- gpiochip_remove(&pc->gpio_chip);
--- /dev/null
+From 0c941589b9bfb07cd31c792b445e630817e956d1 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Mon, 7 Oct 2019 14:02:57 +0100
+Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in
+ dma_buf_get/dma_buf_put
+
+When represented with a dmabuf buffer that had previously been
+imported, there was a call to dma_buf_get without a matching
+dma_buf_put. This left dmabufs in limbo after all users had
+supposedly released them.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str
+ }
+
+ buf->mmal.dma_buf = dma_buf;
++ } else {
++ /* We already have a reference count on the dmabuf, so
++ * release the one we acquired above.
++ */
++ dma_buf_put(dma_buf);
+ }
+ ret = 0;
+ break;
--- /dev/null
+From b92ed4ca0f9be3c8cc1a21dbbef346338d336329 Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Wed, 16 Oct 2019 14:49:23 +0100
+Subject: [PATCH] drm:vc4 Added calls for firmware display
+ blank/unblank
+
+Requires new display power mailbox call to be present.
+
+Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
+ 2 files changed, 27 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -94,6 +94,12 @@ struct mailbox_blank_display {
+ u32 blank;
+ };
+
++struct mailbox_display_pwr {
++ struct rpi_firmware_property_tag_header tag1;
++ u32 display;
++ u32 state;
++};
++
+ struct mailbox_get_edid {
+ struct rpi_firmware_property_tag_header tag1;
+ u32 block;
+@@ -274,6 +280,8 @@ to_vc4_crtc_state(struct drm_crtc_state
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
++ bool rgb_range_selectable;
++ int display_num;
+ };
+
+ static inline struct vc4_fkms_encoder *
+@@ -1637,13 +1645,29 @@ static const struct drm_encoder_funcs vc
+ .destroy = vc4_fkms_encoder_destroy,
+ };
+
++static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
++{
++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
++ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
++
++ struct mailbox_display_pwr pwr = {
++ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
++ .display = vc4_encoder->display_num,
++ .state = power ? 1 : 0,
++ };
++
++ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
++}
++
+ static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
+ {
++ vc4_fkms_display_power(encoder, true);
+ DRM_DEBUG_KMS("Encoder_enable\n");
+ }
+
+ static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
+ {
++ vc4_fkms_display_power(encoder, false);
+ DRM_DEBUG_KMS("Encoder_disable\n");
+ }
+
+@@ -1719,6 +1743,8 @@ static int vc4_fkms_create_screen(struct
+ if (!vc4_encoder)
+ return -ENOMEM;
+ vc4_crtc->encoder = &vc4_encoder->base;
++
++ vc4_encoder->display_num = display_ref;
+ vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
+
+ drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -153,7 +153,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
+ RPI_FIRMWARE_SET_TIMING = 0x00048017,
+ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
+-
++ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+ };
+++ /dev/null
-From a822f97a094991b08a50352355b0a376086b46c4 Mon Sep 17 00:00:00 2001
-From: Matteo Croce <mcroce@redhat.com>
-Date: Sun, 6 Oct 2019 03:23:15 +0200
-Subject: [PATCH] vchiq_2835_arm: suppress warning
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Suppress the following warning by casting the pointer to and uintptr_t
-before void*:
-
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c: In function ‘vchiq_prepare_bulk_data’:
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c:260:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
- bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
- ^
-
-Signed-off-by: Matteo Croce <mcroce@redhat.com>
----
- .../staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
-@@ -255,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul
- if (!pagelistinfo)
- return VCHIQ_ERROR;
-
-- bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
-+ bulk->data = (void *)(uintptr_t)VC_SAFE(pagelistinfo->dma_addr);
-
- /*
- * Store the pagelistinfo address in remote_data,
+++ /dev/null
-From 95709d5c58c57f31a70e96fe9ebb8d34c046f877 Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Tue, 24 Sep 2019 18:26:55 +0100
-Subject: [PATCH] Rename HDMI ALSA device names, check for enable state
-
-HDMI Alsa devices renamed to match names used by DRM, to
-HDMI 1 and HDMI 2
-
-Check for which HDMI devices are connected and only create
-devices for those that are present.
-
-The rename of the devices might cause some backwards compatibility
-issues, but since this particular part of the driver needs to be
-specifically enabled, I suspect the number of people who will see
-the problem will be very small.
-
-Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
----
- .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++--
- 1 file changed, 63 insertions(+), 7 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
-@@ -9,8 +9,9 @@
- #include <linux/of.h>
-
- #include "bcm2835.h"
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-
--static bool enable_hdmi;
-+static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
- static bool enable_headphones;
- static bool enable_compat_alsa = true;
-
-@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
- },
-- .shortname = "bcm2835 HDMI",
-- .longname = "bcm2835 HDMI",
-+ .shortname = "bcm2835 HDMI 1",
-+ .longname = "bcm2835 HDMI 1",
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28
- .name = "bcm2835_hdmi",
- .owner = THIS_MODULE,
- },
-- .shortname = "bcm2835 HDMI 1",
-- .longname = "bcm2835 HDMI 1",
-+ .shortname = "bcm2835 HDMI 2",
-+ .longname = "bcm2835 HDMI 2",
- .minchannels = 1,
- .newpcm = bcm2835_audio_simple_newpcm,
- .newctl = snd_bcm2835_new_hdmi_ctl,
-@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil
- },
- {
- .audio_driver = &bcm2835_audio_hdmi0,
-- .is_enabled = &enable_hdmi,
-+ .is_enabled = &enable_hdmi0,
- },
- {
- .audio_driver = &bcm2835_audio_hdmi1,
-- .is_enabled = &enable_hdmi,
-+ .is_enabled = &enable_hdmi1,
- },
- {
- .audio_driver = &bcm2835_audio_headphones,
-@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct
- return 0;
- }
-
-+static void set_hdmi_enables(struct device *dev)
-+{
-+ struct device_node *firmware_node;
-+ struct rpi_firmware *firmware;
-+ u32 num_displays, i, display_id;
-+ int ret;
-+
-+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
-+ firmware = rpi_firmware_get(firmware_node);
-+
-+ if (!firmware)
-+ return;
-+
-+ of_node_put(firmware_node);
-+
-+ ret = rpi_firmware_property(firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
-+ &num_displays, sizeof(u32));
-+
-+ if (ret)
-+ return;
-+
-+ for (i = 0; i < num_displays; i++) {
-+ display_id = i;
-+ ret = rpi_firmware_property(firmware,
-+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
-+ &display_id, sizeof(display_id));
-+ if (!ret) {
-+ if (display_id == 2)
-+ enable_hdmi0 = true;
-+ if (display_id == 7)
-+ enable_hdmi1 = true;
-+ }
-+ }
-+
-+ if (!enable_hdmi0 && enable_hdmi1) {
-+ /* Swap them over and reassign route. This means
-+ * that if we only have one connected, it is always named
-+ * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
-+ * This should match with the naming of HDMI ports in DRM
-+ */
-+ enable_hdmi0 = true;
-+ enable_hdmi1 = false;
-+ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
-+ }
-+}
-+
- static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct
- numchans);
- }
-
-+ if (!enable_compat_alsa) {
-+ set_hdmi_enables(dev);
-+ // In this mode, always enable analog output
-+ enable_headphones = true;
-+ } else {
-+ enable_hdmi0 = enable_hdmi;
-+ }
-+
- err = bcm2835_devm_add_vchi_ctx(dev);
- if (err)
- return err;
--- /dev/null
+From b1d33d1e5a44afd2025c5a44a85dc2fab00ec6a7 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 5 Nov 2019 11:28:19 +0000
+Subject: [PATCH] Revert "pinctrl: bcm2835: Pass irqchip when adding
+ gpiochip"
+
+This reverts commit 73345a18d464b1b945b29f54f630ace6873344e2.
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 55 +++++++++++++++------------
+ 1 file changed, 30 insertions(+), 25 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -78,6 +78,7 @@
+ struct bcm2835_pinctrl {
+ struct device *dev;
+ void __iomem *base;
++ int irq[BCM2835_NUM_IRQS];
+
+ /* note: locking assumes each bank will have its own unsigned long */
+ unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
+@@ -381,14 +382,14 @@ static void bcm2835_gpio_irq_handler(str
+ int group;
+ int i;
+
+- for (i = 0; i < BCM2835_NUM_IRQS; i++) {
+- if (chip->irq.parents[i] == irq) {
++ for (i = 0; i < ARRAY_SIZE(pc->irq); i++) {
++ if (pc->irq[i] == irq) {
+ group = i;
+ break;
+ }
+ }
+ /* This should not happen, every IRQ has a bank */
+- if (i == BCM2835_NUM_IRQS)
++ if (i == ARRAY_SIZE(pc->irq))
+ BUG();
+
+ chained_irq_enter(host_chip, desc);
+@@ -1086,7 +1087,6 @@ static int bcm2835_pinctrl_probe(struct
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct bcm2835_pinctrl *pc;
+- struct gpio_irq_chip *girq;
+ struct resource iomem;
+ int err, i;
+ const struct of_device_id *match;
+@@ -1135,33 +1135,38 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
+- girq = &pc->gpio_chip.irq;
+- girq->chip = &bcm2835_gpio_irq_chip;
+- girq->parent_handler = bcm2835_gpio_irq_handler;
+- girq->num_parents = BCM2835_NUM_IRQS;
+- girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
+- sizeof(*girq->parents),
+- GFP_KERNEL);
+- if (!girq->parents)
+- return -ENOMEM;
+- /*
+- * Use the same handler for all groups: this is necessary
+- * since we use one gpiochip to cover all lines - the
+- * irq handler then needs to figure out which group and
+- * bank that was firing the IRQ and look up the per-group
+- * and bank data.
+- */
+- for (i = 0; i < BCM2835_NUM_IRQS; i++)
+- girq->parents[i] = irq_of_parse_and_map(np, i);
+- girq->default_type = IRQ_TYPE_NONE;
+- girq->handler = handle_level_irq;
+-
+ err = gpiochip_add_data(&pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
+ return err;
+ }
+
++ err = gpiochip_irqchip_add(&pc->gpio_chip, &bcm2835_gpio_irq_chip,
++ 0, handle_level_irq, IRQ_TYPE_NONE);
++ if (err) {
++ dev_info(dev, "could not add irqchip\n");
++ return err;
++ }
++
++ for (i = 0; i < BCM2835_NUM_IRQS; i++) {
++ pc->irq[i] = irq_of_parse_and_map(np, i);
++
++ if (pc->irq[i] == 0)
++ continue;
++
++ /*
++ * Use the same handler for all groups: this is necessary
++ * since we use one gpiochip to cover all lines - the
++ * irq handler then needs to figure out which group and
++ * bank that was firing the IRQ and look up the per-group
++ * and bank data.
++ */
++ gpiochip_set_chained_irqchip(&pc->gpio_chip,
++ &bcm2835_gpio_irq_chip,
++ pc->irq[i],
++ bcm2835_gpio_irq_handler);
++ }
++
+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+ if (match) {
+ bcm2835_pinctrl_desc.confops =
--- /dev/null
+From e2d8a52d3ade83f5c114b1edba601ebcf2c39517 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 11 Nov 2019 14:01:41 +0000
+Subject: [PATCH] drm/v3d: Don't clear MMU control bits on exception
+
+MMU exception conditions are reported in the V3D_MMU_CTRL register as
+write-1-to-clear (W1C) bits. The MMU interrupt handling code clears any
+exceptions, but does so by masking out any other bits and writing the
+result back. There are some important control bits in that register,
+including MMU_ENABLE, so a safer approach is to simply write back the
+value just read unaltered.
+
+This patch doesn't remove the cause of the apparent PTE errors, but it
+does reduce the impact to just an error in the kernel log.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_irq.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -178,10 +178,7 @@ v3d_hub_irq(int irq, void *arg)
+ };
+ const char *client = "?";
+
+- V3D_WRITE(V3D_MMU_CTL,
+- V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED |
+- V3D_MMU_CTL_PT_INVALID |
+- V3D_MMU_CTL_WRITE_VIOLATION));
++ V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
+
+ if (v3d->ver >= 41) {
+ axi_id = axi_id >> 5;
+++ /dev/null
-From 2340a88a493d750dc3fcfa48de880fc4b8e479d2 Mon Sep 17 00:00:00 2001
-From: Floris Bos <bos@je-eigen-domein.nl>
-Date: Fri, 4 Oct 2019 16:41:30 +0200
-Subject: [PATCH] pcie-brcmstb-bounce64.c: dev_err() -> dev_info() for
- info messages
-
-"dmabounce: initialised" is not an error, so do not log it as such.
-Prevents screen polution on OS with "quiet" as kernel parameter.
-
-Closes #3266
----
- drivers/pci/controller/pcie-brcmstb-bounce64.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -517,7 +517,7 @@ int brcm_pcie_bounce_init(struct device
-
- g_dmabounce_device_info = device_info;
-
-- dev_err(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
-+ dev_info(dev, "dmabounce: initialised - %ld kB, threshold %pad\n",
- buffer_size / 1024, &threshold);
-
- return 0;
--- /dev/null
+From f1f228c84864bad0bb07de1c72ceafaec035ac15 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 11 Nov 2019 20:18:08 +0000
+Subject: [PATCH] drm/v3d: Suppress all but the first MMU error
+
+The v3d driver currently encounters a lot of MMU PTE exceptions, so
+only log the first to avoid swamping the kernel log.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_irq.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -177,6 +177,7 @@ v3d_hub_irq(int irq, void *arg)
+ "GMP",
+ };
+ const char *client = "?";
++ static int logged_error;
+
+ V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
+
+@@ -186,6 +187,7 @@ v3d_hub_irq(int irq, void *arg)
+ client = v3d41_axi_ids[axi_id];
+ }
+
++ if (!logged_error)
+ dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
+ client, axi_id, (long long)vio_addr,
+ ((intsts & V3D_HUB_INT_MMU_WRV) ?
+@@ -194,6 +196,7 @@ v3d_hub_irq(int irq, void *arg)
+ ", pte invalid" : ""),
+ ((intsts & V3D_HUB_INT_MMU_CAP) ?
+ ", cap exceeded" : ""));
++ logged_error = 1;
+ status = IRQ_HANDLED;
+ }
+
+++ /dev/null
-From fb76c3ded8c771e8b9287d62b5e13666037f890e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 17 Sep 2019 18:28:17 +0100
-Subject: [PATCH] drm/vc4: Add support for YUV color encodings and
- ranges
-
-The BT601/BT709 color encoding and limited vs full
-range properties were not being exposed, defaulting
-always to BT601 limited range.
-
-Expose the parameters and set the registers appropriately.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++--
- drivers/gpu/drm/vc4/vc4_regs.h | 3 ++
- 2 files changed, 72 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_plane.c
-+++ b/drivers/gpu/drm/vc4/vc4_plane.c
-@@ -577,6 +577,53 @@ static int vc4_plane_allocate_lbm(struct
- return 0;
- }
-
-+/* The colorspace conversion matrices are held in 3 entries in the dlist.
-+ * Create an array of them, with entries for each full and limited mode, and
-+ * each supported colorspace.
-+ */
-+#define VC4_LIMITED_RANGE 0
-+#define VC4_FULL_RANGE 1
-+
-+static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
-+ {
-+ /* Limited range */
-+ {
-+ /* BT601 */
-+ SCALER_CSC0_ITR_R_601_5,
-+ SCALER_CSC1_ITR_R_601_5,
-+ SCALER_CSC2_ITR_R_601_5,
-+ }, {
-+ /* BT709 */
-+ SCALER_CSC0_ITR_R_709_3,
-+ SCALER_CSC1_ITR_R_709_3,
-+ SCALER_CSC2_ITR_R_709_3,
-+ }, {
-+ /* BT2020. Not supported yet - copy 601 */
-+ SCALER_CSC0_ITR_R_601_5,
-+ SCALER_CSC1_ITR_R_601_5,
-+ SCALER_CSC2_ITR_R_601_5,
-+ }
-+ }, {
-+ /* Full range */
-+ {
-+ /* JFIF */
-+ SCALER_CSC0_JPEG_JFIF,
-+ SCALER_CSC1_JPEG_JFIF,
-+ SCALER_CSC2_JPEG_JFIF,
-+ }, {
-+ /* BT709 */
-+ SCALER_CSC0_ITR_R_709_3_FR,
-+ SCALER_CSC1_ITR_R_709_3_FR,
-+ SCALER_CSC2_ITR_R_709_3_FR,
-+ }, {
-+ /* BT2020. Not supported yet - copy JFIF */
-+ SCALER_CSC0_JPEG_JFIF,
-+ SCALER_CSC1_JPEG_JFIF,
-+ SCALER_CSC2_JPEG_JFIF,
-+ }
-+ }
-+};
-+
- /* Writes out a full display list for an active plane to the plane's
- * private dlist state.
- */
-@@ -856,9 +903,20 @@ static int vc4_plane_mode_set(struct drm
-
- /* Colorspace conversion words */
- if (vc4_state->is_yuv) {
-- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
-- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
-- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
-+ enum drm_color_encoding color_encoding = state->color_encoding;
-+ enum drm_color_range color_range = state->color_range;
-+ const u32 *ccm;
-+
-+ if (color_encoding >= DRM_COLOR_ENCODING_MAX)
-+ color_encoding = DRM_COLOR_YCBCR_BT601;
-+ if (color_range >= DRM_COLOR_RANGE_MAX)
-+ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
-+
-+ ccm = colorspace_coeffs[color_range][color_encoding];
-+
-+ vc4_dlist_write(vc4_state, ccm[0]);
-+ vc4_dlist_write(vc4_state, ccm[1]);
-+ vc4_dlist_write(vc4_state, ccm[2]);
- }
-
- vc4_state->lbm_offset = 0;
-@@ -1265,5 +1323,13 @@ struct drm_plane *vc4_plane_init(struct
- DRM_MODE_REFLECT_X |
- DRM_MODE_REFLECT_Y);
-
-+ drm_plane_create_color_properties(plane,
-+ BIT(DRM_COLOR_YCBCR_BT601) |
-+ BIT(DRM_COLOR_YCBCR_BT709),
-+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-+ DRM_COLOR_YCBCR_BT709,
-+ DRM_COLOR_YCBCR_LIMITED_RANGE);
-+
- return plane;
- }
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -950,6 +950,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC0_ITR_R_601_5 0x00f00000
- #define SCALER_CSC0_ITR_R_709_3 0x00f00000
- #define SCALER_CSC0_JPEG_JFIF 0x00000000
-+#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
-
- /* S2.8 contribution of Cb to Green */
- #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
-@@ -966,6 +967,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC1_ITR_R_601_5 0xe73304a8
- #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
- #define SCALER_CSC1_JPEG_JFIF 0xea34a400
-+#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
-
- /* S2.8 contribution of Cb to Red */
- #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
-@@ -979,6 +981,7 @@ enum hvs_pixel_format {
- #define SCALER_CSC2_ITR_R_601_5 0x00066204
- #define SCALER_CSC2_ITR_R_709_3 0x00072a1c
- #define SCALER_CSC2_JPEG_JFIF 0x000599c5
-+#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
-
- #define SCALER_TPZ0_VERT_RECALC BIT(31)
- #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
--- /dev/null
+From 9b2d99c0959e693e4dcea5f454bf84f229ca3d27 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 12 Nov 2019 16:41:21 +0000
+Subject: [PATCH] drm/v3d: Plug dma_fence leak
+
+The irq_fence and done_fence are given a reference that is never
+released. The necessary dma_fence_put()s seem to have been
+deleted in error in an earlier commit.
+
+Fixes: 0b73676836b2 ("drm/v3d: Clock V3D down when not in use.")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -410,6 +410,9 @@ v3d_job_free(struct kref *ref)
+ }
+ xa_destroy(&job->deps);
+
++ dma_fence_put(job->irq_fence);
++ dma_fence_put(job->done_fence);
++
+ v3d_clock_up_put(v3d);
+
+ kfree(job);
+++ /dev/null
-From 23ed834712dfc0d25451f16b46ae9c19abb675b5 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Wed, 18 Sep 2019 15:49:13 +0100
-Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in
- fkms
-
-One bit within DRM_MODE_ROTATE_MASK will always be set to
-determine the base rotation 0/90/180/270, and then REFLECT_X
-and REFLECT_Y are on top.
-
-Correct the handling which was assuming that REFLECT_[X|Y]
-was instead of ROTATE_x.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++----------------
- 1 file changed, 14 insertions(+), 23 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -82,11 +82,6 @@ struct set_plane {
- #define TRANSFORM_FLIP_HRIZ BIT(16)
- #define TRANSFORM_FLIP_VERT BIT(17)
-
--#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \
-- DRM_MODE_ROTATE_180 | \
-- DRM_MODE_REFLECT_X | \
-- DRM_MODE_REFLECT_Y)
--
- struct mailbox_set_plane {
- struct rpi_firmware_property_tag_header tag;
- struct set_plane plane;
-@@ -525,7 +520,7 @@ static int vc4_plane_to_mb(struct drm_pl
- const struct vc_image_format *vc_fmt =
- vc4_get_vc_image_fmt(drm_fmt->format);
- int num_planes = fb->format->num_planes;
-- unsigned int rotation = SUPPORTED_ROTATIONS;
-+ unsigned int rotation;
-
- mb->plane.vc_image_type = vc_fmt->vc_image;
- mb->plane.width = fb->width;
-@@ -546,23 +541,16 @@ static int vc4_plane_to_mb(struct drm_pl
- mb->plane.is_vu = vc_fmt->is_vu;
- mb->plane.planes[0] = bo->paddr + fb->offsets[0];
-
-- rotation = drm_rotation_simplify(state->rotation, rotation);
--
-- switch (rotation) {
-- default:
-- case DRM_MODE_ROTATE_0:
-- mb->plane.transform = TRANSFORM_NO_ROTATE;
-- break;
-- case DRM_MODE_ROTATE_180:
-- mb->plane.transform = TRANSFORM_ROTATE_180;
-- break;
-- case DRM_MODE_REFLECT_X:
-- mb->plane.transform = TRANSFORM_FLIP_HRIZ;
-- break;
-- case DRM_MODE_REFLECT_Y:
-- mb->plane.transform = TRANSFORM_FLIP_VERT;
-- break;
-- }
-+ rotation = drm_rotation_simplify(state->rotation,
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
-+
-+ mb->plane.transform = TRANSFORM_NO_ROTATE;
-+ if (rotation & DRM_MODE_REFLECT_X)
-+ mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
-+ if (rotation & DRM_MODE_REFLECT_Y)
-+ mb->plane.transform |= TRANSFORM_FLIP_VERT;
-
- vc4_fkms_margins_adj(state, &mb->plane);
-
-@@ -803,7 +791,10 @@ static struct drm_plane *vc4_fkms_plane_
-
- drm_plane_create_alpha_property(plane);
- drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-- SUPPORTED_ROTATIONS);
-+ DRM_MODE_ROTATE_0 |
-+ DRM_MODE_ROTATE_180 |
-+ DRM_MODE_REFLECT_X |
-+ DRM_MODE_REFLECT_Y);
- drm_plane_create_color_properties(plane,
- BIT(DRM_COLOR_YCBCR_BT601) |
- BIT(DRM_COLOR_YCBCR_BT709) |
+++ /dev/null
-From 5db0abcd74512cf7013c2ea87d347cd158726be3 Mon Sep 17 00:00:00 2001
-From: Markus Proeller <markus.proeller@pieye.org>
-Date: Thu, 10 Oct 2019 19:12:08 +0200
-Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125
- sensor
-
-Adds a binding for the Infineon IRS1125 time-of-flight depth
-sensor.
-
-Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
----
- .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++
- 1 file changed, 48 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt
-@@ -0,0 +1,48 @@
-+* Infineon irs1125 time of flight sensor
-+
-+The Infineon irs1125 is a time of flight digital image sensor with
-+an active array size of 352H x 286V. It is programmable through I2C
-+interface. The I2C address defaults to 0x3D, but can be reconfigured
-+to address 0x3C or 0x41 via I2C commands. Image data is sent through
-+MIPI CSI-2, which is configured as either 1 or 2 data lanes.
-+
-+Required Properties:
-+- compatible: value should be "infineon,irs1125" for irs1125 sensor
-+- reg: I2C bus address of the device
-+- clocks: reference to the xclk input clock.
-+- pwdn-gpios: reference to the GPIO connected to the reset pin.
-+ This is an active low signal to the iirs1125.
-+
-+The irs1125 device node should contain one 'port' child node with
-+an 'endpoint' subnode. For further reading on port node refer to
-+Documentation/devicetree/bindings/media/video-interfaces.txt.
-+
-+Endpoint node required properties for CSI-2 connection are:
-+- remote-endpoint: a phandle to the bus receiver's endpoint node.
-+- clock-lanes: should be set to <0> (clock lane on hardware lane 0)
-+- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2
-+ supported)
-+
-+Example:
-+ sensor@10 {
-+ compatible = "infineon,irs1125";
-+ reg = <0x3D>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ clocks = <&irs1125_clk>;
-+ pwdn-gpios = <&gpio 5 0>;
-+
-+ irs1125_clk: camera-clk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <26000000>;
-+ };
-+
-+ port {
-+ sensor_out: endpoint {
-+ remote-endpoint = <&csiss_in>;
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ };
-+ };
-+ };
--- /dev/null
+From efe24599e8996ef5844e73feae1ca1b27d8740ab Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 6 Nov 2019 13:57:48 +0000
+Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform
+ driver
+
+Following the same pattern as bcm2835-camera and bcm2835-audio,
+register the vcsm-cma driver as a platform driver
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -140,6 +140,7 @@ static struct class *vchiq_class;
+ static DEFINE_SPINLOCK(msg_queue_spinlock);
+ static struct platform_device *bcm2835_camera;
+ static struct platform_device *bcm2835_audio;
++static struct platform_device *vcsm_cma;
+
+ static struct vchiq_drvdata bcm2835_drvdata = {
+ .cache_line_size = 32,
+@@ -3250,6 +3251,7 @@ static int vchiq_probe(struct platform_d
+ VCHIQ_VERSION, VCHIQ_VERSION_MIN,
+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
+
++ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
+ bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
+
+@@ -3266,6 +3268,7 @@ static int vchiq_remove(struct platform_
+ {
+ if (!IS_ERR(bcm2835_camera))
+ platform_device_unregister(bcm2835_camera);
++ platform_device_unregister(vcsm_cma);
+ vchiq_debugfs_deinit();
+ device_destroy(vchiq_class, vchiq_devid);
+ cdev_del(&vchiq_cdev);
+++ /dev/null
-From 54e4ff9b3cae743ca90b86a8fef72810d431e143 Mon Sep 17 00:00:00 2001
-From: Markus Proeller <markus.proeller@pieye.org>
-Date: Thu, 10 Oct 2019 19:12:36 +0200
-Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125
- depth sensor
-
-The Infineon IRS1125 is a time of flight depth sensor that
-has a CSI-2 interface.
-
-Add a V4L2 subdevice driver for this device.
-
-Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
----
- drivers/media/i2c/Kconfig | 12 +
- drivers/media/i2c/Makefile | 1 +
- drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++
- drivers/media/i2c/irs1125.h | 61 ++
- 4 files changed, 1186 insertions(+)
- create mode 100644 drivers/media/i2c/irs1125.c
- create mode 100644 drivers/media/i2c/irs1125.h
-
---- a/drivers/media/i2c/Kconfig
-+++ b/drivers/media/i2c/Kconfig
-@@ -850,6 +850,18 @@ config VIDEO_OV13858
- This is a Video4Linux2 sensor driver for the OmniVision
- OV13858 camera.
-
-+config VIDEO_IRS1125
-+ tristate "Infineon IRS1125 sensor support"
-+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-+ depends on MEDIA_CAMERA_SUPPORT
-+ select V4L2_FWNODE
-+ help
-+ This is a Video4Linux2 sensor-level driver for the Infineon
-+ IRS1125 camera.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called irs1125.
-+
- config VIDEO_VS6624
- tristate "ST VS6624 sensor support"
- depends on VIDEO_V4L2 && I2C
---- a/drivers/media/i2c/Makefile
-+++ b/drivers/media/i2c/Makefile
-@@ -82,6 +82,7 @@ obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
- obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
- obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
- obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
-+obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o
- obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
- obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
- obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
---- /dev/null
-+++ b/drivers/media/i2c/irs1125.c
-@@ -0,0 +1,1112 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
-+ * Copyright (C) 2018, pieye GmbH
-+ *
-+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
-+ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
-+ *
-+ * DT / fwnode changes, and GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#include "irs1125.h"
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of_graph.h>
-+#include <linux/slab.h>
-+#include <linux/videodev2.h>
-+#include <linux/firmware.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-image-sizes.h>
-+#include <media/v4l2-mediabus.h>
-+#include <media/v4l2-ctrls.h>
-+
-+#define CHECK_BIT(val, pos) ((val) & BIT(pos))
-+
-+#define SENSOR_NAME "irs1125"
-+
-+#define RESET_ACTIVE_DELAY_MS 20
-+
-+#define IRS1125_ALTERNATE_FW "irs1125_af.bin"
-+
-+#define IRS1125_REG_CSICFG 0xA882
-+#define IRS1125_REG_DESIGN_STEP 0xB0AD
-+#define IRS1125_REG_EFUSEVAL2 0xB09F
-+#define IRS1125_REG_EFUSEVAL3 0xB0A0
-+#define IRS1125_REG_EFUSEVAL4 0xB0A1
-+#define IRS1125_REG_DMEM_SHADOW 0xC320
-+
-+#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12
-+
-+#define IRS1125_ROW_START_DEF 0
-+#define IRS1125_COLUMN_START_DEF 0
-+#define IRS1125_WINDOW_HEIGHT_DEF 288
-+#define IRS1125_WINDOW_WIDTH_DEF 352
-+
-+struct regval_list {
-+ u16 addr;
-+ u16 data;
-+};
-+
-+struct irs1125 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ /* the parsed DT endpoint info */
-+ struct v4l2_fwnode_endpoint ep;
-+
-+ struct clk *xclk;
-+ struct v4l2_ctrl_handler ctrl_handler;
-+
-+ /* To serialize asynchronus callbacks */
-+ struct mutex lock;
-+
-+ /* image data layout */
-+ unsigned int num_seq;
-+
-+ /* reset pin */
-+ struct gpio_desc *reset;
-+
-+ /* V4l2 Controls to grab */
-+ struct v4l2_ctrl *ctrl_modplls;
-+ struct v4l2_ctrl *ctrl_numseq;
-+
-+ int power_count;
-+};
-+
-+static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct irs1125, sd);
-+}
-+
-+static struct regval_list irs1125_26MHz[] = {
-+ {0xB017, 0x0413},
-+ {0xB086, 0x3535},
-+ {0xB0AE, 0xEF02},
-+ {0xA000, 0x0004},
-+ {0xFFFF, 100},
-+
-+ {0xB062, 0x6383},
-+ {0xB063, 0x55A8},
-+ {0xB068, 0x7628},
-+ {0xB069, 0x03E2},
-+
-+ {0xFFFF, 100},
-+ {0xB05A, 0x01C5},
-+ {0xB05C, 0x0206},
-+ {0xB05D, 0x01C5},
-+ {0xB05F, 0x0206},
-+ {0xB016, 0x1335},
-+ {0xFFFF, 100},
-+ {0xA893, 0x8261},
-+ {0xA894, 0x89d8},
-+ {0xA895, 0x131d},
-+ {0xA896, 0x4251},
-+ {0xA897, 0x9D8A},
-+ {0xA898, 0x0BD8},
-+ {0xA899, 0x2245},
-+ {0xA89A, 0xAB9B},
-+ {0xA89B, 0x03B9},
-+ {0xA89C, 0x8041},
-+ {0xA89D, 0xE07E},
-+ {0xA89E, 0x0307},
-+ {0xFFFF, 100},
-+ {0xA88D, 0x0004},
-+ {0xA800, 0x0E68},
-+ {0xA801, 0x0000},
-+ {0xA802, 0x000C},
-+ {0xA803, 0x0000},
-+ {0xA804, 0x0E68},
-+ {0xA805, 0x0000},
-+ {0xA806, 0x0440},
-+ {0xA807, 0x0000},
-+ {0xA808, 0x0E68},
-+ {0xA809, 0x0000},
-+ {0xA80A, 0x0884},
-+ {0xA80B, 0x0000},
-+ {0xA80C, 0x0E68},
-+ {0xA80D, 0x0000},
-+ {0xA80E, 0x0CC8},
-+ {0xA80F, 0x0000},
-+ {0xA810, 0x0E68},
-+ {0xA811, 0x0000},
-+ {0xA812, 0x2000},
-+ {0xA813, 0x0000},
-+ {0xA882, 0x0081},
-+ {0xA88C, 0x403A},
-+ {0xA88F, 0x031E},
-+ {0xA892, 0x0351},
-+ {0x9813, 0x13FF},
-+ {0x981B, 0x7608},
-+
-+ {0xB008, 0x0000},
-+ {0xB015, 0x1513},
-+
-+ {0xFFFF, 100}
-+};
-+
-+static struct regval_list irs1125_seq_cfg[] = {
-+ {0xC3A0, 0x823D},
-+ {0xC3A1, 0xB13B},
-+ {0xC3A2, 0x0313},
-+ {0xC3A3, 0x4659},
-+ {0xC3A4, 0xC4EC},
-+ {0xC3A5, 0x03CE},
-+ {0xC3A6, 0x4259},
-+ {0xC3A7, 0xC4EC},
-+ {0xC3A8, 0x03CE},
-+ {0xC3A9, 0x8839},
-+ {0xC3AA, 0x89D8},
-+ {0xC3AB, 0x031D},
-+
-+ {0xC24C, 0x5529},
-+ {0xC24D, 0x0000},
-+ {0xC24E, 0x1200},
-+ {0xC24F, 0x6CB2},
-+ {0xC250, 0x0000},
-+ {0xC251, 0x5529},
-+ {0xC252, 0x42F4},
-+ {0xC253, 0xD1AF},
-+ {0xC254, 0x8A18},
-+ {0xC255, 0x0002},
-+ {0xC256, 0x5529},
-+ {0xC257, 0x6276},
-+ {0xC258, 0x11A7},
-+ {0xC259, 0xD907},
-+ {0xC25A, 0x0000},
-+ {0xC25B, 0x5529},
-+ {0xC25C, 0x07E0},
-+ {0xC25D, 0x7BFE},
-+ {0xC25E, 0x6402},
-+ {0xC25F, 0x0019},
-+
-+ {0xC3AC, 0x0007},
-+ {0xC3AD, 0xED88},
-+ {0xC320, 0x003E},
-+ {0xC321, 0x0000},
-+ {0xC322, 0x2000},
-+ {0xC323, 0x0000},
-+ {0xC324, 0x0271},
-+ {0xC325, 0x0000},
-+ {0xC326, 0x000C},
-+ {0xC327, 0x0000},
-+ {0xC328, 0x0271},
-+ {0xC329, 0x0000},
-+ {0xC32A, 0x0440},
-+ {0xC32B, 0x0000},
-+ {0xC32C, 0x0271},
-+ {0xC32D, 0x0000},
-+ {0xC32E, 0x0884},
-+ {0xC32F, 0x0000},
-+ {0xC330, 0x0271},
-+ {0xC331, 0x0000},
-+ {0xC332, 0x0CC8},
-+ {0xC333, 0x0000},
-+ {0xA88D, 0x0004},
-+
-+ {0xA890, 0x0000},
-+ {0xC219, 0x0002},
-+ {0xC21A, 0x0000},
-+ {0xC21B, 0x0000},
-+ {0xC21C, 0x00CD},
-+ {0xC21D, 0x0009},
-+ {0xC21E, 0x00CD},
-+ {0xC21F, 0x0009},
-+
-+ {0xA87C, 0x0000},
-+ {0xC032, 0x0001},
-+ {0xC034, 0x0000},
-+ {0xC035, 0x0001},
-+ {0xC039, 0x0000},
-+ {0xC401, 0x0002},
-+
-+ {0xFFFF, 1},
-+ {0xA87C, 0x0001}
-+};
-+
-+static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
-+{
-+ int ret;
-+ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff};
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = i2c_master_send(client, data, 4);
-+ if (ret < 0)
-+ dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
-+ __func__, reg);
-+
-+ return ret;
-+}
-+
-+static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val)
-+{
-+ int ret;
-+ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
-+ char rdval[2];
-+
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = i2c_master_send(client, data_w, 2);
-+ if (ret < 0) {
-+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ ret = i2c_master_recv(client, rdval, 2);
-+ if (ret < 0)
-+ dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
-+ __func__, reg);
-+
-+ *val = rdval[1] | (rdval[0] << 8);
-+
-+ return ret;
-+}
-+
-+static int irs1125_write_array(struct v4l2_subdev *sd,
-+ struct regval_list *regs, int array_size)
-+{
-+ int i, ret;
-+
-+ for (i = 0; i < array_size; i++) {
-+ if (regs[i].addr == 0xFFFF) {
-+ msleep(regs[i].data);
-+ } else {
-+ ret = irs1125_write(sd, regs[i].addr, regs[i].data);
-+ if (ret < 0)
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_stream_on(struct v4l2_subdev *sd)
-+{
-+ int ret;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1);
-+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1);
-+
-+ ret = irs1125_write(sd, 0xC400, 0x0001);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error enabling firmware: %d", ret);
-+ return ret;
-+ }
-+
-+ msleep(100);
-+
-+ return irs1125_write(sd, 0xA87C, 0x0001);
-+}
-+
-+static int irs1125_stream_off(struct v4l2_subdev *sd)
-+{
-+ int ret;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0);
-+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0);
-+
-+ ret = irs1125_write(sd, 0xA87C, 0x0000);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error disabling trigger: %d", ret);
-+ return ret;
-+ }
-+
-+ msleep(100);
-+
-+ return irs1125_write(sd, 0xC400, 0x0002);
-+}
-+
-+static int __sensor_init(struct v4l2_subdev *sd)
-+{
-+ unsigned int cnt, idx;
-+ int ret;
-+ u16 val;
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ struct irs1125 *irs1125 = to_state(sd);
-+ const struct firmware *fw;
-+ struct regval_list *reg_data;
-+
-+ cnt = 0;
-+ while (1) {
-+ ret = irs1125_read(sd, 0xC40F, &val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "read register 0xC40F failed\n");
-+ return ret;
-+ }
-+ if (CHECK_BIT(val, 14) == 0)
-+ break;
-+
-+ if (cnt >= 5) {
-+ dev_err(&client->dev, "timeout waiting for 0xC40F\n");
-+ return -EAGAIN;
-+ }
-+
-+ cnt++;
-+ }
-+
-+ ret = irs1125_write_array(sd, irs1125_26MHz,
-+ ARRAY_SIZE(irs1125_26MHz));
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write sensor default regs error\n");
-+ return ret;
-+ }
-+
-+ /* set CSI-2 number of data lanes */
-+ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) {
-+ val = 0x0001;
-+ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) {
-+ val = 0x0081;
-+ } else {
-+ dev_err(&client->dev, "invalid number of data lanes %d\n",
-+ irs1125->ep.bus.mipi_csi2.num_data_lanes);
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write sensor csi2 config error\n");
-+ return ret;
-+ }
-+
-+ /* request the firmware, this will block and timeout */
-+ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev);
-+ if (ret) {
-+ dev_err(&client->dev,
-+ "did not find the firmware file '%s' (status %d)\n",
-+ IRS1125_ALTERNATE_FW, ret);
-+ return ret;
-+ }
-+
-+ if (fw->size % 4) {
-+ dev_err(&client->dev, "firmware file '%s' invalid\n",
-+ IRS1125_ALTERNATE_FW);
-+ release_firmware(fw);
-+ return -EINVAL;
-+ }
-+
-+ for (idx = 0; idx < fw->size; idx += 4) {
-+ reg_data = (struct regval_list *)&fw->data[idx];
-+ ret = irs1125_write(sd, reg_data->addr, reg_data->data);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "firmware write error\n");
-+ release_firmware(fw);
-+ return ret;
-+ }
-+ }
-+ release_firmware(fw);
-+
-+ ret = irs1125_write_array(sd, irs1125_seq_cfg,
-+ ARRAY_SIZE(irs1125_seq_cfg));
-+ if (ret < 0) {
-+ dev_err(&client->dev, "write default sequence failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
-+{
-+ int ret = 0;
-+ struct irs1125 *irs1125 = to_state(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ mutex_lock(&irs1125->lock);
-+
-+ if (on && !irs1125->power_count) {
-+ gpiod_set_value_cansleep(irs1125->reset, 1);
-+ msleep(RESET_ACTIVE_DELAY_MS);
-+
-+ ret = clk_prepare_enable(irs1125->xclk);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "clk prepare enable failed\n");
-+ goto out;
-+ }
-+
-+ ret = __sensor_init(sd);
-+ if (ret < 0) {
-+ clk_disable_unprepare(irs1125->xclk);
-+ dev_err(&client->dev,
-+ "Camera not available, check Power\n");
-+ goto out;
-+ }
-+ } else if (!on && irs1125->power_count == 1) {
-+ gpiod_set_value_cansleep(irs1125->reset, 0);
-+ }
-+
-+ /* Update the power count. */
-+ irs1125->power_count += on ? 1 : -1;
-+ WARN_ON(irs1125->power_count < 0);
-+
-+out:
-+ mutex_unlock(&irs1125->lock);
-+
-+ return ret;
-+}
-+
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+static int irs1125_sensor_get_register(struct v4l2_subdev *sd,
-+ struct v4l2_dbg_register *reg)
-+{
-+ u16 val;
-+ int ret;
-+
-+ ret = irs1125_read(sd, reg->reg & 0xffff, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ reg->val = val;
-+ reg->size = 1;
-+
-+ return 0;
-+}
-+
-+static int irs1125_sensor_set_register(struct v4l2_subdev *sd,
-+ const struct v4l2_dbg_register *reg)
-+{
-+ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff);
-+}
-+#endif
-+
-+static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = {
-+ .s_power = irs1125_sensor_power,
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+ .g_register = irs1125_sensor_get_register,
-+ .s_register = irs1125_sensor_set_register,
-+#endif
-+};
-+
-+static int irs1125_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ if (enable)
-+ return irs1125_stream_on(sd);
-+ else
-+ return irs1125_stream_off(sd);
-+}
-+
-+static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = {
-+ .s_stream = irs1125_s_stream,
-+};
-+
-+static int irs1125_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->index > 0)
-+ return -EINVAL;
-+
-+ code->code = MEDIA_BUS_FMT_Y12_1X12;
-+
-+ return 0;
-+}
-+
-+static int irs1125_set_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_pad_config *cfg,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct v4l2_mbus_framefmt *fmt = &format->format;
-+ struct irs1125 *irs1125 = to_state(sd);
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ /* Only one format is supported, so return that */
-+ memset(fmt, 0, sizeof(*fmt));
-+ fmt->code = MEDIA_BUS_FMT_Y12_1X12;
-+ fmt->colorspace = V4L2_COLORSPACE_RAW;
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->width = IRS1125_WINDOW_WIDTH_DEF;
-+ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq;
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = {
-+ .enum_mbus_code = irs1125_enum_mbus_code,
-+ .set_fmt = irs1125_set_get_fmt,
-+ .get_fmt = irs1125_set_get_fmt,
-+};
-+
-+static const struct v4l2_subdev_ops irs1125_subdev_ops = {
-+ .core = &irs1125_subdev_core_ops,
-+ .video = &irs1125_subdev_video_ops,
-+ .pad = &irs1125_subdev_pad_ops,
-+};
-+
-+static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct irs1125 *dev = container_of(ctrl->handler,
-+ struct irs1125, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-+ int err, i;
-+ struct irs1125_mod_pll *mod_cur, *mod_new;
-+ struct irs1125_seq_cfg *cfg_cur, *cfg_new;
-+ u16 addr, val;
-+
-+ err = 0;
-+
-+ switch (ctrl->id) {
-+ case IRS1125_CID_SAFE_RECONFIG:
-+ {
-+ struct irs1125_illu *illu_cur, *illu_new;
-+
-+ illu_new = (struct irs1125_illu *)ctrl->p_new.p;
-+ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
-+ if (illu_cur[i].exposure != illu_new[i].exposure) {
-+ addr = 0xA850 + i * 2;
-+ val = illu_new[i].exposure;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (illu_cur[i].framerate != illu_new[i].framerate) {
-+ addr = 0xA851 + i * 2;
-+ val = illu_new[i].framerate;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ }
-+ case IRS1125_CID_MOD_PLL:
-+ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
-+ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
-+ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
-+ addr = 0xC3A0 + i * 3;
-+ val = mod_new[i].pllcfg1;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
-+ addr = 0xC3A1 + i * 3;
-+ val = mod_new[i].pllcfg2;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
-+ addr = 0xC3A2 + i * 3;
-+ val = mod_new[i].pllcfg3;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
-+ addr = 0xC24C + i * 5;
-+ val = mod_new[i].pllcfg4;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
-+ addr = 0xC24D + i * 5;
-+ val = mod_new[i].pllcfg5;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
-+ addr = 0xC24E + i * 5;
-+ val = mod_new[i].pllcfg6;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
-+ addr = 0xC24F + i * 5;
-+ val = mod_new[i].pllcfg7;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
-+ addr = 0xC250 + i * 5;
-+ val = mod_new[i].pllcfg8;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ case IRS1125_CID_SEQ_CONFIG:
-+ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p;
-+ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p;
-+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) {
-+ if (cfg_cur[i].exposure != cfg_new[i].exposure) {
-+ addr = IRS1125_REG_DMEM_SHADOW + i * 4;
-+ val = cfg_new[i].exposure;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].framerate != cfg_new[i].framerate) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4;
-+ val = cfg_new[i].framerate;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].ps != cfg_new[i].ps) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4;
-+ val = cfg_new[i].ps;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ if (cfg_cur[i].pll != cfg_new[i].pll) {
-+ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4;
-+ val = cfg_new[i].pll;
-+ err = irs1125_write(&dev->sd, addr, val);
-+ if (err < 0)
-+ break;
-+ }
-+ }
-+ break;
-+ case IRS1125_CID_NUM_SEQS:
-+ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1);
-+ if (err >= 0)
-+ dev->num_seq = ctrl->val;
-+ break;
-+ case IRS1125_CID_CONTINUOUS_TRIG:
-+ if (ctrl->val == 0)
-+ err = irs1125_write(&dev->sd, 0xA87C, 0);
-+ else
-+ err = irs1125_write(&dev->sd, 0xA87C, 1);
-+ break;
-+ case IRS1125_CID_TRIGGER:
-+ if (ctrl->val != 0) {
-+ err = irs1125_write(&dev->sd, 0xA87C, 1);
-+ if (err >= 0)
-+ err = irs1125_write(&dev->sd, 0xA87C, 0);
-+ }
-+ break;
-+ case IRS1125_CID_RECONFIG:
-+ if (ctrl->val != 0)
-+ err = irs1125_write(&dev->sd, 0xA87A, 1);
-+ break;
-+ case IRS1125_CID_ILLU_ON:
-+ if (ctrl->val == 0)
-+ err = irs1125_write(&dev->sd, 0xA892, 0x377);
-+ else
-+ err = irs1125_write(&dev->sd, 0xA892, 0x355);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (err < 0)
-+ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d",
-+ ctrl->id, ctrl->val, err);
-+ else
-+ err = 0;
-+
-+ return err;
-+}
-+
-+static const struct v4l2_ctrl_ops irs1125_ctrl_ops = {
-+ .s_ctrl = irs1125_s_ctrl,
-+};
-+
-+static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = {
-+ {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_NUM_SEQS,
-+ .name = "Change number of sequences",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
-+ .min = 1,
-+ .max = 20,
-+ .step = 1,
-+ .def = 5,
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_MOD_PLL,
-+ .name = "Reconfigure modulation PLLs",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16),
-+ IRS1125_NUM_MOD_PLLS}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_SAFE_RECONFIG,
-+ .name = "Change exposure and pause of single seq",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_illu) / sizeof(u16),
-+ IRS1125_NUM_SEQ_ENTRIES}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_SEQ_CONFIG,
-+ .name = "Change sequence settings",
-+ .type = V4L2_CTRL_TYPE_U16,
-+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD,
-+ .min = 0,
-+ .max = U16_MAX,
-+ .step = 1,
-+ .def = 0,
-+ .elem_size = sizeof(u16),
-+ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16),
-+ IRS1125_NUM_SEQ_ENTRIES}
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_CONTINUOUS_TRIG,
-+ .name = "Enable/disable continuous trigger",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_TRIGGER,
-+ .name = "Capture a single sequence",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_RECONFIG,
-+ .name = "Trigger imager reconfiguration",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_ILLU_ON,
-+ .name = "Turn illu on or off",
-+ .type = V4L2_CTRL_TYPE_BOOLEAN,
-+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
-+ .min = 0,
-+ .max = 1,
-+ .step = 1,
-+ .def = 1
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT0,
-+ .name = "Get ident 0 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT1,
-+ .name = "Get ident 1 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }, {
-+ .ops = &irs1125_ctrl_ops,
-+ .id = IRS1125_CID_IDENT2,
-+ .name = "Get ident 2 information",
-+ .type = V4L2_CTRL_TYPE_INTEGER,
-+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
-+ .min = S32_MIN,
-+ .max = S32_MAX,
-+ .step = 1,
-+ .def = 0
-+ }
-+};
-+
-+static int irs1125_detect(struct v4l2_subdev *sd)
-+{
-+ u16 read;
-+ int ret;
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "error reading from i2c\n");
-+ return ret;
-+ }
-+
-+ if (read != IRS1125_DESIGN_STEP_EXPECTED) {
-+ dev_err(&client->dev, "Design step expected 0x%x got 0x%x",
-+ IRS1125_DESIGN_STEP_EXPECTED, read);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_mbus_framefmt *format =
-+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
-+
-+ format->code = MEDIA_BUS_FMT_Y12_1X12;
-+ format->width = IRS1125_WINDOW_WIDTH_DEF;
-+ format->height = IRS1125_WINDOW_HEIGHT_DEF;
-+ format->field = V4L2_FIELD_NONE;
-+ format->colorspace = V4L2_COLORSPACE_RAW;
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = {
-+ .open = irs1125_open,
-+};
-+
-+static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev)
-+{
-+ struct v4l2_ctrl *ctrl;
-+ int err, i;
-+ struct v4l2_ctrl_handler *hdl;
-+
-+ hdl = &sensor->ctrl_handler;
-+ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls));
-+
-+ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) {
-+ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i],
-+ NULL);
-+ if (!ctrl)
-+ dev_err(dev, "Failed to init custom control %s\n",
-+ irs1125_custom_ctrls[i].name);
-+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS)
-+ sensor->ctrl_numseq = ctrl;
-+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL)
-+ sensor->ctrl_modplls = ctrl;
-+ }
-+
-+ if (hdl->error) {
-+ dev_err(dev, "Error %d adding controls\n", hdl->error);
-+ err = hdl->error;
-+ goto error_ctrls;
-+ }
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+error_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrl_handler);
-+ return -err;
-+}
-+
-+static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev)
-+{
-+ int ret;
-+ struct v4l2_ctrl *ctrl;
-+ struct v4l2_subdev *sd;
-+ u16 read;
-+
-+ sd = &sensor->sd;
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+
-+ v4l2_ctrl_s_ctrl(ctrl, read);
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+
-+ v4l2_ctrl_s_ctrl(ctrl, read);
-+
-+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2);
-+ if (!ctrl) {
-+ dev_err(dev, "could not find device ctrl.\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read);
-+ if (ret < 0) {
-+ dev_err(dev, "error reading from i2c\n");
-+ return -EIO;
-+ }
-+ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC);
-+
-+ return 0;
-+}
-+
-+static int irs1125_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct device *dev = &client->dev;
-+ struct irs1125 *sensor;
-+ int ret;
-+ struct fwnode_handle *endpoint;
-+ u32 xclk_freq;
-+ int gpio_num;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops);
-+
-+ /* Get CSI2 bus config */
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "could not get xclk");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ xclk_freq = clk_get_rate(sensor->xclk);
-+ if (xclk_freq != 26000000) {
-+ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ sensor->num_seq = 5;
-+
-+ /* Request the power down GPIO */
-+ sensor->reset = devm_gpiod_get(&client->dev, "pwdn",
-+ GPIOD_OUT_LOW);
-+
-+ if (IS_ERR(sensor->reset)) {
-+ dev_err(dev, "could not get reset");
-+ return PTR_ERR(sensor->reset);
-+ }
-+
-+ gpio_num = desc_to_gpio(sensor->reset);
-+
-+ mutex_init(&sensor->lock);
-+
-+ ret = irs1125_ctrls_init(sensor, dev);
-+ if (ret < 0)
-+ goto mutex_remove;
-+
-+ sensor->sd.internal_ops = &irs1125_subdev_internal_ops;
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret < 0)
-+ goto mutex_remove;
-+
-+ gpiod_set_value_cansleep(sensor->reset, 1);
-+ msleep(RESET_ACTIVE_DELAY_MS);
-+
-+ ret = irs1125_detect(&sensor->sd);
-+ if (ret < 0)
-+ goto error;
-+
-+ ret = irs1125_ident_setup(sensor, dev);
-+ if (ret < 0)
-+ goto error;
-+
-+ gpiod_set_value_cansleep(sensor->reset, 0);
-+
-+ ret = v4l2_async_register_subdev(&sensor->sd);
-+ if (ret < 0)
-+ goto error;
-+
-+ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n");
-+
-+ return 0;
-+
-+error:
-+ media_entity_cleanup(&sensor->sd.entity);
-+mutex_remove:
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static int irs1125_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct irs1125 *irs1125 = to_state(sd);
-+
-+ v4l2_async_unregister_subdev(&irs1125->sd);
-+ media_entity_cleanup(&irs1125->sd.entity);
-+ v4l2_device_unregister_subdev(sd);
-+ mutex_destroy(&irs1125->lock);
-+ v4l2_ctrl_handler_free(&irs1125->ctrl_handler);
-+
-+ return 0;
-+}
-+
-+#if IS_ENABLED(CONFIG_OF)
-+static const struct of_device_id irs1125_of_match[] = {
-+ { .compatible = "infineon,irs1125" },
-+ { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, irs1125_of_match);
-+#endif
-+
-+static struct i2c_driver irs1125_driver = {
-+ .driver = {
-+ .of_match_table = of_match_ptr(irs1125_of_match),
-+ .name = SENSOR_NAME,
-+ },
-+ .probe = irs1125_probe,
-+ .remove = irs1125_remove,
-+};
-+
-+module_i2c_driver(irs1125_driver);
-+
-+MODULE_AUTHOR("Markus Proeller <markus.proeller@pieye.org>");
-+MODULE_DESCRIPTION("Infineon irs1125 sensor driver");
-+MODULE_LICENSE("GPL v2");
-+
---- /dev/null
-+++ b/drivers/media/i2c/irs1125.h
-@@ -0,0 +1,61 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * A V4L2 driver for Infineon IRS1125 TOF cameras.
-+ * Copyright (C) 2018, pieye GmbH
-+ *
-+ * Based on V4L2 OmniVision OV5647 Image Sensor driver
-+ * Copyright (C) 2016 Ramiro Oliveira <roliveir@synopsys.com>
-+ *
-+ * DT / fwnode changes, and GPIO control taken from ov5640.c
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#ifndef IRS1125_H
-+#define IRS1125_H
-+
-+#include <linux/v4l2-controls.h>
-+#include <linux/types.h>
-+
-+#define IRS1125_NUM_SEQ_ENTRIES 20
-+#define IRS1125_NUM_MOD_PLLS 4
-+
-+#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
-+#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0)
-+#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1)
-+#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2)
-+#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3)
-+#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4)
-+#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5)
-+#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6)
-+#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7)
-+#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8)
-+#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9)
-+#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10)
-+
-+struct irs1125_seq_cfg {
-+ __u16 exposure;
-+ __u16 framerate;
-+ __u16 ps;
-+ __u16 pll;
-+};
-+
-+struct irs1125_illu {
-+ __u16 exposure;
-+ __u16 framerate;
-+};
-+
-+struct irs1125_mod_pll {
-+ __u16 pllcfg1;
-+ __u16 pllcfg2;
-+ __u16 pllcfg3;
-+ __u16 pllcfg4;
-+ __u16 pllcfg5;
-+ __u16 pllcfg6;
-+ __u16 pllcfg7;
-+ __u16 pllcfg8;
-+};
-+
-+#endif /* IRS1125 */
-+
--- /dev/null
+From 16422635ebace7f01b42412e5c0d889f5ad7512e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 6 Nov 2019 13:57:58 +0000
+Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a
+ platform driver
+
+Following the same pattern as bcm2835-camera and bcm2835-audio,
+register the V4L2 codec driver as a platform driver
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -140,6 +140,7 @@ static struct class *vchiq_class;
+ static DEFINE_SPINLOCK(msg_queue_spinlock);
+ static struct platform_device *bcm2835_camera;
+ static struct platform_device *bcm2835_audio;
++static struct platform_device *bcm2835_codec;
+ static struct platform_device *vcsm_cma;
+
+ static struct vchiq_drvdata bcm2835_drvdata = {
+@@ -3252,6 +3253,7 @@ static int vchiq_probe(struct platform_d
+ MAJOR(vchiq_devid), MINOR(vchiq_devid));
+
+ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
++ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec");
+ bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
+ bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
+
+@@ -3268,6 +3270,7 @@ static int vchiq_remove(struct platform_
+ {
+ if (!IS_ERR(bcm2835_camera))
+ platform_device_unregister(bcm2835_camera);
++ platform_device_unregister(bcm2835_codec);
+ platform_device_unregister(vcsm_cma);
+ vchiq_debugfs_deinit();
+ device_destroy(vchiq_class, vchiq_devid);
+++ /dev/null
-From 3d9d9ae68a1fb5451d12b46b65289e67cca2a340 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 13 Sep 2019 17:19:33 +0100
-Subject: [PATCH] staging:bcm2835-codec: Add support for
- ENUM_FRAMESIZES
-
-Required for compliance testing for the encoder.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++--
- 1 file changed, 44 insertions(+), 4 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo
- return &dev->supported_fmts[capture ? 1 : 0].list[0];
- }
-
--static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
-- struct bcm2835_codec_dev *dev,
-- bool capture)
-+static
-+struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt,
-+ struct bcm2835_codec_dev *dev,
-+ bool capture)
- {
- struct bcm2835_codec_fmt *fmt;
- unsigned int k;
-@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo
-
- for (k = 0; k < fmts->num_entries; k++) {
- fmt = &fmts->list[k];
-- if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
-+ if (fmt->fourcc == pix_fmt)
- break;
- }
- if (k == fmts->num_entries)
-@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo
- return &fmts->list[k];
- }
-
-+static inline
-+struct bcm2835_codec_fmt *find_format(struct v4l2_format *f,
-+ struct bcm2835_codec_dev *dev,
-+ bool capture)
-+{
-+ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture);
-+}
-+
- static inline struct bcm2835_codec_ctx *file2ctx(struct file *file)
- {
- return container_of(file->private_data, struct bcm2835_codec_ctx, fh);
-@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil
- return 0;
- }
-
-+static int vidioc_enum_framesizes(struct file *file, void *fh,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ struct bcm2835_codec_fmt *fmt;
-+
-+ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev,
-+ true);
-+ if (!fmt)
-+ fmt = find_format_pix_fmt(fsize->pixel_format,
-+ file2ctx(file)->dev,
-+ false);
-+
-+ if (!fmt)
-+ return -EINVAL;
-+
-+ if (fsize->index)
-+ return -EINVAL;
-+
-+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-+
-+ fsize->stepwise.min_width = MIN_W;
-+ fsize->stepwise.max_width = MAX_W;
-+ fsize->stepwise.step_width = 1;
-+ fsize->stepwise.min_height = MIN_H;
-+ fsize->stepwise.max_height = MAX_H;
-+ fsize->stepwise.step_height = 1;
-+
-+ return 0;
-+}
-+
- static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
-
-@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28
- .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
- .vidioc_encoder_cmd = vidioc_encoder_cmd,
- .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
-+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
- };
-
- static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx)
--- /dev/null
+From 6d59110f7aa7c86caf2c3a29169ace33556f690b Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 6 Nov 2019 13:58:08 +0000
+Subject: [PATCH] staging: bcm2835-codec: Fix potential memory leak of
+ isp instance
+
+"d867785 staging: bcm2835-codec: add media controller support" added
+a new error path that jumped to end, but didn't add the free
+of the ISP device should that path be taken.
+Fix this.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+@@ -2841,6 +2841,10 @@ static int bcm2835_codec_probe(struct pl
+ return 0;
+
+ out:
++ if (drv->isp) {
++ bcm2835_codec_destroy(drv->isp);
++ drv->isp = NULL;
++ }
+ if (drv->encode) {
+ bcm2835_codec_destroy(drv->encode);
+ drv->encode = NULL;
+++ /dev/null
-From 0ff5cd805e7db4003ad5a0d783b4d029b23b7ece Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 13 Sep 2019 17:22:08 +0100
-Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on
- G_PARM
-
-The output queue buffer type is now OUTPUT_MPLANE.
-
-Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi
- {
- struct bcm2835_codec_ctx *ctx = file2ctx(file);
-
-- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
- parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
--- /dev/null
+From 91da858c9327352c17a1f20ec10e78113ed45c82 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 6 Nov 2019 13:58:18 +0000
+Subject: [PATCH] staging: vchiq_arm: Unify the unload handling of
+ platform devs
+
+A helper function vchiq_register_child was added to deal with
+adding the platform devices. This returns NULL on failure, and
+that is assigned to the struct platform_device. There is
+therefore no way for remove to encounter an error pointer, so
+checking for IS_ERR() is redundant.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3268,8 +3268,7 @@ failed_platform_init:
+
+ static int vchiq_remove(struct platform_device *pdev)
+ {
+- if (!IS_ERR(bcm2835_camera))
+- platform_device_unregister(bcm2835_camera);
++ platform_device_unregister(bcm2835_camera);
+ platform_device_unregister(bcm2835_codec);
+ platform_device_unregister(vcsm_cma);
+ vchiq_debugfs_deinit();
--- /dev/null
+From c2863af34286fda317891bb893f8a2e16bf5707e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 14 Nov 2019 11:59:01 +0000
+Subject: [PATCH] net: bcmgenet: The second IRQ is optional
+
+As of 5.4, the kernel logs errors for absent IRQs unless requested
+with platform_get_irq_optional.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_irq.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -217,7 +217,7 @@ v3d_irq_init(struct v3d_dev *v3d)
+ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
+ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
+
+- irq1 = platform_get_irq(v3d->pdev, 1);
++ irq1 = platform_get_irq_optional(v3d->pdev, 1);
+ if (irq1 == -EPROBE_DEFER)
+ return irq1;
+ if (irq1 > 0) {
+++ /dev/null
-From 6680d139ee23cf655c0aa43581604a7c5de31803 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Fri, 13 Sep 2019 17:23:26 +0100
-Subject: [PATCH] staging: bcm2835-codec: Set default and error check
- timeperframe
-
-G_PARM default was invalid as 0/0, and the driver didn't check
-the value set in S_PARM wasn't 0/0.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi
- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return -EINVAL;
-
-+ if (!parm->parm.output.timeperframe.denominator ||
-+ !parm->parm.output.timeperframe.numerator)
-+ return -EINVAL;
-+
- ctx->framerate_num =
- parm->parm.output.timeperframe.denominator;
- ctx->framerate_denom =
-@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil
- ctx->colorspace = V4L2_COLORSPACE_REC709;
- ctx->bitrate = 10 * 1000 * 1000;
-
-+ ctx->framerate_num = 30;
-+ ctx->framerate_denom = 1;
-+
- /* Initialise V4L2 contexts */
- v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
--- /dev/null
+From 92f17eecf263f3705a6e1a4f27ecb273ed3a33e5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 14 Nov 2019 12:00:43 +0000
+Subject: [PATCH] drm/v3d: The third IRQ is optional
+
+As of 5.4, the kernel logs errors for absent IRQs unless requested
+with platform_get_irq_optional.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -3468,7 +3468,7 @@ static int bcmgenet_probe(struct platfor
+ priv = netdev_priv(dev);
+ priv->irq0 = platform_get_irq(pdev, 0);
+ priv->irq1 = platform_get_irq(pdev, 1);
+- priv->wol_irq = platform_get_irq(pdev, 2);
++ priv->wol_irq = platform_get_irq_optional(pdev, 2);
+ if (!priv->irq0 || !priv->irq1) {
+ dev_err(&pdev->dev, "can't find IRQs\n");
+ err = -EINVAL;
+++ /dev/null
-From 0c941589b9bfb07cd31c792b445e630817e956d1 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Mon, 7 Oct 2019 14:02:57 +0100
-Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in
- dma_buf_get/dma_buf_put
-
-When represented with a dmabuf buffer that had previously been
-imported, there was a call to dma_buf_get without a matching
-dma_buf_put. This left dmabufs in limbo after all users had
-supposedly released them.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str
- }
-
- buf->mmal.dma_buf = dma_buf;
-+ } else {
-+ /* We already have a reference count on the dmabuf, so
-+ * release the one we acquired above.
-+ */
-+ dma_buf_put(dma_buf);
- }
- ret = 0;
- break;
+++ /dev/null
-From b92ed4ca0f9be3c8cc1a21dbbef346338d336329 Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Wed, 16 Oct 2019 14:49:23 +0100
-Subject: [PATCH] drm:vc4 Added calls for firmware display
- blank/unblank
-
-Requires new display power mailbox call to be present.
-
-Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
----
- drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
- 2 files changed, 27 insertions(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
-@@ -94,6 +94,12 @@ struct mailbox_blank_display {
- u32 blank;
- };
-
-+struct mailbox_display_pwr {
-+ struct rpi_firmware_property_tag_header tag1;
-+ u32 display;
-+ u32 state;
-+};
-+
- struct mailbox_get_edid {
- struct rpi_firmware_property_tag_header tag1;
- u32 block;
-@@ -274,6 +280,8 @@ to_vc4_crtc_state(struct drm_crtc_state
- struct vc4_fkms_encoder {
- struct drm_encoder base;
- bool hdmi_monitor;
-+ bool rgb_range_selectable;
-+ int display_num;
- };
-
- static inline struct vc4_fkms_encoder *
-@@ -1637,13 +1645,29 @@ static const struct drm_encoder_funcs vc
- .destroy = vc4_fkms_encoder_destroy,
- };
-
-+static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
-+{
-+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
-+ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
-+
-+ struct mailbox_display_pwr pwr = {
-+ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
-+ .display = vc4_encoder->display_num,
-+ .state = power ? 1 : 0,
-+ };
-+
-+ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
-+}
-+
- static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
- {
-+ vc4_fkms_display_power(encoder, true);
- DRM_DEBUG_KMS("Encoder_enable\n");
- }
-
- static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
- {
-+ vc4_fkms_display_power(encoder, false);
- DRM_DEBUG_KMS("Encoder_disable\n");
- }
-
-@@ -1719,6 +1743,8 @@ static int vc4_fkms_create_screen(struct
- if (!vc4_encoder)
- return -ENOMEM;
- vc4_crtc->encoder = &vc4_encoder->base;
-+
-+ vc4_encoder->display_num = display_ref;
- vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
-
- drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -153,7 +153,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
- RPI_FIRMWARE_SET_TIMING = 0x00048017,
- RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
--
-+ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
- RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
- RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
- };
--- /dev/null
+From 941d43e29b1fa7352eb006b5ec37d6990ed3b877 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 15 Nov 2019 08:48:08 +0000
+Subject: [PATCH] dwc_otg: Declare DMA capability with HCD_DMA flag
+
+Following [1], USB controllers have to declare DMA capabilities in
+order for them to be used by adding the HCD_DMA flag to their hc_driver
+struct.
+
+[1] 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of guestimating DMA capabilities")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -138,7 +138,7 @@ static struct hc_driver dwc_otg_hc_drive
+
+ .irq = dwc_otg_hcd_irq,
+
+- .flags = HCD_MEMORY | HCD_USB2,
++ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
+
+ //.reset =
+ .start = hcd_start,
+++ /dev/null
-From b1d33d1e5a44afd2025c5a44a85dc2fab00ec6a7 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 5 Nov 2019 11:28:19 +0000
-Subject: [PATCH] Revert "pinctrl: bcm2835: Pass irqchip when adding
- gpiochip"
-
-This reverts commit 73345a18d464b1b945b29f54f630ace6873344e2.
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 55 +++++++++++++++------------
- 1 file changed, 30 insertions(+), 25 deletions(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -78,6 +78,7 @@
- struct bcm2835_pinctrl {
- struct device *dev;
- void __iomem *base;
-+ int irq[BCM2835_NUM_IRQS];
-
- /* note: locking assumes each bank will have its own unsigned long */
- unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
-@@ -381,14 +382,14 @@ static void bcm2835_gpio_irq_handler(str
- int group;
- int i;
-
-- for (i = 0; i < BCM2835_NUM_IRQS; i++) {
-- if (chip->irq.parents[i] == irq) {
-+ for (i = 0; i < ARRAY_SIZE(pc->irq); i++) {
-+ if (pc->irq[i] == irq) {
- group = i;
- break;
- }
- }
- /* This should not happen, every IRQ has a bank */
-- if (i == BCM2835_NUM_IRQS)
-+ if (i == ARRAY_SIZE(pc->irq))
- BUG();
-
- chained_irq_enter(host_chip, desc);
-@@ -1086,7 +1087,6 @@ static int bcm2835_pinctrl_probe(struct
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct bcm2835_pinctrl *pc;
-- struct gpio_irq_chip *girq;
- struct resource iomem;
- int err, i;
- const struct of_device_id *match;
-@@ -1135,33 +1135,38 @@ static int bcm2835_pinctrl_probe(struct
- raw_spin_lock_init(&pc->irq_lock[i]);
- }
-
-- girq = &pc->gpio_chip.irq;
-- girq->chip = &bcm2835_gpio_irq_chip;
-- girq->parent_handler = bcm2835_gpio_irq_handler;
-- girq->num_parents = BCM2835_NUM_IRQS;
-- girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
-- sizeof(*girq->parents),
-- GFP_KERNEL);
-- if (!girq->parents)
-- return -ENOMEM;
-- /*
-- * Use the same handler for all groups: this is necessary
-- * since we use one gpiochip to cover all lines - the
-- * irq handler then needs to figure out which group and
-- * bank that was firing the IRQ and look up the per-group
-- * and bank data.
-- */
-- for (i = 0; i < BCM2835_NUM_IRQS; i++)
-- girq->parents[i] = irq_of_parse_and_map(np, i);
-- girq->default_type = IRQ_TYPE_NONE;
-- girq->handler = handle_level_irq;
--
- err = gpiochip_add_data(&pc->gpio_chip, pc);
- if (err) {
- dev_err(dev, "could not add GPIO chip\n");
- return err;
- }
-
-+ err = gpiochip_irqchip_add(&pc->gpio_chip, &bcm2835_gpio_irq_chip,
-+ 0, handle_level_irq, IRQ_TYPE_NONE);
-+ if (err) {
-+ dev_info(dev, "could not add irqchip\n");
-+ return err;
-+ }
-+
-+ for (i = 0; i < BCM2835_NUM_IRQS; i++) {
-+ pc->irq[i] = irq_of_parse_and_map(np, i);
-+
-+ if (pc->irq[i] == 0)
-+ continue;
-+
-+ /*
-+ * Use the same handler for all groups: this is necessary
-+ * since we use one gpiochip to cover all lines - the
-+ * irq handler then needs to figure out which group and
-+ * bank that was firing the IRQ and look up the per-group
-+ * and bank data.
-+ */
-+ gpiochip_set_chained_irqchip(&pc->gpio_chip,
-+ &bcm2835_gpio_irq_chip,
-+ pc->irq[i],
-+ bcm2835_gpio_irq_handler);
-+ }
-+
- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
- if (match) {
- bcm2835_pinctrl_desc.confops =
--- /dev/null
+From 3223b1605ea10821a90867ee7a79d9030d7ca44f Mon Sep 17 00:00:00 2001
+From: Serge Schneider <serge@raspberrypi.org>
+Date: Thu, 31 Oct 2019 13:37:16 +0000
+Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes
+
+Signed-off-by: Serge Schneider <serge@raspberrypi.org>
+---
+ drivers/hwmon/rpi-poe-fan.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/hwmon/rpi-poe-fan.c
++++ b/drivers/hwmon/rpi-poe-fan.c
+@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe
+ if (ctx->def_pwm_value == def_pwm)
+ goto exit_set_def_pwm_err;
+
+- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm);
++ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm);
+ if (!ret)
+ ctx->def_pwm_value = def_pwm;
+ exit_set_def_pwm_err:
+++ /dev/null
-From e2d8a52d3ade83f5c114b1edba601ebcf2c39517 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 11 Nov 2019 14:01:41 +0000
-Subject: [PATCH] drm/v3d: Don't clear MMU control bits on exception
-
-MMU exception conditions are reported in the V3D_MMU_CTRL register as
-write-1-to-clear (W1C) bits. The MMU interrupt handling code clears any
-exceptions, but does so by masking out any other bits and writing the
-result back. There are some important control bits in that register,
-including MMU_ENABLE, so a safer approach is to simply write back the
-value just read unaltered.
-
-This patch doesn't remove the cause of the apparent PTE errors, but it
-does reduce the impact to just an error in the kernel log.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_irq.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -178,10 +178,7 @@ v3d_hub_irq(int irq, void *arg)
- };
- const char *client = "?";
-
-- V3D_WRITE(V3D_MMU_CTL,
-- V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED |
-- V3D_MMU_CTL_PT_INVALID |
-- V3D_MMU_CTL_WRITE_VIOLATION));
-+ V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
-
- if (v3d->ver >= 41) {
- axi_id = axi_id >> 5;
--- /dev/null
+From eef2d9aeb08a227d0a9c5734214425a3b9693f50 Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Thu, 31 Oct 2019 14:39:44 +0000
+Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via
+ device tree
+
+Add device tree entries and code to allow the specification of
+the lighting modes for the LED's on the ethernet connector.
+
+Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++
+ arch/arm/boot/dts/bcm2838.dtsi | 1 +
+ arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++--------
+ drivers/net/phy/broadcom.c | 9 +++++++--
+ 4 files changed, 31 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -334,5 +334,8 @@
+ pwr_led_gpio = <&pwr_led>,"gpios:4";
+ pwr_led_activelow = <&pwr_led>,"gpios:8";
+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -380,6 +380,7 @@
+ /* No interrupts - use PHY_POLL */
+ max-speed = <1000>;
+ reg = <0x1>;
++ led-modes = <0x02 0x02>;
+ };
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -102,26 +102,38 @@ Params:
+
+ eee Enable Energy Efficient Ethernet support for
+ compatible devices (default "on"). See also
+- "tx_lpi_timer".
++ "tx_lpi_timer". Pi3B+ only.
+
+ eth_downshift_after Set the number of auto-negotiation failures
+ after which the 1000Mbps modes are disabled.
+ Legal values are 2, 3, 4, 5 and 0, where
+- 0 means never downshift (default 2).
++ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange) (default
+- "1"). The legal values are:
+- 0=link/activity 1=link1000/activity
++ eth_led0 Set mode of LED0 (usually orange). The legal
++ values are:
++
++ Pi3B+
++
++ 0=link/activity 1=link1000/activity (default)
+ 2=link100/activity 3=link10/activity
+ 4=link100/1000/activity 5=link10/1000/activity
+ 6=link10/100/activity 14=off 15=on
+
+- eth_led1 Set mode of LED1 (usually green) (default
+- "6"). See eth_led0 for legal values.
++ Pi4
++
++ 0=Speed/Activity (default) 1=Speed
++ 2=Speed/Flash activity 3=FDX
++ 4=Off 5=On
++ 6=Alt 7=Speed/Flash
++ 8=Link 9=Activity
++
++ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
++ "6", Pi4 default "0"). See eth_led0 for legal
++ values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+ to negotiate. Legal values are 10, 100 and
+- 1000 (default 1000).
++ 1000 (default 1000). Pi3B+ only.
+
+ i2c_arm Set to "on" to enable the ARM's i2c interface
+ (default "off")
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -267,6 +267,9 @@ static void bcm54xx_adjust_rxrefclk(stru
+ static int bcm54xx_config_init(struct phy_device *phydev)
+ {
+ int reg, err, val;
++ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
++ BCM_LED_MULTICOLOR_LINK_ACT};
++ struct device_node *np = phydev->mdio.dev.of_node;
+
+ reg = phy_read(phydev, MII_BCM54XX_ECR);
+ if (reg < 0)
+@@ -318,6 +321,8 @@ static int bcm54xx_config_init(struct ph
+
+ bcm54xx_phydsp_config(phydev);
+
++ of_property_read_u32_array(np, "led-modes", led_modes, 2);
++
+ /* Encode link speed into LED1 and LED3 pair (green/amber).
+ * Also flash these two LEDs on activity. This means configuring
+ * them for MULTICOLOR and encoding link/activity into them.
+@@ -327,8 +332,8 @@ static int bcm54xx_config_init(struct ph
+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
+
+ val = BCM_LED_MULTICOLOR_IN_PHASE |
+- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
+- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
++ BCM5482_SHD_LEDS1_LED1(led_modes[0]) |
++ BCM5482_SHD_LEDS1_LED3(led_modes[1]);
+ bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
+
+ return 0;
+++ /dev/null
-From f1f228c84864bad0bb07de1c72ceafaec035ac15 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 11 Nov 2019 20:18:08 +0000
-Subject: [PATCH] drm/v3d: Suppress all but the first MMU error
-
-The v3d driver currently encounters a lot of MMU PTE exceptions, so
-only log the first to avoid swamping the kernel log.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_irq.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -177,6 +177,7 @@ v3d_hub_irq(int irq, void *arg)
- "GMP",
- };
- const char *client = "?";
-+ static int logged_error;
-
- V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
-
-@@ -186,6 +187,7 @@ v3d_hub_irq(int irq, void *arg)
- client = v3d41_axi_ids[axi_id];
- }
-
-+ if (!logged_error)
- dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
- client, axi_id, (long long)vio_addr,
- ((intsts & V3D_HUB_INT_MMU_WRV) ?
-@@ -194,6 +196,7 @@ v3d_hub_irq(int irq, void *arg)
- ", pte invalid" : ""),
- ((intsts & V3D_HUB_INT_MMU_CAP) ?
- ", cap exceeded" : ""));
-+ logged_error = 1;
- status = IRQ_HANDLED;
- }
-
--- /dev/null
+From 2a65ed9d89f32a0e87d99ccdfd21ab140637063a Mon Sep 17 00:00:00 2001
+From: Pierre-jean Texier <texier.pj2@gmail.com>
+Date: Wed, 6 Nov 2019 10:00:43 +0100
+Subject: [PATCH] overlays: smi: fix typo in comment (#3320)
+
+5 represent alt1 function not alt0.
+
+Signed-off-by: Pierre-Jean Texier <pjtexier@koncepto.io>
+---
+ arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/smi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
+@@ -24,7 +24,7 @@
+ these are already used as ID_SD and ID_SC */
+ brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ 16 17 18 19 20 21 22 23 24 25>;
+- /* Alt 0: SMI */
++ /* Alt 1: SMI */
+ brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5>;
+ /* /CS, /WE and /OE are pulled high, as they are
+++ /dev/null
-From 9b2d99c0959e693e4dcea5f454bf84f229ca3d27 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 12 Nov 2019 16:41:21 +0000
-Subject: [PATCH] drm/v3d: Plug dma_fence leak
-
-The irq_fence and done_fence are given a reference that is never
-released. The necessary dma_fence_put()s seem to have been
-deleted in error in an earlier commit.
-
-Fixes: 0b73676836b2 ("drm/v3d: Clock V3D down when not in use.")
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_gem.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -410,6 +410,9 @@ v3d_job_free(struct kref *ref)
- }
- xa_destroy(&job->deps);
-
-+ dma_fence_put(job->irq_fence);
-+ dma_fence_put(job->done_fence);
-+
- v3d_clock_up_put(v3d);
-
- kfree(job);
--- /dev/null
+From e459a2c448d7d71718769a9966543a964d1803bd Mon Sep 17 00:00:00 2001
+From: James Hughes <james.hughes@raspberrypi.org>
+Date: Thu, 7 Nov 2019 14:59:59 +0000
+Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions
+
+This should return default behaviour back to that of previous
+releases.
+---
+ drivers/net/phy/broadcom.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/drivers/net/phy/broadcom.c
++++ b/drivers/net/phy/broadcom.c
+@@ -268,7 +268,7 @@ static int bcm54xx_config_init(struct ph
+ {
+ int reg, err, val;
+ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
+- BCM_LED_MULTICOLOR_LINK_ACT};
++ BCM_LED_MULTICOLOR_LINK};
+ struct device_node *np = phydev->mdio.dev.of_node;
+
+ reg = phy_read(phydev, MII_BCM54XX_ECR);
+@@ -323,10 +323,6 @@ static int bcm54xx_config_init(struct ph
+
+ of_property_read_u32_array(np, "led-modes", led_modes, 2);
+
+- /* Encode link speed into LED1 and LED3 pair (green/amber).
+- * Also flash these two LEDs on activity. This means configuring
+- * them for MULTICOLOR and encoding link/activity into them.
+- */
+ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
--- /dev/null
+From 62cd48ebf18c1eb0bbddba080476201bdfae4126 Mon Sep 17 00:00:00 2001
+From: Michael Kaplan <m.kaplan@evva.com>
+Date: Fri, 8 Nov 2019 10:35:57 +0100
+Subject: [PATCH] overlays: Add apds9960 overlay
+
+Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor.
+Also update overlay README and Makefile.
+
+Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 8 +++
+ .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++
+ 3 files changed, 66 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ allo-katana-dac-audio.dtbo \
+ allo-piano-dac-pcm512x-audio.dtbo \
+ allo-piano-dac-plus-pcm512x-audio.dtbo \
++ apds9960.dtbo \
+ applepi-dac.dtbo \
+ at86rf233.dtbo \
+ audioinjector-addons.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga
+ better voice quality. (default Off)
+
+
++Name: apds9960
++Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
++ gesture sensor
++Load: dtoverlay=apds9960,<param>=<val>
++Params: gpiopin GPIO used for INT (default 4)
++ noints Disable the interrupt GPIO line.
++
++
+ Name: applepi-dac
+ Info: Configures the Orchard Audio ApplePi-DAC audio card
+ Load: dtoverlay=applepi-dac
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts
+@@ -0,0 +1,57 @@
++// Definitions for APDS-9960 ambient light and gesture sensor
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2c1>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ apds9960_pins: apds9960_pins@39 {
++ brcm,pins = <4>;
++ brcm,function = <0>;
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ apds9960: apds@39 {
++ compatible = "avago,apds9960";
++ reg = <0x39>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&i2c1>;
++ __overlay__ {
++ apds9960_irq: apds@39 {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 1>;
++ };
++ };
++ };
++
++ __overrides__ {
++ gpiopin = <&apds9960_pins>,"brcm,pins:0",
++ <&apds9960_irq>,"interrupts:0";
++ noints = <0>,"!1!3";
++ };
++};
++
+++ /dev/null
-From efe24599e8996ef5844e73feae1ca1b27d8740ab Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 6 Nov 2019 13:57:48 +0000
-Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform
- driver
-
-Following the same pattern as bcm2835-camera and bcm2835-audio,
-register the vcsm-cma driver as a platform driver
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -140,6 +140,7 @@ static struct class *vchiq_class;
- static DEFINE_SPINLOCK(msg_queue_spinlock);
- static struct platform_device *bcm2835_camera;
- static struct platform_device *bcm2835_audio;
-+static struct platform_device *vcsm_cma;
-
- static struct vchiq_drvdata bcm2835_drvdata = {
- .cache_line_size = 32,
-@@ -3250,6 +3251,7 @@ static int vchiq_probe(struct platform_d
- VCHIQ_VERSION, VCHIQ_VERSION_MIN,
- MAJOR(vchiq_devid), MINOR(vchiq_devid));
-
-+ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
- bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
- bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
-
-@@ -3266,6 +3268,7 @@ static int vchiq_remove(struct platform_
- {
- if (!IS_ERR(bcm2835_camera))
- platform_device_unregister(bcm2835_camera);
-+ platform_device_unregister(vcsm_cma);
- vchiq_debugfs_deinit();
- device_destroy(vchiq_class, vchiq_devid);
- cdev_del(&vchiq_cdev);
--- /dev/null
+From d24bb9c4b5d3b0bb2bd5dd922bae3fce894ab87e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 1 Oct 2019 10:19:50 +0100
+Subject: [PATCH] overlays: Remove hack from uart0 overlay
+
+The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs
+when the UART0 function was moved to alternative pins. This has the
+unwanted side effect of claiming GPIOs 14 & 15, preventing them being
+used for something else.
+
+See: https://github.com/raspberrypi/linux/issues/2856
+ https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911
+
+Signed-off-by: Stefan Enge <stefan.enge@escatec.com>
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
+@@ -17,17 +17,16 @@
+ target = <&gpio>;
+ __overlay__ {
+ uart0_pins: uart0_pins {
+- brcm,pins = <14 15 14 15>;
+- brcm,function = <0 0 4 4>; /* alt0 */
+- brcm,pull = <0 0 0 2>;
++ brcm,pins = <14 15>;
++ brcm,function = <4>; /* alt0 */
++ brcm,pull = <0 2>;
+ };
+ };
+ };
+
+ __overrides__ {
+- txd0_pin = <&uart0_pins>,"brcm,pins:8";
+- rxd0_pin = <&uart0_pins>,"brcm,pins:12";
+- pin_func = <&uart0_pins>,"brcm,function:8",
+- <&uart0_pins>,"brcm,function:12";
++ txd0_pin = <&uart0_pins>,"brcm,pins:0";
++ rxd0_pin = <&uart0_pins>,"brcm,pins:4";
++ pin_func = <&uart0_pins>,"brcm,function:0";
+ };
+ };
+++ /dev/null
-From 16422635ebace7f01b42412e5c0d889f5ad7512e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 6 Nov 2019 13:57:58 +0000
-Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a
- platform driver
-
-Following the same pattern as bcm2835-camera and bcm2835-audio,
-register the V4L2 codec driver as a platform driver
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -140,6 +140,7 @@ static struct class *vchiq_class;
- static DEFINE_SPINLOCK(msg_queue_spinlock);
- static struct platform_device *bcm2835_camera;
- static struct platform_device *bcm2835_audio;
-+static struct platform_device *bcm2835_codec;
- static struct platform_device *vcsm_cma;
-
- static struct vchiq_drvdata bcm2835_drvdata = {
-@@ -3252,6 +3253,7 @@ static int vchiq_probe(struct platform_d
- MAJOR(vchiq_devid), MINOR(vchiq_devid));
-
- vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
-+ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec");
- bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
- bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
-
-@@ -3268,6 +3270,7 @@ static int vchiq_remove(struct platform_
- {
- if (!IS_ERR(bcm2835_camera))
- platform_device_unregister(bcm2835_camera);
-+ platform_device_unregister(bcm2835_codec);
- platform_device_unregister(vcsm_cma);
- vchiq_debugfs_deinit();
- device_destroy(vchiq_class, vchiq_devid);
--- /dev/null
+From 47a9af99289ef0b9d60a72cd7147958e4745468c Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Sun, 17 Nov 2019 16:20:24 +0000
+Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream
+ compatible
+
+The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible
+string explicitly for this screen config and not a hx8357d generic for
+the controller so add that in as well so it will work with an unmodified
+upstream kernel driver. We leave the downstream as the priority.
+
+Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
+---
+ arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
+@@ -49,7 +49,7 @@
+ #size-cells = <0>;
+
+ pitft: pitft@0{
+- compatible = "himax,hx8357d";
++ compatible = "himax,hx8357d", "adafruit,yx350hv15";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pitft_pins>;
+++ /dev/null
-From 6d59110f7aa7c86caf2c3a29169ace33556f690b Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 6 Nov 2019 13:58:08 +0000
-Subject: [PATCH] staging: bcm2835-codec: Fix potential memory leak of
- isp instance
-
-"d867785 staging: bcm2835-codec: add media controller support" added
-a new error path that jumped to end, but didn't add the free
-of the ISP device should that path be taken.
-Fix this.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
-@@ -2841,6 +2841,10 @@ static int bcm2835_codec_probe(struct pl
- return 0;
-
- out:
-+ if (drv->isp) {
-+ bcm2835_codec_destroy(drv->isp);
-+ drv->isp = NULL;
-+ }
- if (drv->encode) {
- bcm2835_codec_destroy(drv->encode);
- drv->encode = NULL;
+++ /dev/null
-From 91da858c9327352c17a1f20ec10e78113ed45c82 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 6 Nov 2019 13:58:18 +0000
-Subject: [PATCH] staging: vchiq_arm: Unify the unload handling of
- platform devs
-
-A helper function vchiq_register_child was added to deal with
-adding the platform devices. This returns NULL on failure, and
-that is assigned to the struct platform_device. There is
-therefore no way for remove to encounter an error pointer, so
-checking for IS_ERR() is redundant.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3268,8 +3268,7 @@ failed_platform_init:
-
- static int vchiq_remove(struct platform_device *pdev)
- {
-- if (!IS_ERR(bcm2835_camera))
-- platform_device_unregister(bcm2835_camera);
-+ platform_device_unregister(bcm2835_camera);
- platform_device_unregister(bcm2835_codec);
- platform_device_unregister(vcsm_cma);
- vchiq_debugfs_deinit();
--- /dev/null
+From 43406ddc1adaebe9b03d010fd024a96cee139cc2 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 23 Aug 2019 16:34:38 +0100
+Subject: [PATCH] v3d_drv: Handle missing clock more gracefully
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -286,9 +286,9 @@ static int v3d_platform_drm_probe(struct
+ }
+
+ v3d->clk = devm_clk_get(dev, NULL);
+- if (IS_ERR(v3d->clk)) {
+- if (ret != -EPROBE_DEFER)
+- dev_err(dev, "Failed to get clock\n");
++ 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));
+ goto dev_free;
+ }
+ v3d->clk_up_rate = clk_get_rate(v3d->clk);
+++ /dev/null
-From c2863af34286fda317891bb893f8a2e16bf5707e Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 14 Nov 2019 11:59:01 +0000
-Subject: [PATCH] net: bcmgenet: The second IRQ is optional
-
-As of 5.4, the kernel logs errors for absent IRQs unless requested
-with platform_get_irq_optional.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_irq.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/gpu/drm/v3d/v3d_irq.c
-+++ b/drivers/gpu/drm/v3d/v3d_irq.c
-@@ -217,7 +217,7 @@ v3d_irq_init(struct v3d_dev *v3d)
- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
-
-- irq1 = platform_get_irq(v3d->pdev, 1);
-+ irq1 = platform_get_irq_optional(v3d->pdev, 1);
- if (irq1 == -EPROBE_DEFER)
- return irq1;
- if (irq1 > 0) {
--- /dev/null
+From a19956ff2941b73204c96127a22edef71b5d0d34 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 9 Sep 2019 23:50:44 +0100
+Subject: [PATCH] v3d_drv: Allow clock retrieval by name
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ 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));
+++ /dev/null
-From 92f17eecf263f3705a6e1a4f27ecb273ed3a33e5 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 14 Nov 2019 12:00:43 +0000
-Subject: [PATCH] drm/v3d: The third IRQ is optional
-
-As of 5.4, the kernel logs errors for absent IRQs unless requested
-with platform_get_irq_optional.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -3468,7 +3468,7 @@ static int bcmgenet_probe(struct platfor
- priv = netdev_priv(dev);
- priv->irq0 = platform_get_irq(pdev, 0);
- priv->irq1 = platform_get_irq(pdev, 1);
-- priv->wol_irq = platform_get_irq(pdev, 2);
-+ priv->wol_irq = platform_get_irq_optional(pdev, 2);
- if (!priv->irq0 || !priv->irq1) {
- dev_err(&pdev->dev, "can't find IRQs\n");
- err = -EINVAL;
--- /dev/null
+From dfc842c139ef08e21647c43c19c2a23090b65b27 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Thu, 5 Sep 2019 17:59:14 +0100
+Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are
+ using firmware clock interface
+
+Setting the v3d clock to low value allows firmware to handle dvfs in case
+where v3d hardware is not being actively used (e.g. console use).
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -918,6 +918,10 @@ v3d_gem_init(struct drm_device *dev)
+ mutex_init(&v3d->clk_lock);
+ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
+
++ /* kick the clock so firmware knows we are using firmware clock interface */
++ v3d_clock_up_get(v3d);
++ v3d_clock_up_put(v3d);
++
+ /* Note: We don't allocate address 0. Various bits of HW
+ * treat 0 as special, such as the occlusion query counters
+ * where 0 means "disabled".
--- /dev/null
+From 3e2eb77ba8d0c6913138382512309e7892907a1c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 9 Sep 2019 15:49:56 +0100
+Subject: [PATCH] clk-raspberrypi: Allow cpufreq driver to also adjust
+ gpu clocks
+
+For performance/power it is beneficial to adjust gpu clocks with arm clock.
+This is how the downstream cpufreq driver works
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -70,7 +70,7 @@ static int raspberrypi_clock_property(st
+ struct raspberrypi_firmware_prop msg = {
+ .id = cpu_to_le32(clk),
+ .val = cpu_to_le32(*val),
+- .disable_turbo = cpu_to_le32(1),
++ .disable_turbo = cpu_to_le32(0),
+ };
+ int ret;
+
+++ /dev/null
-From 941d43e29b1fa7352eb006b5ec37d6990ed3b877 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 15 Nov 2019 08:48:08 +0000
-Subject: [PATCH] dwc_otg: Declare DMA capability with HCD_DMA flag
-
-Following [1], USB controllers have to declare DMA capabilities in
-order for them to be used by adding the HCD_DMA flag to their hc_driver
-struct.
-
-[1] 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of guestimating DMA capabilities")
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -138,7 +138,7 @@ static struct hc_driver dwc_otg_hc_drive
-
- .irq = dwc_otg_hcd_irq,
-
-- .flags = HCD_MEMORY | HCD_USB2,
-+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
-
- //.reset =
- .start = hcd_start,
--- /dev/null
+From e2262c8ab4755ab574580611d7da22509f07871c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 21 Aug 2019 14:55:56 +0100
+Subject: [PATCH] clk-raspberrypi: Also support v3d clock
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ 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 <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+-
++#include <dt-bindings/clock/bcm2835.h>
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #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);
+
+++ /dev/null
-From 3223b1605ea10821a90867ee7a79d9030d7ca44f Mon Sep 17 00:00:00 2001
-From: Serge Schneider <serge@raspberrypi.org>
-Date: Thu, 31 Oct 2019 13:37:16 +0000
-Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes
-
-Signed-off-by: Serge Schneider <serge@raspberrypi.org>
----
- drivers/hwmon/rpi-poe-fan.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/hwmon/rpi-poe-fan.c
-+++ b/drivers/hwmon/rpi-poe-fan.c
-@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe
- if (ctx->def_pwm_value == def_pwm)
- goto exit_set_def_pwm_err;
-
-- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm);
-+ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm);
- if (!ret)
- ctx->def_pwm_value = def_pwm;
- exit_set_def_pwm_err:
--- /dev/null
+From 6c37f43308f29a59bc67d4ed010f8fbbf076ec79 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 3 Sep 2019 20:28:00 +0100
+Subject: [PATCH] clk-bcm2835: Disable v3d clock
+
+This is controlled by firmware, see clk-raspberrypi.c
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------
+ 1 file changed, 12 insertions(+), 18 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1716,16 +1716,12 @@ static const struct bcm2835_clk_desc clk
+ .hold_mask = CM_PLLA_HOLDCORE,
+ .fixed_divider = 1,
+ .flags = CLK_SET_RATE_PARENT),
+- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
+- SOC_ALL,
+- .name = "plla_per",
+- .source_pll = "plla",
+- .cm_reg = CM_PLLA,
+- .a2w_reg = A2W_PLLA_PER,
+- .load_mask = CM_PLLA_LOADPER,
+- .hold_mask = CM_PLLA_HOLDPER,
+- .fixed_divider = 1,
+- .flags = CLK_SET_RATE_PARENT),
++
++ /*
++ * PLLA_PER is used for gpu clocks. Controlled by firmware, see
++ * clk-raspberrypi.c.
++ */
++
+ [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
+ SOC_ALL,
+ .name = "plla_dsi0",
+@@ -2003,14 +1999,12 @@ static const struct bcm2835_clk_desc clk
+ .int_bits = 6,
+ .frac_bits = 0,
+ .tcnt_mux = 3),
+- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
+- SOC_ALL,
+- .name = "v3d",
+- .ctl_reg = CM_V3DCTL,
+- .div_reg = CM_V3DDIV,
+- .int_bits = 4,
+- .frac_bits = 8,
+- .tcnt_mux = 4),
++
++ /*
++ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see
++ * clk-raspberrypi.c.
++ */
++
+ /*
+ * VPU clock. This doesn't have an enable bit, since it drives
+ * the bus for everything else, and is special so it doesn't need
+++ /dev/null
-From eef2d9aeb08a227d0a9c5734214425a3b9693f50 Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Thu, 31 Oct 2019 14:39:44 +0000
-Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via
- device tree
-
-Add device tree entries and code to allow the specification of
-the lighting modes for the LED's on the ethernet connector.
-
-Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++
- arch/arm/boot/dts/bcm2838.dtsi | 1 +
- arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++--------
- drivers/net/phy/broadcom.c | 9 +++++++--
- 4 files changed, 31 insertions(+), 10 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -334,5 +334,8 @@
- pwr_led_gpio = <&pwr_led>,"gpios:4";
- pwr_led_activelow = <&pwr_led>,"gpios:8";
- pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ eth_led0 = <&phy1>,"led-modes:0";
-+ eth_led1 = <&phy1>,"led-modes:4";
- };
- };
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -380,6 +380,7 @@
- /* No interrupts - use PHY_POLL */
- max-speed = <1000>;
- reg = <0x1>;
-+ led-modes = <0x02 0x02>;
- };
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -102,26 +102,38 @@ Params:
-
- eee Enable Energy Efficient Ethernet support for
- compatible devices (default "on"). See also
-- "tx_lpi_timer".
-+ "tx_lpi_timer". Pi3B+ only.
-
- eth_downshift_after Set the number of auto-negotiation failures
- after which the 1000Mbps modes are disabled.
- Legal values are 2, 3, 4, 5 and 0, where
-- 0 means never downshift (default 2).
-+ 0 means never downshift (default 2). Pi3B+ only.
-
-- eth_led0 Set mode of LED0 (usually orange) (default
-- "1"). The legal values are:
-- 0=link/activity 1=link1000/activity
-+ eth_led0 Set mode of LED0 (usually orange). The legal
-+ values are:
-+
-+ Pi3B+
-+
-+ 0=link/activity 1=link1000/activity (default)
- 2=link100/activity 3=link10/activity
- 4=link100/1000/activity 5=link10/1000/activity
- 6=link10/100/activity 14=off 15=on
-
-- eth_led1 Set mode of LED1 (usually green) (default
-- "6"). See eth_led0 for legal values.
-+ Pi4
-+
-+ 0=Speed/Activity (default) 1=Speed
-+ 2=Speed/Flash activity 3=FDX
-+ 4=Off 5=On
-+ 6=Alt 7=Speed/Flash
-+ 8=Link 9=Activity
-+
-+ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
-+ "6", Pi4 default "0"). See eth_led0 for legal
-+ values.
-
- eth_max_speed Set the maximum speed a link is allowed
- to negotiate. Legal values are 10, 100 and
-- 1000 (default 1000).
-+ 1000 (default 1000). Pi3B+ only.
-
- i2c_arm Set to "on" to enable the ARM's i2c interface
- (default "off")
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -267,6 +267,9 @@ static void bcm54xx_adjust_rxrefclk(stru
- static int bcm54xx_config_init(struct phy_device *phydev)
- {
- int reg, err, val;
-+ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
-+ BCM_LED_MULTICOLOR_LINK_ACT};
-+ struct device_node *np = phydev->mdio.dev.of_node;
-
- reg = phy_read(phydev, MII_BCM54XX_ECR);
- if (reg < 0)
-@@ -318,6 +321,8 @@ static int bcm54xx_config_init(struct ph
-
- bcm54xx_phydsp_config(phydev);
-
-+ of_property_read_u32_array(np, "led-modes", led_modes, 2);
-+
- /* Encode link speed into LED1 and LED3 pair (green/amber).
- * Also flash these two LEDs on activity. This means configuring
- * them for MULTICOLOR and encoding link/activity into them.
-@@ -327,8 +332,8 @@ static int bcm54xx_config_init(struct ph
- bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
-
- val = BCM_LED_MULTICOLOR_IN_PHASE |
-- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
-- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
-+ BCM5482_SHD_LEDS1_LED1(led_modes[0]) |
-+ BCM5482_SHD_LEDS1_LED3(led_modes[1]);
- bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
-
- return 0;
+++ /dev/null
-From 2a65ed9d89f32a0e87d99ccdfd21ab140637063a Mon Sep 17 00:00:00 2001
-From: Pierre-jean Texier <texier.pj2@gmail.com>
-Date: Wed, 6 Nov 2019 10:00:43 +0100
-Subject: [PATCH] overlays: smi: fix typo in comment (#3320)
-
-5 represent alt1 function not alt0.
-
-Signed-off-by: Pierre-Jean Texier <pjtexier@koncepto.io>
----
- arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/smi-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/smi-overlay.dts
-@@ -24,7 +24,7 @@
- these are already used as ID_SD and ID_SC */
- brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15
- 16 17 18 19 20 21 22 23 24 25>;
-- /* Alt 0: SMI */
-+ /* Alt 1: SMI */
- brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
- 5 5 5 5 5 5 5 5 5>;
- /* /CS, /WE and /OE are pulled high, as they are
--- /dev/null
+From 814af1a008845b61a08111f2f9cf7e66511ab362 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 13 Sep 2019 13:45:11 +0100
+Subject: [PATCH] raspberrypi-cpufreq: Only report integer pll divisor
+ frequencies
+
+---
+ drivers/cpufreq/raspberrypi-cpufreq.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/raspberrypi-cpufreq.c
++++ b/drivers/cpufreq/raspberrypi-cpufreq.c
+@@ -8,6 +8,7 @@
+ #include <linux/clk.h>
+ #include <linux/cpu.h>
+ #include <linux/cpufreq.h>
++#include <linux/math64.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_opp.h>
+@@ -22,6 +23,7 @@ static int raspberrypi_cpufreq_probe(str
+ unsigned long min, max;
+ unsigned long rate;
+ struct clk *clk;
++ int div;
+ int ret;
+
+ cpu_dev = get_cpu_device(0);
+@@ -44,7 +46,10 @@ static int raspberrypi_cpufreq_probe(str
+ max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
+ clk_put(clk);
+
+- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
++ for (div = 2; ; div++) {
++ rate = div_u64((u64)max * 2, div);
++ if (rate < min)
++ break;
+ ret = dev_pm_opp_add(cpu_dev, rate, 0);
+ if (ret)
+ goto remove_opp;
--- /dev/null
+From 4768e4d0e87e5814d3f315f7a575cad123fc2e36 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 22 Nov 2019 15:08:25 +0000
+Subject: [PATCH] arm/dts: Correct Pi 4B LED values
+
+The initial PHY LED settings are wrong Pi 4B (the correct values got
+dropped somewhere along the way). The PHY declaration should arguably
+go in a separate file included by bcm2711-rpi-4-b.dts, but we can
+fix that as we switch over to using more of the upstream BCM2711
+support in 5.4 and later.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 2 +-
+ arch/arm/boot/dts/overlays/README | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -380,7 +380,7 @@
+ /* No interrupts - use PHY_POLL */
+ max-speed = <1000>;
+ reg = <0x1>;
+- led-modes = <0x02 0x02>;
++ led-modes = <0x00 0x08>; /* link/activity link */
+ };
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -128,7 +128,7 @@ Params:
+ 8=Link 9=Activity
+
+ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
+- "6", Pi4 default "0"). See eth_led0 for legal
++ "6", Pi4 default "8"). See eth_led0 for legal
+ values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+++ /dev/null
-From e459a2c448d7d71718769a9966543a964d1803bd Mon Sep 17 00:00:00 2001
-From: James Hughes <james.hughes@raspberrypi.org>
-Date: Thu, 7 Nov 2019 14:59:59 +0000
-Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions
-
-This should return default behaviour back to that of previous
-releases.
----
- drivers/net/phy/broadcom.c | 6 +-----
- 1 file changed, 1 insertion(+), 5 deletions(-)
-
---- a/drivers/net/phy/broadcom.c
-+++ b/drivers/net/phy/broadcom.c
-@@ -268,7 +268,7 @@ static int bcm54xx_config_init(struct ph
- {
- int reg, err, val;
- u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT,
-- BCM_LED_MULTICOLOR_LINK_ACT};
-+ BCM_LED_MULTICOLOR_LINK};
- struct device_node *np = phydev->mdio.dev.of_node;
-
- reg = phy_read(phydev, MII_BCM54XX_ECR);
-@@ -323,10 +323,6 @@ static int bcm54xx_config_init(struct ph
-
- of_property_read_u32_array(np, "led-modes", led_modes, 2);
-
-- /* Encode link speed into LED1 and LED3 pair (green/amber).
-- * Also flash these two LEDs on activity. This means configuring
-- * them for MULTICOLOR and encoding link/activity into them.
-- */
- val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
- BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
- bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
--- /dev/null
+From 159ccf0090f202cf031fa429df22e8b3f775ece8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 22 Nov 2019 16:23:32 +0000
+Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask
+
+Both coherent_dma_mask and dma_mask act as constraints on allocations
+and bounce buffer usage, so be sure to set dma_mask to the appropriate
+value otherwise the effective mask could be incorrect.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/gpu/drm/v3d/v3d_drv.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/v3d/v3d_drv.c
++++ b/drivers/gpu/drm/v3d/v3d_drv.c
+@@ -259,8 +259,8 @@ static int v3d_platform_drm_probe(struct
+ goto dev_free;
+
+ mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
+- dev->coherent_dma_mask =
+- DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
++ dma_set_mask_and_coherent(dev,
++ DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)));
+ v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
+
+ ident1 = V3D_READ(V3D_HUB_IDENT1);
+++ /dev/null
-From 62cd48ebf18c1eb0bbddba080476201bdfae4126 Mon Sep 17 00:00:00 2001
-From: Michael Kaplan <m.kaplan@evva.com>
-Date: Fri, 8 Nov 2019 10:35:57 +0100
-Subject: [PATCH] overlays: Add apds9960 overlay
-
-Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor.
-Also update overlay README and Makefile.
-
-Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 8 +++
- .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++
- 3 files changed, 66 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- allo-katana-dac-audio.dtbo \
- allo-piano-dac-pcm512x-audio.dtbo \
- allo-piano-dac-plus-pcm512x-audio.dtbo \
-+ apds9960.dtbo \
- applepi-dac.dtbo \
- at86rf233.dtbo \
- audioinjector-addons.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga
- better voice quality. (default Off)
-
-
-+Name: apds9960
-+Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
-+ gesture sensor
-+Load: dtoverlay=apds9960,<param>=<val>
-+Params: gpiopin GPIO used for INT (default 4)
-+ noints Disable the interrupt GPIO line.
-+
-+
- Name: applepi-dac
- Info: Configures the Orchard Audio ApplePi-DAC audio card
- Load: dtoverlay=applepi-dac
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts
-@@ -0,0 +1,57 @@
-+// Definitions for APDS-9960 ambient light and gesture sensor
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ apds9960_pins: apds9960_pins@39 {
-+ brcm,pins = <4>;
-+ brcm,function = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ apds9960: apds@39 {
-+ compatible = "avago,apds9960";
-+ reg = <0x39>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ apds9960_irq: apds@39 {
-+ #interrupt-cells=<2>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <4 1>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpiopin = <&apds9960_pins>,"brcm,pins:0",
-+ <&apds9960_irq>,"interrupts:0";
-+ noints = <0>,"!1!3";
-+ };
-+};
-+
--- /dev/null
+From ea94fb0b5693c354e5281eb3fcdbc9700cdd3d7f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 28 Nov 2019 15:49:08 +0000
+Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias
+
+It is useful for the firmware to be able to locate the pcie DT node,
+so add an alias pointing to it in the same way that "ethernet0"
+points to the genet.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -30,6 +30,7 @@
+ /delete-property/ ethernet;
+ /delete-property/ intc;
+ ethernet0 = &genet;
++ pcie0 = &pcie_0;
+ };
+ };
+
+++ /dev/null
-From d24bb9c4b5d3b0bb2bd5dd922bae3fce894ab87e Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 1 Oct 2019 10:19:50 +0100
-Subject: [PATCH] overlays: Remove hack from uart0 overlay
-
-The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs
-when the UART0 function was moved to alternative pins. This has the
-unwanted side effect of claiming GPIOs 14 & 15, preventing them being
-used for something else.
-
-See: https://github.com/raspberrypi/linux/issues/2856
- https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911
-
-Signed-off-by: Stefan Enge <stefan.enge@escatec.com>
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++-------
- 1 file changed, 6 insertions(+), 7 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
-@@ -17,17 +17,16 @@
- target = <&gpio>;
- __overlay__ {
- uart0_pins: uart0_pins {
-- brcm,pins = <14 15 14 15>;
-- brcm,function = <0 0 4 4>; /* alt0 */
-- brcm,pull = <0 0 0 2>;
-+ brcm,pins = <14 15>;
-+ brcm,function = <4>; /* alt0 */
-+ brcm,pull = <0 2>;
- };
- };
- };
-
- __overrides__ {
-- txd0_pin = <&uart0_pins>,"brcm,pins:8";
-- rxd0_pin = <&uart0_pins>,"brcm,pins:12";
-- pin_func = <&uart0_pins>,"brcm,function:8",
-- <&uart0_pins>,"brcm,function:12";
-+ txd0_pin = <&uart0_pins>,"brcm,pins:0";
-+ rxd0_pin = <&uart0_pins>,"brcm,pins:4";
-+ pin_func = <&uart0_pins>,"brcm,function:0";
- };
- };
+++ /dev/null
-From 47a9af99289ef0b9d60a72cd7147958e4745468c Mon Sep 17 00:00:00 2001
-From: Peter Robinson <pbrobinson@gmail.com>
-Date: Sun, 17 Nov 2019 16:20:24 +0000
-Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream
- compatible
-
-The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible
-string explicitly for this screen config and not a hx8357d generic for
-the controller so add that in as well so it will work with an unmodified
-upstream kernel driver. We leave the downstream as the priority.
-
-Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
----
- arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
-@@ -49,7 +49,7 @@
- #size-cells = <0>;
-
- pitft: pitft@0{
-- compatible = "himax,hx8357d";
-+ compatible = "himax,hx8357d", "adafruit,yx350hv15";
- reg = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&pitft_pins>;
--- /dev/null
+From 01f45f7d4403e40f28f626296bec3ccae1b1f65b Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Sat, 30 Nov 2019 23:10:26 +0100
+Subject: [PATCH] rpi-cirrus-wm5102-overlay: fix pinctrl configuration
+
+Separate GPIOs connected to wm5102 and wm8804 into 2 pinctrl
+blocks and properly reference them from the DT nodes to have
+correct pinmux owners.
+
+Setup spi0 to use only one CS line on GPIO7 so that GPIO8 is
+no longer claimed by spi0 but can be used by wm8804.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ .../overlays/rpi-cirrus-wm5102-overlay.dts | 40 ++++++++++++++-----
+ 1 file changed, 30 insertions(+), 10 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
+@@ -18,19 +18,31 @@
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+- wlf_pins: wlf_pins {
+- brcm,pins = <17 22 27 8>;
++ wlf_5102_pins: wlf_5102_pins {
++ brcm,pins = <17 22 27>;
+ brcm,function = <
+ BCM2835_FSEL_GPIO_OUT
+ BCM2835_FSEL_GPIO_OUT
+ BCM2835_FSEL_GPIO_IN
+- BCM2835_FSEL_GPIO_OUT
+ >;
+ };
++ wlf_8804_pins: wlf_8804_pins {
++ brcm,pins = <8>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
+ };
+ };
+
+ fragment@2 {
++ target = <&spi0_cs_pins>;
++ __overlay__ {
++ brcm,pins = <7>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++ };
++
++
++ fragment@3 {
+ target-path = "/";
+ __overlay__ {
+ rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 {
+@@ -43,30 +55,34 @@
+ };
+ };
+
+- fragment@3 {
++ fragment@4 {
+ target = <&spidev0>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+
+- fragment@4 {
++ fragment@5 {
+ target = <&spidev1>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+
+- fragment@5 {
++ fragment@6 {
+ target = <&spi0>;
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
++ cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
+
+- wm5102@1{
++ wm5102@0{
+ compatible = "wlf,wm5102";
+- reg = <1>;
++ reg = <0>;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&wlf_5102_pins>;
+
+ spi-max-frequency = <500000>;
+
+@@ -123,7 +139,7 @@
+ };
+ };
+
+- fragment@6 {
++ fragment@7 {
+ target = <&i2c1>;
+ __overlay__ {
+ status = "okay";
+@@ -134,6 +150,10 @@
+ compatible = "wlf,wm8804";
+ reg = <0x3b>;
+ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&wlf_8804_pins>;
++
+ PVDD-supply = <&vdd_3v3_reg>;
+ DVDD-supply = <&vdd_3v3_reg>;
+ wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
+@@ -141,7 +161,7 @@
+ };
+ };
+
+- fragment@7 {
++ fragment@8 {
+ target = <&sound>;
+ __overlay__ {
+ compatible = "wlf,rpi-cirrus";
--- /dev/null
+From a9b691174273348a6818213b9f008ae555e1c98c Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 29 Jan 2019 16:13:25 +0000
+Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child
+ devices
+
+The VCHIQ driver now loads the audio, camera, codec, and vc-sm
+drivers as platform drivers. However they were not being given
+the correct DMA configuration.
+
+Call of_dma_configure with the parent (VCHIQ) parameters to be
+inherited by the child.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3195,6 +3195,12 @@ vchiq_register_child(struct platform_dev
+ child = NULL;
+ }
+
++ /*
++ * We want the dma-ranges etc to be copied from the parent VCHIQ device
++ * to be passed on to the children too.
++ */
++ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
++
+ return child;
+ }
+
+++ /dev/null
-From 43406ddc1adaebe9b03d010fd024a96cee139cc2 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Fri, 23 Aug 2019 16:34:38 +0100
-Subject: [PATCH] v3d_drv: Handle missing clock more gracefully
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -286,9 +286,9 @@ static int v3d_platform_drm_probe(struct
- }
-
- v3d->clk = devm_clk_get(dev, NULL);
-- if (IS_ERR(v3d->clk)) {
-- if (ret != -EPROBE_DEFER)
-- dev_err(dev, "Failed to get clock\n");
-+ 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));
- goto dev_free;
- }
- v3d->clk_up_rate = clk_get_rate(v3d->clk);
--- /dev/null
+From 6aa74a52e014952b1a144def670a03a7deb0e112 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Tue, 18 Jun 2019 12:15:50 +0100
+Subject: [PATCH] staging: vchiq: Use the old dma controller for OF
+ config on platform devices
+
+vchiq on Pi4 is no longer under the soc node, therefore it
+doesn't get the dma-ranges for the VPU.
+
+Switch to using the configuration of the old dma controller as
+that will set the dma-ranges correctly.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3181,6 +3181,7 @@ vchiq_register_child(struct platform_dev
+ {
+ struct platform_device_info pdevinfo;
+ struct platform_device *child;
++ struct device_node *np;
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+
+@@ -3196,10 +3197,20 @@ vchiq_register_child(struct platform_dev
+ }
+
+ /*
+- * We want the dma-ranges etc to be copied from the parent VCHIQ device
+- * to be passed on to the children too.
++ * We want the dma-ranges etc to be copied from a device with the
++ * correct dma-ranges for the VPU.
++ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges.
++ * Take the "dma" node as going to be suitable as it sees the world
++ * through the same eyes as the VPU.
+ */
+- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
++ np = of_find_node_by_path("dma");
++ if (!np)
++ np = pdev->dev.of_node;
++
++ of_dma_configure(&child->dev, np, true);
++
++ if (np != pdev->dev.of_node)
++ of_node_put(np);
+
+ return child;
+ }
+++ /dev/null
-From a19956ff2941b73204c96127a22edef71b5d0d34 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 9 Sep 2019 23:50:44 +0100
-Subject: [PATCH] v3d_drv: Allow clock retrieval by name
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- 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));
--- /dev/null
+From 271a9dfee2eb426ca9ec1ef51c6205de8496b803 Mon Sep 17 00:00:00 2001
+From: Hui Wang <hui.wang@canonical.com>
+Date: Sun, 17 Nov 2019 10:31:46 +0800
+Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early
+ (#3332)
+
+After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't
+work well on Pi2/3 boards with 1G physical ram. Users experience
+the failure when copying a file of 600M size to the USB stick. And
+at the same time, the dmesg shows:
+usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg
+sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
+blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0
+
+When this happens, the sg_buf sent to the driver is located in the
+highmem region, the usb_sg_init() in the core/message.c will leave
+transfer_buffer to NULL if the sg_buf is in highmem, but in the
+dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer
+is NULL.
+
+The driver can handle the situation of buffer to be NULL, if it is in
+DMA mode, it will convert an address from transfer_dma.
+
+But if the conversion fails or it is in the PIO mode, we should check
+buffer and return -EINVAL if it is NULL.
+
+BugLink: https://bugs.launchpad.net/bugs/1852510
+Signed-off-by: Hui Wang <hui.wang@canonical.com>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -821,10 +821,6 @@ static int dwc_otg_urb_enqueue(struct us
+ dump_urb_info(urb, "dwc_otg_urb_enqueue");
+ }
+ #endif
+-
+- if (!urb->transfer_buffer && urb->transfer_buffer_length)
+- return -EINVAL;
+-
+ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+ || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+ if (!dwc_otg_hcd_is_bandwidth_allocated
+@@ -881,6 +877,13 @@ static int dwc_otg_urb_enqueue(struct us
+ &urb->transfer_dma, buf);
+ }
+
++ if (!buf && urb->transfer_buffer_length) {
++ DWC_FREE(dwc_otg_urb);
++ DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
++ "transfer_buffer and transfer_dma are NULL in DMA mode\n");
++ return -EINVAL;
++ }
++
+ if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+ flags |= URB_GIVEBACK_ASAP;
+ if (urb->transfer_flags & URB_ZERO_PACKET)
+++ /dev/null
-From dfc842c139ef08e21647c43c19c2a23090b65b27 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Thu, 5 Sep 2019 17:59:14 +0100
-Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are
- using firmware clock interface
-
-Setting the v3d clock to low value allows firmware to handle dvfs in case
-where v3d hardware is not being actively used (e.g. console use).
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/gpu/drm/v3d/v3d_gem.c
-+++ b/drivers/gpu/drm/v3d/v3d_gem.c
-@@ -918,6 +918,10 @@ v3d_gem_init(struct drm_device *dev)
- mutex_init(&v3d->clk_lock);
- INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
-
-+ /* kick the clock so firmware knows we are using firmware clock interface */
-+ v3d_clock_up_get(v3d);
-+ v3d_clock_up_put(v3d);
-+
- /* Note: We don't allocate address 0. Various bits of HW
- * treat 0 as special, such as the occlusion query counters
- * where 0 means "disabled".
+++ /dev/null
-From 3e2eb77ba8d0c6913138382512309e7892907a1c Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 9 Sep 2019 15:49:56 +0100
-Subject: [PATCH] clk-raspberrypi: Allow cpufreq driver to also adjust
- gpu clocks
-
-For performance/power it is beneficial to adjust gpu clocks with arm clock.
-This is how the downstream cpufreq driver works
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/clk/bcm/clk-raspberrypi.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -70,7 +70,7 @@ static int raspberrypi_clock_property(st
- struct raspberrypi_firmware_prop msg = {
- .id = cpu_to_le32(clk),
- .val = cpu_to_le32(*val),
-- .disable_turbo = cpu_to_le32(1),
-+ .disable_turbo = cpu_to_le32(0),
- };
- int ret;
-
--- /dev/null
+From 00f01136b1c165e0f4a190fcb5ec8aa11428362f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 9 Dec 2019 12:32:20 +0000
+Subject: [PATCH] overlays: Make mcp342x run-time compatible
+
+The order of processing of run-time overlays differs from that done by
+the firmware. This means that certain parameter processing techniques
+are not compatible with run-time use. The mcp342x overlay is one such
+overlay, but it is easy to change the implementation without changing
+the interface.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++----
+ 1 file changed, 102 insertions(+), 31 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
+@@ -8,14 +8,15 @@
+
+ fragment@0 {
+ target = <&i2c1>;
+- __overlay__ {
++ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "okay";
+
+- mcp342x: mcp@68 {
++ mcp3421: mcp@68 {
+ reg = <0x68>;
++ compatible = "microchip,mcp3421";
+
+ status = "okay";
+ };
+@@ -23,71 +24,141 @@
+ };
+
+ fragment@1 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3421";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3422: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3422";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@2 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3422";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3423: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3423";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@3 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3423";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3424: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3424";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@4 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3424";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3425: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3425","mcp3425";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@5 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3425";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3426: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3426";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@6 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3426";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "okay";
++
++ mcp3427: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3427";
++
++ status = "okay";
++ };
+ };
+ };
+
+ fragment@7 {
+- target = <&mcp342x>;
++ target = <&i2c1>;
+ __dormant__ {
+- compatible = "microchip,mcp3427";
+- };
+- };
++ #address-cells = <1>;
++ #size-cells = <0>;
+
+- fragment@8 {
+- target = <&mcp342x>;
+- __dormant__ {
+- compatible = "microchip,mcp3428";
++ status = "okay";
++
++ mcp3428: mcp@68 {
++ reg = <0x68>;
++ compatible = "microchip,mcp3428";
++
++ status = "okay";
++ };
+ };
+ };
+
+ __overrides__ {
+- addr = <&mcp342x>,"reg:0";
+- mcp3421 = <0>,"=1";
+- mcp3422 = <0>,"=2";
+- mcp3423 = <0>,"=3";
+- mcp3424 = <0>,"=4";
+- mcp3425 = <0>,"=5";
+- mcp3426 = <0>,"=6";
+- mcp3427 = <0>,"=7";
+- mcp3428 = <0>,"=8";
++ addr = <&mcp3421>,"reg:0",
++ <&mcp3422>,"reg:0",
++ <&mcp3423>,"reg:0",
++ <&mcp3424>,"reg:0",
++ <&mcp3425>,"reg:0",
++ <&mcp3426>,"reg:0",
++ <&mcp3427>,"reg:0",
++ <&mcp3428>,"reg:0";
++ mcp3421 = <0>,"=0";
++ mcp3422 = <0>,"=1";
++ mcp3423 = <0>,"=2";
++ mcp3424 = <0>,"=3";
++ mcp3425 = <0>,"=4";
++ mcp3426 = <0>,"=5";
++ mcp3427 = <0>,"=6";
++ mcp3428 = <0>,"=7";
+ };
+ };
+
+++ /dev/null
-From e2262c8ab4755ab574580611d7da22509f07871c Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 21 Aug 2019 14:55:56 +0100
-Subject: [PATCH] clk-raspberrypi: Also support v3d clock
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- 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 <linux/io.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
--
-+#include <dt-bindings/clock/bcm2835.h>
- #include <soc/bcm2835/raspberrypi-firmware.h>
-
- #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);
-
--- /dev/null
+From ea2cfc97596be37164d2f5d3d1a4f5e2d6cca062 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Mon, 16 Dec 2019 23:25:44 +0100
+Subject: [PATCH] rpi-cirrus-wm5102-overlay: use reset-gpios instead of
+ wlf,reset
+
+wlf,reset has been deprecated in favour of the standard reset-gpios
+DT property in commit fced2963d84b44990f4aa99ed7268223c294c0df so
+let's use that instead of the old property.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
+@@ -104,7 +104,7 @@
+ SPKVDDR-supply = <&vdd_5v0_reg>;
+ DCVDD-supply = <&arizona_ldo1>;
+
+- wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>;
++ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+ wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>;
+ wlf,gpio-defaults = <
+ ARIZONA_GP_DEFAULT
+++ /dev/null
-From 6c37f43308f29a59bc67d4ed010f8fbbf076ec79 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Tue, 3 Sep 2019 20:28:00 +0100
-Subject: [PATCH] clk-bcm2835: Disable v3d clock
-
-This is controlled by firmware, see clk-raspberrypi.c
-
-Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------
- 1 file changed, 12 insertions(+), 18 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -1716,16 +1716,12 @@ static const struct bcm2835_clk_desc clk
- .hold_mask = CM_PLLA_HOLDCORE,
- .fixed_divider = 1,
- .flags = CLK_SET_RATE_PARENT),
-- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV(
-- SOC_ALL,
-- .name = "plla_per",
-- .source_pll = "plla",
-- .cm_reg = CM_PLLA,
-- .a2w_reg = A2W_PLLA_PER,
-- .load_mask = CM_PLLA_LOADPER,
-- .hold_mask = CM_PLLA_HOLDPER,
-- .fixed_divider = 1,
-- .flags = CLK_SET_RATE_PARENT),
-+
-+ /*
-+ * PLLA_PER is used for gpu clocks. Controlled by firmware, see
-+ * clk-raspberrypi.c.
-+ */
-+
- [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV(
- SOC_ALL,
- .name = "plla_dsi0",
-@@ -2003,14 +1999,12 @@ static const struct bcm2835_clk_desc clk
- .int_bits = 6,
- .frac_bits = 0,
- .tcnt_mux = 3),
-- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK(
-- SOC_ALL,
-- .name = "v3d",
-- .ctl_reg = CM_V3DCTL,
-- .div_reg = CM_V3DDIV,
-- .int_bits = 4,
-- .frac_bits = 8,
-- .tcnt_mux = 4),
-+
-+ /*
-+ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see
-+ * clk-raspberrypi.c.
-+ */
-+
- /*
- * VPU clock. This doesn't have an enable bit, since it drives
- * the bus for everything else, and is special so it doesn't need
--- /dev/null
+From 3a0fad11000e1533c3132e024304cbe8b4f0f826 Mon Sep 17 00:00:00 2001
+From: Johannes Krude <johannes@krude.de>
+Date: Sat, 16 Nov 2019 12:41:06 +0100
+Subject: [PATCH] sound/soc: only first codec is master in multicodec
+ setup
+
+When using multiple codecs, at most one codec should generate the master
+clock. All codecs except the first are therefore configured for slave
+mode.
+
+Signed-off-by: Johannes Krude <johannes@krude.de>
+---
+ sound/soc/soc-core.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -1646,7 +1646,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
+ int ret;
+
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
++ unsigned int codec_dai_fmt = dai_fmt;
++
++ // there can only be one master when using multiple codecs
++ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) {
++ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
++ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
++ }
++
++ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ dev_warn(codec_dai->dev,
+ "ASoC: Failed to set DAI format: %d\n", ret);
--- /dev/null
+From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001
+From: Johannes Krude <johannes@krude.de>
+Date: Sat, 16 Nov 2019 13:14:43 +0100
+Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
+
+Signed-off-by: Johannes Krude <johannes@krude.de>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 20 ++
+ .../dts/overlays/justboom-both-overlay.dts | 65 +++++
+ sound/soc/bcm/Kconfig | 12 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/justboom-both.c | 266 ++++++++++++++++++
+ 11 files changed, 371 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts
+ create mode 100644 sound/soc/bcm/justboom-both.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ iqaudio-digi-wm8804-audio.dtbo \
+ irs1125.dtbo \
+ jedec-spi-nor.dtbo \
++ justboom-both.dtbo \
+ justboom-dac.dtbo \
+ justboom-digi.dtbo \
+ ltc294x.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1388,6 +1388,26 @@ Params: flash-spi<n>-<m> Enables
+ on SPI<n>, CS#<m>.
+
+
++Name: justboom-both
++Info: Simultaneous usage of an justboom-dac and justboom-digi based
++ card
++Load: dtoverlay=justboom-both,<param>=<val>
++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
++ Digital volume control. Enable with
++ "dtoverlay=justboom-dac,24db_digital_gain"
++ (The default behaviour is that the Digital
++ volume control is limited to a maximum of
++ 0dB. ie. it can attenuate but not provide
++ gain. For most users, this will be desired
++ as it will prevent clipping. By appending
++ the 24dB_digital_gain parameter, the Digital
++ volume control will allow up to 24dB of
++ gain. If this parameter is enabled, it is the
++ responsibility of the user to ensure that
++ the Digital volume control is set to a value
++ that does not result in clipping/distortion!)
++
++
+ Name: justboom-dac
+ Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
+ cards
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
+@@ -0,0 +1,65 @@
++// SPDX-License-Identifier: GPL-2.0
++// Definitions for JustBoom Both (Digi+DAC)
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ wm8804@3b {
++ #sound-dai-cells = <0>;
++ compatible = "wlf,wm8804";
++ reg = <0x3b>;
++ PVDD-supply = <&vdd_3v3_reg>;
++ DVDD-supply = <&vdd_3v3_reg>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm5122@4d {
++ #sound-dai-cells = <0>;
++ compatible = "ti,pcm5122";
++ reg = <0x4d>;
++ AVDD-supply = <&vdd_3v3_reg>;
++ DVDD-supply = <&vdd_3v3_reg>;
++ CPVDD-supply = <&vdd_3v3_reg>;
++ status = "okay";
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ frag3: __overlay__ {
++ compatible = "justboom,justboom-both";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++
++ __overrides__ {
++ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
++ };
++};
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -105,6 +105,18 @@ config SND_BCM2708_SOC_RPI_PROTO
+ help
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
+
++config SND_BCM2708_SOC_JUSTBOOM_BOTH
++ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_WM8804
++ select SND_SOC_PCM512x
++ help
++ Say Y or M if you want to add support for simultaneous
++ JustBoom Digi and JustBoom DAC.
++
++ This is not the right choice if you only have one but both of
++ these cards.
++
+ config SND_BCM2708_SOC_JUSTBOOM_DAC
+ tristate "Support for JustBoom DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -17,6 +17,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
++snd-soc-justboom-both-objs := justboom-both.o
+ snd-soc-justboom-dac-objs := justboom-dac.o
+ snd-soc-rpi-cirrus-objs := rpi-cirrus.o
+ snd-soc-rpi-proto-objs := rpi-proto.o
+@@ -43,6 +44,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
++obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
+ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
+ obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
+--- /dev/null
++++ b/sound/soc/bcm/justboom-both.c
+@@ -0,0 +1,266 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
++ *
++ * Authors: Johannes Krude <johannes@krude.de
++ *
++ * Driver for when connecting simultaneously justboom-digi and justboom-dac
++ *
++ * Based upon code from:
++ * justboom-digi.c
++ * by Milan Neskovic <info@justboom.co>
++ * justboom-dac.c
++ * by Milan Neskovic <info@justboom.co>
++ *
++ * 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 <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/jack.h>
++
++#include "../codecs/wm8804.h"
++#include "../codecs/pcm512x.h"
++
++
++static bool digital_gain_0db_limit = true;
++
++static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ /* enable TX output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ if (digital_gain_0db_limit) {
++ int ret;
++ struct snd_soc_card *card = rtd->card;
++
++ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
++ 207);
++ if (ret < 0)
++ dev_warn(card->dev, "Failed to set volume limit: %d\n",
++ ret);
++ }
++
++ return 0;
++}
++
++static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ int sysclk = 27000000; /* This is fixed on this board */
++
++ long mclk_freq = 0;
++ int mclk_div = 1;
++ int sampling_freq = 1;
++
++ int ret;
++
++ int samplerate = params_rate(params);
++
++ if (samplerate <= 96000) {
++ mclk_freq = samplerate*256;
++ mclk_div = WM8804_MCLKDIV_256FS;
++ } else {
++ mclk_freq = samplerate*128;
++ mclk_div = WM8804_MCLKDIV_128FS;
++ }
++
++ switch (samplerate) {
++ case 32000:
++ sampling_freq = 0x03;
++ break;
++ case 44100:
++ sampling_freq = 0x00;
++ break;
++ case 48000:
++ sampling_freq = 0x02;
++ break;
++ case 88200:
++ sampling_freq = 0x08;
++ break;
++ case 96000:
++ sampling_freq = 0x0a;
++ break;
++ case 176400:
++ sampling_freq = 0x0c;
++ break;
++ case 192000:
++ sampling_freq = 0x0e;
++ break;
++ default:
++ dev_err(rtd->card->dev,
++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
++ samplerate);
++ }
++
++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
++
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
++ sysclk, SND_SOC_CLOCK_OUT);
++ if (ret < 0) {
++ dev_err(rtd->card->dev,
++ "Failed to set WM8804 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ /* Enable TX output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
++
++ /* Power on */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
++
++ /* set sampling frequency status bits */
++ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
++
++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
++}
++
++static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ /* turn on digital output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++
++ return 0;
++}
++
++static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
++ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
++
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++
++ /* turn off output */
++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_justboom_both_ops = {
++ .hw_params = snd_rpi_justboom_both_hw_params,
++ .startup = snd_rpi_justboom_both_startup,
++ .shutdown = snd_rpi_justboom_both_shutdown,
++};
++
++SND_SOC_DAILINK_DEFS(rpi_justboom_both,
++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
++ COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
++
++static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
++{
++ .name = "JustBoom Digi",
++ .stream_name = "JustBoom Digi HiFi",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM,
++ .ops = &snd_rpi_justboom_both_ops,
++ .init = snd_rpi_justboom_both_init,
++ SND_SOC_DAILINK_REG(rpi_justboom_both),
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_justboom_both = {
++ .name = "snd_rpi_justboom_both",
++ .driver_name = "JustBoomBoth",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_justboom_both_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
++};
++
++static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct snd_soc_card *card = &snd_rpi_justboom_both;
++
++ snd_rpi_justboom_both.dev = &pdev->dev;
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
++
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ int i;
++
++ for (i = 0; i < card->num_links; i++) {
++ dai->cpus->dai_name = NULL;
++ dai->cpus->of_node = i2s_node;
++ dai->platforms->name = NULL;
++ dai->platforms->of_node = i2s_node;
++ }
++ }
++
++ digital_gain_0db_limit = !of_property_read_bool(
++ pdev->dev.of_node, "justboom,24db_digital_gain");
++ }
++
++ ret = snd_soc_register_card(card);
++ if (ret && ret != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ }
++
++ return ret;
++}
++
++static int snd_rpi_justboom_both_remove(struct platform_device *pdev)
++{
++ return snd_soc_unregister_card(&snd_rpi_justboom_both);
++}
++
++static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
++ { .compatible = "justboom,justboom-both", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
++
++static struct platform_driver snd_rpi_justboom_both_driver = {
++ .driver = {
++ .name = "snd-rpi-justboom-both",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_justboom_both_of_match,
++ },
++ .probe = snd_rpi_justboom_both_probe,
++ .remove = snd_rpi_justboom_both_remove,
++};
++
++module_platform_driver(snd_rpi_justboom_both_driver);
++
++MODULE_AUTHOR("Johannes Krude <johannes@krude.de>");
++MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
++MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 814af1a008845b61a08111f2f9cf7e66511ab362 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Fri, 13 Sep 2019 13:45:11 +0100
-Subject: [PATCH] raspberrypi-cpufreq: Only report integer pll divisor
- frequencies
-
----
- drivers/cpufreq/raspberrypi-cpufreq.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/cpufreq/raspberrypi-cpufreq.c
-+++ b/drivers/cpufreq/raspberrypi-cpufreq.c
-@@ -8,6 +8,7 @@
- #include <linux/clk.h>
- #include <linux/cpu.h>
- #include <linux/cpufreq.h>
-+#include <linux/math64.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_opp.h>
-@@ -22,6 +23,7 @@ static int raspberrypi_cpufreq_probe(str
- unsigned long min, max;
- unsigned long rate;
- struct clk *clk;
-+ int div;
- int ret;
-
- cpu_dev = get_cpu_device(0);
-@@ -44,7 +46,10 @@ static int raspberrypi_cpufreq_probe(str
- max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
- clk_put(clk);
-
-- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
-+ for (div = 2; ; div++) {
-+ rate = div_u64((u64)max * 2, div);
-+ if (rate < min)
-+ break;
- ret = dev_pm_opp_add(cpu_dev, rate, 0);
- if (ret)
- goto remove_opp;
+++ /dev/null
-From 4768e4d0e87e5814d3f315f7a575cad123fc2e36 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 22 Nov 2019 15:08:25 +0000
-Subject: [PATCH] arm/dts: Correct Pi 4B LED values
-
-The initial PHY LED settings are wrong Pi 4B (the correct values got
-dropped somewhere along the way). The PHY declaration should arguably
-go in a separate file included by bcm2711-rpi-4-b.dts, but we can
-fix that as we switch over to using more of the upstream BCM2711
-support in 5.4 and later.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2838.dtsi | 2 +-
- arch/arm/boot/dts/overlays/README | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -380,7 +380,7 @@
- /* No interrupts - use PHY_POLL */
- max-speed = <1000>;
- reg = <0x1>;
-- led-modes = <0x02 0x02>;
-+ led-modes = <0x00 0x08>; /* link/activity link */
- };
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -128,7 +128,7 @@ Params:
- 8=Link 9=Activity
-
- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
-- "6", Pi4 default "0"). See eth_led0 for legal
-+ "6", Pi4 default "8"). See eth_led0 for legal
- values.
-
- eth_max_speed Set the maximum speed a link is allowed
--- /dev/null
+From 5c1a2df946720816c155ff38b01bcd49a0f44f78 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 18 Dec 2019 10:41:33 +0000
+Subject: [PATCH] overlays: dht11: Allow multiple instantiation
+
+Add addresses to the dht11 and dht11_pins nodes to allow unique names
+to be generated by assigning to the "reg" property.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
+@@ -24,7 +24,7 @@
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+- dht11_pins: dht11_pins {
++ dht11_pins: dht11_pins@0 {
+ brcm,pins = <4>;
+ brcm,function = <0>; // in
+ brcm,pull = <0>; // off
+@@ -34,6 +34,8 @@
+
+ __overrides__ {
+ gpiopin = <&dht11_pins>,"brcm,pins:0",
+- <&dht11>,"gpios:4";
++ <&dht11_pins>, "reg:0",
++ <&dht11>,"gpios:4",
++ <&dht11>,"reg:0";
+ };
+ };
+++ /dev/null
-From 159ccf0090f202cf031fa429df22e8b3f775ece8 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 22 Nov 2019 16:23:32 +0000
-Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask
-
-Both coherent_dma_mask and dma_mask act as constraints on allocations
-and bounce buffer usage, so be sure to set dma_mask to the appropriate
-value otherwise the effective mask could be incorrect.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/gpu/drm/v3d/v3d_drv.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/gpu/drm/v3d/v3d_drv.c
-+++ b/drivers/gpu/drm/v3d/v3d_drv.c
-@@ -259,8 +259,8 @@ static int v3d_platform_drm_probe(struct
- goto dev_free;
-
- mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
-- dev->coherent_dma_mask =
-- DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
-+ dma_set_mask_and_coherent(dev,
-+ DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)));
- v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
-
- ident1 = V3D_READ(V3D_HUB_IDENT1);
--- /dev/null
+From 32dbe4ebb10b96eed117852f1643bf1f854d96c0 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Sun, 22 Dec 2019 15:29:40 +0000
+Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support
+
+See: https://github.com/raspberrypi/firmware/issues/1309
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++
+ 2 files changed, 18 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1078,6 +1078,8 @@ Params: abx80x Select o
+
+ pcf8523 Select the PCF8523 device
+
++ pcf85363 Select the PCF85363 device
++
+ pcf8563 Select the PCF8563 device
+
+ rv3028 Select the Micro Crystal RV3028 device
+--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+@@ -188,6 +188,21 @@
+ };
+ };
+
++ fragment@12 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcf85363@51 {
++ compatible = "nxp,pcf85363";
++ reg = <0x51>;
++ status = "okay";
++ };
++ };
++ };
++
+ __overrides__ {
+ abx80x = <0>,"+0";
+ ds1307 = <0>,"+1";
+@@ -201,6 +216,7 @@
+ m41t62 = <0>,"+9";
+ rv3028 = <0>,"+10";
+ pcf2129 = <0>,"+11";
++ pcf85363 = <0>,"+12";
+
+ addr = <&abx80x>, "reg:0",
+ <&ds1307>, "reg:0",
+++ /dev/null
-From ea94fb0b5693c354e5281eb3fcdbc9700cdd3d7f Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 28 Nov 2019 15:49:08 +0000
-Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias
-
-It is useful for the firmware to be able to locate the pcie DT node,
-so add an alias pointing to it in the same way that "ethernet0"
-points to the genet.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -30,6 +30,7 @@
- /delete-property/ ethernet;
- /delete-property/ intc;
- ethernet0 = &genet;
-+ pcie0 = &pcie_0;
- };
- };
-
--- /dev/null
+From 0cddfafa817a776063ba6f00fb439d9a415235f9 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Jan 2020 16:04:30 +0000
+Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error
+
+A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix
+the leak with the use of devm_gpiochip_add_data.
+
+Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP")
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1135,7 +1135,7 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
+- err = gpiochip_add_data(&pc->gpio_chip, pc);
++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
+ return err;
--- /dev/null
+From 27cb8bf0442f677380a1df93b93b7589b7ce5243 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Jan 2020 14:05:42 +0000
+Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs
+
+pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio
+side is registered first, but this breaks gpio hogs (which are
+configured during gpiochip_add_data). Part of the hog initialisation
+is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't
+yet been registered this results in an -EPROBE_DEFER from which it can
+never recover.
+
+Change the initialisation sequence to register the pinctrl driver
+first.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 40 ++++++++++++---------------
+ 1 file changed, 17 insertions(+), 23 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1135,9 +1135,25 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
++ if (match) {
++ bcm2835_pinctrl_desc.confops =
++ (const struct pinconf_ops *)match->data;
++ }
++
++ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
++ if (IS_ERR(pc->pctl_dev))
++ return PTR_ERR(pc->pctl_dev);
++
++ pc->gpio_range = bcm2835_pinctrl_gpio_range;
++ pc->gpio_range.base = pc->gpio_chip.base;
++ pc->gpio_range.gc = &pc->gpio_chip;
++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
++
+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1145,6 +1161,7 @@ static int bcm2835_pinctrl_probe(struct
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_info(dev, "could not add irqchip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1167,29 +1184,6 @@ static int bcm2835_pinctrl_probe(struct
+ bcm2835_gpio_irq_handler);
+ }
+
+- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+- if (match) {
+- bcm2835_pinctrl_desc.confops =
+- (const struct pinconf_ops *)match->data;
+- }
+-
+- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+- if (match) {
+- bcm2835_pinctrl_desc.confops =
+- (const struct pinconf_ops *)match->data;
+- }
+-
+- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
+- if (IS_ERR(pc->pctl_dev)) {
+- gpiochip_remove(&pc->gpio_chip);
+- return PTR_ERR(pc->pctl_dev);
+- }
+-
+- pc->gpio_range = bcm2835_pinctrl_gpio_range;
+- pc->gpio_range.base = pc->gpio_chip.base;
+- pc->gpio_range.gc = &pc->gpio_chip;
+- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+-
+ return 0;
+ }
+
+++ /dev/null
-From 01f45f7d4403e40f28f626296bec3ccae1b1f65b Mon Sep 17 00:00:00 2001
-From: Matthias Reichl <hias@horus.com>
-Date: Sat, 30 Nov 2019 23:10:26 +0100
-Subject: [PATCH] rpi-cirrus-wm5102-overlay: fix pinctrl configuration
-
-Separate GPIOs connected to wm5102 and wm8804 into 2 pinctrl
-blocks and properly reference them from the DT nodes to have
-correct pinmux owners.
-
-Setup spi0 to use only one CS line on GPIO7 so that GPIO8 is
-no longer claimed by spi0 but can be used by wm8804.
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
----
- .../overlays/rpi-cirrus-wm5102-overlay.dts | 40 ++++++++++++++-----
- 1 file changed, 30 insertions(+), 10 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-@@ -18,19 +18,31 @@
- fragment@1 {
- target = <&gpio>;
- __overlay__ {
-- wlf_pins: wlf_pins {
-- brcm,pins = <17 22 27 8>;
-+ wlf_5102_pins: wlf_5102_pins {
-+ brcm,pins = <17 22 27>;
- brcm,function = <
- BCM2835_FSEL_GPIO_OUT
- BCM2835_FSEL_GPIO_OUT
- BCM2835_FSEL_GPIO_IN
-- BCM2835_FSEL_GPIO_OUT
- >;
- };
-+ wlf_8804_pins: wlf_8804_pins {
-+ brcm,pins = <8>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
- };
- };
-
- fragment@2 {
-+ target = <&spi0_cs_pins>;
-+ __overlay__ {
-+ brcm,pins = <7>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+ };
-+
-+
-+ fragment@3 {
- target-path = "/";
- __overlay__ {
- rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 {
-@@ -43,30 +55,34 @@
- };
- };
-
-- fragment@3 {
-+ fragment@4 {
- target = <&spidev0>;
- __overlay__ {
- status = "disabled";
- };
- };
-
-- fragment@4 {
-+ fragment@5 {
- target = <&spidev1>;
- __overlay__ {
- status = "disabled";
- };
- };
-
-- fragment@5 {
-+ fragment@6 {
- target = <&spi0>;
- __overlay__ {
- #address-cells = <1>;
- #size-cells = <0>;
- status = "okay";
-+ cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
-
-- wm5102@1{
-+ wm5102@0{
- compatible = "wlf,wm5102";
-- reg = <1>;
-+ reg = <0>;
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&wlf_5102_pins>;
-
- spi-max-frequency = <500000>;
-
-@@ -123,7 +139,7 @@
- };
- };
-
-- fragment@6 {
-+ fragment@7 {
- target = <&i2c1>;
- __overlay__ {
- status = "okay";
-@@ -134,6 +150,10 @@
- compatible = "wlf,wm8804";
- reg = <0x3b>;
- status = "okay";
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&wlf_8804_pins>;
-+
- PVDD-supply = <&vdd_3v3_reg>;
- DVDD-supply = <&vdd_3v3_reg>;
- wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
-@@ -141,7 +161,7 @@
- };
- };
-
-- fragment@7 {
-+ fragment@8 {
- target = <&sound>;
- __overlay__ {
- compatible = "wlf,rpi-cirrus";
--- /dev/null
+From 67dd4d137557909279a21c1b5de87a24c84903f9 Mon Sep 17 00:00:00 2001
+From: Giedrius <giedrius@blokas.io>
+Date: Tue, 7 Jan 2020 11:04:21 +0200
+Subject: [PATCH] Pisound: MIDI communication fixes for scaled down
+ CPU.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+* Increased maximum SPI communication speed to avoid running too slow
+ when the CPU is scaled down and losing MIDI data.
+
+* Keep track of buffer usage in millibytes for higher precision.
+
+Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
+---
+ sound/soc/bcm/pisound.c | 31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -1,6 +1,6 @@
+ /*
+ * Pisound Linux kernel module.
+- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
++ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t *
+ transfer.tx_buf = txbuf;
+ transfer.rx_buf = rxbuf;
+ transfer.len = len;
+- transfer.speed_hz = 100000;
++ transfer.speed_hz = 150000;
+ transfer.delay_usecs = 10;
+ spi_message_add_tail(&transfer, &msg);
+
+@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find
+ static void pisnd_work_handler(struct work_struct *work)
+ {
+ enum { TRANSFER_SIZE = 4 };
+- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
+- enum { MIDI_BYTES_PER_SECOND = 3125 };
+- int out_buffer_used = 0;
++ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 };
++ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ };
++ int out_buffer_used_millibytes = 0;
+ unsigned long now;
+ uint8_t val;
+ uint8_t txbuf[TRANSFER_SIZE];
+@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo
+ had_data = false;
+ memset(txbuf, 0, sizeof(txbuf));
+ for (i = 0; i < sizeof(txbuf) &&
+- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
++ ((out_buffer_used_millibytes+1000 <
++ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) ||
++ g_ledFlashDurationChanged);
+ i += 2) {
+
+ val = 0;
+@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo
+ } else if (kfifo_get(&spi_fifo_out, &val)) {
+ txbuf[i+0] = 0x0f;
+ txbuf[i+1] = val;
+- ++out_buffer_used;
++ out_buffer_used_millibytes += 1000;
+ }
+ }
+
+@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo
+ * rate.
+ */
+ now = jiffies;
+- out_buffer_used -=
+- (MIDI_BYTES_PER_SECOND / HZ) /
+- (now - last_transfer_at);
+- if (out_buffer_used < 0)
+- out_buffer_used = 0;
+- last_transfer_at = now;
++ if (now != last_transfer_at) {
++ out_buffer_used_millibytes -=
++ (now - last_transfer_at) *
++ MIDI_MILLIBYTES_PER_JIFFIE;
++ if (out_buffer_used_millibytes < 0)
++ out_buffer_used_millibytes = 0;
++ last_transfer_at = now;
++ }
+
+ for (i = 0; i < sizeof(rxbuf); i += 2) {
+ if (rxbuf[i]) {
+@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo
+ || !kfifo_is_empty(&spi_fifo_out)
+ || pisnd_spi_has_more()
+ || g_ledFlashDurationChanged
++ || out_buffer_used_millibytes != 0
+ );
+
+ if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
+++ /dev/null
-From a9b691174273348a6818213b9f008ae555e1c98c Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 29 Jan 2019 16:13:25 +0000
-Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child
- devices
-
-The VCHIQ driver now loads the audio, camera, codec, and vc-sm
-drivers as platform drivers. However they were not being given
-the correct DMA configuration.
-
-Call of_dma_configure with the parent (VCHIQ) parameters to be
-inherited by the child.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3195,6 +3195,12 @@ vchiq_register_child(struct platform_dev
- child = NULL;
- }
-
-+ /*
-+ * We want the dma-ranges etc to be copied from the parent VCHIQ device
-+ * to be passed on to the children too.
-+ */
-+ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
-+
- return child;
- }
-
--- /dev/null
+From 238506ebdea7a0bb928af8403287d5b0d71cdfee Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 16 Aug 2019 22:32:02 +0200
+Subject: [PATCH] ARM: dts: bcm283x: Remove simple-bus from fixed
+ clocks
+
+commit 4b2d24662126b1e2a6b95c9dfe9e9044e105e5bd upstream.
+
+The fixed clocks doesn't form some kind of bus. So let's remove it.
+This fixes the follow DT schema warnings:
+
+clocks: clock@3:reg:0: [3] is too short
+clocks: clock@4:reg:0: [4] is too short
+clocks: $nodename:0: 'clocks' does not match '^(bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$'
+clocks: #size-cells:0:0: 0 is not one of [1, 2]
+clocks: 'ranges' is a required property
+clock@3: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+'
+clock@4: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+'
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm283x.dtsi | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -634,22 +634,16 @@
+ };
+
+ clocks {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+ /* The oscillator is the root of the clock tree. */
+- clk_osc: clock@3 {
++ clk_osc: clk-osc {
+ compatible = "fixed-clock";
+- reg = <3>;
+ #clock-cells = <0>;
+ clock-output-names = "osc";
+ clock-frequency = <19200000>;
+ };
+
+- clk_usb: clock@4 {
++ clk_usb: clk-usb {
+ compatible = "fixed-clock";
+- reg = <4>;
+ #clock-cells = <0>;
+ clock-output-names = "otg";
+ clock-frequency = <480000000>;
+++ /dev/null
-From 6aa74a52e014952b1a144def670a03a7deb0e112 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 18 Jun 2019 12:15:50 +0100
-Subject: [PATCH] staging: vchiq: Use the old dma controller for OF
- config on platform devices
-
-vchiq on Pi4 is no longer under the soc node, therefore it
-doesn't get the dma-ranges for the VPU.
-
-Switch to using the configuration of the old dma controller as
-that will set the dma-ranges correctly.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++---
- 1 file changed, 14 insertions(+), 3 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3181,6 +3181,7 @@ vchiq_register_child(struct platform_dev
- {
- struct platform_device_info pdevinfo;
- struct platform_device *child;
-+ struct device_node *np;
-
- memset(&pdevinfo, 0, sizeof(pdevinfo));
-
-@@ -3196,10 +3197,20 @@ vchiq_register_child(struct platform_dev
- }
-
- /*
-- * We want the dma-ranges etc to be copied from the parent VCHIQ device
-- * to be passed on to the children too.
-+ * We want the dma-ranges etc to be copied from a device with the
-+ * correct dma-ranges for the VPU.
-+ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges.
-+ * Take the "dma" node as going to be suitable as it sees the world
-+ * through the same eyes as the VPU.
- */
-- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true);
-+ np = of_find_node_by_path("dma");
-+ if (!np)
-+ np = pdev->dev.of_node;
-+
-+ of_dma_configure(&child->dev, np, true);
-+
-+ if (np != pdev->dev.of_node)
-+ of_node_put(np);
-
- return child;
- }
--- /dev/null
+From fcd4bc412167d2a79bf63603e883f4960ca6b2a1 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 27 Dec 2019 11:15:00 +0100
+Subject: [PATCH] ARM: dts: bcm283x: Move system timer back to
+ bcm283x.dtsi
+
+During Raspberry Pi 4 upstream discussion Tim Gover confirmed that the
+system timer also exists on BCM2711. So move it back to bcm283x.dtsi and
+overwrite the interrupt definition in bcm2838.dtsi.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2835-common.dtsi | 11 -----------
+ arch/arm/boot/dts/bcm2838.dtsi | 7 +++++++
+ arch/arm/boot/dts/bcm283x.dtsi | 11 +++++++++++
+ 3 files changed, 18 insertions(+), 11 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-common.dtsi
++++ b/arch/arm/boot/dts/bcm2835-common.dtsi
+@@ -6,17 +6,6 @@
+
+ / {
+ soc {
+- timer@7e003000 {
+- compatible = "brcm,bcm2835-system-timer";
+- reg = <0x7e003000 0x1000>;
+- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+- /* This could be a reference to BCM2835_CLOCK_TIMER,
+- * but we don't have the driver using the common clock
+- * support yet.
+- */
+- clock-frequency = <1000000>;
+- };
+-
+ intc: interrupt-controller@7e00b200 {
+ compatible = "brcm,bcm2835-armctrl-ic";
+ reg = <0x7e00b200 0x200>;
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -711,6 +711,13 @@
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
++&system_timer {
++ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
++};
++
+ &uart0 {
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ };
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -56,6 +56,17 @@
+ #address-cells = <1>;
+ #size-cells = <1>;
+
++ system_timer: timer@7e003000 {
++ compatible = "brcm,bcm2835-system-timer";
++ reg = <0x7e003000 0x1000>;
++ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
++ /* This could be a reference to BCM2835_CLOCK_TIMER,
++ * but we don't have the driver using the common clock
++ * support yet.
++ */
++ clock-frequency = <1000000>;
++ };
++
+ txp: txp@7e004000 {
+ compatible = "brcm,bcm2835-txp";
+ reg = <0x7e004000 0x20>;
+++ /dev/null
-From 271a9dfee2eb426ca9ec1ef51c6205de8496b803 Mon Sep 17 00:00:00 2001
-From: Hui Wang <hui.wang@canonical.com>
-Date: Sun, 17 Nov 2019 10:31:46 +0800
-Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early
- (#3332)
-
-After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't
-work well on Pi2/3 boards with 1G physical ram. Users experience
-the failure when copying a file of 600M size to the USB stick. And
-at the same time, the dmesg shows:
-usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg
-sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
-blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0
-
-When this happens, the sg_buf sent to the driver is located in the
-highmem region, the usb_sg_init() in the core/message.c will leave
-transfer_buffer to NULL if the sg_buf is in highmem, but in the
-dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer
-is NULL.
-
-The driver can handle the situation of buffer to be NULL, if it is in
-DMA mode, it will convert an address from transfer_dma.
-
-But if the conversion fails or it is in the PIO mode, we should check
-buffer and return -EINVAL if it is NULL.
-
-BugLink: https://bugs.launchpad.net/bugs/1852510
-Signed-off-by: Hui Wang <hui.wang@canonical.com>
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -821,10 +821,6 @@ static int dwc_otg_urb_enqueue(struct us
- dump_urb_info(urb, "dwc_otg_urb_enqueue");
- }
- #endif
--
-- if (!urb->transfer_buffer && urb->transfer_buffer_length)
-- return -EINVAL;
--
- if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
- || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
- if (!dwc_otg_hcd_is_bandwidth_allocated
-@@ -881,6 +877,13 @@ static int dwc_otg_urb_enqueue(struct us
- &urb->transfer_dma, buf);
- }
-
-+ if (!buf && urb->transfer_buffer_length) {
-+ DWC_FREE(dwc_otg_urb);
-+ DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
-+ "transfer_buffer and transfer_dma are NULL in DMA mode\n");
-+ return -EINVAL;
-+ }
-+
- if (!(urb->transfer_flags & URB_NO_INTERRUPT))
- flags |= URB_GIVEBACK_ASAP;
- if (urb->transfer_flags & URB_ZERO_PACKET)
--- /dev/null
+From d884dfd722a8207749f5c6c08b69287f0c75a553 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 27 Dec 2019 16:06:13 +0100
+Subject: [PATCH] ARM: dts: bcm283x: Move pixelvalve to
+ bcm2835-common.dtsi
+
+According to Eric Anholt the pixelvalves doesn't exists on BCM2711.
+So move it to bcm2835-common.dtsi.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2835-common.dtsi | 18 ++++++++++++++++++
+ arch/arm/boot/dts/bcm2838.dtsi | 12 ------------
+ arch/arm/boot/dts/bcm283x.dtsi | 18 ------------------
+ 3 files changed, 18 insertions(+), 30 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2835-common.dtsi
++++ b/arch/arm/boot/dts/bcm2835-common.dtsi
+@@ -13,6 +13,18 @@
+ #interrupt-cells = <2>;
+ };
+
++ pixelvalve@7e206000 {
++ compatible = "brcm,bcm2835-pixelvalve0";
++ reg = <0x7e206000 0x100>;
++ interrupts = <2 13>; /* pwa0 */
++ };
++
++ pixelvalve@7e207000 {
++ compatible = "brcm,bcm2835-pixelvalve1";
++ reg = <0x7e207000 0x100>;
++ interrupts = <2 14>; /* pwa1 */
++ };
++
+ thermal: thermal@7e212000 {
+ compatible = "brcm,bcm2835-thermal";
+ reg = <0x7e212000 0x8>;
+@@ -21,6 +33,12 @@
+ status = "disabled";
+ };
+
++ pixelvalve@7e807000 {
++ compatible = "brcm,bcm2835-pixelvalve2";
++ reg = <0x7e807000 0x100>;
++ interrupts = <2 10>; /* pixelvalve */
++ };
++
+ v3d: v3d@7ec00000 {
+ compatible = "brcm,bcm2835-v3d";
+ reg = <0x7ec00000 0x1000>;
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -188,14 +188,6 @@
+ status = "disabled";
+ };
+
+- pixelvalve@7e206000 {
+- interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- pixelvalve@7e207000 {
+- interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+ pwm1: pwm@7e20c800 {
+ compatible = "brcm,bcm2835-pwm";
+ reg = <0x7e20c800 0x28>;
+@@ -217,10 +209,6 @@
+ hvs@7e400000 {
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ };
+-
+- pixelvalve@7e807000 {
+- interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+- };
+ };
+
+ arm-pmu {
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -432,18 +432,6 @@
+ status = "disabled";
+ };
+
+- pixelvalve@7e206000 {
+- compatible = "brcm,bcm2835-pixelvalve0";
+- reg = <0x7e206000 0x100>;
+- interrupts = <2 13>; /* pwa0 */
+- };
+-
+- pixelvalve@7e207000 {
+- compatible = "brcm,bcm2835-pixelvalve1";
+- reg = <0x7e207000 0x100>;
+- interrupts = <2 14>; /* pwa1 */
+- };
+-
+ dpi: dpi@7e208000 {
+ compatible = "brcm,bcm2835-dpi";
+ reg = <0x7e208000 0x8c>;
+@@ -607,12 +595,6 @@
+ status = "disabled";
+ };
+
+- pixelvalve@7e807000 {
+- compatible = "brcm,bcm2835-pixelvalve2";
+- reg = <0x7e807000 0x100>;
+- interrupts = <2 10>; /* pixelvalve */
+- };
+-
+ hdmi: hdmi@7e902000 {
+ compatible = "brcm,bcm2835-hdmi";
+ reg = <0x7e902000 0x600>,
+++ /dev/null
-From 00f01136b1c165e0f4a190fcb5ec8aa11428362f Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 9 Dec 2019 12:32:20 +0000
-Subject: [PATCH] overlays: Make mcp342x run-time compatible
-
-The order of processing of run-time overlays differs from that done by
-the firmware. This means that certain parameter processing techniques
-are not compatible with run-time use. The mcp342x overlay is one such
-overlay, but it is easy to change the implementation without changing
-the interface.
-
-See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++----
- 1 file changed, 102 insertions(+), 31 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts
-@@ -8,14 +8,15 @@
-
- fragment@0 {
- target = <&i2c1>;
-- __overlay__ {
-+ __dormant__ {
- #address-cells = <1>;
- #size-cells = <0>;
-
- status = "okay";
-
-- mcp342x: mcp@68 {
-+ mcp3421: mcp@68 {
- reg = <0x68>;
-+ compatible = "microchip,mcp3421";
-
- status = "okay";
- };
-@@ -23,71 +24,141 @@
- };
-
- fragment@1 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3421";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3422: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3422";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@2 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3422";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3423: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3423";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@3 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3423";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3424: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3424";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@4 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3424";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3425: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3425","mcp3425";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@5 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3425";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3426: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3426";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@6 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3426";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ status = "okay";
-+
-+ mcp3427: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3427";
-+
-+ status = "okay";
-+ };
- };
- };
-
- fragment@7 {
-- target = <&mcp342x>;
-+ target = <&i2c1>;
- __dormant__ {
-- compatible = "microchip,mcp3427";
-- };
-- };
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-
-- fragment@8 {
-- target = <&mcp342x>;
-- __dormant__ {
-- compatible = "microchip,mcp3428";
-+ status = "okay";
-+
-+ mcp3428: mcp@68 {
-+ reg = <0x68>;
-+ compatible = "microchip,mcp3428";
-+
-+ status = "okay";
-+ };
- };
- };
-
- __overrides__ {
-- addr = <&mcp342x>,"reg:0";
-- mcp3421 = <0>,"=1";
-- mcp3422 = <0>,"=2";
-- mcp3423 = <0>,"=3";
-- mcp3424 = <0>,"=4";
-- mcp3425 = <0>,"=5";
-- mcp3426 = <0>,"=6";
-- mcp3427 = <0>,"=7";
-- mcp3428 = <0>,"=8";
-+ addr = <&mcp3421>,"reg:0",
-+ <&mcp3422>,"reg:0",
-+ <&mcp3423>,"reg:0",
-+ <&mcp3424>,"reg:0",
-+ <&mcp3425>,"reg:0",
-+ <&mcp3426>,"reg:0",
-+ <&mcp3427>,"reg:0",
-+ <&mcp3428>,"reg:0";
-+ mcp3421 = <0>,"=0";
-+ mcp3422 = <0>,"=1";
-+ mcp3423 = <0>,"=2";
-+ mcp3424 = <0>,"=3";
-+ mcp3425 = <0>,"=4";
-+ mcp3426 = <0>,"=5";
-+ mcp3427 = <0>,"=6";
-+ mcp3428 = <0>,"=7";
- };
- };
-
--- /dev/null
+From 91ebd8e0ceb2de047e89e1253ff8ddefbc8aa65e Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 15:32:29 +0100
+Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Fix memory node
+
+We need to declare the proper device type, otherwise U-Boot won't boot
+with this devicetree. While we are this let the bootloader set the actual
+memory size.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -14,7 +14,8 @@
+ };
+
+ memory@0 {
+- reg = <0 0 0x40000000>;
++ device_type = "memory";
++ reg = <0x0 0x0 0x0>;
+ };
+
+ leds {
+++ /dev/null
-From ea2cfc97596be37164d2f5d3d1a4f5e2d6cca062 Mon Sep 17 00:00:00 2001
-From: Matthias Reichl <hias@horus.com>
-Date: Mon, 16 Dec 2019 23:25:44 +0100
-Subject: [PATCH] rpi-cirrus-wm5102-overlay: use reset-gpios instead of
- wlf,reset
-
-wlf,reset has been deprecated in favour of the standard reset-gpios
-DT property in commit fced2963d84b44990f4aa99ed7268223c294c0df so
-let's use that instead of the old property.
-
-Signed-off-by: Matthias Reichl <hias@horus.com>
----
- arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts
-@@ -104,7 +104,7 @@
- SPKVDDR-supply = <&vdd_5v0_reg>;
- DCVDD-supply = <&arizona_ldo1>;
-
-- wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>;
-+ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
- wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>;
- wlf,gpio-defaults = <
- ARIZONA_GP_DEFAULT
--- /dev/null
+From 10430ccee66023c26c90cdbc0d6381b41dcecfb7 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 15:43:41 +0100
+Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Backport BT part from
+ upstream
+
+The CYW43455 on the Raspberry Pi 4 doesn't use an external pin as lower
+power clock anymore. So drop the GPIO clock from pinctrl. While we are at
+this add the missing declaration of hardware flow control.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -101,7 +101,8 @@
+ /* uart0 communicates with the BT module */
+ &uart0 {
+ pinctrl-names = "default";
+- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
++ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+++ /dev/null
-From 3a0fad11000e1533c3132e024304cbe8b4f0f826 Mon Sep 17 00:00:00 2001
-From: Johannes Krude <johannes@krude.de>
-Date: Sat, 16 Nov 2019 12:41:06 +0100
-Subject: [PATCH] sound/soc: only first codec is master in multicodec
- setup
-
-When using multiple codecs, at most one codec should generate the master
-clock. All codecs except the first are therefore configured for slave
-mode.
-
-Signed-off-by: Johannes Krude <johannes@krude.de>
----
- sound/soc/soc-core.c | 10 +++++++++-
- 1 file changed, 9 insertions(+), 1 deletion(-)
-
---- a/sound/soc/soc-core.c
-+++ b/sound/soc/soc-core.c
-@@ -1646,7 +1646,15 @@ int snd_soc_runtime_set_dai_fmt(struct s
- int ret;
-
- for_each_rtd_codec_dai(rtd, i, codec_dai) {
-- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
-+ unsigned int codec_dai_fmt = dai_fmt;
-+
-+ // there can only be one master when using multiple codecs
-+ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) {
-+ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-+ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
-+ }
-+
-+ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
- if (ret != 0 && ret != -ENOTSUPP) {
- dev_warn(codec_dai->dev,
- "ASoC: Failed to set DAI format: %d\n", ret);
--- /dev/null
+From 92606b5e0000c25f5daae6c17b0ab71e9fb4c3b4 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 15:55:29 +0100
+Subject: [PATCH] ARM: dts: bcm2838: Backport node names from upstream
+
+According to devicetree specification the node name should describe
+the general class of device like ethernet or interrupt-controller.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -27,7 +27,7 @@
+ reg = <0x40000000 0x100>;
+ };
+
+- gicv2: gic400@40041000 {
++ gicv2: interrupt-controller@40041000 {
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ compatible = "arm,gic-400";
+@@ -346,7 +346,7 @@
+ status = "okay";
+ };
+
+- genet: genet@7d580000 {
++ genet: ethernet@7d580000 {
+ compatible = "brcm,genet-v5";
+ reg = <0x0 0x7d580000 0x10000>;
+ status = "okay";
+@@ -362,7 +362,7 @@
+ compatible = "brcm,genet-mdio-v5";
+ reg = <0xe14 0x8>;
+ reg-names = "mdio";
+- phy1: genet-phy@0 {
++ phy1: ethernet-phy@0 {
+ compatible =
+ "ethernet-phy-ieee802.3-c22";
+ /* No interrupts - use PHY_POLL */
+++ /dev/null
-From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001
-From: Johannes Krude <johannes@krude.de>
-Date: Sat, 16 Nov 2019 13:14:43 +0100
-Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
-
-Signed-off-by: Johannes Krude <johannes@krude.de>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 20 ++
- .../dts/overlays/justboom-both-overlay.dts | 65 +++++
- sound/soc/bcm/Kconfig | 12 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/justboom-both.c | 266 ++++++++++++++++++
- 11 files changed, 371 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts
- create mode 100644 sound/soc/bcm/justboom-both.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- iqaudio-digi-wm8804-audio.dtbo \
- irs1125.dtbo \
- jedec-spi-nor.dtbo \
-+ justboom-both.dtbo \
- justboom-dac.dtbo \
- justboom-digi.dtbo \
- ltc294x.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1388,6 +1388,26 @@ Params: flash-spi<n>-<m> Enables
- on SPI<n>, CS#<m>.
-
-
-+Name: justboom-both
-+Info: Simultaneous usage of an justboom-dac and justboom-digi based
-+ card
-+Load: dtoverlay=justboom-both,<param>=<val>
-+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
-+ Digital volume control. Enable with
-+ "dtoverlay=justboom-dac,24db_digital_gain"
-+ (The default behaviour is that the Digital
-+ volume control is limited to a maximum of
-+ 0dB. ie. it can attenuate but not provide
-+ gain. For most users, this will be desired
-+ as it will prevent clipping. By appending
-+ the 24dB_digital_gain parameter, the Digital
-+ volume control will allow up to 24dB of
-+ gain. If this parameter is enabled, it is the
-+ responsibility of the user to ensure that
-+ the Digital volume control is set to a value
-+ that does not result in clipping/distortion!)
-+
-+
- Name: justboom-dac
- Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
- cards
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
-@@ -0,0 +1,65 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Definitions for JustBoom Both (Digi+DAC)
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ wm8804@3b {
-+ #sound-dai-cells = <0>;
-+ compatible = "wlf,wm8804";
-+ reg = <0x3b>;
-+ PVDD-supply = <&vdd_3v3_reg>;
-+ DVDD-supply = <&vdd_3v3_reg>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm5122@4d {
-+ #sound-dai-cells = <0>;
-+ compatible = "ti,pcm5122";
-+ reg = <0x4d>;
-+ AVDD-supply = <&vdd_3v3_reg>;
-+ DVDD-supply = <&vdd_3v3_reg>;
-+ CPVDD-supply = <&vdd_3v3_reg>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ frag3: __overlay__ {
-+ compatible = "justboom,justboom-both";
-+ i2s-controller = <&i2s>;
-+ status = "okay";
-+ };
-+ };
-+
-+ __overrides__ {
-+ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
-+ };
-+};
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -105,6 +105,18 @@ config SND_BCM2708_SOC_RPI_PROTO
- help
- Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
-
-+config SND_BCM2708_SOC_JUSTBOOM_BOTH
-+ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_WM8804
-+ select SND_SOC_PCM512x
-+ help
-+ Say Y or M if you want to add support for simultaneous
-+ JustBoom Digi and JustBoom DAC.
-+
-+ This is not the right choice if you only have one but both of
-+ these cards.
-+
- config SND_BCM2708_SOC_JUSTBOOM_DAC
- tristate "Support for JustBoom DAC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -17,6 +17,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
- snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
-+snd-soc-justboom-both-objs := justboom-both.o
- snd-soc-justboom-dac-objs := justboom-dac.o
- snd-soc-rpi-cirrus-objs := rpi-cirrus.o
- snd-soc-rpi-proto-objs := rpi-proto.o
-@@ -43,6 +44,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
-+obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
- obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
- obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
---- /dev/null
-+++ b/sound/soc/bcm/justboom-both.c
-@@ -0,0 +1,266 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
-+ *
-+ * Authors: Johannes Krude <johannes@krude.de
-+ *
-+ * Driver for when connecting simultaneously justboom-digi and justboom-dac
-+ *
-+ * Based upon code from:
-+ * justboom-digi.c
-+ * by Milan Neskovic <info@justboom.co>
-+ * justboom-dac.c
-+ * by Milan Neskovic <info@justboom.co>
-+ *
-+ * 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 <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/jack.h>
-+
-+#include "../codecs/wm8804.h"
-+#include "../codecs/pcm512x.h"
-+
-+
-+static bool digital_gain_0db_limit = true;
-+
-+static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ /* enable TX output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ if (digital_gain_0db_limit) {
-+ int ret;
-+ struct snd_soc_card *card = rtd->card;
-+
-+ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
-+ 207);
-+ if (ret < 0)
-+ dev_warn(card->dev, "Failed to set volume limit: %d\n",
-+ ret);
-+ }
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ int sysclk = 27000000; /* This is fixed on this board */
-+
-+ long mclk_freq = 0;
-+ int mclk_div = 1;
-+ int sampling_freq = 1;
-+
-+ int ret;
-+
-+ int samplerate = params_rate(params);
-+
-+ if (samplerate <= 96000) {
-+ mclk_freq = samplerate*256;
-+ mclk_div = WM8804_MCLKDIV_256FS;
-+ } else {
-+ mclk_freq = samplerate*128;
-+ mclk_div = WM8804_MCLKDIV_128FS;
-+ }
-+
-+ switch (samplerate) {
-+ case 32000:
-+ sampling_freq = 0x03;
-+ break;
-+ case 44100:
-+ sampling_freq = 0x00;
-+ break;
-+ case 48000:
-+ sampling_freq = 0x02;
-+ break;
-+ case 88200:
-+ sampling_freq = 0x08;
-+ break;
-+ case 96000:
-+ sampling_freq = 0x0a;
-+ break;
-+ case 176400:
-+ sampling_freq = 0x0c;
-+ break;
-+ case 192000:
-+ sampling_freq = 0x0e;
-+ break;
-+ default:
-+ dev_err(rtd->card->dev,
-+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
-+ samplerate);
-+ }
-+
-+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
-+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
-+
-+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
-+ sysclk, SND_SOC_CLOCK_OUT);
-+ if (ret < 0) {
-+ dev_err(rtd->card->dev,
-+ "Failed to set WM8804 SYSCLK: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Enable TX output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
-+
-+ /* Power on */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
-+
-+ /* set sampling frequency status bits */
-+ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
-+
-+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
-+}
-+
-+static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ /* turn on digital output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+
-+ return 0;
-+}
-+
-+static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
-+{
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+ struct snd_soc_component *digi = rtd->codec_dais[0]->component;
-+ struct snd_soc_component *dac = rtd->codec_dais[1]->component;
-+
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+
-+ /* turn off output */
-+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_justboom_both_ops = {
-+ .hw_params = snd_rpi_justboom_both_hw_params,
-+ .startup = snd_rpi_justboom_both_startup,
-+ .shutdown = snd_rpi_justboom_both_shutdown,
-+};
-+
-+SND_SOC_DAILINK_DEFS(rpi_justboom_both,
-+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
-+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
-+ COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
-+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
-+
-+static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
-+{
-+ .name = "JustBoom Digi",
-+ .stream_name = "JustBoom Digi HiFi",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBM_CFM,
-+ .ops = &snd_rpi_justboom_both_ops,
-+ .init = snd_rpi_justboom_both_init,
-+ SND_SOC_DAILINK_REG(rpi_justboom_both),
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_justboom_both = {
-+ .name = "snd_rpi_justboom_both",
-+ .driver_name = "JustBoomBoth",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_justboom_both_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
-+};
-+
-+static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ struct snd_soc_card *card = &snd_rpi_justboom_both;
-+
-+ snd_rpi_justboom_both.dev = &pdev->dev;
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
-+
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ int i;
-+
-+ for (i = 0; i < card->num_links; i++) {
-+ dai->cpus->dai_name = NULL;
-+ dai->cpus->of_node = i2s_node;
-+ dai->platforms->name = NULL;
-+ dai->platforms->of_node = i2s_node;
-+ }
-+ }
-+
-+ digital_gain_0db_limit = !of_property_read_bool(
-+ pdev->dev.of_node, "justboom,24db_digital_gain");
-+ }
-+
-+ ret = snd_soc_register_card(card);
-+ if (ret && ret != -EPROBE_DEFER) {
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_justboom_both_remove(struct platform_device *pdev)
-+{
-+ return snd_soc_unregister_card(&snd_rpi_justboom_both);
-+}
-+
-+static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
-+ { .compatible = "justboom,justboom-both", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
-+
-+static struct platform_driver snd_rpi_justboom_both_driver = {
-+ .driver = {
-+ .name = "snd-rpi-justboom-both",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_justboom_both_of_match,
-+ },
-+ .probe = snd_rpi_justboom_both_probe,
-+ .remove = snd_rpi_justboom_both_remove,
-+};
-+
-+module_platform_driver(snd_rpi_justboom_both_driver);
-+
-+MODULE_AUTHOR("Johannes Krude <johannes@krude.de>");
-+MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From b124d4fdc62b91441173854872c26bea6e36d2e5 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 18:01:57 +0100
+Subject: [PATCH] ARM: dts: bcm283x: Move intc label to
+ bcm2835-common.dtsi
+
+The intc label isn't defined in bcm283x.dtsi, so we cannot use it there.
+So move it to bcm2835-common.dtsi.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2835-common.dtsi | 2 ++
+ arch/arm/boot/dts/bcm283x.dtsi | 1 -
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2835-common.dtsi
++++ b/arch/arm/boot/dts/bcm2835-common.dtsi
+@@ -5,6 +5,8 @@
+ */
+
+ / {
++ interrupt-parent = <&intc>;
++
+ soc {
+ intc: interrupt-controller@7e00b200 {
+ compatible = "brcm,bcm2835-armctrl-ic";
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -18,7 +18,6 @@
+ / {
+ compatible = "brcm,bcm2835";
+ model = "BCM2835";
+- interrupt-parent = <&intc>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+++ /dev/null
-From 5c1a2df946720816c155ff38b01bcd49a0f44f78 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 18 Dec 2019 10:41:33 +0000
-Subject: [PATCH] overlays: dht11: Allow multiple instantiation
-
-Add addresses to the dht11 and dht11_pins nodes to allow unique names
-to be generated by assigning to the "reg" property.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/dht11-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts
-@@ -24,7 +24,7 @@
- fragment@1 {
- target = <&gpio>;
- __overlay__ {
-- dht11_pins: dht11_pins {
-+ dht11_pins: dht11_pins@0 {
- brcm,pins = <4>;
- brcm,function = <0>; // in
- brcm,pull = <0>; // off
-@@ -34,6 +34,8 @@
-
- __overrides__ {
- gpiopin = <&dht11_pins>,"brcm,pins:0",
-- <&dht11>,"gpios:4";
-+ <&dht11_pins>, "reg:0",
-+ <&dht11>,"gpios:4",
-+ <&dht11>,"reg:0";
- };
- };
--- /dev/null
+From 2810c8dae6aa7749bc787329d1d5841d0fdaea97 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 18:19:28 +0100
+Subject: [PATCH] ARM: dts: bcm2838: Remove always-on from armv7-timer
+
+After moving bcm2835-system-timer to bcm283x.dtsi there is no need for
+the always-on for armv7-timer anymore.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -231,7 +231,6 @@
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ arm,cpu-registers-not-fw-configured;
+- always-on;
+ };
+
+ cpus: cpus {
+++ /dev/null
-From 32dbe4ebb10b96eed117852f1643bf1f854d96c0 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Sun, 22 Dec 2019 15:29:40 +0000
-Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support
-
-See: https://github.com/raspberrypi/firmware/issues/1309
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/README | 2 ++
- arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++
- 2 files changed, 18 insertions(+)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1078,6 +1078,8 @@ Params: abx80x Select o
-
- pcf8523 Select the PCF8523 device
-
-+ pcf85363 Select the PCF85363 device
-+
- pcf8563 Select the PCF8563 device
-
- rv3028 Select the Micro Crystal RV3028 device
---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
-@@ -188,6 +188,21 @@
- };
- };
-
-+ fragment@12 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcf85363@51 {
-+ compatible = "nxp,pcf85363";
-+ reg = <0x51>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
- __overrides__ {
- abx80x = <0>,"+0";
- ds1307 = <0>,"+1";
-@@ -201,6 +216,7 @@
- m41t62 = <0>,"+9";
- rv3028 = <0>,"+10";
- pcf2129 = <0>,"+11";
-+ pcf85363 = <0>,"+12";
-
- addr = <&abx80x>, "reg:0",
- <&ds1307>, "reg:0",
--- /dev/null
+From b0aff8993c458396b82ad7d0792199f971413bb8 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 16:35:54 +0100
+Subject: [PATCH] net: bcmgenet: Add RGMII_RXID support
+
+This adds the missing support for the PHY mode RGMII_RXID.
+It's necessary for the Raspberry Pi 4.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ drivers/net/ethernet/broadcom/genet/bcmmii.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+@@ -274,10 +274,11 @@ int bcmgenet_mii_config(struct net_devic
+ id_mode_dis = BIT(16);
+ /* fall through */
+ case PHY_INTERFACE_MODE_RGMII_TXID:
++ case PHY_INTERFACE_MODE_RGMII_RXID:
+ if (id_mode_dis)
+ phy_name = "external RGMII (no delay)";
+ else
+- phy_name = "external RGMII (TX delay)";
++ phy_name = "external RGMII";
+ bcmgenet_sys_writel(priv,
+ PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
+ break;
+++ /dev/null
-From 0cddfafa817a776063ba6f00fb439d9a415235f9 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 6 Jan 2020 16:04:30 +0000
-Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error
-
-A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix
-the leak with the use of devm_gpiochip_add_data.
-
-Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP")
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -1135,7 +1135,7 @@ static int bcm2835_pinctrl_probe(struct
- raw_spin_lock_init(&pc->irq_lock[i]);
- }
-
-- err = gpiochip_add_data(&pc->gpio_chip, pc);
-+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
- if (err) {
- dev_err(dev, "could not add GPIO chip\n");
- return err;
--- /dev/null
+From 30bd619480b6a2b92d404a61a1e90ddb76ae4be8 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Wed, 25 Dec 2019 16:40:47 +0100
+Subject: [PATCH] ARM: dts: bcm2838: Backport genet from upstream
+
+This backport all genet differences (different compatible, right PHY mode,
+board specific stuff) from upstream.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 14 ++++++++++++++
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 14 ++++++++++++++
+ arch/arm/boot/dts/bcm2838.dtsi | 17 ++++-------------
+ 3 files changed, 32 insertions(+), 13 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -134,6 +134,20 @@
+ vqmmc-supply = <&sd_io_1v8_reg>;
+ };
+
++&genet {
++ phy-handle = <&phy1>;
++ phy-mode = "rgmii-rxid";
++ status = "okay";
++};
++
++&genet_mdio {
++ phy1: ethernet-phy@1 {
++ /* No PHY interrupt */
++ reg = <0x1>;
++ led-modes = <0x00 0x08>; /* link/activity link */
++ };
++};
++
+ &leds {
+ act_led: act {
+ label = "led0";
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+@@ -98,6 +98,20 @@
+ vqmmc-supply = <&sd_io_1v8_reg>;
+ };
+
++&genet {
++ phy-handle = <&phy1>;
++ phy-mode = "rgmii-rxid";
++ status = "okay";
++};
++
++&genet_mdio {
++ phy1: ethernet-phy@1 {
++ /* No PHY interrupt */
++ reg = <0x1>;
++ led-modes = <0x00 0x08>; /* link/activity link */
++ };
++};
++
+ /* uart0 communicates with the BT module */
+ &uart0 {
+ pinctrl-names = "default";
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -346,29 +346,20 @@
+ };
+
+ genet: ethernet@7d580000 {
+- compatible = "brcm,genet-v5";
++ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
+ reg = <0x0 0x7d580000 0x10000>;
+- status = "okay";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+- phy-handle = <&phy1>;
+- phy-mode = "rgmii";
+- mdio@e14 {
++ status = "disabled";
++
++ genet_mdio: mdio@e14 {
+ #address-cells = <0x0>;
+ #size-cells = <0x1>;
+ compatible = "brcm,genet-mdio-v5";
+ reg = <0xe14 0x8>;
+ reg-names = "mdio";
+- phy1: ethernet-phy@0 {
+- compatible =
+- "ethernet-phy-ieee802.3-c22";
+- /* No interrupts - use PHY_POLL */
+- max-speed = <1000>;
+- reg = <0x1>;
+- led-modes = <0x00 0x08>; /* link/activity link */
+- };
+ };
+ };
+
+++ /dev/null
-From 27cb8bf0442f677380a1df93b93b7589b7ce5243 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Mon, 6 Jan 2020 14:05:42 +0000
-Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs
-
-pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio
-side is registered first, but this breaks gpio hogs (which are
-configured during gpiochip_add_data). Part of the hog initialisation
-is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't
-yet been registered this results in an -EPROBE_DEFER from which it can
-never recover.
-
-Change the initialisation sequence to register the pinctrl driver
-first.
-
-See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 40 ++++++++++++---------------
- 1 file changed, 17 insertions(+), 23 deletions(-)
-
---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
-@@ -1135,9 +1135,25 @@ static int bcm2835_pinctrl_probe(struct
- raw_spin_lock_init(&pc->irq_lock[i]);
- }
-
-+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
-+ if (match) {
-+ bcm2835_pinctrl_desc.confops =
-+ (const struct pinconf_ops *)match->data;
-+ }
-+
-+ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
-+ if (IS_ERR(pc->pctl_dev))
-+ return PTR_ERR(pc->pctl_dev);
-+
-+ pc->gpio_range = bcm2835_pinctrl_gpio_range;
-+ pc->gpio_range.base = pc->gpio_chip.base;
-+ pc->gpio_range.gc = &pc->gpio_chip;
-+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
-+
- err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
- if (err) {
- dev_err(dev, "could not add GPIO chip\n");
-+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
- return err;
- }
-
-@@ -1145,6 +1161,7 @@ static int bcm2835_pinctrl_probe(struct
- 0, handle_level_irq, IRQ_TYPE_NONE);
- if (err) {
- dev_info(dev, "could not add irqchip\n");
-+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
- return err;
- }
-
-@@ -1167,29 +1184,6 @@ static int bcm2835_pinctrl_probe(struct
- bcm2835_gpio_irq_handler);
- }
-
-- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
-- if (match) {
-- bcm2835_pinctrl_desc.confops =
-- (const struct pinconf_ops *)match->data;
-- }
--
-- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
-- if (match) {
-- bcm2835_pinctrl_desc.confops =
-- (const struct pinconf_ops *)match->data;
-- }
--
-- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
-- if (IS_ERR(pc->pctl_dev)) {
-- gpiochip_remove(&pc->gpio_chip);
-- return PTR_ERR(pc->pctl_dev);
-- }
--
-- pc->gpio_range = bcm2835_pinctrl_gpio_range;
-- pc->gpio_range.base = pc->gpio_chip.base;
-- pc->gpio_range.gc = &pc->gpio_chip;
-- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
--
- return 0;
- }
-
--- /dev/null
+From 88dacbcd946d2e0cd06337ab3f393064ab6aba82 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 27 Dec 2019 11:40:56 +0100
+Subject: [PATCH] ARM: bcm: Backport BCM2711 support from upstream
+
+Make the BCM2711 a different machine, but keep it in board_bcm2835.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/mach-bcm/Kconfig | 4 ++--
+ arch/arm/mach-bcm/board_bcm2835.c | 17 +++++++++++++++--
+ arch/arm64/Kconfig.platforms | 5 +++--
+ 3 files changed, 20 insertions(+), 6 deletions(-)
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -161,7 +161,7 @@ config ARCH_BCM2835
+ select GPIOLIB
+ select ARM_AMBA
+ select ARM_ERRATA_411920 if ARCH_MULTI_V6
+- select ARM_GIC
++ select ARM_GIC if ARCH_MULTI_V7
+ select ARM_TIMER_SP804
+ select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
+ select TIMER_OF
+@@ -175,7 +175,7 @@ config ARCH_BCM2835
+ select ZONE_DMA if ARM_LPAE
+ select MFD_CORE
+ help
+- This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
++ This enables support for the Broadcom BCM2711 and BCM283x SoCs.
+ This SoC is used in the Raspberry Pi and Roku 2 devices.
+
+ config ARCH_BCM_53573
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -109,17 +109,30 @@ static const char * const bcm2835_compat
+ #ifdef CONFIG_ARCH_MULTI_V7
+ "brcm,bcm2836",
+ "brcm,bcm2837",
+- "brcm,bcm2711",
+ #endif
+ NULL
+ };
+
+ DT_MACHINE_START(BCM2835, "BCM2835")
++ .map_io = bcm2835_map_io,
++ .init_machine = bcm2835_init,
++ .dt_compat = bcm2835_compat,
++ .smp = smp_ops(bcm2836_smp_ops),
++MACHINE_END
++
++static const char * const bcm2711_compat[] = {
++#ifdef CONFIG_ARCH_MULTI_V7
++ "brcm,bcm2711",
++#endif
++ NULL
++};
++
++DT_MACHINE_START(BCM2711, "BCM2711")
+ #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
+ .dma_zone_size = SZ_1G,
+ #endif
+ .map_io = bcm2835_map_io,
+ .init_machine = bcm2835_init,
+- .dt_compat = bcm2835_compat,
++ .dt_compat = bcm2711_compat,
+ .smp = smp_ops(bcm2836_smp_ops),
+ MACHINE_END
+--- a/arch/arm64/Kconfig.platforms
++++ b/arch/arm64/Kconfig.platforms
+@@ -37,11 +37,12 @@ config ARCH_BCM2835
+ select PINCTRL
+ select PINCTRL_BCM2835
+ select ARM_AMBA
++ select ARM_GIC
+ select ARM_TIMER_SP804
+ select HAVE_ARM_ARCH_TIMER
+ help
+- This enables support for the Broadcom BCM2837 SoC.
+- This SoC is used in the Raspberry Pi 3 device.
++ This enables support for the Broadcom BCM2837 and BCM2711 SoC.
++ These SoCs are used in the Raspberry Pi 3 and 4 devices.
+
+ config ARCH_BCM_IPROC
+ bool "Broadcom iProc SoC Family"
+++ /dev/null
-From 67dd4d137557909279a21c1b5de87a24c84903f9 Mon Sep 17 00:00:00 2001
-From: Giedrius <giedrius@blokas.io>
-Date: Tue, 7 Jan 2020 11:04:21 +0200
-Subject: [PATCH] Pisound: MIDI communication fixes for scaled down
- CPU.
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-* Increased maximum SPI communication speed to avoid running too slow
- when the CPU is scaled down and losing MIDI data.
-
-* Keep track of buffer usage in millibytes for higher precision.
-
-Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
----
- sound/soc/bcm/pisound.c | 31 ++++++++++++++++++-------------
- 1 file changed, 18 insertions(+), 13 deletions(-)
-
---- a/sound/soc/bcm/pisound.c
-+++ b/sound/soc/bcm/pisound.c
-@@ -1,6 +1,6 @@
- /*
- * Pisound Linux kernel module.
-- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
-+ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
-@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t *
- transfer.tx_buf = txbuf;
- transfer.rx_buf = rxbuf;
- transfer.len = len;
-- transfer.speed_hz = 100000;
-+ transfer.speed_hz = 150000;
- transfer.delay_usecs = 10;
- spi_message_add_tail(&transfer, &msg);
-
-@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find
- static void pisnd_work_handler(struct work_struct *work)
- {
- enum { TRANSFER_SIZE = 4 };
-- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
-- enum { MIDI_BYTES_PER_SECOND = 3125 };
-- int out_buffer_used = 0;
-+ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 };
-+ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ };
-+ int out_buffer_used_millibytes = 0;
- unsigned long now;
- uint8_t val;
- uint8_t txbuf[TRANSFER_SIZE];
-@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo
- had_data = false;
- memset(txbuf, 0, sizeof(txbuf));
- for (i = 0; i < sizeof(txbuf) &&
-- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
-+ ((out_buffer_used_millibytes+1000 <
-+ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) ||
-+ g_ledFlashDurationChanged);
- i += 2) {
-
- val = 0;
-@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo
- } else if (kfifo_get(&spi_fifo_out, &val)) {
- txbuf[i+0] = 0x0f;
- txbuf[i+1] = val;
-- ++out_buffer_used;
-+ out_buffer_used_millibytes += 1000;
- }
- }
-
-@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo
- * rate.
- */
- now = jiffies;
-- out_buffer_used -=
-- (MIDI_BYTES_PER_SECOND / HZ) /
-- (now - last_transfer_at);
-- if (out_buffer_used < 0)
-- out_buffer_used = 0;
-- last_transfer_at = now;
-+ if (now != last_transfer_at) {
-+ out_buffer_used_millibytes -=
-+ (now - last_transfer_at) *
-+ MIDI_MILLIBYTES_PER_JIFFIE;
-+ if (out_buffer_used_millibytes < 0)
-+ out_buffer_used_millibytes = 0;
-+ last_transfer_at = now;
-+ }
-
- for (i = 0; i < sizeof(rxbuf); i += 2) {
- if (rxbuf[i]) {
-@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo
- || !kfifo_is_empty(&spi_fifo_out)
- || pisnd_spi_has_more()
- || g_ledFlashDurationChanged
-+ || out_buffer_used_millibytes != 0
- );
-
- if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
--- /dev/null
+From d19e54299471dbdf92a3115ec6591a81c527f786 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 27 Dec 2019 11:55:59 +0100
+Subject: [PATCH] hwrng: iproc-rng200 - Add support for BCM2711
+
+commit 0f95b09a5f624964d520c8f6a2674090fb98ae25 upstream.
+
+BCM2711 features a RNG200 hardware random number generator block.
+So make the driver available.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Signed-off-by: Stephen Brennan <stephen@brennan.io>
+Reviewed-by: Matthias Brugger <mbrugger@suse.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+---
+ drivers/char/hw_random/iproc-rng200.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/char/hw_random/iproc-rng200.c
++++ b/drivers/char/hw_random/iproc-rng200.c
+@@ -292,6 +292,7 @@ static int iproc_rng200_probe(struct pla
+ }
+
+ static const struct of_device_id iproc_rng200_of_match[] = {
++ { .compatible = "brcm,bcm2711-rng200", },
+ { .compatible = "brcm,bcm7211-rng200", },
+ { .compatible = "brcm,bcm7278-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
+++ /dev/null
-From 27cf0ad95cdf30f52a5fc6c69014a0d7bf5a1222 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 8 Jan 2020 17:21:09 +0000
-Subject: [PATCH] pcie-brcmstb: Eliminate arch_dma_ops error message
-
-The driver attempts to set the dma_ops for the root complex, but doing
-so causes an error message and only the end points need it. Fix the
-error by making the code specific to the end point case.
-
-Also copy some cosmetic tidy-ups from 5.5.y.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 43 ++++++++++++++-------------
- 1 file changed, 22 insertions(+), 21 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -633,16 +633,17 @@ static int brcmstb_platform_notifier(str
-
- switch (event) {
- case BUS_NOTIFY_ADD_DEVICE:
-- if (max_pfn > (bounce_threshold/PAGE_SIZE) &&
-- strcmp(dev->kobj.name, rc_name)) {
--
-- ret = brcm_pcie_bounce_register_dev(dev);
-- if (ret) {
-- dev_err(dev,
-- "brcm_pcie_bounce_register_dev() failed: %d\n",
-- ret);
-- return ret;
-+ if (strcmp(dev->kobj.name, rc_name)) {
-+ if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ ret = brcm_pcie_bounce_register_dev(dev);
-+ if (ret) {
-+ dev_err(dev,
-+ "brcm_pcie_bounce_register_dev() failed: %d\n",
-+ ret);
-+ return ret;
-+ }
- }
-+ brcm_set_dma_ops(dev);
- } else if (IS_ENABLED(CONFIG_ARM64)) {
- ret = of_dma_configure(dev, dev->of_node, true);
- if (ret) {
-@@ -650,7 +651,6 @@ static int brcmstb_platform_notifier(str
- return ret;
- }
- }
-- brcm_set_dma_ops(dev);
- return NOTIFY_OK;
-
- case BUS_NOTIFY_DEL_DEVICE:
-@@ -1685,7 +1685,8 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match)
-
- static int brcm_pcie_probe(struct platform_device *pdev)
- {
-- struct device_node *dn = pdev->dev.of_node, *msi_dn;
-+ struct device *dev = &pdev->dev;
-+ struct device_node *dn = dev->of_node, *msi_dn;
- const struct of_device_id *of_id;
- const struct pcie_cfg_data *data;
- int ret;
-@@ -1696,7 +1697,7 @@ static int brcm_pcie_probe(struct platfo
- struct pci_bus *child;
- extern unsigned long max_pfn;
-
-- bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
-+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
- if (!bridge)
- return -ENOMEM;
-
-@@ -1705,7 +1706,7 @@ static int brcm_pcie_probe(struct platfo
-
- of_id = of_match_node(brcm_pcie_match, dn);
- if (!of_id) {
-- dev_err(&pdev->dev, "failed to look up compatible string\n");
-+ dev_err(dev, "failed to look up compatible string\n");
- return -EINVAL;
- }
-
-@@ -1715,7 +1716,7 @@ static int brcm_pcie_probe(struct platfo
- pcie->max_burst_size = data->max_burst_size;
- pcie->type = data->type;
- pcie->dn = dn;
-- pcie->dev = &pdev->dev;
-+ pcie->dev = dev;
-
- /* We use the domain number as our controller number */
- pcie->id = of_get_pci_domain_nr(dn);
-@@ -1726,18 +1727,18 @@ static int brcm_pcie_probe(struct platfo
- if (!res)
- return -EINVAL;
-
-- base = devm_ioremap_resource(&pdev->dev, res);
-+ base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- /* To Do: Add hardware check if this ever gets fixed */
- if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
- int ret;
-- ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
-+ ret = brcm_pcie_bounce_init(dev, bounce_buffer,
- (dma_addr_t)bounce_threshold);
- if (ret) {
- if (ret != -EPROBE_DEFER)
-- dev_err(&pdev->dev,
-+ dev_err(dev,
- "could not init bounce buffers: %d\n",
- ret);
- return ret;
-@@ -1746,7 +1747,7 @@ static int brcm_pcie_probe(struct platfo
-
- pcie->clk = of_clk_get_by_name(dn, "sw_pcie");
- if (IS_ERR(pcie->clk)) {
-- dev_warn(&pdev->dev, "could not get clock\n");
-+ dev_warn(dev, "could not get clock\n");
- pcie->clk = NULL;
- }
- pcie->base = base;
-@@ -1756,7 +1757,7 @@ static int brcm_pcie_probe(struct platfo
-
- pcie->ssc = of_property_read_bool(dn, "brcm,enable-ssc");
-
-- ret = irq_of_parse_and_map(pdev->dev.of_node, 0);
-+ ret = irq_of_parse_and_map(dev->of_node, 0);
- if (ret == 0)
- /* keep going, as we don't use this intr yet */
- dev_warn(pcie->dev, "cannot get PCIe interrupt\n");
-@@ -1770,7 +1771,7 @@ static int brcm_pcie_probe(struct platfo
- ret = clk_prepare_enable(pcie->clk);
- if (ret) {
- if (ret != -EPROBE_DEFER)
-- dev_err(&pdev->dev, "could not enable clock\n");
-+ dev_err(dev, "could not enable clock\n");
- return ret;
- }
-
-@@ -1797,7 +1798,7 @@ static int brcm_pcie_probe(struct platfo
- }
-
- list_splice_init(&pcie->resources, &bridge->windows);
-- bridge->dev.parent = &pdev->dev;
-+ bridge->dev.parent = dev;
- bridge->busnr = 0;
- bridge->ops = &brcm_pcie_ops;
- bridge->sysdata = pcie;
--- /dev/null
+From 0f4d508ca3dc0eac4ef4ac85190da58285f1580f Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Fri, 27 Dec 2019 12:01:17 +0100
+Subject: [PATCH] ARM: dts: bcm2838: Add upstream RNG compatible
+
+This adds the ability to use the RNG with an upstream kernel.
+Keep the old one for backward compatibility.
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -682,7 +682,7 @@
+ };
+
+ &rng {
+- compatible = "brcm,bcm2838-rng200";
++ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
+ };
+
+ &sdhost {
+++ /dev/null
-From 238506ebdea7a0bb928af8403287d5b0d71cdfee Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 16 Aug 2019 22:32:02 +0200
-Subject: [PATCH] ARM: dts: bcm283x: Remove simple-bus from fixed
- clocks
-
-commit 4b2d24662126b1e2a6b95c9dfe9e9044e105e5bd upstream.
-
-The fixed clocks doesn't form some kind of bus. So let's remove it.
-This fixes the follow DT schema warnings:
-
-clocks: clock@3:reg:0: [3] is too short
-clocks: clock@4:reg:0: [4] is too short
-clocks: $nodename:0: 'clocks' does not match '^(bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$'
-clocks: #size-cells:0:0: 0 is not one of [1, 2]
-clocks: 'ranges' is a required property
-clock@3: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+'
-clock@4: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+'
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm283x.dtsi | 10 ++--------
- 1 file changed, 2 insertions(+), 8 deletions(-)
-
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -634,22 +634,16 @@
- };
-
- clocks {
-- compatible = "simple-bus";
-- #address-cells = <1>;
-- #size-cells = <0>;
--
- /* The oscillator is the root of the clock tree. */
-- clk_osc: clock@3 {
-+ clk_osc: clk-osc {
- compatible = "fixed-clock";
-- reg = <3>;
- #clock-cells = <0>;
- clock-output-names = "osc";
- clock-frequency = <19200000>;
- };
-
-- clk_usb: clock@4 {
-+ clk_usb: clk-usb {
- compatible = "fixed-clock";
-- reg = <4>;
- #clock-cells = <0>;
- clock-output-names = "otg";
- clock-frequency = <480000000>;
+++ /dev/null
-From fcd4bc412167d2a79bf63603e883f4960ca6b2a1 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 27 Dec 2019 11:15:00 +0100
-Subject: [PATCH] ARM: dts: bcm283x: Move system timer back to
- bcm283x.dtsi
-
-During Raspberry Pi 4 upstream discussion Tim Gover confirmed that the
-system timer also exists on BCM2711. So move it back to bcm283x.dtsi and
-overwrite the interrupt definition in bcm2838.dtsi.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2835-common.dtsi | 11 -----------
- arch/arm/boot/dts/bcm2838.dtsi | 7 +++++++
- arch/arm/boot/dts/bcm283x.dtsi | 11 +++++++++++
- 3 files changed, 18 insertions(+), 11 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-common.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
-@@ -6,17 +6,6 @@
-
- / {
- soc {
-- timer@7e003000 {
-- compatible = "brcm,bcm2835-system-timer";
-- reg = <0x7e003000 0x1000>;
-- interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-- /* This could be a reference to BCM2835_CLOCK_TIMER,
-- * but we don't have the driver using the common clock
-- * support yet.
-- */
-- clock-frequency = <1000000>;
-- };
--
- intc: interrupt-controller@7e00b200 {
- compatible = "brcm,bcm2835-armctrl-ic";
- reg = <0x7e00b200 0x200>;
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -711,6 +711,13 @@
- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
- };
-
-+&system_timer {
-+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
- &uart0 {
- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
- };
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -56,6 +56,17 @@
- #address-cells = <1>;
- #size-cells = <1>;
-
-+ system_timer: timer@7e003000 {
-+ compatible = "brcm,bcm2835-system-timer";
-+ reg = <0x7e003000 0x1000>;
-+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
-+ /* This could be a reference to BCM2835_CLOCK_TIMER,
-+ * but we don't have the driver using the common clock
-+ * support yet.
-+ */
-+ clock-frequency = <1000000>;
-+ };
-+
- txp: txp@7e004000 {
- compatible = "brcm,bcm2835-txp";
- reg = <0x7e004000 0x20>;
--- /dev/null
+From d0be0df98679b7a9a30ba74c065ed30301e2bd22 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 15 Jan 2020 13:59:57 +0000
+Subject: [PATCH] driver: char: rpivid: Destroy the legacy device on
+ remove
+
+The legacy name support created a new device that was never destroyed.
+If the driver was unloaded and reloaded, it failed due to the
+device already existing.
+
+Fixes: "75f1d14 driver: char: rpivid - also support legacy name"
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -233,6 +233,7 @@ static int rpivid_mem_remove(struct plat
+ struct device *dev = &pdev->dev;
+ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
+
++ device_destroy(priv->class, priv->devid + 1);
+ device_destroy(priv->class, priv->devid);
+ class_destroy(priv->class);
+ cdev_del(&priv->rpivid_mem_cdev);
+++ /dev/null
-From d884dfd722a8207749f5c6c08b69287f0c75a553 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 27 Dec 2019 16:06:13 +0100
-Subject: [PATCH] ARM: dts: bcm283x: Move pixelvalve to
- bcm2835-common.dtsi
-
-According to Eric Anholt the pixelvalves doesn't exists on BCM2711.
-So move it to bcm2835-common.dtsi.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2835-common.dtsi | 18 ++++++++++++++++++
- arch/arm/boot/dts/bcm2838.dtsi | 12 ------------
- arch/arm/boot/dts/bcm283x.dtsi | 18 ------------------
- 3 files changed, 18 insertions(+), 30 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2835-common.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
-@@ -13,6 +13,18 @@
- #interrupt-cells = <2>;
- };
-
-+ pixelvalve@7e206000 {
-+ compatible = "brcm,bcm2835-pixelvalve0";
-+ reg = <0x7e206000 0x100>;
-+ interrupts = <2 13>; /* pwa0 */
-+ };
-+
-+ pixelvalve@7e207000 {
-+ compatible = "brcm,bcm2835-pixelvalve1";
-+ reg = <0x7e207000 0x100>;
-+ interrupts = <2 14>; /* pwa1 */
-+ };
-+
- thermal: thermal@7e212000 {
- compatible = "brcm,bcm2835-thermal";
- reg = <0x7e212000 0x8>;
-@@ -21,6 +33,12 @@
- status = "disabled";
- };
-
-+ pixelvalve@7e807000 {
-+ compatible = "brcm,bcm2835-pixelvalve2";
-+ reg = <0x7e807000 0x100>;
-+ interrupts = <2 10>; /* pixelvalve */
-+ };
-+
- v3d: v3d@7ec00000 {
- compatible = "brcm,bcm2835-v3d";
- reg = <0x7ec00000 0x1000>;
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -188,14 +188,6 @@
- status = "disabled";
- };
-
-- pixelvalve@7e206000 {
-- interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
-- pixelvalve@7e207000 {
-- interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
- pwm1: pwm@7e20c800 {
- compatible = "brcm,bcm2835-pwm";
- reg = <0x7e20c800 0x28>;
-@@ -217,10 +209,6 @@
- hvs@7e400000 {
- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
- };
--
-- pixelvalve@7e807000 {
-- interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
-- };
- };
-
- arm-pmu {
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -432,18 +432,6 @@
- status = "disabled";
- };
-
-- pixelvalve@7e206000 {
-- compatible = "brcm,bcm2835-pixelvalve0";
-- reg = <0x7e206000 0x100>;
-- interrupts = <2 13>; /* pwa0 */
-- };
--
-- pixelvalve@7e207000 {
-- compatible = "brcm,bcm2835-pixelvalve1";
-- reg = <0x7e207000 0x100>;
-- interrupts = <2 14>; /* pwa1 */
-- };
--
- dpi: dpi@7e208000 {
- compatible = "brcm,bcm2835-dpi";
- reg = <0x7e208000 0x8c>;
-@@ -607,12 +595,6 @@
- status = "disabled";
- };
-
-- pixelvalve@7e807000 {
-- compatible = "brcm,bcm2835-pixelvalve2";
-- reg = <0x7e807000 0x100>;
-- interrupts = <2 10>; /* pixelvalve */
-- };
--
- hdmi: hdmi@7e902000 {
- compatible = "brcm,bcm2835-hdmi";
- reg = <0x7e902000 0x600>,
--- /dev/null
+From 8b95d0d18fcfb940fb0d171663ce5c93b8fb0024 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 21 Jan 2020 16:24:45 +0000
+Subject: [PATCH] driver: char: rpivid: Clean up error handling use of
+ ERR_PTR/IS_ERR
+
+The driver used an unnecessary intermediate void* variable so it
+only called ERR_PTR once to convert to the error value.
+
+Switch to converting as the error arises to remove these intermediate
+variables.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -130,10 +130,8 @@ static const struct of_device_id rpivid_
+ static int rpivid_mem_probe(struct platform_device *pdev)
+ {
+ int err;
+- void *ptr_err;
+ const struct of_device_id *id;
+ struct device *dev = &pdev->dev;
+- struct device *rpivid_mem_dev;
+ struct resource *ioresource;
+ struct rpivid_mem_priv *priv;
+
+@@ -183,16 +181,16 @@ static int rpivid_mem_probe(struct platf
+ /* Create sysfs entries */
+
+ priv->class = class_create(THIS_MODULE, priv->name);
+- ptr_err = priv->class;
+- if (IS_ERR(ptr_err))
++ if (IS_ERR(priv->class)) {
++ err = PTR_ERR(priv->class);
+ goto failed_class_create;
++ }
+
+- rpivid_mem_dev = device_create(priv->class, NULL,
+- priv->devid, NULL,
+- priv->name);
+- ptr_err = rpivid_mem_dev;
+- if (IS_ERR(ptr_err))
++ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name);
++ if (IS_ERR(dev)) {
++ err = PTR_ERR(dev);
+ goto failed_device_create;
++ }
+
+ /* Legacy alias */
+ {
+@@ -217,7 +215,6 @@ failed_device_create:
+ class_destroy(priv->class);
+ failed_class_create:
+ cdev_del(&priv->rpivid_mem_cdev);
+- err = PTR_ERR(ptr_err);
+ failed_cdev_add:
+ unregister_chrdev_region(priv->devid, 1);
+ failed_alloc_chrdev:
+++ /dev/null
-From 91ebd8e0ceb2de047e89e1253ff8ddefbc8aa65e Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 15:32:29 +0100
-Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Fix memory node
-
-We need to declare the proper device type, otherwise U-Boot won't boot
-with this devicetree. While we are this let the bootloader set the actual
-memory size.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -14,7 +14,8 @@
- };
-
- memory@0 {
-- reg = <0 0 0x40000000>;
-+ device_type = "memory";
-+ reg = <0x0 0x0 0x0>;
- };
-
- leds {
--- /dev/null
+From 7b4ea31990c1c43ad8ea86d42c1e451c85933d87 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 15 Jan 2020 14:02:43 +0000
+Subject: [PATCH] driver: char: rpivid: Add error handling to the
+ legacy device load
+
+The return value from device_create for the legacy device was never
+checked or handled. Add the required error handling.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -201,9 +201,14 @@ static int rpivid_mem_probe(struct platf
+ oldname[3] = 'g';
+ oldname[4] = 'o';
+ oldname[5] = 'n';
+- (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
+- oldname + 1);
++ dev = device_create(priv->class, NULL, priv->devid + 1, NULL,
++ oldname + 1);
+ kfree(oldname);
++
++ if (IS_ERR(dev)) {
++ err = PTR_ERR(dev);
++ goto failed_legacy_device_create;
++ }
+ }
+
+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
+@@ -211,6 +216,8 @@ static int rpivid_mem_probe(struct platf
+
+ return 0;
+
++failed_legacy_device_create:
++ device_destroy(priv->class, priv->devid);
+ failed_device_create:
+ class_destroy(priv->class);
+ failed_class_create:
+++ /dev/null
-From 10430ccee66023c26c90cdbc0d6381b41dcecfb7 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 15:43:41 +0100
-Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Backport BT part from
- upstream
-
-The CYW43455 on the Raspberry Pi 4 doesn't use an external pin as lower
-power clock anymore. So drop the GPIO clock from pinctrl. While we are at
-this add the missing declaration of hardware flow control.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -101,7 +101,8 @@
- /* uart0 communicates with the BT module */
- &uart0 {
- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
-+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
-+ uart-has-rtscts;
- status = "okay";
-
- bluetooth {
--- /dev/null
+From c9faef0f02397b30c389352ab9915fe529889143 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 15 Jan 2020 14:05:45 +0000
+Subject: [PATCH] driver: char: rpivid: Fix coding style whitespace
+ issues.
+
+Makes checkpatch happier.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -66,6 +66,7 @@ static int rpivid_mem_open(struct inode
+ int dev = iminor(inode);
+ int ret = 0;
+ struct rpivid_mem_priv *priv;
++
+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
+ ret = -ENXIO;
+
+@@ -135,7 +136,6 @@ static int rpivid_mem_probe(struct platf
+ struct resource *ioresource;
+ struct rpivid_mem_priv *priv;
+
+-
+ /* Allocate buffers and instance data */
+
+ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
+++ /dev/null
-From 92606b5e0000c25f5daae6c17b0ab71e9fb4c3b4 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 15:55:29 +0100
-Subject: [PATCH] ARM: dts: bcm2838: Backport node names from upstream
-
-According to devicetree specification the node name should describe
-the general class of device like ethernet or interrupt-controller.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2838.dtsi | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -27,7 +27,7 @@
- reg = <0x40000000 0x100>;
- };
-
-- gicv2: gic400@40041000 {
-+ gicv2: interrupt-controller@40041000 {
- interrupt-controller;
- #interrupt-cells = <3>;
- compatible = "arm,gic-400";
-@@ -346,7 +346,7 @@
- status = "okay";
- };
-
-- genet: genet@7d580000 {
-+ genet: ethernet@7d580000 {
- compatible = "brcm,genet-v5";
- reg = <0x0 0x7d580000 0x10000>;
- status = "okay";
-@@ -362,7 +362,7 @@
- compatible = "brcm,genet-mdio-v5";
- reg = <0xe14 0x8>;
- reg-names = "mdio";
-- phy1: genet-phy@0 {
-+ phy1: ethernet-phy@0 {
- compatible =
- "ethernet-phy-ieee802.3-c22";
- /* No interrupts - use PHY_POLL */
--- /dev/null
+From aa5c03a34b59ad840eeac990185c06b631a1e87e Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 15 Jan 2020 14:07:16 +0000
+Subject: [PATCH] driver: char: rpimem: Add SPDX licence header.
+
+Stops checkpatch complaining.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -1,3 +1,4 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ /**
+ * rpivid-mem.c - character device access to the RPiVid decoder registers
+ *
+++ /dev/null
-From b124d4fdc62b91441173854872c26bea6e36d2e5 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 18:01:57 +0100
-Subject: [PATCH] ARM: dts: bcm283x: Move intc label to
- bcm2835-common.dtsi
-
-The intc label isn't defined in bcm283x.dtsi, so we cannot use it there.
-So move it to bcm2835-common.dtsi.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2835-common.dtsi | 2 ++
- arch/arm/boot/dts/bcm283x.dtsi | 1 -
- 2 files changed, 2 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2835-common.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
-@@ -5,6 +5,8 @@
- */
-
- / {
-+ interrupt-parent = <&intc>;
-+
- soc {
- intc: interrupt-controller@7e00b200 {
- compatible = "brcm,bcm2835-armctrl-ic";
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -18,7 +18,6 @@
- / {
- compatible = "brcm,bcm2835";
- model = "BCM2835";
-- interrupt-parent = <&intc>;
- #address-cells = <1>;
- #size-cells = <1>;
-
--- /dev/null
+From be492eed9f4724798a7b85cf8779772dc901f986 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Tue, 21 Jan 2020 16:44:14 +0000
+Subject: [PATCH] driver: char: rpivid: Fix access to freed memory
+
+The error path during probe frees the private memory block, and
+then promptly dereferences it to log an error message.
+
+Use the base device instead of the pointer to it in the private
+structure.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/char/broadcom/rpivid-mem.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/char/broadcom/rpivid-mem.c
++++ b/drivers/char/broadcom/rpivid-mem.c
+@@ -229,7 +229,7 @@ failed_alloc_chrdev:
+ failed_get_resource:
+ kfree(priv);
+ failed_inst_alloc:
+- dev_err(priv->dev, "could not load rpivid_mem");
++ dev_err(&pdev->dev, "could not load rpivid_mem");
+ return err;
+ }
+
+++ /dev/null
-From 2810c8dae6aa7749bc787329d1d5841d0fdaea97 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 18:19:28 +0100
-Subject: [PATCH] ARM: dts: bcm2838: Remove always-on from armv7-timer
-
-After moving bcm2835-system-timer to bcm283x.dtsi there is no need for
-the always-on for armv7-timer anymore.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2838.dtsi | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -231,7 +231,6 @@
- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
- IRQ_TYPE_LEVEL_LOW)>;
- arm,cpu-registers-not-fw-configured;
-- always-on;
- };
-
- cpus: cpus {
--- /dev/null
+From 13047f38ca9adef0c0a0b0afce420dc912290d35 Mon Sep 17 00:00:00 2001
+From: Willem Remie <w.remie@drebble.io>
+Date: Thu, 9 Jan 2020 21:16:49 +0100
+Subject: [PATCH] add BME680 to i2c-sensor overlay
+
+---
+ arch/arm/boot/dts/overlays/README | 7 +++++--
+ .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++-
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1159,12 +1159,15 @@ Name: i2c-sensor
+ Info: Adds support for a number of I2C barometric pressure and temperature
+ sensors on i2c_arm
+ Load: dtoverlay=i2c-sensor,<param>=<val>
+-Params: addr Set the address for the BME280, BMP280, DS1621,
+- HDC100X, LM75, SHT3x or TMP102
++Params: addr Set the address for the BME280, BME680, BMP280,
++ DS1621, HDC100X, LM75, SHT3x or TMP102
+
+ bme280 Select the Bosch Sensortronic BME280
+ Valid addresses 0x76-0x77, default 0x76
+
++ bme680 Select the Bosch Sensortronic BME680
++ Valid addresses 0x76-0x77, default 0x76
++
+ bmp085 Select the Bosch Sensortronic BMP085
+
+ bmp180 Select the Bosch Sensortronic BMP180
+--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+@@ -216,10 +216,26 @@
+ };
+ };
+
++ fragment@14 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ bme680: bme680@76 {
++ compatible = "bosch,bme680";
++ reg = <0x76>;
++ status = "okay";
++ };
++ };
++ };
++
++
+ __overrides__ {
+ addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
+ <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
+- <&ds1621>,"reg:0";
++ <&ds1621>,"reg:0", <&bme680>,"reg:0";
+ bme280 = <0>,"+0";
+ bmp085 = <0>,"+1";
+ bmp180 = <0>,"+2";
+@@ -235,5 +251,6 @@
+ sht3x = <0>,"+11";
+ ds1621 = <0>,"+12";
+ max17040 = <0>,"+13";
++ bme680 = <0>,"+14";
+ };
+ };
--- /dev/null
+From b7944a79716c115d881898e6a95705b262e7c1c9 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 7 Jan 2020 10:08:19 +0000
+Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer
+ size on split IN
+
+The hcd would unconditionally set the transfer length to the endpoint
+packet size for non-isoc IN transfers. If the remaining buffer length
+was less than the length of returned data, random memory would get
+scribbled over, with bad effects if it crossed a page boundary.
+
+Force a babble error if this happens by limiting the max transfer size
+to the available buffer space. DMA will stop writing to memory on a
+babble condition.
+
+The hardware expects xfersize to be an integer multiple of maxpacket
+size, so override hcchar.b.mps as well.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->nr_errors = 0;
+
+ st->hcchar_copy.d32 = 0;
+- st->hcchar_copy.b.mps = hc->max_packet;
++ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ st->hcchar_copy.b.epdir = hc->ep_is_in;
+ st->hcchar_copy.b.devaddr = hc->dev_addr;
+ st->hcchar_copy.b.epnum = hc->ep_num;
+@@ -1858,7 +1858,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->hctsiz_copy.b.pid = hc->data_pid_start;
+
+ if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+- hc->xfer_len = hc->max_packet;
++ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+ hc->xfer_len = 188;
+ }
+++ /dev/null
-From b0aff8993c458396b82ad7d0792199f971413bb8 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 16:35:54 +0100
-Subject: [PATCH] net: bcmgenet: Add RGMII_RXID support
-
-This adds the missing support for the PHY mode RGMII_RXID.
-It's necessary for the Raspberry Pi 4.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- drivers/net/ethernet/broadcom/genet/bcmmii.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
-@@ -274,10 +274,11 @@ int bcmgenet_mii_config(struct net_devic
- id_mode_dis = BIT(16);
- /* fall through */
- case PHY_INTERFACE_MODE_RGMII_TXID:
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
- if (id_mode_dis)
- phy_name = "external RGMII (no delay)";
- else
-- phy_name = "external RGMII (TX delay)";
-+ phy_name = "external RGMII";
- bcmgenet_sys_writel(priv,
- PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
- break;
+++ /dev/null
-From 30bd619480b6a2b92d404a61a1e90ddb76ae4be8 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Wed, 25 Dec 2019 16:40:47 +0100
-Subject: [PATCH] ARM: dts: bcm2838: Backport genet from upstream
-
-This backport all genet differences (different compatible, right PHY mode,
-board specific stuff) from upstream.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 14 ++++++++++++++
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 14 ++++++++++++++
- arch/arm/boot/dts/bcm2838.dtsi | 17 ++++-------------
- 3 files changed, 32 insertions(+), 13 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -134,6 +134,20 @@
- vqmmc-supply = <&sd_io_1v8_reg>;
- };
-
-+&genet {
-+ phy-handle = <&phy1>;
-+ phy-mode = "rgmii-rxid";
-+ status = "okay";
-+};
-+
-+&genet_mdio {
-+ phy1: ethernet-phy@1 {
-+ /* No PHY interrupt */
-+ reg = <0x1>;
-+ led-modes = <0x00 0x08>; /* link/activity link */
-+ };
-+};
-+
- &leds {
- act_led: act {
- label = "led0";
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-@@ -98,6 +98,20 @@
- vqmmc-supply = <&sd_io_1v8_reg>;
- };
-
-+&genet {
-+ phy-handle = <&phy1>;
-+ phy-mode = "rgmii-rxid";
-+ status = "okay";
-+};
-+
-+&genet_mdio {
-+ phy1: ethernet-phy@1 {
-+ /* No PHY interrupt */
-+ reg = <0x1>;
-+ led-modes = <0x00 0x08>; /* link/activity link */
-+ };
-+};
-+
- /* uart0 communicates with the BT module */
- &uart0 {
- pinctrl-names = "default";
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -346,29 +346,20 @@
- };
-
- genet: ethernet@7d580000 {
-- compatible = "brcm,genet-v5";
-+ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
- reg = <0x0 0x7d580000 0x10000>;
-- status = "okay";
- #address-cells = <0x1>;
- #size-cells = <0x1>;
- interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-- phy-handle = <&phy1>;
-- phy-mode = "rgmii";
-- mdio@e14 {
-+ status = "disabled";
-+
-+ genet_mdio: mdio@e14 {
- #address-cells = <0x0>;
- #size-cells = <0x1>;
- compatible = "brcm,genet-mdio-v5";
- reg = <0xe14 0x8>;
- reg-names = "mdio";
-- phy1: ethernet-phy@0 {
-- compatible =
-- "ethernet-phy-ieee802.3-c22";
-- /* No interrupts - use PHY_POLL */
-- max-speed = <1000>;
-- reg = <0x1>;
-- led-modes = <0x00 0x08>; /* link/activity link */
-- };
- };
- };
-
--- /dev/null
+From 09648b92a71b03450e9482f0cc5bd22298f78d44 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Wed, 8 Jan 2020 12:48:09 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split
+ transactions
+
+Non-periodic splits will DMA to/from the driver-provided transfer_buffer,
+which may be freed immediately after the dequeue call returns. Block until
+we know the transfer is complete.
+
+A similar delay is needed when cleaning up disconnects, as the FIQ could
+have started a periodic transfer in the previous microframe to the one
+that triggered a disconnect.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++--
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 +
+ 2 files changed, 32 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg
+ dwc_list_link_t *qh_item, *qh_tmp;
+ dwc_otg_qh_t *qh;
+ dwc_otg_qtd_t *qtd, *qtd_tmp;
++ int quiesced = 0;
+
+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
+ qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
+@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
++ /* We're called from disconnect callback or in the middle of freeing the HCD here,
++ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock.
++ * No further URBs will be submitted, but wait 1 microframe for any previously
++ * submitted periodic DMA to finish.
++ */
++ if (!quiesced) {
++ udelay(125);
++ quiesced = 1;
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
+ /* In FIQ FSM mode, we need to shut down carefully.
+ * The FIQ may attempt to restart a disabled channel */
+ if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
++ int retries = 3;
++ int running = 0;
++ enum fiq_fsm_state state;
++
+ local_fiq_disable();
+ fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
+ fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+ local_fiq_enable();
++
++ if (dwc_qh_is_non_per(qh)) {
++ do {
++ state = READ_ONCE(hcd->fiq_state->channel[n].fsm);
++ running = (state != FIQ_NP_SPLIT_DONE) &&
++ (state != FIQ_NP_SPLIT_LS_ABORTED) &&
++ (state != FIQ_NP_SPLIT_HS_ABORTED);
++ if (!running)
++ break;
++ udelay(125);
++ } while(--retries);
++ if (!retries)
++ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d",
++ qh->channel->hc_num);
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -27,6 +27,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/stat.h>
+ #include <linux/pci.h>
++#include <linux/compiler.h>
+
+ #include <linux/version.h>
+
+++ /dev/null
-From 88dacbcd946d2e0cd06337ab3f393064ab6aba82 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 27 Dec 2019 11:40:56 +0100
-Subject: [PATCH] ARM: bcm: Backport BCM2711 support from upstream
-
-Make the BCM2711 a different machine, but keep it in board_bcm2835.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/mach-bcm/Kconfig | 4 ++--
- arch/arm/mach-bcm/board_bcm2835.c | 17 +++++++++++++++--
- arch/arm64/Kconfig.platforms | 5 +++--
- 3 files changed, 20 insertions(+), 6 deletions(-)
-
---- a/arch/arm/mach-bcm/Kconfig
-+++ b/arch/arm/mach-bcm/Kconfig
-@@ -161,7 +161,7 @@ config ARCH_BCM2835
- select GPIOLIB
- select ARM_AMBA
- select ARM_ERRATA_411920 if ARCH_MULTI_V6
-- select ARM_GIC
-+ select ARM_GIC if ARCH_MULTI_V7
- select ARM_TIMER_SP804
- select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
- select TIMER_OF
-@@ -175,7 +175,7 @@ config ARCH_BCM2835
- select ZONE_DMA if ARM_LPAE
- select MFD_CORE
- help
-- This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
-+ This enables support for the Broadcom BCM2711 and BCM283x SoCs.
- This SoC is used in the Raspberry Pi and Roku 2 devices.
-
- config ARCH_BCM_53573
---- a/arch/arm/mach-bcm/board_bcm2835.c
-+++ b/arch/arm/mach-bcm/board_bcm2835.c
-@@ -109,17 +109,30 @@ static const char * const bcm2835_compat
- #ifdef CONFIG_ARCH_MULTI_V7
- "brcm,bcm2836",
- "brcm,bcm2837",
-- "brcm,bcm2711",
- #endif
- NULL
- };
-
- DT_MACHINE_START(BCM2835, "BCM2835")
-+ .map_io = bcm2835_map_io,
-+ .init_machine = bcm2835_init,
-+ .dt_compat = bcm2835_compat,
-+ .smp = smp_ops(bcm2836_smp_ops),
-+MACHINE_END
-+
-+static const char * const bcm2711_compat[] = {
-+#ifdef CONFIG_ARCH_MULTI_V7
-+ "brcm,bcm2711",
-+#endif
-+ NULL
-+};
-+
-+DT_MACHINE_START(BCM2711, "BCM2711")
- #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
- .dma_zone_size = SZ_1G,
- #endif
- .map_io = bcm2835_map_io,
- .init_machine = bcm2835_init,
-- .dt_compat = bcm2835_compat,
-+ .dt_compat = bcm2711_compat,
- .smp = smp_ops(bcm2836_smp_ops),
- MACHINE_END
---- a/arch/arm64/Kconfig.platforms
-+++ b/arch/arm64/Kconfig.platforms
-@@ -37,11 +37,12 @@ config ARCH_BCM2835
- select PINCTRL
- select PINCTRL_BCM2835
- select ARM_AMBA
-+ select ARM_GIC
- select ARM_TIMER_SP804
- select HAVE_ARM_ARCH_TIMER
- help
-- This enables support for the Broadcom BCM2837 SoC.
-- This SoC is used in the Raspberry Pi 3 device.
-+ This enables support for the Broadcom BCM2837 and BCM2711 SoC.
-+ These SoCs are used in the Raspberry Pi 3 and 4 devices.
-
- config ARCH_BCM_IPROC
- bool "Broadcom iProc SoC Family"
--- /dev/null
+From edbbc60ed86f4b690838e6c4b0aed48803e334cc Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Mon, 13 Jan 2020 15:54:55 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ
+ handler(s)
+
+On BCM2835, there is no hardware guarantee that multiple outstanding
+reads to different peripherals will complete in-order. The FIQ code
+uses peripheral reads without barriers for performance, so in the case
+where a read to a slow peripheral was issued immediately prior to FIQ
+entry, the first peripheral read that the FIQ did could end up with
+wrong read data returned.
+
+Add dsb(sy) on entry so that all outstanding reads are retired.
+
+The FIQ only issues reads to the dwc_otg core, so per-read barriers
+in the handler itself are not required.
+
+On BCM2836 and BCM2837 the barrier is not strictly required due to
+differences in how the peripheral bus is implemented, but having
+arch-specific handlers that introduce different latencies is risky.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+ haintmsk_data_t haintmsk;
+ int kick_irq = 0;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ gintsts_handled.d32 = 0;
+ haint_handled.d32 = 0;
+
+@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+ gintmsk_data_t gintmsk;
+ hfnum_data_t hfnum;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ fiq_fsm_spin_lock(&state->lock);
+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM);
+ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
--- /dev/null
+From 17159731ae064a70031d746284855b7d30f17407 Mon Sep 17 00:00:00 2001
+From: Ed Spiridonov <edo.rus@gmail.com>
+Date: Tue, 10 Dec 2019 22:45:04 +0300
+Subject: [PATCH] Add universal device tree overlay for SPI devices
+
+Just specify the SPI address and device name ("compatible" property).
+This overlay lacks any device-specific parameter support!
+(some of them could be added later)
+
+Examples:
+1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
+ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
+2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
+ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
+
+Signed-off-by: Ed Spiridonov <edo.rus@gmail.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 23 ++
+ arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++
+ 3 files changed, 229 insertions(+)
+ create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ allo-katana-dac-audio.dtbo \
+ allo-piano-dac-pcm512x-audio.dtbo \
+ allo-piano-dac-plus-pcm512x-audio.dtbo \
++ anyspi.dtbo \
+ apds9960.dtbo \
+ applepi-dac.dtbo \
+ at86rf233.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga
+ better voice quality. (default Off)
+
+
++Name: anyspi
++Info: Universal device tree overlay for SPI devices
++
++ Just specify the SPI address and device name ("compatible" property).
++ This overlay lacks any device-specific parameter support!
++
++ For devices on spi1 or spi2, the interfaces should be enabled
++ with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
++
++ Examples:
++ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
++ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
++ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
++ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
++Load: dtoverlay=anyspi,<param>=<val>
++Params: spi<n>-<m> Configure device at spi<n>, cs<m>
++ (boolean, required)
++ dev Set device name to search compatible module
++ (string, required)
++ speed Set SPI clock frequency in Hz
++ (integer, optional, default 500000)
++
++
+ Name: apds9960
+ Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
+ gesture sensor
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts
+@@ -0,0 +1,205 @@
++/*
++ * Universal device tree overlay for SPI devices
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spidev0>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev1>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target-path = "spi1/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target-path = "spi1/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@4 {
++ target-path = "spi1/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@5 {
++ target-path = "spi2/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@6 {
++ target-path = "spi2/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@7 {
++ target-path = "spi2/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@8 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_00: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@9 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_01: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@10 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_10: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@11 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_11: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@12 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_12: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@13 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_20: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@14 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_21: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@15 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_22: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ __overrides__ {
++ spi0-0 = <0>, "+0+8";
++ spi0-1 = <0>, "+1+9";
++ spi1-0 = <0>, "+2+10";
++ spi1-1 = <0>, "+3+11";
++ spi1-2 = <0>, "+4+12";
++ spi2-0 = <0>, "+5+13";
++ spi2-1 = <0>, "+6+14";
++ spi2-2 = <0>, "+7+15";
++ dev = <&anyspi_00>,"compatible",
++ <&anyspi_01>,"compatible",
++ <&anyspi_10>,"compatible",
++ <&anyspi_11>,"compatible",
++ <&anyspi_12>,"compatible",
++ <&anyspi_20>,"compatible",
++ <&anyspi_21>,"compatible",
++ <&anyspi_22>,"compatible";
++ speed = <&anyspi_00>, "spi-max-frequency:0",
++ <&anyspi_01>, "spi-max-frequency:0",
++ <&anyspi_10>, "spi-max-frequency:0",
++ <&anyspi_11>, "spi-max-frequency:0",
++ <&anyspi_12>, "spi-max-frequency:0",
++ <&anyspi_20>, "spi-max-frequency:0",
++ <&anyspi_21>, "spi-max-frequency:0",
++ <&anyspi_22>, "spi-max-frequency:0";
++ };
++};
+++ /dev/null
-From d19e54299471dbdf92a3115ec6591a81c527f786 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 27 Dec 2019 11:55:59 +0100
-Subject: [PATCH] hwrng: iproc-rng200 - Add support for BCM2711
-
-commit 0f95b09a5f624964d520c8f6a2674090fb98ae25 upstream.
-
-BCM2711 features a RNG200 hardware random number generator block.
-So make the driver available.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
-Signed-off-by: Stephen Brennan <stephen@brennan.io>
-Reviewed-by: Matthias Brugger <mbrugger@suse.com>
-Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/char/hw_random/iproc-rng200.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/char/hw_random/iproc-rng200.c
-+++ b/drivers/char/hw_random/iproc-rng200.c
-@@ -292,6 +292,7 @@ static int iproc_rng200_probe(struct pla
- }
-
- static const struct of_device_id iproc_rng200_of_match[] = {
-+ { .compatible = "brcm,bcm2711-rng200", },
- { .compatible = "brcm,bcm7211-rng200", },
- { .compatible = "brcm,bcm7278-rng200", },
- { .compatible = "brcm,iproc-rng200", },
+++ /dev/null
-From 0f4d508ca3dc0eac4ef4ac85190da58285f1580f Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Fri, 27 Dec 2019 12:01:17 +0100
-Subject: [PATCH] ARM: dts: bcm2838: Add upstream RNG compatible
-
-This adds the ability to use the RNG with an upstream kernel.
-Keep the old one for backward compatibility.
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
----
- arch/arm/boot/dts/bcm2838.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -682,7 +682,7 @@
- };
-
- &rng {
-- compatible = "brcm,bcm2838-rng200";
-+ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
- };
-
- &sdhost {
--- /dev/null
+From 221b442eb7e5b4ed16151b5501f4b905a9b8455c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+ <j-schambacher@users.noreply.github.com>
+Date: Tue, 21 Jan 2020 15:58:39 +0100
+Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version
+
+This adds the driver for the DAC+HD version supporting HiFiBerry's
+PCM179x based DACs. It also adds PLL control for clock generation.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++
+ drivers/clk/Kconfig | 3 +
+ drivers/clk/Makefile | 1 +
+ drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++
+ sound/soc/bcm/Kconfig | 9 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplushd.c | 238 +++++++++++++
+ 14 files changed, 704 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+ create mode 100644 drivers/clk/clk-hifiberry-dachd.c
+ create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-dacplusadc.dtbo \
+ hifiberry-dacplusadcpro.dtbo \
+ hifiberry-dacplusdsp.dtbo \
++ hifiberry-dacplushd.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp
+ Params: <None>
+
+
++Name: hifiberry-dacplushd
++Info: Configures the HifiBerry DAC+ HD audio card
++Load: dtoverlay=hifiberry-dacplushd
++Params: <None>
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+@@ -0,0 +1,106 @@
++// Definitions for HiFiBerry DAC+ HD
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dachd_osc: pll_dachd_osc {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm1792a@4c {
++ compatible = "ti,pcm1792a";
++ #sound-dai-cells = <0>;
++ #clock-cells = <0>;
++ clocks = <&dachd_osc>;
++ reg = <0x4c>;
++ status = "okay";
++ };
++ pll: pll@62 {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ reg = <0x62>;
++ clocks = <&dachd_osc>;
++ status = "okay";
++ common_pll_regs = [
++ 02 53 03 00 07 20 0F 00
++ 10 0D 11 1D 12 0D 13 8C
++ 14 8C 15 8C 16 8C 17 8C
++ 18 2A 1C 00 1D 0F 1F 00
++ 2A 00 2C 00 2F 00 30 00
++ 31 00 32 00 34 00 37 00
++ 38 00 39 00 3A 00 3B 01
++ 3E 00 3F 00 40 00 41 00
++ 5A 00 5B 00 95 00 96 00
++ 97 00 98 00 99 00 9A 00
++ 9B 00 A2 00 A3 00 A4 00
++ B7 92 ];
++ 192k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 22 36 80 3C 22
++ 3D 46 ];
++ 96k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 47 36 00 3C 32
++ 3D 46 ];
++ 48k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 90 36 00 3C 42
++ 3D 46 ];
++ 176k4_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 02 35 25 36 C0 3C 22
++ 3D 7A ];
++ 88k2_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 4D 36 80 3C 32
++ 3D 7A ];
++ 44k1_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 9D 36 00 3C 42
++ 3D 7A ];
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplushd";
++ i2s-controller = <&i2s>;
++ clocks = <&pll 0>;
++ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
++ status = "okay";
++ };
++ };
++
++};
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X
+ multi-function device has one fixed-rate oscillator, clocked
+ at 32KHz.
+
++config COMMON_CLK_HIFIBERRY_DACPLUSHD
++ tristate
++
+ config COMMON_CLK_HIFIBERRY_DACPRO
+ tristate
+
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-high
+ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
+ obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
+ obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o
++obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
+ obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+ obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
+ obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
+--- /dev/null
++++ b/drivers/clk/clk-hifiberry-dachd.c
+@@ -0,0 +1,333 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Clock Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * 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 <linux/clk-provider.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/regmap.h>
++
++#define NO_PLL_RESET 0
++#define PLL_RESET 1
++#define HIFIBERRY_PLL_MAX_REGISTER 256
++#define DEFAULT_RATE 44100
++
++static struct reg_default hifiberry_pll_reg_defaults[] = {
++ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
++ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
++ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
++ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
++ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
++ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
++ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
++ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
++ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
++ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
++ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
++ {0xB7, 0x92},
++ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
++ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
++ {0x3D, 0x7A},
++ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
++ { 177, 0xAC},
++};
++static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_common_pll_regs;
++static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_192k_pll_regs;
++static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_96k_pll_regs;
++static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_48k_pll_regs;
++static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_176k4_pll_regs;
++static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_88k2_pll_regs;
++static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_44k1_pll_regs;
++
++/**
++ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
++ * @hw: clk_hw for the common clk framework
++ */
++struct clk_hifiberry_drvdata {
++ struct regmap *regmap;
++ struct clk *clk;
++ struct clk_hw hw;
++ unsigned long rate;
++};
++
++#define to_hifiberry_clk(_hw) \
++ container_of(_hw, struct clk_hifiberry_drvdata, hw)
++
++static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
++ struct reg_default *regs,
++ int num, int do_pll_reset)
++{
++ int i;
++ int ret = 0;
++ char pll_soft_reset[] = { 177, 0xAC, };
++
++ for (i = 0; i < num; i++) {
++ ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
++ if (ret)
++ return ret;
++ }
++ if (do_pll_reset) {
++ ret |= regmap_write(regmap, pll_soft_reset[0],
++ pll_soft_reset[1]);
++ mdelay(10);
++ }
++ return ret;
++}
++
++static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ return to_hifiberry_clk(hw)->rate;
++}
++
++static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long *parent_rate)
++{
++ return rate;
++}
++
++static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ int ret;
++ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
++
++ switch (rate) {
++ case 44100:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
++ PLL_RESET);
++ break;
++ case 88200:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
++ PLL_RESET);
++ break;
++ case 176400:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
++ PLL_RESET);
++ break;
++ case 48000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
++ PLL_RESET);
++ break;
++ case 96000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
++ PLL_RESET);
++ break;
++ case 192000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
++ PLL_RESET);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ to_hifiberry_clk(hw)->rate = rate;
++
++ return ret;
++}
++
++const struct clk_ops clk_hifiberry_dachd_rate_ops = {
++ .recalc_rate = clk_hifiberry_dachd_recalc_rate,
++ .round_rate = clk_hifiberry_dachd_round_rate,
++ .set_rate = clk_hifiberry_dachd_set_rate,
++};
++
++static int clk_hifiberry_get_prop_values(struct device *dev,
++ char *prop_name,
++ struct reg_default *regs)
++{
++ int ret;
++ int i;
++ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
++
++ ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
++ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
++ if (ret < 0)
++ return ret;
++ if (ret & 1) {
++ dev_err(dev,
++ "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
++ __func__,
++ prop_name,
++ ret);
++ return -EINVAL;
++ }
++ ret /= 2;
++ for (i = 0; i < ret; i++) {
++ regs[i].reg = (u32)tmp[2 * i];
++ regs[i].def = (u32)tmp[2 * i + 1];
++ }
++ return ret;
++}
++
++
++static int clk_hifiberry_dachd_dt_parse(struct device *dev)
++{
++ num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "common_pll_regs", common_pll_regs);
++ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "44k1_pll_regs", dedicated_44k1_pll_regs);
++ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "88k2_pll_regs", dedicated_88k2_pll_regs);
++ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "176k4_pll_regs", dedicated_176k4_pll_regs);
++ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "48k_pll_regs", dedicated_48k_pll_regs);
++ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "96k_pll_regs", dedicated_96k_pll_regs);
++ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "192k_pll_regs", dedicated_192k_pll_regs);
++ return 0;
++}
++
++
++static int clk_hifiberry_dachd_remove(struct device *dev)
++{
++ of_clk_del_provider(dev->of_node);
++ return 0;
++}
++
++const struct regmap_config hifiberry_pll_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = HIFIBERRY_PLL_MAX_REGISTER,
++ .reg_defaults = hifiberry_pll_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ .cache_type = REGCACHE_RBTREE,
++};
++EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
++
++
++static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct clk_hifiberry_drvdata *hdclk;
++ int ret = 0;
++ struct clk_init_data init;
++ struct device *dev = &i2c->dev;
++ struct device_node *dev_node = dev->of_node;
++ struct regmap_config config = hifiberry_pll_regmap;
++
++ hdclk = devm_kzalloc(&i2c->dev,
++ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
++ if (!hdclk)
++ return -ENOMEM;
++
++ i2c_set_clientdata(i2c, hdclk);
++
++ hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
++
++ if (IS_ERR(hdclk->regmap))
++ return PTR_ERR(hdclk->regmap);
++
++ /* start PLL to allow detection of DAC */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
++ hifiberry_pll_reg_defaults,
++ ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ PLL_RESET);
++ if (ret)
++ return ret;
++
++ clk_hifiberry_dachd_dt_parse(dev);
++
++ /* restart PLL with configs from DTB */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
++ num_common_pll_regs, PLL_RESET);
++ if (ret)
++ return ret;
++
++ init.name = "clk-hifiberry-dachd";
++ init.ops = &clk_hifiberry_dachd_rate_ops;
++ init.flags = 0;
++ init.parent_names = NULL;
++ init.num_parents = 0;
++
++ hdclk->hw.init = &init;
++
++ hdclk->clk = devm_clk_register(dev, &hdclk->hw);
++ if (IS_ERR(hdclk->clk)) {
++ dev_err(dev, "unable to register %s\n", init.name);
++ return PTR_ERR(hdclk->clk);
++ }
++
++ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
++ if (ret != 0) {
++ dev_err(dev, "Cannot of_clk_add_provider");
++ return ret;
++ }
++
++ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
++ if (ret != 0) {
++ dev_err(dev, "Cannot set rate : %d\n", ret);
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
++{
++ clk_hifiberry_dachd_remove(&i2c->dev);
++ return 0;
++}
++
++static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
++ { "dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
++
++static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
++ { .compatible = "hifiberry,dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
++
++static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
++ .probe = clk_hifiberry_dachd_i2c_probe,
++ .remove = clk_hifiberry_dachd_i2c_remove,
++ .id_table = clk_hifiberry_dachd_i2c_id,
++ .driver = {
++ .name = "dachd-clk",
++ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
++ },
++};
++
++module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
++
++
++MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:clk-hifiberry-dachd");
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -42,6 +42,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
++ tristate "Support for HifiBerry DAC+ HD"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM179X_I2C
++ select COMMON_CLK_HIFIBERRY_DACPLUSHD
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ HD.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
+ tristate "Support for HifiBerry DAC+ADC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+@@ -56,6 +64,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM512x_I2C
+ select SND_SOC_PCM186X_I2C
++ select COMMON_CLK_HIFIBERRY_DACPRO
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
+
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
++snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
+@@ -41,6 +42,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplushd.c
+@@ -0,0 +1,238 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ASoC Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * 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 <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++
++#include "../codecs/pcm179x.h"
++
++#define DEFAULT_RATE 44100
++
++struct brd_drv_data {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++static struct brd_drv_data drvdata;
++static struct gpio_desc *reset_gpio;
++static const unsigned int hb_dacplushd_rates[] = {
++ 192000, 96000, 48000, 176400, 88200, 44100,
++};
++
++static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
++ .list = hb_dacplushd_rates,
++ .count = ARRAY_SIZE(hb_dacplushd_rates),
++};
++
++static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
++{
++ /* constraints for standard sample rates */
++ snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &hb_dacplushd_constraints);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplushd_set_sclk(
++ struct snd_soc_component *component,
++ int sample_rate)
++{
++ if (!IS_ERR(drvdata.sclk))
++ clk_set_rate(drvdata.sclk, sample_rate);
++}
++
++static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ dai->name = "HiFiBerry DAC+ HD";
++ dai->stream_name = "HiFiBerry DAC+ HD HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
++
++ /* allow only fixed 32 clock counts per channel */
++ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplushd_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
++ return ret;
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
++ .startup = snd_rpi_hb_dacplushd_startup,
++ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
++};
++
++SND_SOC_DAILINK_DEFS(hifi,
++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")),
++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
++
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
++{
++ .name = "HiFiBerry DAC+ HD",
++ .stream_name = "HiFiBerry DAC+ HD HiFi",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplushd_ops,
++ .init = snd_rpi_hifiberry_dacplushd_init,
++ SND_SOC_DAILINK_REG(hifi),
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
++ .name = "snd_rpi_hifiberry_dacplushd",
++ .driver_name = "HifiberryDacplusHD",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplushd_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
++};
++
++static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ static int dac_reset_done;
++ struct device *dev = &pdev->dev;
++ struct device_node *dev_node = dev->of_node;
++
++ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
++
++ /* get GPIO and release DAC from RESET */
++ if (!dac_reset_done) {
++ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
++ if (IS_ERR(reset_gpio)) {
++ dev_err(&pdev->dev, "gpiod_get() failed\n");
++ return -EINVAL;
++ }
++ dac_reset_done = 1;
++ }
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 1);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplushd_dai[0];
++ i2s_node = of_parse_phandle(pdev->dev.of_node,
++ "i2s-controller", 0);
++
++ if (i2s_node) {
++ dai->cpus->of_node = i2s_node;
++ dai->platforms->of_node = i2s_node;
++ dai->cpus->dai_name = NULL;
++ dai->platforms->name = NULL;
++ } else {
++ return -EPROBE_DEFER;
++ }
++
++ }
++
++ ret = devm_snd_soc_register_card(&pdev->dev,
++ &snd_rpi_hifiberry_dacplushd);
++ if (ret && ret != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ return ret;
++ }
++ if (ret == -EPROBE_DEFER)
++ return ret;
++
++ dev_set_drvdata(dev, &drvdata);
++ if (dev_node == NULL) {
++ dev_err(&pdev->dev, "Device tree node not found\n");
++ return -ENODEV;
++ }
++
++ drvdata.sclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(drvdata.sclk)) {
++ drvdata.sclk = ERR_PTR(-ENOENT);
++ return -ENODEV;
++ }
++
++ clk_set_rate(drvdata.sclk, DEFAULT_RATE);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
++{
++ if (IS_ERR(reset_gpio))
++ return -EINVAL;
++
++ /* put DAC into RESET and release GPIO */
++ gpiod_set_value(reset_gpio, 0);
++ gpiod_put(reset_gpio);
++
++ return 0;
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplushd", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplushd",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplushd_probe,
++ .remove = snd_rpi_hifiberry_dacplushd_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
++
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 2c1a5dae2fb127729773685e3cd1e48934edf1f2 Mon Sep 17 00:00:00 2001
+From: Luke Hinds <7058938+lukehinds@users.noreply.github.com>
+Date: Wed, 22 Jan 2020 16:03:00 +0000
+Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835
+
+The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted
+Platform Module) having been registered when it initialises; otherwise
+it assumes there is no TPM. It has been observed on BCM2835 that IMA
+is initialised before TPM, and that initialising the BCM2835 clock
+driver before the firmware driver has the effect of reversing this
+order.
+
+Change the firmware driver to initialise at core_initcall, delaying the
+BCM2835 clock driver to postcore_initcall.
+
+See: https://github.com/raspberrypi/linux/issues/3291
+ https://github.com/raspberrypi/linux/pull/3297
+
+Signed-off-by: Luke Hinds <lhinds@redhat.com>
+Co-authored-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 2 +-
+ drivers/firmware/raspberrypi.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2382,7 +2382,7 @@ static int __init __bcm2835_clk_driver_i
+ {
+ return platform_driver_register(&bcm2835_clk_driver);
+ }
+-core_initcall(__bcm2835_clk_driver_init);
++postcore_initcall(__bcm2835_clk_driver_init);
+
+ MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+ MODULE_DESCRIPTION("BCM2835 clock driver");
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -416,7 +416,7 @@ out2:
+ out1:
+ return ret;
+ }
+-subsys_initcall(rpi_firmware_init);
++core_initcall(rpi_firmware_init);
+
+ static void __init rpi_firmware_exit(void)
+ {
+++ /dev/null
-From d0be0df98679b7a9a30ba74c065ed30301e2bd22 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 15 Jan 2020 13:59:57 +0000
-Subject: [PATCH] driver: char: rpivid: Destroy the legacy device on
- remove
-
-The legacy name support created a new device that was never destroyed.
-If the driver was unloaded and reloaded, it failed due to the
-device already existing.
-
-Fixes: "75f1d14 driver: char: rpivid - also support legacy name"
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -233,6 +233,7 @@ static int rpivid_mem_remove(struct plat
- struct device *dev = &pdev->dev;
- struct rpivid_mem_priv *priv = platform_get_drvdata(pdev);
-
-+ device_destroy(priv->class, priv->devid + 1);
- device_destroy(priv->class, priv->devid);
- class_destroy(priv->class);
- cdev_del(&priv->rpivid_mem_cdev);
--- /dev/null
+From fa93fc95e5fb4e75a2a5ea930509d80083dee9b3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+ <j-schambacher@users.noreply.github.com>
+Date: Thu, 23 Jan 2020 13:32:13 +0100
+Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO
+ card (#3424)
+
+This patch fixes the board DAI setting when in master-mode.
+Wrong setting could have caused random pop noise.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ dai->name = "HiFiBerry DAC+ADC Pro";
+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
+
+ // set DAC DAI configuration
+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
+++ /dev/null
-From 8b95d0d18fcfb940fb0d171663ce5c93b8fb0024 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Tue, 21 Jan 2020 16:24:45 +0000
-Subject: [PATCH] driver: char: rpivid: Clean up error handling use of
- ERR_PTR/IS_ERR
-
-The driver used an unnecessary intermediate void* variable so it
-only called ERR_PTR once to convert to the error value.
-
-Switch to converting as the error arises to remove these intermediate
-variables.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 17 +++++++----------
- 1 file changed, 7 insertions(+), 10 deletions(-)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -130,10 +130,8 @@ static const struct of_device_id rpivid_
- static int rpivid_mem_probe(struct platform_device *pdev)
- {
- int err;
-- void *ptr_err;
- const struct of_device_id *id;
- struct device *dev = &pdev->dev;
-- struct device *rpivid_mem_dev;
- struct resource *ioresource;
- struct rpivid_mem_priv *priv;
-
-@@ -183,16 +181,16 @@ static int rpivid_mem_probe(struct platf
- /* Create sysfs entries */
-
- priv->class = class_create(THIS_MODULE, priv->name);
-- ptr_err = priv->class;
-- if (IS_ERR(ptr_err))
-+ if (IS_ERR(priv->class)) {
-+ err = PTR_ERR(priv->class);
- goto failed_class_create;
-+ }
-
-- rpivid_mem_dev = device_create(priv->class, NULL,
-- priv->devid, NULL,
-- priv->name);
-- ptr_err = rpivid_mem_dev;
-- if (IS_ERR(ptr_err))
-+ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name);
-+ if (IS_ERR(dev)) {
-+ err = PTR_ERR(dev);
- goto failed_device_create;
-+ }
-
- /* Legacy alias */
- {
-@@ -217,7 +215,6 @@ failed_device_create:
- class_destroy(priv->class);
- failed_class_create:
- cdev_del(&priv->rpivid_mem_cdev);
-- err = PTR_ERR(ptr_err);
- failed_cdev_add:
- unregister_chrdev_region(priv->devid, 1);
- failed_alloc_chrdev:
+++ /dev/null
-From 7b4ea31990c1c43ad8ea86d42c1e451c85933d87 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 15 Jan 2020 14:02:43 +0000
-Subject: [PATCH] driver: char: rpivid: Add error handling to the
- legacy device load
-
-The return value from device_create for the legacy device was never
-checked or handled. Add the required error handling.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -201,9 +201,14 @@ static int rpivid_mem_probe(struct platf
- oldname[3] = 'g';
- oldname[4] = 'o';
- oldname[5] = 'n';
-- (void)device_create(priv->class, NULL, priv->devid + 1, NULL,
-- oldname + 1);
-+ dev = device_create(priv->class, NULL, priv->devid + 1, NULL,
-+ oldname + 1);
- kfree(oldname);
-+
-+ if (IS_ERR(dev)) {
-+ err = PTR_ERR(dev);
-+ goto failed_legacy_device_create;
-+ }
- }
-
- dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx",
-@@ -211,6 +216,8 @@ static int rpivid_mem_probe(struct platf
-
- return 0;
-
-+failed_legacy_device_create:
-+ device_destroy(priv->class, priv->devid);
- failed_device_create:
- class_destroy(priv->class);
- failed_class_create:
--- /dev/null
+From f50f0425592a8496d6d25b4936caadfe64523c91 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 24 Jan 2020 09:02:37 +0000
+Subject: [PATCH] overlays: Use preferred compatible strings
+
+Make sure all overlays have correct compatible strings before enabling
+the automated checking.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++
+ 5 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+@@ -17,6 +17,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/pwm-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
+@@ -15,6 +15,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
+@@ -5,6 +5,8 @@
+ /plugin/;
+
+ /{
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&soc>;
+ __overlay__ {
+++ /dev/null
-From c9faef0f02397b30c389352ab9915fe529889143 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 15 Jan 2020 14:05:45 +0000
-Subject: [PATCH] driver: char: rpivid: Fix coding style whitespace
- issues.
-
-Makes checkpatch happier.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -66,6 +66,7 @@ static int rpivid_mem_open(struct inode
- int dev = iminor(inode);
- int ret = 0;
- struct rpivid_mem_priv *priv;
-+
- if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1)
- ret = -ENXIO;
-
-@@ -135,7 +136,6 @@ static int rpivid_mem_probe(struct platf
- struct resource *ioresource;
- struct rpivid_mem_priv *priv;
-
--
- /* Allocate buffers and instance data */
-
- priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL);
--- /dev/null
+From a3749ee48539fa832b1832cdcae26d34e5d20f00 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 24 Jan 2020 11:38:28 +0000
+Subject: [PATCH] tty: amba-pl011: Add un/throttle support
+
+The PL011 driver lacks throttle and unthrottle methods. As a result,
+sending more data to the Pi than it can immediately sink while CRTSCTS
+is enabled causes a NULL pointer to be followed.
+
+Add a throttle handler that disables the RX interrupts, and an
+unthrottle handler that reenables them.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1323,6 +1323,32 @@ static void pl011_start_tx(struct uart_p
+ pl011_start_tx_pio(uap);
+ }
+
++static void pl011_throttle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im &= ~(UART011_RTIM | UART011_RXIM);
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
++static void pl011_unthrottle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im |= UART011_RTIM;
++ if (!pl011_dma_rx_running(uap))
++ uap->im |= UART011_RXIM;
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
+ static void pl011_stop_rx(struct uart_port *port)
+ {
+ struct uart_amba_port *uap =
+@@ -2164,6 +2190,8 @@ static const struct uart_ops amba_pl011_
+ .stop_tx = pl011_stop_tx,
+ .start_tx = pl011_start_tx,
+ .stop_rx = pl011_stop_rx,
++ .throttle = pl011_throttle,
++ .unthrottle = pl011_unthrottle,
+ .enable_ms = pl011_enable_ms,
+ .break_ctl = pl011_break_ctl,
+ .startup = pl011_startup,
--- /dev/null
+From 1cf854cd3531b10168b8f9aeb93bb0ab4b9a9003 Mon Sep 17 00:00:00 2001
+From: MikeDK <m.kaplan@evva.com>
+Date: Sun, 26 Jan 2020 23:33:54 +0100
+Subject: [PATCH] Fix i2c-pwm-pca9685a overlay
+
+---
+ arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+@@ -13,7 +13,7 @@
+ status = "okay";
+
+ pca: pca@40 {
+- compatible = "nxp,pca9685";
++ compatible = "nxp,pca9685-pwm";
+ #pwm-cells = <2>;
+ reg = <0x40>;
+ status = "okay";
+++ /dev/null
-From aa5c03a34b59ad840eeac990185c06b631a1e87e Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Wed, 15 Jan 2020 14:07:16 +0000
-Subject: [PATCH] driver: char: rpimem: Add SPDX licence header.
-
-Stops checkpatch complaining.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -1,3 +1,4 @@
-+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
- /**
- * rpivid-mem.c - character device access to the RPiVid decoder registers
- *
--- /dev/null
+From 4a773d6535c3386044490156264ebd2a3b1bc38b Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 17:45:51 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound
+ card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++--
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ADC Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusdsp
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -60,5 +60,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
++ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x10
+@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ ret = pcm1863_add_controls(adc);
+ if (ret < 0)
+@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+ /* set GPIO2 to output, GPIO3 input */
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
+- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++ if (leds_off)
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
+
++ if (leds_off)
++ return 0;
+ /* switch on respective LED */
+ if (!substream->stream)
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+@@ -500,6 +509,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadcpro,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadcpro,leds_off");
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
+ if (ret && ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+++ /dev/null
-From be492eed9f4724798a7b85cf8779772dc901f986 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.com>
-Date: Tue, 21 Jan 2020 16:44:14 +0000
-Subject: [PATCH] driver: char: rpivid: Fix access to freed memory
-
-The error path during probe frees the private memory block, and
-then promptly dereferences it to log an error message.
-
-Use the base device instead of the pointer to it in the private
-structure.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
----
- drivers/char/broadcom/rpivid-mem.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/char/broadcom/rpivid-mem.c
-+++ b/drivers/char/broadcom/rpivid-mem.c
-@@ -229,7 +229,7 @@ failed_alloc_chrdev:
- failed_get_resource:
- kfree(priv);
- failed_inst_alloc:
-- dev_err(priv->dev, "could not load rpivid_mem");
-+ dev_err(&pdev->dev, "could not load rpivid_mem");
- return err;
- }
-
+++ /dev/null
-From 13047f38ca9adef0c0a0b0afce420dc912290d35 Mon Sep 17 00:00:00 2001
-From: Willem Remie <w.remie@drebble.io>
-Date: Thu, 9 Jan 2020 21:16:49 +0100
-Subject: [PATCH] add BME680 to i2c-sensor overlay
-
----
- arch/arm/boot/dts/overlays/README | 7 +++++--
- .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++-
- 2 files changed, 23 insertions(+), 3 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -1159,12 +1159,15 @@ Name: i2c-sensor
- Info: Adds support for a number of I2C barometric pressure and temperature
- sensors on i2c_arm
- Load: dtoverlay=i2c-sensor,<param>=<val>
--Params: addr Set the address for the BME280, BMP280, DS1621,
-- HDC100X, LM75, SHT3x or TMP102
-+Params: addr Set the address for the BME280, BME680, BMP280,
-+ DS1621, HDC100X, LM75, SHT3x or TMP102
-
- bme280 Select the Bosch Sensortronic BME280
- Valid addresses 0x76-0x77, default 0x76
-
-+ bme680 Select the Bosch Sensortronic BME680
-+ Valid addresses 0x76-0x77, default 0x76
-+
- bmp085 Select the Bosch Sensortronic BMP085
-
- bmp180 Select the Bosch Sensortronic BMP180
---- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
-@@ -216,10 +216,26 @@
- };
- };
-
-+ fragment@14 {
-+ target = <&i2c_arm>;
-+ __dormant__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ bme680: bme680@76 {
-+ compatible = "bosch,bme680";
-+ reg = <0x76>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+
-+
- __overrides__ {
- addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
- <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
-- <&ds1621>,"reg:0";
-+ <&ds1621>,"reg:0", <&bme680>,"reg:0";
- bme280 = <0>,"+0";
- bmp085 = <0>,"+1";
- bmp180 = <0>,"+2";
-@@ -235,5 +251,6 @@
- sht3x = <0>,"+11";
- ds1621 = <0>,"+12";
- max17040 = <0>,"+13";
-+ bme680 = <0>,"+14";
- };
- };
--- /dev/null
+From 36949b2ea78d5782faed2fb00a037f37789fa85d Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 20:37:34 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadcpro
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -67,5 +67,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
++ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadc.c
++++ b/sound/soc/bcm/hifiberry_dacplusadc.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -254,6 +258,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
+ 0x08, 0x08);
+ hifiberry_dacplusadc_LED_cnt++;
+@@ -330,6 +336,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadc,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadc,leds_off");
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
+ &snd_rpi_hifiberry_dacplusadc);
--- /dev/null
+From 4b3cdf84c4d8156c01fa02e4d511f7529cae488f Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 20:58:24 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound
+ cards
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadc
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -55,5 +55,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -50,6 +50,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit)
+ {
+@@ -249,6 +253,8 @@ static int snd_rpi_hifiberry_dacplus_sta
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+ return 0;
+ }
+@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplus,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplus,leds_off");
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
+++ /dev/null
-From b7944a79716c115d881898e6a95705b262e7c1c9 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Tue, 7 Jan 2020 10:08:19 +0000
-Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer
- size on split IN
-
-The hcd would unconditionally set the transfer length to the endpoint
-packet size for non-isoc IN transfers. If the remaining buffer length
-was less than the length of returned data, random memory would get
-scribbled over, with bad effects if it crossed a page boundary.
-
-Force a babble error if this happens by limiting the max transfer size
-to the available buffer space. DMA will stop writing to memory on a
-babble condition.
-
-The hardware expects xfersize to be an integer multiple of maxpacket
-size, so override hcchar.b.mps as well.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_
- st->nr_errors = 0;
-
- st->hcchar_copy.d32 = 0;
-- st->hcchar_copy.b.mps = hc->max_packet;
-+ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
- st->hcchar_copy.b.epdir = hc->ep_is_in;
- st->hcchar_copy.b.devaddr = hc->dev_addr;
- st->hcchar_copy.b.epnum = hc->ep_num;
-@@ -1858,7 +1858,7 @@ int fiq_fsm_queue_split_transaction(dwc_
- st->hctsiz_copy.b.pid = hc->data_pid_start;
-
- if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
-- hc->xfer_len = hc->max_packet;
-+ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
- } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
- hc->xfer_len = 188;
- }
+++ /dev/null
-From 09648b92a71b03450e9482f0cc5bd22298f78d44 Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Wed, 8 Jan 2020 12:48:09 +0000
-Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split
- transactions
-
-Non-periodic splits will DMA to/from the driver-provided transfer_buffer,
-which may be freed immediately after the dequeue call returns. Block until
-we know the transfer is complete.
-
-A similar delay is needed when cleaning up disconnects, as the FIQ could
-have started a periodic transfer in the previous microframe to the one
-that triggered a disconnect.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++--
- drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 +
- 2 files changed, 32 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg
- dwc_list_link_t *qh_item, *qh_tmp;
- dwc_otg_qh_t *qh;
- dwc_otg_qtd_t *qtd, *qtd_tmp;
-+ int quiesced = 0;
-
- DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
- qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
-@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg
- qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
- qh->channel->halt_pending = 1;
- if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
-- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
-+ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
- hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
-+ /* We're called from disconnect callback or in the middle of freeing the HCD here,
-+ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock.
-+ * No further URBs will be submitted, but wait 1 microframe for any previously
-+ * submitted periodic DMA to finish.
-+ */
-+ if (!quiesced) {
-+ udelay(125);
-+ quiesced = 1;
-+ }
- } else {
- dwc_otg_hc_halt(hcd->core_if, qh->channel,
- DWC_OTG_HC_XFER_URB_DEQUEUE);
-@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
- /* In FIQ FSM mode, we need to shut down carefully.
- * The FIQ may attempt to restart a disabled channel */
- if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
-+ int retries = 3;
-+ int running = 0;
-+ enum fiq_fsm_state state;
-+
- local_fiq_disable();
- fiq_fsm_spin_lock(&hcd->fiq_state->lock);
- qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
- qh->channel->halt_pending = 1;
- if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
-- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
-+ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
- hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
- fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
- local_fiq_enable();
-+
-+ if (dwc_qh_is_non_per(qh)) {
-+ do {
-+ state = READ_ONCE(hcd->fiq_state->channel[n].fsm);
-+ running = (state != FIQ_NP_SPLIT_DONE) &&
-+ (state != FIQ_NP_SPLIT_LS_ABORTED) &&
-+ (state != FIQ_NP_SPLIT_HS_ABORTED);
-+ if (!running)
-+ break;
-+ udelay(125);
-+ } while(--retries);
-+ if (!retries)
-+ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d",
-+ qh->channel->hc_num);
-+ }
- } else {
- dwc_otg_hc_halt(hcd->core_if, qh->channel,
- DWC_OTG_HC_XFER_URB_DEQUEUE);
---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-@@ -27,6 +27,7 @@
- #include <linux/workqueue.h>
- #include <linux/stat.h>
- #include <linux/pci.h>
-+#include <linux/compiler.h>
-
- #include <linux/version.h>
-
--- /dev/null
+From 21dace2c687d45819cb0dfc4f32f005da82d9197 Mon Sep 17 00:00:00 2001
+From: gtrainavicius <gtrainavicius@users.noreply.github.com>
+Date: Tue, 28 Jan 2020 14:16:37 +0200
+Subject: [PATCH] pisound: Added reading Pisound board hardware
+ revision and exposing it (#3425)
+
+pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file:
+
+/sys/kernel/pisound/hw_version
+
+Signed-off-by: Giedrius <giedrius@blokas.io>
+---
+ sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 59 insertions(+), 27 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void);
+ static const char *pisnd_spi_get_id(void);
+-static const char *pisnd_spi_get_version(void);
++static const char *pisnd_spi_get_fw_version(void);
++static const char *pisnd_spi_get_hw_version(void);
+
+ static int pisnd_midi_init(struct snd_card *card);
+ static void pisnd_midi_uninit(void);
+@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback;
+
+ static char g_serial_num[11];
+ static char g_id[25];
+-static char g_version[5];
++enum { MAX_VERSION_STR_LEN = 6 };
++static char g_fw_version[MAX_VERSION_STR_LEN];
++static char g_hw_version[MAX_VERSION_STR_LEN];
+
+ static uint8_t g_ledFlashDuration;
+ static bool g_ledFlashDurationChanged;
+@@ -558,7 +561,8 @@ static int spi_read_info(void)
+ char *p;
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version.
+ memset(g_id, 0, sizeof(g_id));
+
+ tmp = spi_transfer16(0);
+@@ -581,12 +585,28 @@ static int spi_read_info(void)
+ return -EINVAL;
+
+ snprintf(
+- g_version,
+- sizeof(g_version),
++ g_fw_version,
++ MAX_VERSION_STR_LEN,
+ "%x.%02x",
+ buffer[0],
+ buffer[1]
+ );
++
++ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0';
++ break;
++ case 3:
++ if (n != 2)
++ return -EINVAL;
++
++ snprintf(
++ g_hw_version,
++ MAX_VERSION_STR_LEN,
++ "%x.%x",
++ buffer[0],
++ buffer[1]
++ );
++
++ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0';
+ break;
+ case 1:
+ if (n >= sizeof(g_serial_num))
+@@ -596,12 +616,14 @@ static int spi_read_info(void)
+ break;
+ case 2:
+ {
+- if (n >= sizeof(g_id))
++ if (n*2 >= sizeof(g_id))
+ return -EINVAL;
+
+ p = g_id;
+ for (j = 0; j < n; ++j)
+ p += sprintf(p, "%02x", buffer[j]);
++
++ *p = '\0';
+ }
+ break;
+ default:
+@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+ memset(g_id, 0, sizeof(g_id));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ memset(g_hw_version, 0, sizeof(g_hw_version));
+
+ spi = pisnd_spi_find_device();
+
+@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void)
+ {
+- if (strlen(g_serial_num))
+- return g_serial_num;
+-
+- return "";
++ return g_serial_num;
+ }
+
+ static const char *pisnd_spi_get_id(void)
+ {
+- if (strlen(g_id))
+- return g_id;
+-
+- return "";
++ return g_id;
+ }
+
+-static const char *pisnd_spi_get_version(void)
++static const char *pisnd_spi_get_fw_version(void)
+ {
+- if (strlen(g_version))
+- return g_version;
++ return g_fw_version;
++}
+
+- return "";
++static const char *pisnd_spi_get_hw_version(void)
++{
++ return g_hw_version;
+ }
+
+ static const struct of_device_id pisound_of_match[] = {
+@@ -1056,13 +1075,22 @@ static ssize_t pisnd_id_show(
+ return sprintf(buf, "%s\n", pisnd_spi_get_id());
+ }
+
+-static ssize_t pisnd_version_show(
++static ssize_t pisnd_fw_version_show(
+ struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf
+ )
+ {
+- return sprintf(buf, "%s\n", pisnd_spi_get_version());
++ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version());
++}
++
++static ssize_t pisnd_hw_version_show(
++ struct kobject *kobj,
++ struct kobj_attribute *attr,
++ char *buf
++)
++{
++ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version());
+ }
+
+ static ssize_t pisnd_led_store(
+@@ -1087,15 +1115,18 @@ static struct kobj_attribute pisnd_seria
+ __ATTR(serial, 0444, pisnd_serial_show, NULL);
+ static struct kobj_attribute pisnd_id_attribute =
+ __ATTR(id, 0444, pisnd_id_show, NULL);
+-static struct kobj_attribute pisnd_version_attribute =
+- __ATTR(version, 0444, pisnd_version_show, NULL);
++static struct kobj_attribute pisnd_fw_version_attribute =
++ __ATTR(version, 0444, pisnd_fw_version_show, NULL);
++static struct kobj_attribute pisnd_hw_version_attribute =
++__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL);
+ static struct kobj_attribute pisnd_led_attribute =
+ __ATTR(led, 0644, NULL, pisnd_led_store);
+
+ static struct attribute *attrs[] = {
+ &pisnd_serial_attribute.attr,
+ &pisnd_id_attribute.attr,
+- &pisnd_version_attribute.attr,
++ &pisnd_fw_version_attribute.attr,
++ &pisnd_hw_version_attribute.attr,
+ &pisnd_led_attribute.attr,
+ NULL
+ };
+@@ -1114,9 +1145,10 @@ static int pisnd_probe(struct platform_d
+ }
+
+ printi("Detected Pisound card:\n");
+- printi("\tSerial: %s\n", pisnd_spi_get_serial());
+- printi("\tVersion: %s\n", pisnd_spi_get_version());
+- printi("\tId: %s\n", pisnd_spi_get_id());
++ printi("\tSerial: %s\n", pisnd_spi_get_serial());
++ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version());
++ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version());
++ printi("\tId: %s\n", pisnd_spi_get_id());
+
+ pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
+ if (!pisnd_kobj) {
+++ /dev/null
-From edbbc60ed86f4b690838e6c4b0aed48803e334cc Mon Sep 17 00:00:00 2001
-From: Jonathan Bell <jonathan@raspberrypi.org>
-Date: Mon, 13 Jan 2020 15:54:55 +0000
-Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ
- handler(s)
-
-On BCM2835, there is no hardware guarantee that multiple outstanding
-reads to different peripherals will complete in-order. The FIQ code
-uses peripheral reads without barriers for performance, so in the case
-where a read to a slow peripheral was issued immediately prior to FIQ
-entry, the first peripheral read that the FIQ did could end up with
-wrong read data returned.
-
-Add dsb(sy) on entry so that all outstanding reads are retired.
-
-The FIQ only issues reads to the dwc_otg core, so per-read barriers
-in the handler itself are not required.
-
-On BCM2836 and BCM2837 the barrier is not strictly required due to
-differences in how the peripheral bus is implemented, but having
-arch-specific handlers that introduce different latencies is risky.
-
-Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
----
- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
-@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
- haintmsk_data_t haintmsk;
- int kick_irq = 0;
-
-+ /* Ensure peripheral reads issued prior to FIQ entry are complete */
-+ dsb(sy);
-+
- gintsts_handled.d32 = 0;
- haint_handled.d32 = 0;
-
-@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_
- gintmsk_data_t gintmsk;
- hfnum_data_t hfnum;
-
-+ /* Ensure peripheral reads issued prior to FIQ entry are complete */
-+ dsb(sy);
-+
- fiq_fsm_spin_lock(&state->lock);
- hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM);
- gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
--- /dev/null
+From 703920ad5199c46f98cf107c75a2de61608f85fd Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 2 Aug 2019 15:20:11 +0100
+Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc
+
+The Linux support for controlling card power via regulators appears to
+be contentious. I would argue that the default behaviour is contrary to
+the SDHCI spec - turning off the power writes a reserved value to the
+SD Bus Voltage Select field of the Power Control Register, which
+seems to kill the Arasan/iProc controller - but fortunately there is a
+hook in sdhci_ops to override the behaviour. Borrow the implementation
+from sdhci_arasan_set_power.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -173,6 +173,17 @@ static unsigned int sdhci_iproc_get_max_
+ return pltfm_host->clock;
+ }
+
++static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode,
++ unsigned short vdd)
++{
++ if (!IS_ERR(host->mmc->supply.vmmc)) {
++ struct mmc_host *mmc = host->mmc;
++
++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
++ }
++ sdhci_set_power_noreg(host, mode, vdd);
++}
++
+ static const struct sdhci_ops sdhci_iproc_ops = {
+ .set_clock = sdhci_set_clock,
+ .get_max_clock = sdhci_iproc_get_max_clock,
+@@ -190,6 +201,7 @@ static const struct sdhci_ops sdhci_ipro
+ .write_b = sdhci_iproc_writeb,
+ .set_clock = sdhci_set_clock,
+ .get_max_clock = sdhci_iproc_get_max_clock,
++ .set_power = sdhci_iproc_set_power,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
--- /dev/null
+From ade82688b687b3340ca5e7883646ad51291d49cd Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 30 Jul 2019 12:37:02 +0100
+Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator
+
+Later revisions of the Raspberry Pi 4B have a separate control over the
+SD card power. Expose that control to Linux as a fixed regulator with
+a GPIO enable.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -122,6 +122,16 @@
+ states = <1800000 0x1
+ 3300000 0x0>;
+ };
++
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
++ };
+ };
+
+ &sdhost {
+@@ -132,6 +142,7 @@
+ status = "okay";
+ broken-cd;
+ vqmmc-supply = <&sd_io_1v8_reg>;
++ vmmc-supply = <&sd_vcc_reg>;
+ };
+
+ &genet {
+++ /dev/null
-From 17159731ae064a70031d746284855b7d30f17407 Mon Sep 17 00:00:00 2001
-From: Ed Spiridonov <edo.rus@gmail.com>
-Date: Tue, 10 Dec 2019 22:45:04 +0300
-Subject: [PATCH] Add universal device tree overlay for SPI devices
-
-Just specify the SPI address and device name ("compatible" property).
-This overlay lacks any device-specific parameter support!
-(some of them could be added later)
-
-Examples:
-1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
- dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
-2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
- dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
-
-Signed-off-by: Ed Spiridonov <edo.rus@gmail.com>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 23 ++
- arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++
- 3 files changed, 229 insertions(+)
- create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- allo-katana-dac-audio.dtbo \
- allo-piano-dac-pcm512x-audio.dtbo \
- allo-piano-dac-plus-pcm512x-audio.dtbo \
-+ anyspi.dtbo \
- apds9960.dtbo \
- applepi-dac.dtbo \
- at86rf233.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga
- better voice quality. (default Off)
-
-
-+Name: anyspi
-+Info: Universal device tree overlay for SPI devices
-+
-+ Just specify the SPI address and device name ("compatible" property).
-+ This overlay lacks any device-specific parameter support!
-+
-+ For devices on spi1 or spi2, the interfaces should be enabled
-+ with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
-+
-+ Examples:
-+ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
-+ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
-+ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
-+ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
-+Load: dtoverlay=anyspi,<param>=<val>
-+Params: spi<n>-<m> Configure device at spi<n>, cs<m>
-+ (boolean, required)
-+ dev Set device name to search compatible module
-+ (string, required)
-+ speed Set SPI clock frequency in Hz
-+ (integer, optional, default 500000)
-+
-+
- Name: apds9960
- Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
- gesture sensor
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts
-@@ -0,0 +1,205 @@
-+/*
-+ * Universal device tree overlay for SPI devices
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spidev0>;
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev1>;
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target-path = "spi1/spidev@0";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target-path = "spi1/spidev@1";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@4 {
-+ target-path = "spi1/spidev@2";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@5 {
-+ target-path = "spi2/spidev@0";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@6 {
-+ target-path = "spi2/spidev@1";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@7 {
-+ target-path = "spi2/spidev@2";
-+ __dormant__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@8 {
-+ target = <&spi0>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_00: anyspi@0 {
-+ reg = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@9 {
-+ target = <&spi0>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_01: anyspi@1 {
-+ reg = <1>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@10 {
-+ target = <&spi1>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_10: anyspi@0 {
-+ reg = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@11 {
-+ target = <&spi1>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_11: anyspi@1 {
-+ reg = <1>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@12 {
-+ target = <&spi1>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_12: anyspi@2 {
-+ reg = <2>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@13 {
-+ target = <&spi2>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_20: anyspi@0 {
-+ reg = <0>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@14 {
-+ target = <&spi2>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_21: anyspi@1 {
-+ reg = <1>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ fragment@15 {
-+ target = <&spi2>;
-+ __dormant__ {
-+ status = "okay";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ anyspi_22: anyspi@2 {
-+ reg = <2>;
-+ spi-max-frequency = <500000>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ spi0-0 = <0>, "+0+8";
-+ spi0-1 = <0>, "+1+9";
-+ spi1-0 = <0>, "+2+10";
-+ spi1-1 = <0>, "+3+11";
-+ spi1-2 = <0>, "+4+12";
-+ spi2-0 = <0>, "+5+13";
-+ spi2-1 = <0>, "+6+14";
-+ spi2-2 = <0>, "+7+15";
-+ dev = <&anyspi_00>,"compatible",
-+ <&anyspi_01>,"compatible",
-+ <&anyspi_10>,"compatible",
-+ <&anyspi_11>,"compatible",
-+ <&anyspi_12>,"compatible",
-+ <&anyspi_20>,"compatible",
-+ <&anyspi_21>,"compatible",
-+ <&anyspi_22>,"compatible";
-+ speed = <&anyspi_00>, "spi-max-frequency:0",
-+ <&anyspi_01>, "spi-max-frequency:0",
-+ <&anyspi_10>, "spi-max-frequency:0",
-+ <&anyspi_11>, "spi-max-frequency:0",
-+ <&anyspi_12>, "spi-max-frequency:0",
-+ <&anyspi_20>, "spi-max-frequency:0",
-+ <&anyspi_21>, "spi-max-frequency:0",
-+ <&anyspi_22>, "spi-max-frequency:0";
-+ };
-+};
--- /dev/null
+From 8be8dc74799fe7c0e09dfa53aa41e954ffba291c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 12 Jul 2019 11:43:03 +0100
+Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string
+
+The BCM2711 PCIe controller has a limited address range in the B0
+silicon, and the driver uses a compatible string to identify the
+limitation. The current Pi 4 firmware will override the compatible
+string if it detects a downstream DTB and it is running on a newer
+revision but set the default value to enable the workaround for
+backwards-compatibility with old firmware.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -314,7 +314,8 @@
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ bus-range = <0x0 0x01>;
+- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
++ compatible = "brcm,bcm2711b0-pcie", // Safe value
++ "brcm,bcm2711-pcie",
+ "brcm,pci-plat-dev";
+ max-link-speed = <2>;
+ tot-num-pcie = <1>;
+++ /dev/null
-From 221b442eb7e5b4ed16151b5501f4b905a9b8455c Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
- <j-schambacher@users.noreply.github.com>
-Date: Tue, 21 Jan 2020 15:58:39 +0100
-Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version
-
-This adds the driver for the DAC+HD version supporting HiFiBerry's
-PCM179x based DACs. It also adds PLL control for clock generation.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 6 +
- .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++
- drivers/clk/Kconfig | 3 +
- drivers/clk/Makefile | 1 +
- drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++
- sound/soc/bcm/Kconfig | 9 +
- sound/soc/bcm/Makefile | 2 +
- sound/soc/bcm/hifiberry_dacplushd.c | 238 +++++++++++++
- 14 files changed, 704 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
- create mode 100644 drivers/clk/clk-hifiberry-dachd.c
- create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- hifiberry-dacplusadc.dtbo \
- hifiberry-dacplusadcpro.dtbo \
- hifiberry-dacplusdsp.dtbo \
-+ hifiberry-dacplushd.dtbo \
- hifiberry-digi.dtbo \
- hifiberry-digi-pro.dtbo \
- hy28a.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp
- Params: <None>
-
-
-+Name: hifiberry-dacplushd
-+Info: Configures the HifiBerry DAC+ HD audio card
-+Load: dtoverlay=hifiberry-dacplushd
-+Params: <None>
-+
-+
- Name: hifiberry-digi
- Info: Configures the HifiBerry Digi and Digi+ audio card
- Load: dtoverlay=hifiberry-digi
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
-@@ -0,0 +1,106 @@
-+// Definitions for HiFiBerry DAC+ HD
-+/dts-v1/;
-+/plugin/;
-+
-+#include <dt-bindings/gpio/gpio.h>
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target-path = "/clocks";
-+ __overlay__ {
-+ dachd_osc: pll_dachd_osc {
-+ compatible = "hifiberry,dachd-clk";
-+ #clock-cells = <0>;
-+ };
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&i2s>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&i2c1>;
-+ __overlay__ {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ pcm1792a@4c {
-+ compatible = "ti,pcm1792a";
-+ #sound-dai-cells = <0>;
-+ #clock-cells = <0>;
-+ clocks = <&dachd_osc>;
-+ reg = <0x4c>;
-+ status = "okay";
-+ };
-+ pll: pll@62 {
-+ compatible = "hifiberry,dachd-clk";
-+ #clock-cells = <0>;
-+ reg = <0x62>;
-+ clocks = <&dachd_osc>;
-+ status = "okay";
-+ common_pll_regs = [
-+ 02 53 03 00 07 20 0F 00
-+ 10 0D 11 1D 12 0D 13 8C
-+ 14 8C 15 8C 16 8C 17 8C
-+ 18 2A 1C 00 1D 0F 1F 00
-+ 2A 00 2C 00 2F 00 30 00
-+ 31 00 32 00 34 00 37 00
-+ 38 00 39 00 3A 00 3B 01
-+ 3E 00 3F 00 40 00 41 00
-+ 5A 00 5B 00 95 00 96 00
-+ 97 00 98 00 99 00 9A 00
-+ 9B 00 A2 00 A3 00 A4 00
-+ B7 92 ];
-+ 192k_pll_regs = [
-+ 1A 0C 1B 35 1E F0 20 09
-+ 21 50 2B 02 2D 10 2E 40
-+ 33 01 35 22 36 80 3C 22
-+ 3D 46 ];
-+ 96k_pll_regs = [
-+ 1A 0C 1B 35 1E F0 20 09
-+ 21 50 2B 02 2D 10 2E 40
-+ 33 01 35 47 36 00 3C 32
-+ 3D 46 ];
-+ 48k_pll_regs = [
-+ 1A 0C 1B 35 1E F0 20 09
-+ 21 50 2B 02 2D 10 2E 40
-+ 33 01 35 90 36 00 3C 42
-+ 3D 46 ];
-+ 176k4_pll_regs = [
-+ 1A 3D 1B 09 1E F3 20 13
-+ 21 75 2B 04 2D 11 2E E0
-+ 33 02 35 25 36 C0 3C 22
-+ 3D 7A ];
-+ 88k2_pll_regs = [
-+ 1A 3D 1B 09 1E F3 20 13
-+ 21 75 2B 04 2D 11 2E E0
-+ 33 01 35 4D 36 80 3C 32
-+ 3D 7A ];
-+ 44k1_pll_regs = [
-+ 1A 3D 1B 09 1E F3 20 13
-+ 21 75 2B 04 2D 11 2E E0
-+ 33 01 35 9D 36 00 3C 42
-+ 3D 7A ];
-+ };
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&sound>;
-+ __overlay__ {
-+ compatible = "hifiberry,hifiberry-dacplushd";
-+ i2s-controller = <&i2s>;
-+ clocks = <&pll 0>;
-+ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
-+ status = "okay";
-+ };
-+ };
-+
-+};
---- a/drivers/clk/Kconfig
-+++ b/drivers/clk/Kconfig
-@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X
- multi-function device has one fixed-rate oscillator, clocked
- at 32KHz.
-
-+config COMMON_CLK_HIFIBERRY_DACPLUSHD
-+ tristate
-+
- config COMMON_CLK_HIFIBERRY_DACPRO
- tristate
-
---- a/drivers/clk/Makefile
-+++ b/drivers/clk/Makefile
-@@ -36,6 +36,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-high
- obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
- obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
- obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o
-+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
- obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
- obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
- obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
---- /dev/null
-+++ b/drivers/clk/clk-hifiberry-dachd.c
-@@ -0,0 +1,333 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Clock Driver for HiFiBerry DAC+ HD
-+ *
-+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
-+ * Copyright 2020
-+ *
-+ * 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 <linux/clk-provider.h>
-+#include <linux/clk.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/slab.h>
-+#include <linux/platform_device.h>
-+#include <linux/i2c.h>
-+#include <linux/regmap.h>
-+
-+#define NO_PLL_RESET 0
-+#define PLL_RESET 1
-+#define HIFIBERRY_PLL_MAX_REGISTER 256
-+#define DEFAULT_RATE 44100
-+
-+static struct reg_default hifiberry_pll_reg_defaults[] = {
-+ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
-+ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
-+ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
-+ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
-+ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
-+ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
-+ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
-+ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
-+ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
-+ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
-+ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
-+ {0xB7, 0x92},
-+ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
-+ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
-+ {0x3D, 0x7A},
-+ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
-+ { 177, 0xAC},
-+};
-+static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_common_pll_regs;
-+static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_192k_pll_regs;
-+static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_96k_pll_regs;
-+static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_48k_pll_regs;
-+static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_176k4_pll_regs;
-+static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_88k2_pll_regs;
-+static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
-+static int num_dedicated_44k1_pll_regs;
-+
-+/**
-+ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
-+ * @hw: clk_hw for the common clk framework
-+ */
-+struct clk_hifiberry_drvdata {
-+ struct regmap *regmap;
-+ struct clk *clk;
-+ struct clk_hw hw;
-+ unsigned long rate;
-+};
-+
-+#define to_hifiberry_clk(_hw) \
-+ container_of(_hw, struct clk_hifiberry_drvdata, hw)
-+
-+static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
-+ struct reg_default *regs,
-+ int num, int do_pll_reset)
-+{
-+ int i;
-+ int ret = 0;
-+ char pll_soft_reset[] = { 177, 0xAC, };
-+
-+ for (i = 0; i < num; i++) {
-+ ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
-+ if (ret)
-+ return ret;
-+ }
-+ if (do_pll_reset) {
-+ ret |= regmap_write(regmap, pll_soft_reset[0],
-+ pll_soft_reset[1]);
-+ mdelay(10);
-+ }
-+ return ret;
-+}
-+
-+static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ return to_hifiberry_clk(hw)->rate;
-+}
-+
-+static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long *parent_rate)
-+{
-+ return rate;
-+}
-+
-+static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long parent_rate)
-+{
-+ int ret;
-+ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
-+
-+ switch (rate) {
-+ case 44100:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
-+ PLL_RESET);
-+ break;
-+ case 88200:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
-+ PLL_RESET);
-+ break;
-+ case 176400:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
-+ PLL_RESET);
-+ break;
-+ case 48000:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
-+ PLL_RESET);
-+ break;
-+ case 96000:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
-+ PLL_RESET);
-+ break;
-+ case 192000:
-+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
-+ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
-+ PLL_RESET);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+ to_hifiberry_clk(hw)->rate = rate;
-+
-+ return ret;
-+}
-+
-+const struct clk_ops clk_hifiberry_dachd_rate_ops = {
-+ .recalc_rate = clk_hifiberry_dachd_recalc_rate,
-+ .round_rate = clk_hifiberry_dachd_round_rate,
-+ .set_rate = clk_hifiberry_dachd_set_rate,
-+};
-+
-+static int clk_hifiberry_get_prop_values(struct device *dev,
-+ char *prop_name,
-+ struct reg_default *regs)
-+{
-+ int ret;
-+ int i;
-+ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
-+
-+ ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
-+ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
-+ if (ret < 0)
-+ return ret;
-+ if (ret & 1) {
-+ dev_err(dev,
-+ "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
-+ __func__,
-+ prop_name,
-+ ret);
-+ return -EINVAL;
-+ }
-+ ret /= 2;
-+ for (i = 0; i < ret; i++) {
-+ regs[i].reg = (u32)tmp[2 * i];
-+ regs[i].def = (u32)tmp[2 * i + 1];
-+ }
-+ return ret;
-+}
-+
-+
-+static int clk_hifiberry_dachd_dt_parse(struct device *dev)
-+{
-+ num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "common_pll_regs", common_pll_regs);
-+ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "44k1_pll_regs", dedicated_44k1_pll_regs);
-+ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "88k2_pll_regs", dedicated_88k2_pll_regs);
-+ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "176k4_pll_regs", dedicated_176k4_pll_regs);
-+ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "48k_pll_regs", dedicated_48k_pll_regs);
-+ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "96k_pll_regs", dedicated_96k_pll_regs);
-+ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
-+ "192k_pll_regs", dedicated_192k_pll_regs);
-+ return 0;
-+}
-+
-+
-+static int clk_hifiberry_dachd_remove(struct device *dev)
-+{
-+ of_clk_del_provider(dev->of_node);
-+ return 0;
-+}
-+
-+const struct regmap_config hifiberry_pll_regmap = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = HIFIBERRY_PLL_MAX_REGISTER,
-+ .reg_defaults = hifiberry_pll_reg_defaults,
-+ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
-+ .cache_type = REGCACHE_RBTREE,
-+};
-+EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
-+
-+
-+static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
-+ const struct i2c_device_id *id)
-+{
-+ struct clk_hifiberry_drvdata *hdclk;
-+ int ret = 0;
-+ struct clk_init_data init;
-+ struct device *dev = &i2c->dev;
-+ struct device_node *dev_node = dev->of_node;
-+ struct regmap_config config = hifiberry_pll_regmap;
-+
-+ hdclk = devm_kzalloc(&i2c->dev,
-+ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
-+ if (!hdclk)
-+ return -ENOMEM;
-+
-+ i2c_set_clientdata(i2c, hdclk);
-+
-+ hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
-+
-+ if (IS_ERR(hdclk->regmap))
-+ return PTR_ERR(hdclk->regmap);
-+
-+ /* start PLL to allow detection of DAC */
-+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
-+ hifiberry_pll_reg_defaults,
-+ ARRAY_SIZE(hifiberry_pll_reg_defaults),
-+ PLL_RESET);
-+ if (ret)
-+ return ret;
-+
-+ clk_hifiberry_dachd_dt_parse(dev);
-+
-+ /* restart PLL with configs from DTB */
-+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
-+ num_common_pll_regs, PLL_RESET);
-+ if (ret)
-+ return ret;
-+
-+ init.name = "clk-hifiberry-dachd";
-+ init.ops = &clk_hifiberry_dachd_rate_ops;
-+ init.flags = 0;
-+ init.parent_names = NULL;
-+ init.num_parents = 0;
-+
-+ hdclk->hw.init = &init;
-+
-+ hdclk->clk = devm_clk_register(dev, &hdclk->hw);
-+ if (IS_ERR(hdclk->clk)) {
-+ dev_err(dev, "unable to register %s\n", init.name);
-+ return PTR_ERR(hdclk->clk);
-+ }
-+
-+ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
-+ if (ret != 0) {
-+ dev_err(dev, "Cannot of_clk_add_provider");
-+ return ret;
-+ }
-+
-+ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
-+ if (ret != 0) {
-+ dev_err(dev, "Cannot set rate : %d\n", ret);
-+ return -EINVAL;
-+ }
-+
-+ return ret;
-+}
-+
-+static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
-+{
-+ clk_hifiberry_dachd_remove(&i2c->dev);
-+ return 0;
-+}
-+
-+static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
-+ { "dachd-clk", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
-+
-+static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
-+ { .compatible = "hifiberry,dachd-clk", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
-+
-+static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
-+ .probe = clk_hifiberry_dachd_i2c_probe,
-+ .remove = clk_hifiberry_dachd_i2c_remove,
-+ .id_table = clk_hifiberry_dachd_i2c_id,
-+ .driver = {
-+ .name = "dachd-clk",
-+ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
-+ },
-+};
-+
-+module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
-+
-+
-+MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
-+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:clk-hifiberry-dachd");
---- a/sound/soc/bcm/Kconfig
-+++ b/sound/soc/bcm/Kconfig
-@@ -42,6 +42,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- help
- Say Y or M if you want to add support for HifiBerry DAC+.
-
-+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
-+ tristate "Support for HifiBerry DAC+ HD"
-+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-+ select SND_SOC_PCM179X_I2C
-+ select COMMON_CLK_HIFIBERRY_DACPLUSHD
-+ help
-+ Say Y or M if you want to add support for HifiBerry DAC+ HD.
-+
- config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
- tristate "Support for HifiBerry DAC+ADC"
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
-@@ -56,6 +64,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
- select SND_SOC_PCM512x_I2C
- select SND_SOC_PCM186X_I2C
-+ select COMMON_CLK_HIFIBERRY_DACPRO
- help
- Say Y or M if you want to add support for HifiBerry DAC+ADC PRO.
-
---- a/sound/soc/bcm/Makefile
-+++ b/sound/soc/bcm/Makefile
-@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo
-
- # BCM2708 Machine Support
- snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
-+snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
- snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
- snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
- snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
-@@ -41,6 +42,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
-
- obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
-+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
- obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
---- /dev/null
-+++ b/sound/soc/bcm/hifiberry_dacplushd.c
-@@ -0,0 +1,238 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * ASoC Driver for HiFiBerry DAC+ HD
-+ *
-+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
-+ * Copyright 2020
-+ *
-+ * 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 <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/delay.h>
-+#include <linux/gpio.h>
-+#include <linux/gpio/consumer.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <linux/i2c.h>
-+#include <linux/clk.h>
-+
-+#include "../codecs/pcm179x.h"
-+
-+#define DEFAULT_RATE 44100
-+
-+struct brd_drv_data {
-+ struct regmap *regmap;
-+ struct clk *sclk;
-+};
-+
-+static struct brd_drv_data drvdata;
-+static struct gpio_desc *reset_gpio;
-+static const unsigned int hb_dacplushd_rates[] = {
-+ 192000, 96000, 48000, 176400, 88200, 44100,
-+};
-+
-+static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
-+ .list = hb_dacplushd_rates,
-+ .count = ARRAY_SIZE(hb_dacplushd_rates),
-+};
-+
-+static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
-+{
-+ /* constraints for standard sample rates */
-+ snd_pcm_hw_constraint_list(substream->runtime, 0,
-+ SNDRV_PCM_HW_PARAM_RATE,
-+ &hb_dacplushd_constraints);
-+ return 0;
-+}
-+
-+static void snd_rpi_hifiberry_dacplushd_set_sclk(
-+ struct snd_soc_component *component,
-+ int sample_rate)
-+{
-+ if (!IS_ERR(drvdata.sclk))
-+ clk_set_rate(drvdata.sclk, sample_rate);
-+}
-+
-+static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
-+{
-+ struct snd_soc_dai_link *dai = rtd->dai_link;
-+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-+
-+ dai->name = "HiFiBerry DAC+ HD";
-+ dai->stream_name = "HiFiBerry DAC+ HD HiFi";
-+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM;
-+
-+ /* allow only fixed 32 clock counts per channel */
-+ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
-+
-+ return 0;
-+}
-+
-+static int snd_rpi_hifiberry_dacplushd_hw_params(
-+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
-+{
-+ int ret = 0;
-+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
-+
-+ struct snd_soc_component *component = rtd->codec_dai->component;
-+
-+ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
-+ return ret;
-+}
-+
-+/* machine stream operations */
-+static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
-+ .startup = snd_rpi_hb_dacplushd_startup,
-+ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
-+};
-+
-+SND_SOC_DAILINK_DEFS(hifi,
-+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
-+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")),
-+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
-+
-+
-+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
-+{
-+ .name = "HiFiBerry DAC+ HD",
-+ .stream_name = "HiFiBerry DAC+ HD HiFi",
-+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-+ SND_SOC_DAIFMT_CBS_CFS,
-+ .ops = &snd_rpi_hifiberry_dacplushd_ops,
-+ .init = snd_rpi_hifiberry_dacplushd_init,
-+ SND_SOC_DAILINK_REG(hifi),
-+},
-+};
-+
-+/* audio machine driver */
-+static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
-+ .name = "snd_rpi_hifiberry_dacplushd",
-+ .driver_name = "HifiberryDacplusHD",
-+ .owner = THIS_MODULE,
-+ .dai_link = snd_rpi_hifiberry_dacplushd_dai,
-+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
-+};
-+
-+static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ static int dac_reset_done;
-+ struct device *dev = &pdev->dev;
-+ struct device_node *dev_node = dev->of_node;
-+
-+ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
-+
-+ /* get GPIO and release DAC from RESET */
-+ if (!dac_reset_done) {
-+ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
-+ if (IS_ERR(reset_gpio)) {
-+ dev_err(&pdev->dev, "gpiod_get() failed\n");
-+ return -EINVAL;
-+ }
-+ dac_reset_done = 1;
-+ }
-+ if (!IS_ERR(reset_gpio))
-+ gpiod_set_value(reset_gpio, 0);
-+ msleep(1);
-+ if (!IS_ERR(reset_gpio))
-+ gpiod_set_value(reset_gpio, 1);
-+ msleep(1);
-+ if (!IS_ERR(reset_gpio))
-+ gpiod_set_value(reset_gpio, 0);
-+
-+ if (pdev->dev.of_node) {
-+ struct device_node *i2s_node;
-+ struct snd_soc_dai_link *dai;
-+
-+ dai = &snd_rpi_hifiberry_dacplushd_dai[0];
-+ i2s_node = of_parse_phandle(pdev->dev.of_node,
-+ "i2s-controller", 0);
-+
-+ if (i2s_node) {
-+ dai->cpus->of_node = i2s_node;
-+ dai->platforms->of_node = i2s_node;
-+ dai->cpus->dai_name = NULL;
-+ dai->platforms->name = NULL;
-+ } else {
-+ return -EPROBE_DEFER;
-+ }
-+
-+ }
-+
-+ ret = devm_snd_soc_register_card(&pdev->dev,
-+ &snd_rpi_hifiberry_dacplushd);
-+ if (ret && ret != -EPROBE_DEFER) {
-+ dev_err(&pdev->dev,
-+ "snd_soc_register_card() failed: %d\n", ret);
-+ return ret;
-+ }
-+ if (ret == -EPROBE_DEFER)
-+ return ret;
-+
-+ dev_set_drvdata(dev, &drvdata);
-+ if (dev_node == NULL) {
-+ dev_err(&pdev->dev, "Device tree node not found\n");
-+ return -ENODEV;
-+ }
-+
-+ drvdata.sclk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(drvdata.sclk)) {
-+ drvdata.sclk = ERR_PTR(-ENOENT);
-+ return -ENODEV;
-+ }
-+
-+ clk_set_rate(drvdata.sclk, DEFAULT_RATE);
-+
-+ return ret;
-+}
-+
-+static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
-+{
-+ if (IS_ERR(reset_gpio))
-+ return -EINVAL;
-+
-+ /* put DAC into RESET and release GPIO */
-+ gpiod_set_value(reset_gpio, 0);
-+ gpiod_put(reset_gpio);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
-+ { .compatible = "hifiberry,hifiberry-dacplushd", },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
-+
-+static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
-+ .driver = {
-+ .name = "snd-rpi-hifiberry-dacplushd",
-+ .owner = THIS_MODULE,
-+ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
-+ },
-+ .probe = snd_rpi_hifiberry_dacplushd_probe,
-+ .remove = snd_rpi_hifiberry_dacplushd_remove,
-+};
-+
-+module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
-+
-+MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
-+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
-+MODULE_LICENSE("GPL v2");
--- /dev/null
+From 3c099a50b3d609206a86896405cfdc8a94cd7aa4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 11:29:06 +0000
+Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts
+
+Upstream are not going to use the bcm2838 identifier, so begin the
+cleanup by removing the suggested upstream Pi 4 .dts file.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/Makefile | 1 -
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 134 --------------------------
+ 2 files changed, 135 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -97,7 +97,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
+ bcm2837-rpi-cm3-io3.dtb \
+- bcm2838-rpi-4-b.dtb \
+ bcm2835-rpi-zero.dtb \
+ bcm2835-rpi-zero-w.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ /dev/null
+@@ -1,134 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-#include "bcm2838.dtsi"
+-#include "bcm2835-rpi.dtsi"
+-#include "bcm2838-rpi.dtsi"
+-
+-/ {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+- model = "Raspberry Pi 4 Model B";
+-
+- chosen {
+- /* 8250 auxiliary UART instead of pl011 */
+- stdout-path = "serial1:115200n8";
+- };
+-
+- memory@0 {
+- device_type = "memory";
+- reg = <0x0 0x0 0x0>;
+- };
+-
+- leds {
+- act {
+- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+- };
+-
+- pwr {
+- label = "PWR";
+- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+- };
+- };
+-
+- wifi_pwrseq: wifi-pwrseq {
+- compatible = "mmc-pwrseq-simple";
+- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- status = "okay";
+- compatible = "regulator-gpio";
+- vin-supply = <&vdd_5v0_reg>;
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+-
+- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- };
+-};
+-
+-&firmware {
+- expgpio: gpio {
+- compatible = "raspberrypi,firmware-gpio";
+- gpio-controller;
+- #gpio-cells = <2>;
+- gpio-line-names = "BT_ON",
+- "WL_ON",
+- "PWR_LED_OFF",
+- "GLOBAL_RESET",
+- "VDD_SD_IO_SEL",
+- "CAM_GPIO",
+- "",
+- "";
+- status = "okay";
+- };
+-};
+-
+-&pwm1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
+- status = "okay";
+-};
+-
+-/* SDHCI is used to control the SDIO for wireless */
+-&sdhci {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio34>;
+- status = "okay";
+- bus-width = <4>;
+- non-removable;
+- mmc-pwrseq = <&wifi_pwrseq>;
+-
+- brcmf: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- };
+-};
+-
+-/* EMMC2 is used to drive the SD card */
+-&emmc2 {
+- status = "okay";
+- broken-cd;
+- vqmmc-supply = <&sd_io_1v8_reg>;
+-};
+-
+-&genet {
+- phy-handle = <&phy1>;
+- phy-mode = "rgmii-rxid";
+- status = "okay";
+-};
+-
+-&genet_mdio {
+- phy1: ethernet-phy@1 {
+- /* No PHY interrupt */
+- reg = <0x1>;
+- led-modes = <0x00 0x08>; /* link/activity link */
+- };
+-};
+-
+-/* uart0 communicates with the BT module */
+-&uart0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
+- uart-has-rtscts;
+- status = "okay";
+-
+- bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <2000000>;
+- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+- };
+-};
+-
+-/* uart1 is mapped to the pin header */
+-&uart1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart1_gpio14>;
+- status = "okay";
+-};
+++ /dev/null
-From 2c1a5dae2fb127729773685e3cd1e48934edf1f2 Mon Sep 17 00:00:00 2001
-From: Luke Hinds <7058938+lukehinds@users.noreply.github.com>
-Date: Wed, 22 Jan 2020 16:03:00 +0000
-Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835
-
-The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted
-Platform Module) having been registered when it initialises; otherwise
-it assumes there is no TPM. It has been observed on BCM2835 that IMA
-is initialised before TPM, and that initialising the BCM2835 clock
-driver before the firmware driver has the effect of reversing this
-order.
-
-Change the firmware driver to initialise at core_initcall, delaying the
-BCM2835 clock driver to postcore_initcall.
-
-See: https://github.com/raspberrypi/linux/issues/3291
- https://github.com/raspberrypi/linux/pull/3297
-
-Signed-off-by: Luke Hinds <lhinds@redhat.com>
-Co-authored-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/clk/bcm/clk-bcm2835.c | 2 +-
- drivers/firmware/raspberrypi.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/bcm/clk-bcm2835.c
-+++ b/drivers/clk/bcm/clk-bcm2835.c
-@@ -2382,7 +2382,7 @@ static int __init __bcm2835_clk_driver_i
- {
- return platform_driver_register(&bcm2835_clk_driver);
- }
--core_initcall(__bcm2835_clk_driver_init);
-+postcore_initcall(__bcm2835_clk_driver_init);
-
- MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
- MODULE_DESCRIPTION("BCM2835 clock driver");
---- a/drivers/firmware/raspberrypi.c
-+++ b/drivers/firmware/raspberrypi.c
-@@ -416,7 +416,7 @@ out2:
- out1:
- return ret;
- }
--subsys_initcall(rpi_firmware_init);
-+core_initcall(rpi_firmware_init);
-
- static void __init rpi_firmware_exit(void)
- {
+++ /dev/null
-From fa93fc95e5fb4e75a2a5ea930509d80083dee9b3 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
- <j-schambacher@users.noreply.github.com>
-Date: Thu, 23 Jan 2020 13:32:13 +0100
-Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO
- card (#3424)
-
-This patch fixes the board DAI setting when in master-mode.
-Wrong setting could have caused random pop noise.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
-+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
-@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp
-
- dai->name = "HiFiBerry DAC+ADC Pro";
- dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
-+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-+ | SND_SOC_DAIFMT_CBM_CFM;
-
- // set DAC DAI configuration
- ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
--- /dev/null
+From 66ca4b2544dbd4f10d8f387782f5c7200d1e2167 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 09:35:19 +0000
+Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error
+
+Under some circumstances on BCM283x processors data loss can be
+observed - a single byte missing from the TX output stream. These bytes
+are always the last byte of a batch of 8 written from pl011_tx_chars
+when from_irq is true, meaning that the FIFO full flag is not checked
+before writing.
+
+The transmit optimisation relies on the FIFO being half-empty when the
+TX interrupt is raised. Instrumenting the driver further showed that
+the failure case correlated with the TX FIFO full flag being set at the
+point where the last byte was written to the data register, which
+explains the data loss but not how the FIFO appeared to be prematurely
+full. A possible explanation is that a FIFO write was in flight at the
+time the interrupt was raised, but as yet there is no hypothesis as to
+how this might occur.
+
+In the absence of a clear understanding of the failure mechanism, avoid
+the problem by checking the FIFO levels before writing the last byte of
+the group, which will have minimal performance impact.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1444,6 +1444,10 @@ static bool pl011_tx_chars(struct uart_a
+ if (likely(from_irq) && count-- == 0)
+ break;
+
++ if (likely(from_irq) && count == 0 &&
++ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
++ break;
++
+ if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ break;
+
+++ /dev/null
-From f50f0425592a8496d6d25b4936caadfe64523c91 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 24 Jan 2020 09:02:37 +0000
-Subject: [PATCH] overlays: Use preferred compatible strings
-
-Make sure all overlays have correct compatible strings before enabling
-the automated checking.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++
- arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++
- arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++
- 5 files changed, 8 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target-path = "/clocks";
---- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
-@@ -3,7 +3,7 @@
- /plugin/;
-
- / {
-- compatible = "brcm,bcm2708";
-+ compatible = "brcm,bcm2835";
-
- fragment@0 {
- target = <&i2s>;
---- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
-@@ -17,6 +17,8 @@ N.B.:
- */
-
- / {
-+ compatible = "brcm,bcm2835";
-+
- fragment@0 {
- target = <&gpio>;
- __overlay__ {
---- a/arch/arm/boot/dts/overlays/pwm-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
-@@ -15,6 +15,8 @@ N.B.:
- */
-
- / {
-+ compatible = "brcm,bcm2835";
-+
- fragment@0 {
- target = <&gpio>;
- __overlay__ {
---- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
-@@ -5,6 +5,8 @@
- /plugin/;
-
- /{
-+ compatible = "brcm,bcm2835";
-+
- fragment@0 {
- target = <&soc>;
- __overlay__ {
--- /dev/null
+From 333c4158645fe8aaacbd644bcdf7bc4c5b93cc26 Mon Sep 17 00:00:00 2001
+From: Tim Gover <990920+timg236@users.noreply.github.com>
+Date: Wed, 15 Jan 2020 11:26:19 +0000
+Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805
+
+The VL805 FW may either be loaded from an SPI EEPROM or alternatively
+loaded directly by the VideoCore firmware. A PCI reset will reset
+the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware
+to be reloaded if an SPI EEPROM is not present.
+
+Use a VideoCore mailbox to trigger the loading of the VL805
+firmware (if necessary) after a PCI reset.
+
+Signed-off-by: Tim Gover <tim.gover@raspberrypi.org>
+---
+ drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++-
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -18,7 +18,7 @@
+ #include <linux/dmi.h>
+ #include "pci-quirks.h"
+ #include "xhci-ext-caps.h"
+-
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define UHCI_USBLEGSUP 0xc0 /* legacy support */
+ #define UHCI_USBCMD 0 /* command register */
+@@ -634,6 +634,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port)
+
+ #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+
++/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into
++ * memory. If run from memory it must be reloaded after a PCI fundmental reset.
++ * The Raspberry Pi firmware acts as the BIOS in this case.
++ */
++static void usb_vl805_init(struct pci_dev *pdev)
++{
++#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
++ struct rpi_firmware *fw;
++ struct {
++ u32 dev_addr;
++ } packet;
++ int ret;
++
++ fw = rpi_firmware_get(NULL);
++ if (!fw)
++ return;
++
++ packet.dev_addr = (pdev->bus->number << 20) |
++ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12);
++
++ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr);
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
++ &packet, sizeof(packet));
++#endif
++}
++
+ #if IS_ENABLED(CONFIG_USB_UHCI_HCD)
+
+ /*
+@@ -1222,6 +1248,9 @@ hc_init:
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ usb_enable_intel_xhci_ports(pdev);
+
++ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
++ usb_vl805_init(pdev);
++
+ op_reg_base = base + XHCI_HC_LENGTH(readl(base));
+
+ /* Wait for the host controller to be ready before writing any
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -95,7 +95,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
+ RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
+ RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
+-
++ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
--- /dev/null
+From b058c3c898472ad8799bba29365c3295fdd24970 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 14:32:51 +0000
+Subject: [PATCH] overlays: Correct the eth_led* colour assignments
+
+See: https://github.com/raspberrypi/firmware/issues/1311
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -109,27 +109,28 @@ Params:
+ Legal values are 2, 3, 4, 5 and 0, where
+ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange). The legal
+- values are:
++ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"),
++ green on Pi4 (default "0").
++ The legal values are:
+
+ Pi3B+
+
+- 0=link/activity 1=link1000/activity (default)
++ 0=link/activity 1=link1000/activity
+ 2=link100/activity 3=link10/activity
+ 4=link100/1000/activity 5=link10/1000/activity
+ 6=link10/100/activity 14=off 15=on
+
+ Pi4
+
+- 0=Speed/Activity (default) 1=Speed
+- 2=Speed/Flash activity 3=FDX
++ 0=Speed/Activity 1=Speed
++ 2=Flash activity 3=FDX
+ 4=Off 5=On
+ 6=Alt 7=Speed/Flash
+ 8=Link 9=Activity
+
+- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
+- "6", Pi4 default "8"). See eth_led0 for legal
+- values.
++ eth_led1 Set mode of LED1 - green on Pi3B (default "6"),
++ amber on Pi4 (default "8"). See eth_led0 for
++ legal values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+ to negotiate. Legal values are 10, 100 and
+++ /dev/null
-From a3749ee48539fa832b1832cdcae26d34e5d20f00 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 24 Jan 2020 11:38:28 +0000
-Subject: [PATCH] tty: amba-pl011: Add un/throttle support
-
-The PL011 driver lacks throttle and unthrottle methods. As a result,
-sending more data to the Pi than it can immediately sink while CRTSCTS
-is enabled causes a NULL pointer to be followed.
-
-Add a throttle handler that disables the RX interrupts, and an
-unthrottle handler that reenables them.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
- 1 file changed, 28 insertions(+)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -1323,6 +1323,32 @@ static void pl011_start_tx(struct uart_p
- pl011_start_tx_pio(uap);
- }
-
-+static void pl011_throttle(struct uart_port *port)
-+{
-+ struct uart_amba_port *uap =
-+ container_of(port, struct uart_amba_port, port);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&uap->port.lock, flags);
-+ uap->im &= ~(UART011_RTIM | UART011_RXIM);
-+ pl011_write(uap->im, uap, REG_IMSC);
-+ spin_unlock_irqrestore(&uap->port.lock, flags);
-+}
-+
-+static void pl011_unthrottle(struct uart_port *port)
-+{
-+ struct uart_amba_port *uap =
-+ container_of(port, struct uart_amba_port, port);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&uap->port.lock, flags);
-+ uap->im |= UART011_RTIM;
-+ if (!pl011_dma_rx_running(uap))
-+ uap->im |= UART011_RXIM;
-+ pl011_write(uap->im, uap, REG_IMSC);
-+ spin_unlock_irqrestore(&uap->port.lock, flags);
-+}
-+
- static void pl011_stop_rx(struct uart_port *port)
- {
- struct uart_amba_port *uap =
-@@ -2164,6 +2190,8 @@ static const struct uart_ops amba_pl011_
- .stop_tx = pl011_stop_tx,
- .start_tx = pl011_start_tx,
- .stop_rx = pl011_stop_rx,
-+ .throttle = pl011_throttle,
-+ .unthrottle = pl011_unthrottle,
- .enable_ms = pl011_enable_ms,
- .break_ctl = pl011_break_ctl,
- .startup = pl011_startup,
--- /dev/null
+From 3ef2bbe381adc17d135f8f9b22a43a242eb80c63 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 30 Jan 2020 09:47:00 +0000
+Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711
+
+The old sdtweak overlay allowed the SD interface to be effectively
+disabled unless there was a card present at boot time, but that
+overlay doesn't work on bcm2711 and has largely been replaced by
+a set of sd_* dtparams (which have the advantage of being board-
+specific.
+
+Add an sd_poll_once dtparam to allow the same functionality on
+all Raspberry Pi boards.
+
+See: https://github.com/raspberrypi/linux/issues/3286
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++
+ arch/arm/boot/dts/overlays/README | 7 +++++++
+ 3 files changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -92,6 +92,7 @@
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_poll_once = <&sdhost>,"non-removable?";
+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+ sd_debug = <&sdhost>,"brcm,debug";
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -363,5 +363,7 @@
+
+ eth_led0 = <&phy1>,"led-modes:0";
+ eth_led1 = <&phy1>,"led-modes:4";
++
++ sd_poll_once = <&emmc2>, "non-removable?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -165,6 +165,13 @@ Params:
+ sd_overclock Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+
++ sd_poll_once Looks for a card once after booting. Useful
++ for network booting scenarios to avoid the
++ overhead of continuous polling. N.B. Using
++ this option restricts the system to using a
++ single card per boot (or none at all).
++ (default off)
++
+ sd_force_pio Disable DMA support for SD driver (default off)
+
+ sd_pio_limit Number of blocks above which to use DMA for
+++ /dev/null
-From 1cf854cd3531b10168b8f9aeb93bb0ab4b9a9003 Mon Sep 17 00:00:00 2001
-From: MikeDK <m.kaplan@evva.com>
-Date: Sun, 26 Jan 2020 23:33:54 +0100
-Subject: [PATCH] Fix i2c-pwm-pca9685a overlay
-
----
- arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
-@@ -13,7 +13,7 @@
- status = "okay";
-
- pca: pca@40 {
-- compatible = "nxp,pca9685";
-+ compatible = "nxp,pca9685-pwm";
- #pwm-cells = <2>;
- reg = <0x40>;
- status = "okay";
+++ /dev/null
-From 4a773d6535c3386044490156264ebd2a3b1bc38b Mon Sep 17 00:00:00 2001
-From: j-schambacher <joerg@i2audio.com>
-Date: Mon, 27 Jan 2020 17:45:51 +0100
-Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound
- card
-
-This adds a DT overlay parameter 'leds_off' which allows
-to switch off the onboard activity LEDs at all times
-which has been requested by some users.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- arch/arm/boot/dts/overlays/README | 2 ++
- .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 +
- sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++--
- 3 files changed, 16 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga
- that does not result in clipping/distortion!)
- slave Force DAC+ADC Pro into slave mode, using Pi as
- master for bit clock and frame clock.
-+ leds_off If set to 'true' the onboard indicator LEDs
-+ are switched off at all times.
-
-
- Name: hifiberry-dacplusdsp
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-@@ -60,5 +60,6 @@
- 24db_digital_gain =
- <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
- slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
-+ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?";
- };
- };
---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
-+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
-@@ -54,6 +54,7 @@ struct pcm512x_priv {
- static bool slave;
- static bool snd_rpi_hifiberry_is_dacpro;
- static bool digital_gain_0db_limit = true;
-+static bool leds_off;
-
- static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
- 0x00, 0x01, 0x02, 0x03, 0x10
-@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp
-
- snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
- snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+ if (leds_off)
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+ else
-+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-
- ret = pcm1863_add_controls(adc);
- if (ret < 0)
-@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp
- /* set GPIO2 to output, GPIO3 input */
- snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
- snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
-- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-+ if (leds_off)
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
-+ else
-+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
-
- if (digital_gain_0db_limit) {
- int ret;
-@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp
- struct snd_soc_component *dac = rtd->codec_dais[0]->component;
- struct snd_soc_component *adc = rtd->codec_dais[1]->component;
-
-+ if (leds_off)
-+ return 0;
- /* switch on respective LED */
- if (!substream->stream)
- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-@@ -500,6 +509,8 @@ static int snd_rpi_hifiberry_dacplusadcp
- pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
- slave = of_property_read_bool(pdev->dev.of_node,
- "hifiberry-dacplusadcpro,slave");
-+ leds_off = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplusadcpro,leds_off");
- ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
- if (ret && ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
--- /dev/null
+From fe90ee51b283f7cbbce9980b76b3da8b31d39c60 Mon Sep 17 00:00:00 2001
+From: MikeDK <m.kaplan@evva.com>
+Date: Fri, 31 Jan 2020 10:57:21 +0100
+Subject: [PATCH] overlays: Add ssd1306-spi, ssh1106-spi, ssd-1351-spi
+
+Add overlays for SSD1306, SH1106 and SSD1351 based OLED displays.
+SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in
+1.5 inch RGB OLEDs from AliExpress.
+
+This will load the staging fbtft drivers.
+
+Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 3 +
+ arch/arm/boot/dts/overlays/README | 35 ++++++++
+ .../boot/dts/overlays/sh1106-spi-overlay.dts | 84 +++++++++++++++++++
+ .../boot/dts/overlays/ssd1306-spi-overlay.dts | 84 +++++++++++++++++++
+ .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 ++++++++++++++++++
+ 5 files changed, 289 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ sdhost.dtbo \
+ sdio.dtbo \
+ sdtweak.dtbo \
++ sh1106-spi.dtbo \
+ smi.dtbo \
+ smi-dev.dtbo \
+ smi-nand.dtbo \
+@@ -168,6 +169,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi6-1cs.dtbo \
+ spi6-2cs.dtbo \
+ ssd1306.dtbo \
++ ssd1306-spi.dtbo \
++ ssd1351-spi.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i
+ (default on)
+
+
++Name: sh1106-spi
++Info: Overlay for SH1106 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=sh1106-spi,<param>=<val>
++Params: speed SPI bus speed (default 4000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
+ Name: smi
+ Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
+ Load: dtoverlay=smi
+@@ -2428,6 +2440,29 @@ Params: address Location
+ https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
+
+
++Name: ssd1306-spi
++Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1306-spi,<param>=<val>
++Params: speed SPI bus speed (default 10000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
++Name: ssd1351-spi
++Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1351-spi,<param>=<val>
++Params: speed SPI bus speed (default 4500000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -0,0 +1,84 @@
++/*
++ * Device Tree overlay for SH1106 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ sh1106_pins: sh1106_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ sh1106: sh1106@0{
++ compatible = "sinowealth,sh1106";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&sh1106_pins>;
++
++ spi-max-frequency = <4000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ sinowealth,height = <64>;
++ sinowealth,width = <128>;
++ sinowealth,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&sh1106>,"spi-max-frequency:0";
++ rotate = <&sh1106>,"rotate:0";
++ fps = <&sh1106>,"fps:0";
++ debug = <&sh1106>,"debug:0";
++ dc_pin = <&sh1106>,"dc-gpios:4",
++ <&sh1106_pins>,"brcm,pins:4";
++ reset_pin = <&sh1106>,"reset-gpios:4",
++ <&sh1106_pins>,"brcm,pins:0";
++ height = <&sh1106>,"sinowealth,height:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -0,0 +1,84 @@
++/*
++ * Device Tree overlay for SSD1306 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1306_pins: ssd1306_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1306: ssd1306@0{
++ compatible = "solomon,ssd1306";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1306_pins>;
++
++ spi-max-frequency = <10000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <64>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1306>,"spi-max-frequency:0";
++ rotate = <&ssd1306>,"rotate:0";
++ fps = <&ssd1306>,"fps:0";
++ debug = <&ssd1306>,"debug:0";
++ dc_pin = <&ssd1306>,"dc-gpios:4",
++ <&ssd1306_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1306>,"reset-gpios:4",
++ <&ssd1306_pins>,"brcm,pins:0";
++ height = <&ssd1306>,"solomon,height:0";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -0,0 +1,83 @@
++/*
++ * Device Tree overlay for SSD1351 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1351_pins: ssd1351_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1351: ssd1351@0{
++ compatible = "solomon,ssd1351";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1351_pins>;
++
++ spi-max-frequency = <4500000>;
++ bgr = <0>;
++ bpp = <16>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <128>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1351>,"spi-max-frequency:0";
++ rotate = <&ssd1351>,"rotate:0";
++ fps = <&ssd1351>,"fps:0";
++ debug = <&ssd1351>,"debug:0";
++ dc_pin = <&ssd1351>,"dc-gpios:4",
++ <&ssd1351_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1351>,"reset-gpios:4",
++ <&ssd1351_pins>,"brcm,pins:0";
++ };
++};
+++ /dev/null
-From 36949b2ea78d5782faed2fb00a037f37789fa85d Mon Sep 17 00:00:00 2001
-From: j-schambacher <joerg@i2audio.com>
-Date: Mon, 27 Jan 2020 20:37:34 +0100
-Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card
-
-This adds a DT overlay parameter 'leds_off' which allows
-to switch off the onboard activity LEDs at all times
-which has been requested by some users.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- arch/arm/boot/dts/overlays/README | 2 ++
- .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 +
- sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++-
- 3 files changed, 12 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga
- that does not result in clipping/distortion!)
- slave Force DAC+ Pro into slave mode, using Pi as
- master for bit clock and frame clock.
-+ leds_off If set to 'true' the onboard indicator LEDs
-+ are switched off at all times.
-
-
- Name: hifiberry-dacplusadcpro
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-@@ -67,5 +67,6 @@
- 24db_digital_gain =
- <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
- slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
-+ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?";
- };
- };
---- a/sound/soc/bcm/hifiberry_dacplusadc.c
-+++ b/sound/soc/bcm/hifiberry_dacplusadc.c
-@@ -54,6 +54,7 @@ struct pcm512x_priv {
- static bool slave;
- static bool snd_rpi_hifiberry_is_dacpro;
- static bool digital_gain_0db_limit = true;
-+static bool leds_off;
-
- static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
- int clk_id)
-@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_
-
- snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
- snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+ if (leds_off)
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+ else
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-
- if (digital_gain_0db_limit) {
- int ret;
-@@ -254,6 +258,8 @@ static int snd_rpi_hifiberry_dacplusadc_
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_component *component = rtd->codec_dai->component;
-
-+ if (leds_off)
-+ return 0;
- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
- 0x08, 0x08);
- hifiberry_dacplusadc_LED_cnt++;
-@@ -330,6 +336,8 @@ static int snd_rpi_hifiberry_dacplusadc_
- pdev->dev.of_node, "hifiberry,24db_digital_gain");
- slave = of_property_read_bool(pdev->dev.of_node,
- "hifiberry-dacplusadc,slave");
-+ leds_off = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplusadc,leds_off");
-
- ret = devm_snd_soc_register_card(&pdev->dev,
- &snd_rpi_hifiberry_dacplusadc);
--- /dev/null
+From 1257716d9bae9730c43c636046983f5d80c4efc8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 4 Feb 2020 13:03:21 +0000
+Subject: [PATCH] overlays: dwc2: Increase RX FIFO size
+
+The previous version of the dwc2 overlay set the RX FIFO size to
+256 4-byte words. This sounds large enough for a 1024 byte packet (the
+largest isochronous high speed packet allowed), but it doesn't take
+into account some extra space needed by the hardware.
+
+Minas Harutyunyan at Synopsys (the source of the DWC OTG design)
+came up with a more correct value, 301, but since there is spare packet
+RAM this can be increased to 558 to allow two packets per frame.
+
+Also update the upstream overlay to match.
+
+See: https://github.com/raspberrypi/linux/issues/3447
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -12,7 +12,7 @@
+ compatible = "brcm,bcm2835-usb";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+- g-rx-fifo-size = <256>;
++ g-rx-fifo-size = <558>;
+ g-tx-fifo-size = <512 512 512 512 512 256 256>;
+ status = "okay";
+ };
+--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
+@@ -123,7 +123,7 @@
+ compatible = "brcm,bcm2835-usb";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+- g-rx-fifo-size = <256>;
++ g-rx-fifo-size = <558>;
+ g-tx-fifo-size = <512 512 512 512 512 256 256>;
+ status = "okay";
+ };
+++ /dev/null
-From 4b3cdf84c4d8156c01fa02e4d511f7529cae488f Mon Sep 17 00:00:00 2001
-From: j-schambacher <joerg@i2audio.com>
-Date: Mon, 27 Jan 2020 20:58:24 +0100
-Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound
- cards
-
-This adds a DT overlay parameter 'leds_off' which allows
-to switch off the onboard activity LEDs at all times
-which has been requested by some users.
-
-Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
----
- arch/arm/boot/dts/overlays/README | 2 ++
- .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 +
- sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++-
- 3 files changed, 12 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga
- that does not result in clipping/distortion!)
- slave Force DAC+ Pro into slave mode, using Pi as
- master for bit clock and frame clock.
-+ leds_off If set to 'true' the onboard indicator LEDs
-+ are switched off at all times.
-
-
- Name: hifiberry-dacplusadc
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -55,5 +55,6 @@
- 24db_digital_gain =
- <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
- slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
-+ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?";
- };
- };
---- a/sound/soc/bcm/hifiberry_dacplus.c
-+++ b/sound/soc/bcm/hifiberry_dacplus.c
-@@ -50,6 +50,7 @@ struct pcm512x_priv {
- static bool slave;
- static bool snd_rpi_hifiberry_is_dacpro;
- static bool digital_gain_0db_limit = true;
-+static bool leds_off;
-
- static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
- int clk_id)
-@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini
-
- snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
- snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
-- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-+ if (leds_off)
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
-+ else
-+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
-
- if (digital_gain_0db_limit)
- {
-@@ -249,6 +253,8 @@ static int snd_rpi_hifiberry_dacplus_sta
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_component *component = rtd->codec_dai->component;
-
-+ if (leds_off)
-+ return 0;
- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
- return 0;
- }
-@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro
- pdev->dev.of_node, "hifiberry,24db_digital_gain");
- slave = of_property_read_bool(pdev->dev.of_node,
- "hifiberry-dacplus,slave");
-+ leds_off = of_property_read_bool(pdev->dev.of_node,
-+ "hifiberry-dacplus,leds_off");
- }
-
- ret = devm_snd_soc_register_card(&pdev->dev,
--- /dev/null
+From 9fa750db2d682fa2c124dae609d05d15f93a5e52 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 4 Feb 2020 15:22:55 +0000
+Subject: [PATCH] overlays: Fix mcp23017's addr parameter
+
+The addr parameter of the mcp23017 overlay was broken by the addition
+of the noints parameter; splitting the mcp node in two without also
+modifying the second half from the addr parameter would cause the two
+halves to separate. Change the implementation strategy to patch
+fragment 2 (as was originally proposed). This will prevent the
+overlay from being applied at runtime until the "dtoverlay" command
+is improved, but the overlay already has this restriction due to
+fragment 3 so this isn't a step backwards.
+
+See: https://github.com/raspberrypi/linux/issues/3449
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -48,15 +48,13 @@
+ };
+
+ fragment@4 {
+- target = <&i2c1>;
+- __overlay__ {
+- mcp23017_irq: mcp@20 {
+- #interrupt-cells=<2>;
+- interrupt-parent = <&gpio>;
+- interrupts = <4 2>;
+- interrupt-controller;
+- microchip,irq-mirror;
+- };
++ target = <&mcp23017>;
++ mcp23017_irq: __overlay__ {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 2>;
++ interrupt-controller;
++ microchip,irq-mirror;
+ };
+ };
+
--- /dev/null
+From 69811ede9ad350beb531082177bdc6da92c7fdb9 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 4 Feb 2020 16:35:12 +0000
+Subject: [PATCH] SQUASH: Fix spi driver compiler warnings
+
+Squash with "spi: spi-bcm2835: Disable forced software CS"
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/spi/spi-bcm2835.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -1230,8 +1230,6 @@ static int bcm2835_spi_setup(struct spi_
+ {
+ struct spi_controller *ctlr = spi->controller;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+- struct gpio_chip *chip;
+- enum gpio_lookup_flags lflags;
+ u32 cs;
+
+ /*
+++ /dev/null
-From 21dace2c687d45819cb0dfc4f32f005da82d9197 Mon Sep 17 00:00:00 2001
-From: gtrainavicius <gtrainavicius@users.noreply.github.com>
-Date: Tue, 28 Jan 2020 14:16:37 +0200
-Subject: [PATCH] pisound: Added reading Pisound board hardware
- revision and exposing it (#3425)
-
-pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file:
-
-/sys/kernel/pisound/hw_version
-
-Signed-off-by: Giedrius <giedrius@blokas.io>
----
- sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++-------------
- 1 file changed, 59 insertions(+), 27 deletions(-)
-
---- a/sound/soc/bcm/pisound.c
-+++ b/sound/soc/bcm/pisound.c
-@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd
-
- static const char *pisnd_spi_get_serial(void);
- static const char *pisnd_spi_get_id(void);
--static const char *pisnd_spi_get_version(void);
-+static const char *pisnd_spi_get_fw_version(void);
-+static const char *pisnd_spi_get_hw_version(void);
-
- static int pisnd_midi_init(struct snd_card *card);
- static void pisnd_midi_uninit(void);
-@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback;
-
- static char g_serial_num[11];
- static char g_id[25];
--static char g_version[5];
-+enum { MAX_VERSION_STR_LEN = 6 };
-+static char g_fw_version[MAX_VERSION_STR_LEN];
-+static char g_hw_version[MAX_VERSION_STR_LEN];
-
- static uint8_t g_ledFlashDuration;
- static bool g_ledFlashDurationChanged;
-@@ -558,7 +561,8 @@ static int spi_read_info(void)
- char *p;
-
- memset(g_serial_num, 0, sizeof(g_serial_num));
-- memset(g_version, 0, sizeof(g_version));
-+ memset(g_fw_version, 0, sizeof(g_fw_version));
-+ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version.
- memset(g_id, 0, sizeof(g_id));
-
- tmp = spi_transfer16(0);
-@@ -581,12 +585,28 @@ static int spi_read_info(void)
- return -EINVAL;
-
- snprintf(
-- g_version,
-- sizeof(g_version),
-+ g_fw_version,
-+ MAX_VERSION_STR_LEN,
- "%x.%02x",
- buffer[0],
- buffer[1]
- );
-+
-+ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0';
-+ break;
-+ case 3:
-+ if (n != 2)
-+ return -EINVAL;
-+
-+ snprintf(
-+ g_hw_version,
-+ MAX_VERSION_STR_LEN,
-+ "%x.%x",
-+ buffer[0],
-+ buffer[1]
-+ );
-+
-+ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0';
- break;
- case 1:
- if (n >= sizeof(g_serial_num))
-@@ -596,12 +616,14 @@ static int spi_read_info(void)
- break;
- case 2:
- {
-- if (n >= sizeof(g_id))
-+ if (n*2 >= sizeof(g_id))
- return -EINVAL;
-
- p = g_id;
- for (j = 0; j < n; ++j)
- p += sprintf(p, "%02x", buffer[j]);
-+
-+ *p = '\0';
- }
- break;
- default:
-@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device
-
- memset(g_serial_num, 0, sizeof(g_serial_num));
- memset(g_id, 0, sizeof(g_id));
-- memset(g_version, 0, sizeof(g_version));
-+ memset(g_fw_version, 0, sizeof(g_fw_version));
-+ memset(g_hw_version, 0, sizeof(g_hw_version));
-
- spi = pisnd_spi_find_device();
-
-@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd
-
- static const char *pisnd_spi_get_serial(void)
- {
-- if (strlen(g_serial_num))
-- return g_serial_num;
--
-- return "";
-+ return g_serial_num;
- }
-
- static const char *pisnd_spi_get_id(void)
- {
-- if (strlen(g_id))
-- return g_id;
--
-- return "";
-+ return g_id;
- }
-
--static const char *pisnd_spi_get_version(void)
-+static const char *pisnd_spi_get_fw_version(void)
- {
-- if (strlen(g_version))
-- return g_version;
-+ return g_fw_version;
-+}
-
-- return "";
-+static const char *pisnd_spi_get_hw_version(void)
-+{
-+ return g_hw_version;
- }
-
- static const struct of_device_id pisound_of_match[] = {
-@@ -1056,13 +1075,22 @@ static ssize_t pisnd_id_show(
- return sprintf(buf, "%s\n", pisnd_spi_get_id());
- }
-
--static ssize_t pisnd_version_show(
-+static ssize_t pisnd_fw_version_show(
- struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf
- )
- {
-- return sprintf(buf, "%s\n", pisnd_spi_get_version());
-+ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version());
-+}
-+
-+static ssize_t pisnd_hw_version_show(
-+ struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ char *buf
-+)
-+{
-+ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version());
- }
-
- static ssize_t pisnd_led_store(
-@@ -1087,15 +1115,18 @@ static struct kobj_attribute pisnd_seria
- __ATTR(serial, 0444, pisnd_serial_show, NULL);
- static struct kobj_attribute pisnd_id_attribute =
- __ATTR(id, 0444, pisnd_id_show, NULL);
--static struct kobj_attribute pisnd_version_attribute =
-- __ATTR(version, 0444, pisnd_version_show, NULL);
-+static struct kobj_attribute pisnd_fw_version_attribute =
-+ __ATTR(version, 0444, pisnd_fw_version_show, NULL);
-+static struct kobj_attribute pisnd_hw_version_attribute =
-+__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL);
- static struct kobj_attribute pisnd_led_attribute =
- __ATTR(led, 0644, NULL, pisnd_led_store);
-
- static struct attribute *attrs[] = {
- &pisnd_serial_attribute.attr,
- &pisnd_id_attribute.attr,
-- &pisnd_version_attribute.attr,
-+ &pisnd_fw_version_attribute.attr,
-+ &pisnd_hw_version_attribute.attr,
- &pisnd_led_attribute.attr,
- NULL
- };
-@@ -1114,9 +1145,10 @@ static int pisnd_probe(struct platform_d
- }
-
- printi("Detected Pisound card:\n");
-- printi("\tSerial: %s\n", pisnd_spi_get_serial());
-- printi("\tVersion: %s\n", pisnd_spi_get_version());
-- printi("\tId: %s\n", pisnd_spi_get_id());
-+ printi("\tSerial: %s\n", pisnd_spi_get_serial());
-+ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version());
-+ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version());
-+ printi("\tId: %s\n", pisnd_spi_get_id());
-
- pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
- if (!pisnd_kobj) {
+++ /dev/null
-From 703920ad5199c46f98cf107c75a2de61608f85fd Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 2 Aug 2019 15:20:11 +0100
-Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc
-
-The Linux support for controlling card power via regulators appears to
-be contentious. I would argue that the default behaviour is contrary to
-the SDHCI spec - turning off the power writes a reserved value to the
-SD Bus Voltage Select field of the Power Control Register, which
-seems to kill the Arasan/iProc controller - but fortunately there is a
-hook in sdhci_ops to override the behaviour. Borrow the implementation
-from sdhci_arasan_set_power.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
---- a/drivers/mmc/host/sdhci-iproc.c
-+++ b/drivers/mmc/host/sdhci-iproc.c
-@@ -173,6 +173,17 @@ static unsigned int sdhci_iproc_get_max_
- return pltfm_host->clock;
- }
-
-+static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode,
-+ unsigned short vdd)
-+{
-+ if (!IS_ERR(host->mmc->supply.vmmc)) {
-+ struct mmc_host *mmc = host->mmc;
-+
-+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
-+ }
-+ sdhci_set_power_noreg(host, mode, vdd);
-+}
-+
- static const struct sdhci_ops sdhci_iproc_ops = {
- .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_iproc_get_max_clock,
-@@ -190,6 +201,7 @@ static const struct sdhci_ops sdhci_ipro
- .write_b = sdhci_iproc_writeb,
- .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_iproc_get_max_clock,
-+ .set_power = sdhci_iproc_set_power,
- .set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
--- /dev/null
+From c6e4343e441558f45df2685b9ed7c13daf7988be Mon Sep 17 00:00:00 2001
+From: Michael Kaplan <m.kaplan@evva.com>
+Date: Wed, 5 Feb 2020 10:27:23 +0100
+Subject: [PATCH] overlays: add hdmi-backlight-hwhack-gpio-overlay
+
+This is a Devicetree overlay for GPIO based backlight on/off capability.
+
+Use this if you have one of those HDMI displays whose backlight cannot be controlled via DPMS over HDMI and plan to do a little soldering to use an RPi gpio pin for on/off switching.
+
+See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
+
+This was tested with a clone of the Waveshare "7 inch HDMI Touch LCD C" where I soldered two mosfets to override the backlight dip-switch.
+When the overlay is loaded, a sysfs backlight node appears which can be used to modify the brightness value (0 or 1), and is even used by DPMS to switch the display backlight off after the configured timeout.
+(On current Raspbian Buster Desktop, it's also possible to wakeup the display via a tap on the touch display :-) )
+
+Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 14 ++++++
+ .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 +++++++++++++++++++
+ 3 files changed, 62 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -51,6 +51,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ gpio-poweroff.dtbo \
+ gpio-shutdown.dtbo \
+ hd44780-lcd.dtbo \
++ hdmi-backlight-hwhack-gpio.dtbo \
+ hifiberry-amp.dtbo \
+ hifiberry-dac.dtbo \
+ hifiberry-dacplus.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -883,6 +883,20 @@ Params: pin_d4 GPIO pin
+ display_width Width of the display in characters
+
+
++Name: hdmi-backlight-hwhack-gpio
++Info: Devicetree overlay for GPIO based backlight on/off capability.
++ Use this if you have one of those HDMI displays whose backlight cannot
++ be controlled via DPMS over HDMI and plan to do a little soldering to
++ use an RPi gpio pin for on/off switching. See:
++ https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
++Load: dtoverlay=hdmi-backlight-hwhack-gpio,<param>=<val>
++Params: gpio_pin GPIO pin used (default 17)
++ active_low Set this to 1 if the display backlight is
++ switched on when the wire goes low.
++ Leave the default (value 0) if the backlight
++ expects a high to switch it on.
++
++
+ Name: hifiberry-amp
+ Info: Configures the HifiBerry Amp and Amp+ audio cards
+ Load: dtoverlay=hifiberry-amp
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts
+@@ -0,0 +1,47 @@
++/*
++ * Devicetree overlay for GPIO based backlight on/off capability.
++ *
++ * Use this if you have one of those HDMI displays whose backlight cannot be
++ * controlled via DPMS over HDMI and plan to do a little soldering to use an
++ * RPi gpio pin for on/off switching.
++ *
++ * See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
++ *
++ */
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ hdmi_backlight_hwhack_gpio_pins: hdmi_backlight_hwhack_gpio_pins {
++ brcm,pins = <17>;
++ brcm,function = <1>; /* out */
++ };
++ };
++ };
++
++ fragment@2 {
++ target-path = "/";
++ __overlay__ {
++ hdmi_backlight_hwhack_gpio: hdmi_backlight_hwhack_gpio {
++ compatible = "gpio-backlight";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&hdmi_backlight_hwhack_gpio_pins>;
++
++ gpios = <&gpio 17 0>;
++ default-on;
++ };
++ };
++ };
++
++ __overrides__ {
++ gpio_pin = <&hdmi_backlight_hwhack_gpio>,"gpios:4",
++ <&hdmi_backlight_hwhack_gpio_pins>,"brcm,pins:0";
++ active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8";
++ };
++};
+++ /dev/null
-From ade82688b687b3340ca5e7883646ad51291d49cd Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Tue, 30 Jul 2019 12:37:02 +0100
-Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator
-
-Later revisions of the Raspberry Pi 4B have a separate control over the
-SD card power. Expose that control to Linux as a fixed regulator with
-a GPIO enable.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++
- 3 files changed, 13 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -122,6 +122,16 @@
- states = <1800000 0x1
- 3300000 0x0>;
- };
-+
-+ sd_vcc_reg: sd_vcc_reg {
-+ compatible = "regulator-fixed";
-+ regulator-name = "vcc-sd";
-+ regulator-min-microvolt = <3300000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ enable-active-high;
-+ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
-+ };
- };
-
- &sdhost {
-@@ -132,6 +142,7 @@
- status = "okay";
- broken-cd;
- vqmmc-supply = <&sd_io_1v8_reg>;
-+ vmmc-supply = <&sd_vcc_reg>;
- };
-
- &genet {
--- /dev/null
+From e90536d721612de6a2619ae6727ee12b56bb2660 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 30 Jan 2020 11:39:39 +0000
+Subject: [PATCH] ARM: dts: Revert all changes to upstream dts files
+
+With the possible exception of bcm2711* files where there is a name
+clash, we should not be modifying upstream DTS files.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 348 ++------
+ arch/arm/boot/dts/bcm2711.dtsi | 888 ++++++++++++++++++++-
+ arch/arm/boot/dts/bcm2835-common.dtsi | 131 +++
+ arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi-a.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi-b.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi-zero.dts | 1 -
+ arch/arm/boot/dts/bcm2835-rpi.dtsi | 37 -
+ arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 -
+ arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 1 -
+ arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi | 15 -
+ arch/arm/boot/dts/bcm283x.dtsi | 152 +---
+ 14 files changed, 1068 insertions(+), 511 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -1,54 +1,57 @@
++// SPDX-License-Identifier: GPL-2.0
+ /dts-v1/;
+-
+ #include "bcm2711.dtsi"
+-#include "bcm2711-rpi.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
++#include "bcm2835-rpi.dtsi"
++#include "bcm283x-rpi-usb-peripheral.dtsi"
+
+ / {
+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+ model = "Raspberry Pi 4 Model B";
+
+- memory@0 {
+- device_type = "memory";
+- reg = <0x0 0x0 0x0>;
++ chosen {
++ /* 8250 auxiliary UART instead of pl011 */
++ stdout-path = "serial1:115200n8";
+ };
+
+- chosen {
+- bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
++ /* Will be filled by the bootloader */
++ memory@0 {
++ device_type = "memory";
++ reg = <0 0 0>;
+ };
+
+ aliases {
+- serial0 = &uart1;
+- serial1 = &uart0;
+- mmc0 = &emmc2;
+- mmc1 = &mmcnr;
+- mmc2 = &sdhost;
+- i2c3 = &i2c3;
+- i2c4 = &i2c4;
+- i2c5 = &i2c5;
+- i2c6 = &i2c6;
+- /delete-property/ ethernet;
+- /delete-property/ intc;
+ ethernet0 = &genet;
+- pcie0 = &pcie_0;
+ };
+-};
+
+-&soc {
+- virtgpio: virtgpio {
+- compatible = "brcm,bcm2835-virtgpio";
+- gpio-controller;
+- #gpio-cells = <2>;
+- firmware = <&firmware>;
+- status = "okay";
++ leds {
++ act {
++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
++ };
++
++ pwr {
++ label = "PWR";
++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
++ };
+ };
+-};
+
+-&mmcnr {
+- pinctrl-names = "default";
+- pinctrl-0 = <&sdio_pins>;
+- bus-width = <4>;
+- status = "okay";
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
++ };
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ compatible = "regulator-gpio";
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-settling-time-us = <5000>;
++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++ status = "okay";
++ };
+ };
+
+ &firmware {
+@@ -68,81 +71,34 @@
+ };
+ };
+
+-&uart0 {
++&pwm1 {
+ pinctrl-names = "default";
+- pinctrl-0 = <&uart0_pins &bt_pins>;
++ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
+ status = "okay";
+ };
+
+-&uart1 {
++/* SDHCI is used to control the SDIO for wireless */
++&sdhci {
++ #address-cells = <1>;
++ #size-cells = <0>;
+ pinctrl-names = "default";
+- pinctrl-0 = <&uart1_pins>;
++ pinctrl-0 = <&emmc_gpio34>;
++ bus-width = <4>;
++ non-removable;
++ mmc-pwrseq = <&wifi_pwrseq>;
+ status = "okay";
+-};
+
+-&spi0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
+- cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
+-
+- spidev0: spidev@0{
+- compatible = "spidev";
+- reg = <0>; /* CE0 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <125000000>;
+- };
+-
+- spidev1: spidev@1{
+- compatible = "spidev";
+- reg = <1>; /* CE1 */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- spi-max-frequency = <125000000>;
+- };
+-};
+-
+-// =============================================
+-// Board specific stuff here
+-
+-/ {
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- status = "okay";
+- compatible = "regulator-gpio";
+- vin-supply = <&vdd_5v0_reg>;
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+-
+- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
++ brcmf: wifi@1 {
++ reg = <1>;
++ compatible = "brcm,bcm4329-fmac";
+ };
+-
+- sd_vcc_reg: sd_vcc_reg {
+- compatible = "regulator-fixed";
+- regulator-name = "vcc-sd";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- enable-active-high;
+- gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
+- };
+-};
+-
+-&sdhost {
+- status = "disabled";
+ };
+
++/* EMMC2 is used to drive the SD card */
+ &emmc2 {
+- status = "okay";
+- broken-cd;
+ vqmmc-supply = <&sd_io_1v8_reg>;
+- vmmc-supply = <&sd_vcc_reg>;
++ broken-cd;
++ status = "okay";
+ };
+
+ &genet {
+@@ -155,200 +111,32 @@
+ phy1: ethernet-phy@1 {
+ /* No PHY interrupt */
+ reg = <0x1>;
+- led-modes = <0x00 0x08>; /* link/activity link */
+ };
+ };
+
+-&leds {
+- act_led: act {
+- label = "led0";
+- linux,default-trigger = "mmc0";
+- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+- };
+-
+- pwr_led: pwr {
+- label = "led1";
+- linux,default-trigger = "default-on";
+- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+- };
+-};
+-
+-&audio {
++/* uart0 communicates with the BT module */
++&uart0 {
+ pinctrl-names = "default";
+- pinctrl-0 = <&audio_pins>;
+-};
+-
+-&sdhost_gpio48 {
+- brcm,pins = <22 23 24 25 26 27>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+-};
+-
+-&gpio {
+- spi0_pins: spi0_pins {
+- brcm,pins = <9 10 11>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+-
+- spi0_cs_pins: spi0_cs_pins {
+- brcm,pins = <8 7>;
+- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+- };
+-
+- spi3_pins: spi3_pins {
+- brcm,pins = <1 2 3>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- spi3_cs_pins: spi3_cs_pins {
+- brcm,pins = <0 24>;
+- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+- };
+-
+- spi4_pins: spi4_pins {
+- brcm,pins = <5 6 7>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- spi4_cs_pins: spi4_cs_pins {
+- brcm,pins = <4 25>;
+- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+- };
+-
+- spi5_pins: spi5_pins {
+- brcm,pins = <13 14 15>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- spi5_cs_pins: spi5_cs_pins {
+- brcm,pins = <12 26>;
+- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+- };
+-
+- spi6_pins: spi6_pins {
+- brcm,pins = <19 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- spi6_cs_pins: spi6_cs_pins {
+- brcm,pins = <18 27>;
+- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
+- };
+-
+- i2c0_pins: i2c0 {
+- brcm,pins = <0 1>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2c1_pins: i2c1 {
+- brcm,pins = <2 3>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2c3_pins: i2c3 {
+- brcm,pins = <4 5>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2c4_pins: i2c4 {
+- brcm,pins = <8 9>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2c5_pins: i2c5 {
+- brcm,pins = <12 13>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2c6_pins: i2c6 {
+- brcm,pins = <22 23>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- brcm,pull = <BCM2835_PUD_UP>;
+- };
+-
+- i2s_pins: i2s {
+- brcm,pins = <18 19 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+-
+- sdio_pins: sdio_pins {
+- brcm,pins = <34 35 36 37 38 39>;
+- brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
+- brcm,pull = <0 2 2 2 2 2>;
+- };
+-
+- bt_pins: bt_pins {
+- brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
+- // to fool pinctrl
+- brcm,function = <0>;
+- brcm,pull = <2>;
+- };
+-
+- uart0_pins: uart0_pins {
+- brcm,pins = <32 33>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- brcm,pull = <0 2>;
+- };
+-
+- uart1_pins: uart1_pins {
+- brcm,pins;
+- brcm,function;
+- brcm,pull;
+- };
+-
+- uart2_pins: uart2_pins {
+- brcm,pins = <0 1>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <0 2>;
+- };
+-
+- uart3_pins: uart3_pins {
+- brcm,pins = <4 5>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <0 2>;
+- };
+-
+- uart4_pins: uart4_pins {
+- brcm,pins = <8 9>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <0 2>;
+- };
+-
+- uart5_pins: uart5_pins {
+- brcm,pins = <12 13>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <0 2>;
+- };
++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
++ uart-has-rtscts;
++ status = "okay";
+
+- audio_pins: audio_pins {
+- brcm,pins = <40 41>;
+- brcm,function = <4>;
++ bluetooth {
++ compatible = "brcm,bcm43438-bt";
++ max-speed = <2000000>;
++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+-&i2c0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2c0_pins>;
+- clock-frequency = <100000>;
+-};
+-
+-&i2c1 {
++/* uart1 is mapped to the pin header */
++&uart1 {
+ pinctrl-names = "default";
+- pinctrl-0 = <&i2c1_pins>;
+- clock-frequency = <100000>;
+-};
+-
+-&i2c2 {
+- clock-frequency = <100000>;
++ pinctrl-0 = <&uart1_gpio14>;
++ status = "okay";
+ };
+
+-&i2s {
+- pinctrl-names = "default";
+- pinctrl-0 = <&i2s_pins>;
++&vchiq {
++ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ / {
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -1,44 +1,890 @@
+-#include "bcm2838.dtsi"
+-#include "bcm270x.dtsi"
++// SPDX-License-Identifier: GPL-2.0
++#include "bcm283x.dtsi"
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/soc/bcm2835-pm.h>
+
+ / {
++ compatible = "brcm,bcm2711";
++
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ 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;
++ };
++ };
++
++
+ soc {
+- /delete-node/ v3d@7ec00000;
++ /*
++ * Defined ranges:
++ * Common BCM283x peripherals
++ * BCM2711-specific peripherals
++ * ARM-local peripherals
++ */
++ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
++ <0x7c000000 0x0 0xfc000000 0x02000000>,
++ <0x40000000 0x0 0xff800000 0x00800000>;
++ /* Emulate a contiguous 30-bit address range for DMA */
++ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
++
++ /*
++ * This node is the provider for the enable-method for
++ * bringing up secondary cores.
++ */
++ local_intc: local_intc@40000000 {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ };
++
++ gicv2: interrupt-controller@40041000 {
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ compatible = "arm,gic-400";
++ reg = <0x40041000 0x1000>,
++ <0x40042000 0x2000>,
++ <0x40044000 0x2000>,
++ <0x40046000 0x2000>;
++ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_HIGH)>;
++ };
++
++ dma: dma@7e007000 {
++ compatible = "brcm,bcm2835-dma";
++ reg = <0x7e007000 0xb00>;
++ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
++ /* DMA lite 7 - 10 */
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "dma0",
++ "dma1",
++ "dma2",
++ "dma3",
++ "dma4",
++ "dma5",
++ "dma6",
++ "dma7",
++ "dma8",
++ "dma9",
++ "dma10";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x07f5>;
++ };
++
++ pm: watchdog@7e100000 {
++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
++ #power-domain-cells = <1>;
++ #reset-cells = <1>;
++ reg = <0x7e100000 0x114>,
++ <0x7e00a000 0x24>,
++ <0x7ec11000 0x20>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>,
++ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
++ <&clocks BCM2835_CLOCK_H264>,
++ <&clocks BCM2835_CLOCK_ISP>;
++ clock-names = "v3d", "peri_image", "h264", "isp";
++ system-power-controller;
++ };
++
++ rng@7e104000 {
++ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
++
++ /* RNG is incompatible with brcm,bcm2835-rng */
++ status = "disabled";
++ };
++
++ uart2: serial@7e201400 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201400 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart3: serial@7e201600 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201600 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart4: serial@7e201800 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201800 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart5: serial@7e201a00 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201a00 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ spi3: spi@7e204600 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204600 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi4: spi@7e204800 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204800 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi5: spi@7e204a00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204a00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi6: spi@7e204c00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204c00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c3: i2c@7e205600 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205600 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c4: i2c@7e205800 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205800 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c5: i2c@7e205a00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205a00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c6: i2c@7e205c00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205c00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pwm1: pwm@7e20c800 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7e20c800 0x28>;
++ clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clock-rates = <10000000>;
++ #pwm-cells = <2>;
++ status = "disabled";
++ };
++
++ emmc2: emmc2@7e340000 {
++ compatible = "brcm,bcm2711-emmc2";
++ reg = <0x7e340000 0x100>;
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
++ status = "disabled";
++ };
++
++ hvs@7e400000 {
++ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
++ };
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
++ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++ };
++
++ timer {
++ compatible = "arm,armv8-timer";
++ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>;
++ /* This only applies to the ARMv7 stub */
++ arm,cpu-registers-not-fw-configured;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <0>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000d8>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <1>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e0>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <2>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e8>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <3>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000f0>;
++ };
+ };
+
+- __overrides__ {
+- arm_freq;
++ scb {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
++
++ genet: ethernet@7d580000 {
++ compatible = "brcm,bcm2711-genet-v5";
++ reg = <0x0 0x7d580000 0x10000>;
++ #address-cells = <0x1>;
++ #size-cells = <0x1>;
++ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++
++ genet_mdio: mdio@e14 {
++ compatible = "brcm,genet-mdio-v5";
++ reg = <0xe14 0x8>;
++ reg-names = "mdio";
++ #address-cells = <0x0>;
++ #size-cells = <0x1>;
++ };
++ };
+ };
+ };
+
+-&v3d {
+- status = "disabled";
++&clk_osc {
++ clock-frequency = <54000000>;
+ };
+
+-&firmwarekms {
+- interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++&clocks {
++ compatible = "brcm,bcm2711-cprman";
+ };
+
+-&smi {
+- interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++&cpu_thermal {
++ coefficients = <(-487) 410040>;
+ };
+
+-&mmc {
+- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++&dsi0 {
++ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&dsi1 {
++ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&gpio {
++ compatible = "brcm,bcm2711-gpio";
++ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
++
++ gpclk0_gpio49: gpclk0_gpio49 {
++ pin-gpclk {
++ pins = "gpio49";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ gpclk1_gpio50: gpclk1_gpio50 {
++ pin-gpclk {
++ pins = "gpio50";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ gpclk2_gpio51: gpclk2_gpio51 {
++ pin-gpclk {
++ pins = "gpio51";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++
++ i2c0_gpio46: i2c0_gpio46 {
++ pin-sda {
++ function = "alt0";
++ pins = "gpio46";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt0";
++ pins = "gpio47";
++ bias-disable;
++ };
++ };
++ i2c1_gpio46: i2c1_gpio46 {
++ pin-sda {
++ function = "alt1";
++ pins = "gpio46";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt1";
++ pins = "gpio47";
++ bias-disable;
++ };
++ };
++ i2c3_gpio2: i2c3_gpio2 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio2";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio3";
++ bias-disable;
++ };
++ };
++ i2c3_gpio4: i2c3_gpio4 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio4";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio5";
++ bias-disable;
++ };
++ };
++ i2c4_gpio6: i2c4_gpio6 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio6";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio7";
++ bias-disable;
++ };
++ };
++ i2c4_gpio8: i2c4_gpio8 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio8";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio9";
++ bias-disable;
++ };
++ };
++ i2c5_gpio10: i2c5_gpio10 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio10";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio11";
++ bias-disable;
++ };
++ };
++ i2c5_gpio12: i2c5_gpio12 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio12";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio13";
++ bias-disable;
++ };
++ };
++ i2c6_gpio0: i2c6_gpio0 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio0";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio1";
++ bias-disable;
++ };
++ };
++ i2c6_gpio22: i2c6_gpio22 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio22";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio23";
++ bias-disable;
++ };
++ };
++ i2c_slave_gpio8: i2c_slave_gpio8 {
++ pins-i2c-slave {
++ pins = "gpio8",
++ "gpio9",
++ "gpio10",
++ "gpio11";
++ function = "alt3";
++ };
++ };
++
++ jtag_gpio48: jtag_gpio48 {
++ pins-jtag {
++ pins = "gpio48",
++ "gpio49",
++ "gpio50",
++ "gpio51",
++ "gpio52",
++ "gpio53";
++ function = "alt4";
++ };
++ };
++
++ mii_gpio28: mii_gpio28 {
++ pins-mii {
++ pins = "gpio28",
++ "gpio29",
++ "gpio30",
++ "gpio31";
++ function = "alt4";
++ };
++ };
++ mii_gpio36: mii_gpio36 {
++ pins-mii {
++ pins = "gpio36",
++ "gpio37",
++ "gpio38",
++ "gpio39";
++ function = "alt5";
++ };
++ };
++
++ pcm_gpio50: pcm_gpio50 {
++ pins-pcm {
++ pins = "gpio50",
++ "gpio51",
++ "gpio52",
++ "gpio53";
++ function = "alt2";
++ };
++ };
++
++ pwm0_0_gpio12: pwm0_0_gpio12 {
++ pin-pwm {
++ pins = "gpio12";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_0_gpio18: pwm0_0_gpio18 {
++ pin-pwm {
++ pins = "gpio18";
++ function = "alt5";
++ bias-disable;
++ };
++ };
++ pwm1_0_gpio40: pwm1_0_gpio40 {
++ pin-pwm {
++ pins = "gpio40";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio13: pwm0_1_gpio13 {
++ pin-pwm {
++ pins = "gpio13";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio19: pwm0_1_gpio19 {
++ pin-pwm {
++ pins = "gpio19";
++ function = "alt5";
++ bias-disable;
++ };
++ };
++ pwm1_1_gpio41: pwm1_1_gpio41 {
++ pin-pwm {
++ pins = "gpio41";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio45: pwm0_1_gpio45 {
++ pin-pwm {
++ pins = "gpio45";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_0_gpio52: pwm0_0_gpio52 {
++ pin-pwm {
++ pins = "gpio52";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio53: pwm0_1_gpio53 {
++ pin-pwm {
++ pins = "gpio53";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++
++ rgmii_gpio35: rgmii_gpio35 {
++ pin-start-stop {
++ pins = "gpio35";
++ function = "alt4";
++ };
++ pin-rx-ok {
++ pins = "gpio36";
++ function = "alt4";
++ };
++ };
++ rgmii_irq_gpio34: rgmii_irq_gpio34 {
++ pin-irq {
++ pins = "gpio34";
++ function = "alt5";
++ };
++ };
++ rgmii_irq_gpio39: rgmii_irq_gpio39 {
++ pin-irq {
++ pins = "gpio39";
++ function = "alt4";
++ };
++ };
++ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
++ pins-mdio {
++ pins = "gpio28",
++ "gpio29";
++ function = "alt5";
++ };
++ };
++ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
++ pins-mdio {
++ pins = "gpio37",
++ "gpio38";
++ function = "alt4";
++ };
++ };
++
++ spi0_gpio46: spi0_gpio46 {
++ pins-spi {
++ pins = "gpio46",
++ "gpio47",
++ "gpio48",
++ "gpio49";
++ function = "alt2";
++ };
++ };
++ spi2_gpio46: spi2_gpio46 {
++ pins-spi {
++ pins = "gpio46",
++ "gpio47",
++ "gpio48",
++ "gpio49",
++ "gpio50";
++ function = "alt5";
++ };
++ };
++ spi3_gpio0: spi3_gpio0 {
++ pins-spi {
++ pins = "gpio0",
++ "gpio1",
++ "gpio2",
++ "gpio3";
++ function = "alt3";
++ };
++ };
++ spi4_gpio4: spi4_gpio4 {
++ pins-spi {
++ pins = "gpio4",
++ "gpio5",
++ "gpio6",
++ "gpio7";
++ function = "alt3";
++ };
++ };
++ spi5_gpio12: spi5_gpio12 {
++ pins-spi {
++ pins = "gpio12",
++ "gpio13",
++ "gpio14",
++ "gpio15";
++ function = "alt3";
++ };
++ };
++ spi6_gpio18: spi6_gpio18 {
++ pins-spi {
++ pins = "gpio18",
++ "gpio19",
++ "gpio20",
++ "gpio21";
++ function = "alt3";
++ };
++ };
++
++ uart2_gpio0: uart2_gpio0 {
++ pin-tx {
++ pins = "gpio0";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio1";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
++ pin-cts {
++ pins = "gpio2";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio3";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart3_gpio4: uart3_gpio4 {
++ pin-tx {
++ pins = "gpio4";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio5";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
++ pin-cts {
++ pins = "gpio6";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio7";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart4_gpio8: uart4_gpio8 {
++ pin-tx {
++ pins = "gpio8";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio9";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
++ pin-cts {
++ pins = "gpio10";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio11";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart5_gpio12: uart5_gpio12 {
++ pin-tx {
++ pins = "gpio12";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio13";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
++ pin-cts {
++ pins = "gpio14";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio15";
++ function = "alt4";
++ bias-disable;
++ };
++ };
+ };
+
+-&mmcnr {
++&i2c0 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&i2c1 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mailbox {
++ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&sdhci {
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
++&sdhost {
++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi {
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi2 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&system_timer {
++ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&txp {
++ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart0 {
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
+ &usb {
+- reg = <0x7e980000 0x10000>,
+- <0x7e00b200 0x200>;
+- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+-&gpio {
+- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
++&vec {
++ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ };
+--- a/arch/arm/boot/dts/bcm2835-common.dtsi
++++ b/arch/arm/boot/dts/bcm2835-common.dtsi
+@@ -8,6 +8,47 @@
+ interrupt-parent = <&intc>;
+
+ soc {
++ dma: dma@7e007000 {
++ compatible = "brcm,bcm2835-dma";
++ reg = <0x7e007000 0xf00>;
++ interrupts = <1 16>,
++ <1 17>,
++ <1 18>,
++ <1 19>,
++ <1 20>,
++ <1 21>,
++ <1 22>,
++ <1 23>,
++ <1 24>,
++ <1 25>,
++ <1 26>,
++ /* dma channel 11-14 share one irq */
++ <1 27>,
++ <1 27>,
++ <1 27>,
++ <1 27>,
++ /* unused shared irq for all channels */
++ <1 28>;
++ interrupt-names = "dma0",
++ "dma1",
++ "dma2",
++ "dma3",
++ "dma4",
++ "dma5",
++ "dma6",
++ "dma7",
++ "dma8",
++ "dma9",
++ "dma10",
++ "dma11",
++ "dma12",
++ "dma13",
++ "dma14",
++ "dma-shared-all";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x7f35>;
++ };
++
+ intc: interrupt-controller@7e00b200 {
+ compatible = "brcm,bcm2835-armctrl-ic";
+ reg = <0x7e00b200 0x200>;
+@@ -15,6 +56,20 @@
+ #interrupt-cells = <2>;
+ };
+
++ pm: watchdog@7e100000 {
++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
++ #power-domain-cells = <1>;
++ #reset-cells = <1>;
++ reg = <0x7e100000 0x114>,
++ <0x7e00a000 0x24>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>,
++ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
++ <&clocks BCM2835_CLOCK_H264>,
++ <&clocks BCM2835_CLOCK_ISP>;
++ clock-names = "v3d", "peri_image", "h264", "isp";
++ system-power-controller;
++ };
++
+ pixelvalve@7e206000 {
+ compatible = "brcm,bcm2835-pixelvalve0";
+ reg = <0x7e206000 0x100>;
+@@ -35,21 +90,53 @@
+ status = "disabled";
+ };
+
++ i2c2: i2c@7e805000 {
++ compatible = "brcm,bcm2835-i2c";
++ reg = <0x7e805000 0x1000>;
++ interrupts = <2 21>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++ };
++
+ pixelvalve@7e807000 {
+ compatible = "brcm,bcm2835-pixelvalve2";
+ reg = <0x7e807000 0x100>;
+ interrupts = <2 10>; /* pixelvalve */
+ };
+
++ hdmi: hdmi@7e902000 {
++ compatible = "brcm,bcm2835-hdmi";
++ reg = <0x7e902000 0x600>,
++ <0x7e808000 0x100>;
++ interrupts = <2 8>, <2 9>;
++ ddc = <&i2c2>;
++ clocks = <&clocks BCM2835_PLLH_PIX>,
++ <&clocks BCM2835_CLOCK_HSM>;
++ clock-names = "pixel", "hdmi";
++ dmas = <&dma 17>;
++ dma-names = "audio-rx";
++ status = "disabled";
++ };
++
+ v3d: v3d@7ec00000 {
+ compatible = "brcm,bcm2835-v3d";
+ reg = <0x7ec00000 0x1000>;
+ interrupts = <1 10>;
+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+ };
++
++ vc4: gpu {
++ compatible = "brcm,bcm2835-vc4";
++ };
+ };
+ };
+
++&cpu_thermal {
++ thermal-sensors = <&thermal>;
++};
++
+ &gpio {
+ i2c_slave_gpio18: i2c_slave_gpio18 {
+ brcm,pins = <18 19 20 21>;
+@@ -60,4 +147,48 @@
+ brcm,pins = <4 5 6 12 13>;
+ brcm,function = <BCM2835_FSEL_ALT5>;
+ };
++
++ pwm0_gpio12: pwm0_gpio12 {
++ brcm,pins = <12>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++ pwm0_gpio18: pwm0_gpio18 {
++ brcm,pins = <18>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ pwm0_gpio40: pwm0_gpio40 {
++ brcm,pins = <40>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++ pwm1_gpio13: pwm1_gpio13 {
++ brcm,pins = <13>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++ pwm1_gpio19: pwm1_gpio19 {
++ brcm,pins = <19>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ };
++ pwm1_gpio41: pwm1_gpio41 {
++ brcm,pins = <41>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++ pwm1_gpio45: pwm1_gpio45 {
++ brcm,pins = <45>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++};
++
++&i2s {
++ dmas = <&dma 2>, <&dma 3>;
++ dma-names = "tx", "rx";
++};
++
++&sdhost {
++ dmas = <&dma 13>;
++ dma-names = "rx-tx";
++};
++
++&spi {
++ dmas = <&dma 6>, <&dma 7>;
++ dma-names = "tx", "rx";
+ };
+--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
+@@ -3,7 +3,6 @@
+ #include "bcm2835.dtsi"
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
+@@ -3,7 +3,6 @@
+ #include "bcm2835.dtsi"
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-a", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+@@ -4,7 +4,6 @@
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
+@@ -4,7 +4,6 @@
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9512.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
+@@ -4,7 +4,6 @@
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9512.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-b", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
++++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
+@@ -7,7 +7,6 @@
+ #include "bcm2835.dtsi"
+ #include "bcm2835-rpi.dtsi"
+ #include "bcm283x-rpi-usb-otg.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,model-zero", "brcm,bcm2835";
+--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
+@@ -29,22 +29,6 @@
+ interrupts = <0 2>;
+ };
+ };
+-
+- vdd_3v3_reg: fixedregulator_3v3 {
+- compatible = "regulator-fixed";
+- regulator-name = "3v3";
+- regulator-min-microvolt = <3300000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-always-on;
+- };
+-
+- vdd_5v0_reg: fixedregulator_5v0 {
+- compatible = "regulator-fixed";
+- regulator-name = "5v0";
+- regulator-min-microvolt = <5000000>;
+- regulator-max-microvolt = <5000000>;
+- regulator-always-on;
+- };
+ };
+
+ &gpio {
+@@ -75,23 +59,10 @@
+ clock-frequency = <100000>;
+ };
+
+-&i2c2 {
+- status = "okay";
+-};
+-
+ &usb {
+ power-domains = <&power RPI_POWER_DOMAIN_USB>;
+ };
+
+-&hdmi {
+- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+- status = "okay";
+-};
+-
+-&v3d {
+- power-domains = <&power RPI_POWER_DOMAIN_V3D>;
+-};
+-
+ &vec {
+ power-domains = <&power RPI_POWER_DOMAIN_VEC>;
+ status = "okay";
+@@ -104,11 +75,3 @@
+ &dsi1 {
+ power-domains = <&power RPI_POWER_DOMAIN_DSI1>;
+ };
+-
+-&csi0 {
+- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
+-};
+-
+-&csi1 {
+- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
+-};
+--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
+@@ -4,7 +4,6 @@
+ #include "bcm2836-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
+--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
+@@ -4,7 +4,6 @@
+ #include "bcm2836-rpi.dtsi"
+ #include "bcm283x-rpi-smsc9514.dtsi"
+ #include "bcm283x-rpi-usb-host.dtsi"
+-#include "bcm283x-rpi-csi1-2lane.dtsi"
+
+ / {
+ compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
+--- a/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
++++ b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
+@@ -29,9 +29,6 @@
+ #size-cells = <0x0>;
+ eth_phy: ethernet-phy@1 {
+ reg = <1>;
+- microchip,eee-enabled;
+- microchip,tx-lpi-timer = <600>; /* non-aggressive*/
+- microchip,downshift-after = <2>;
+ microchip,led-modes = <
+ LAN78XX_LINK_1000_ACTIVITY
+ LAN78XX_LINK_10_100_ACTIVITY
+@@ -42,15 +39,3 @@
+ };
+ };
+ };
+-
+-
+-/ {
+- __overrides__ {
+- eee = <ð_phy>,"microchip,eee-enabled?";
+- tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0";
+- eth_led0 = <ð_phy>,"microchip,led-modes:0";
+- eth_led1 = <ð_phy>,"microchip,led-modes:4";
+- eth_downshift_after = <ð_phy>,"microchip,downshift-after:0";
+- eth_max_speed = <ð_phy>,"max-speed:0";
+- };
+-};
+--- a/arch/arm/boot/dts/bcm283x.dtsi
++++ b/arch/arm/boot/dts/bcm283x.dtsi
+@@ -35,8 +35,6 @@
+ polling-delay-passive = <0>;
+ polling-delay = <1000>;
+
+- thermal-sensors = <&thermal>;
+-
+ trips {
+ cpu-crit {
+ temperature = <90000>;
+@@ -72,61 +70,6 @@
+ interrupts = <1 11>;
+ };
+
+- dma: dma@7e007000 {
+- compatible = "brcm,bcm2835-dma";
+- reg = <0x7e007000 0xf00>;
+- interrupts = <1 16>,
+- <1 17>,
+- <1 18>,
+- <1 19>,
+- <1 20>,
+- <1 21>,
+- <1 22>,
+- <1 23>,
+- <1 24>,
+- <1 25>,
+- <1 26>,
+- /* dma channel 11-14 share one irq */
+- <1 27>,
+- <1 27>,
+- <1 27>,
+- <1 27>,
+- /* unused shared irq for all channels */
+- <1 28>;
+- interrupt-names = "dma0",
+- "dma1",
+- "dma2",
+- "dma3",
+- "dma4",
+- "dma5",
+- "dma6",
+- "dma7",
+- "dma8",
+- "dma9",
+- "dma10",
+- "dma11",
+- "dma12",
+- "dma13",
+- "dma14",
+- "dma-shared-all";
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x7f35>;
+- };
+-
+- pm: watchdog@7e100000 {
+- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+- #power-domain-cells = <1>;
+- #reset-cells = <1>;
+- reg = <0x7e100000 0x114>,
+- <0x7e00a000 0x24>;
+- clocks = <&clocks BCM2835_CLOCK_V3D>,
+- <&clocks BCM2835_CLOCK_PERI_IMAGE>,
+- <&clocks BCM2835_CLOCK_H264>,
+- <&clocks BCM2835_CLOCK_ISP>;
+- clock-names = "v3d", "peri_image", "h264", "isp";
+- system-power-controller;
+- };
+-
+ clocks: cprman@7e101000 {
+ compatible = "brcm,bcm2835-cprman";
+ #clock-cells = <1>;
+@@ -141,7 +84,7 @@
+ <&dsi1 0>, <&dsi1 1>, <&dsi1 2>;
+ };
+
+- rng: rng@7e104000 {
++ rng@7e104000 {
+ compatible = "brcm,bcm2835-rng";
+ reg = <0x7e104000 0x10>;
+ interrupts = <2 29>;
+@@ -269,35 +212,6 @@
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+
+- pwm0_gpio12: pwm0_gpio12 {
+- brcm,pins = <12>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+- pwm0_gpio18: pwm0_gpio18 {
+- brcm,pins = <18>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- pwm0_gpio40: pwm0_gpio40 {
+- brcm,pins = <40>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+- pwm1_gpio13: pwm1_gpio13 {
+- brcm,pins = <13>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+- pwm1_gpio19: pwm1_gpio19 {
+- brcm,pins = <19>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- pwm1_gpio41: pwm1_gpio41 {
+- brcm,pins = <41>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+- pwm1_gpio45: pwm1_gpio45 {
+- brcm,pins = <45>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+-
+ sdhost_gpio48: sdhost_gpio48 {
+ brcm,pins = <48 49 50 51 52 53>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
+@@ -379,7 +293,7 @@
+ };
+
+ uart0: serial@7e201000 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
++ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x7e201000 0x200>;
+ interrupts = <2 25>;
+ clocks = <&clocks BCM2835_CLOCK_UART>,
+@@ -393,8 +307,6 @@
+ reg = <0x7e202000 0x100>;
+ interrupts = <2 24>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+- dmas = <&dma (13|(1<<29))>;
+- dma-names = "rx-tx";
+ status = "disabled";
+ };
+
+@@ -402,10 +314,6 @@
+ compatible = "brcm,bcm2835-i2s";
+ reg = <0x7e203000 0x24>;
+ clocks = <&clocks BCM2835_CLOCK_PCM>;
+-
+- dmas = <&dma 2>,
+- <&dma 3>;
+- dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+@@ -414,8 +322,6 @@
+ reg = <0x7e204000 0x200>;
+ interrupts = <2 22>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+- dmas = <&dma 6>, <&dma 7>;
+- dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+@@ -540,32 +446,6 @@
+ status = "disabled";
+ };
+
+- csi0: csi@7e800000 {
+- compatible = "brcm,bcm2835-unicam";
+- reg = <0x7e800000 0x800>,
+- <0x7e802000 0x4>;
+- interrupts = <2 6>;
+- clocks = <&clocks BCM2835_CLOCK_CAM0>;
+- clock-names = "lp";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- #clock-cells = <1>;
+- status = "disabled";
+- };
+-
+- csi1: csi@7e801000 {
+- compatible = "brcm,bcm2835-unicam";
+- reg = <0x7e801000 0x800>,
+- <0x7e802004 0x4>;
+- interrupts = <2 7>;
+- clocks = <&clocks BCM2835_CLOCK_CAM1>;
+- clock-names = "lp";
+- #address-cells = <1>;
+- #size-cells = <0>;
+- #clock-cells = <1>;
+- status = "disabled";
+- };
+-
+ i2c1: i2c@7e804000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e804000 0x1000>;
+@@ -576,16 +456,6 @@
+ status = "disabled";
+ };
+
+- i2c2: i2c@7e805000 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e805000 0x1000>;
+- interrupts = <2 21>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+ vec: vec@7e806000 {
+ compatible = "brcm,bcm2835-vec";
+ reg = <0x7e806000 0x1000>;
+@@ -594,20 +464,6 @@
+ status = "disabled";
+ };
+
+- hdmi: hdmi@7e902000 {
+- compatible = "brcm,bcm2835-hdmi";
+- reg = <0x7e902000 0x600>,
+- <0x7e808000 0x100>;
+- interrupts = <2 8>, <2 9>;
+- ddc = <&i2c2>;
+- clocks = <&clocks BCM2835_PLLH_PIX>,
+- <&clocks BCM2835_CLOCK_HSM>;
+- clock-names = "pixel", "hdmi";
+- dmas = <&dma 17>;
+- dma-names = "audio-rx";
+- status = "disabled";
+- };
+-
+ usb: usb@7e980000 {
+ compatible = "brcm,bcm2835-usb";
+ reg = <0x7e980000 0x10000>;
+@@ -619,10 +475,6 @@
+ phys = <&usbphy>;
+ phy-names = "usb2-phy";
+ };
+-
+- vc4: gpu {
+- compatible = "brcm,bcm2835-vc4";
+- };
+ };
+
+ clocks {
--- /dev/null
+From 134e06abd2d002edfdac3561656ab9e8161b29a3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 31 Jan 2020 16:53:13 +0000
+Subject: [PATCH] ARM: dts: Clean out downstream BCM2711/2838 files
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 157 -----
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 -
+ arch/arm/boot/dts/bcm2711.dtsi | 890 --------------------------
+ arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 -
+ arch/arm/boot/dts/bcm2838.dtsi | 733 ---------------------
+ 5 files changed, 1812 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+ delete mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
+ delete mode 100644 arch/arm/boot/dts/bcm2711.dtsi
+ delete mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi
+ delete mode 100644 arch/arm/boot/dts/bcm2838.dtsi
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ /dev/null
+@@ -1,157 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-#include "bcm2711.dtsi"
+-#include "bcm2835-rpi.dtsi"
+-#include "bcm283x-rpi-usb-peripheral.dtsi"
+-
+-/ {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+- model = "Raspberry Pi 4 Model B";
+-
+- chosen {
+- /* 8250 auxiliary UART instead of pl011 */
+- stdout-path = "serial1:115200n8";
+- };
+-
+- /* Will be filled by the bootloader */
+- memory@0 {
+- device_type = "memory";
+- reg = <0 0 0>;
+- };
+-
+- aliases {
+- ethernet0 = &genet;
+- };
+-
+- leds {
+- act {
+- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+- };
+-
+- pwr {
+- label = "PWR";
+- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+- };
+- };
+-
+- wifi_pwrseq: wifi-pwrseq {
+- compatible = "mmc-pwrseq-simple";
+- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- compatible = "regulator-gpio";
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- status = "okay";
+- };
+-};
+-
+-&firmware {
+- expgpio: gpio {
+- compatible = "raspberrypi,firmware-gpio";
+- gpio-controller;
+- #gpio-cells = <2>;
+- gpio-line-names = "BT_ON",
+- "WL_ON",
+- "PWR_LED_OFF",
+- "GLOBAL_RESET",
+- "VDD_SD_IO_SEL",
+- "CAM_GPIO",
+- "",
+- "";
+- status = "okay";
+- };
+-};
+-
+-&pwm1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
+- status = "okay";
+-};
+-
+-/* SDHCI is used to control the SDIO for wireless */
+-&sdhci {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio34>;
+- bus-width = <4>;
+- non-removable;
+- mmc-pwrseq = <&wifi_pwrseq>;
+- status = "okay";
+-
+- brcmf: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- };
+-};
+-
+-/* EMMC2 is used to drive the SD card */
+-&emmc2 {
+- vqmmc-supply = <&sd_io_1v8_reg>;
+- broken-cd;
+- status = "okay";
+-};
+-
+-&genet {
+- phy-handle = <&phy1>;
+- phy-mode = "rgmii-rxid";
+- status = "okay";
+-};
+-
+-&genet_mdio {
+- phy1: ethernet-phy@1 {
+- /* No PHY interrupt */
+- reg = <0x1>;
+- };
+-};
+-
+-/* uart0 communicates with the BT module */
+-&uart0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
+- uart-has-rtscts;
+- status = "okay";
+-
+- bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <2000000>;
+- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+- };
+-};
+-
+-/* uart1 is mapped to the pin header */
+-&uart1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart1_gpio14>;
+- status = "okay";
+-};
+-
+-&vchiq {
+- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-/ {
+- __overrides__ {
+- act_led_gpio = <&act_led>,"gpios:4";
+- act_led_activelow = <&act_led>,"gpios:8";
+- act_led_trigger = <&act_led>,"linux,default-trigger";
+-
+- pwr_led_gpio = <&pwr_led>,"gpios:4";
+- pwr_led_activelow = <&pwr_led>,"gpios:8";
+- pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
+-
+- eth_led0 = <&phy1>,"led-modes:0";
+- eth_led1 = <&phy1>,"led-modes:4";
+-
+- sd_poll_once = <&emmc2>, "non-removable?";
+- };
+-};
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ /dev/null
+@@ -1,7 +0,0 @@
+-#include "bcm2708-rpi.dtsi"
+-#include "bcm2838-rpi.dtsi"
+-
+-&v3d {
+- /* Undo the overwriting by bcm270x.dtsi */
+- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+-};
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ /dev/null
+@@ -1,890 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include "bcm283x.dtsi"
+-
+-#include <dt-bindings/interrupt-controller/arm-gic.h>
+-#include <dt-bindings/soc/bcm2835-pm.h>
+-
+-/ {
+- compatible = "brcm,bcm2711";
+-
+- #address-cells = <2>;
+- #size-cells = <1>;
+-
+- 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;
+- };
+- };
+-
+-
+- soc {
+- /*
+- * Defined ranges:
+- * Common BCM283x peripherals
+- * BCM2711-specific peripherals
+- * ARM-local peripherals
+- */
+- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
+- <0x7c000000 0x0 0xfc000000 0x02000000>,
+- <0x40000000 0x0 0xff800000 0x00800000>;
+- /* Emulate a contiguous 30-bit address range for DMA */
+- dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
+-
+- /*
+- * This node is the provider for the enable-method for
+- * bringing up secondary cores.
+- */
+- local_intc: local_intc@40000000 {
+- compatible = "brcm,bcm2836-l1-intc";
+- reg = <0x40000000 0x100>;
+- };
+-
+- gicv2: interrupt-controller@40041000 {
+- interrupt-controller;
+- #interrupt-cells = <3>;
+- compatible = "arm,gic-400";
+- reg = <0x40041000 0x1000>,
+- <0x40042000 0x2000>,
+- <0x40044000 0x2000>,
+- <0x40046000 0x2000>;
+- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_HIGH)>;
+- };
+-
+- dma: dma@7e007000 {
+- compatible = "brcm,bcm2835-dma";
+- reg = <0x7e007000 0xb00>;
+- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+- /* DMA lite 7 - 10 */
+- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "dma0",
+- "dma1",
+- "dma2",
+- "dma3",
+- "dma4",
+- "dma5",
+- "dma6",
+- "dma7",
+- "dma8",
+- "dma9",
+- "dma10";
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x07f5>;
+- };
+-
+- pm: watchdog@7e100000 {
+- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
+- #power-domain-cells = <1>;
+- #reset-cells = <1>;
+- reg = <0x7e100000 0x114>,
+- <0x7e00a000 0x24>,
+- <0x7ec11000 0x20>;
+- clocks = <&clocks BCM2835_CLOCK_V3D>,
+- <&clocks BCM2835_CLOCK_PERI_IMAGE>,
+- <&clocks BCM2835_CLOCK_H264>,
+- <&clocks BCM2835_CLOCK_ISP>;
+- clock-names = "v3d", "peri_image", "h264", "isp";
+- system-power-controller;
+- };
+-
+- rng@7e104000 {
+- interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+-
+- /* RNG is incompatible with brcm,bcm2835-rng */
+- status = "disabled";
+- };
+-
+- uart2: serial@7e201400 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7e201400 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart3: serial@7e201600 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7e201600 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart4: serial@7e201800 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7e201800 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart5: serial@7e201a00 {
+- compatible = "arm,pl011", "arm,primecell";
+- reg = <0x7e201a00 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- spi3: spi@7e204600 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204600 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi4: spi@7e204800 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204800 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi5: spi@7e204a00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204a00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi6: spi@7e204c00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204c00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c3: i2c@7e205600 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7e205600 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c4: i2c@7e205800 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7e205800 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c5: i2c@7e205a00 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7e205a00 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c6: i2c@7e205c00 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- reg = <0x7e205c00 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- pwm1: pwm@7e20c800 {
+- compatible = "brcm,bcm2835-pwm";
+- reg = <0x7e20c800 0x28>;
+- clocks = <&clocks BCM2835_CLOCK_PWM>;
+- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
+- assigned-clock-rates = <10000000>;
+- #pwm-cells = <2>;
+- status = "disabled";
+- };
+-
+- emmc2: emmc2@7e340000 {
+- compatible = "brcm,bcm2711-emmc2";
+- reg = <0x7e340000 0x100>;
+- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2711_CLOCK_EMMC2>;
+- status = "disabled";
+- };
+-
+- hvs@7e400000 {
+- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+- };
+- };
+-
+- arm-pmu {
+- compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
+- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+- };
+-
+- timer {
+- compatible = "arm,armv8-timer";
+- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>;
+- /* This only applies to the ARMv7 stub */
+- arm,cpu-registers-not-fw-configured;
+- };
+-
+- cpus: cpus {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
+-
+- cpu0: cpu@0 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <0>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000d8>;
+- };
+-
+- cpu1: cpu@1 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <1>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000e0>;
+- };
+-
+- cpu2: cpu@2 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <2>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000e8>;
+- };
+-
+- cpu3: cpu@3 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <3>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000f0>;
+- };
+- };
+-
+- scb {
+- compatible = "simple-bus";
+- #address-cells = <2>;
+- #size-cells = <1>;
+-
+- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
+-
+- genet: ethernet@7d580000 {
+- compatible = "brcm,bcm2711-genet-v5";
+- reg = <0x0 0x7d580000 0x10000>;
+- #address-cells = <0x1>;
+- #size-cells = <0x1>;
+- interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+-
+- genet_mdio: mdio@e14 {
+- compatible = "brcm,genet-mdio-v5";
+- reg = <0xe14 0x8>;
+- reg-names = "mdio";
+- #address-cells = <0x0>;
+- #size-cells = <0x1>;
+- };
+- };
+- };
+-};
+-
+-&clk_osc {
+- clock-frequency = <54000000>;
+-};
+-
+-&clocks {
+- compatible = "brcm,bcm2711-cprman";
+-};
+-
+-&cpu_thermal {
+- coefficients = <(-487) 410040>;
+-};
+-
+-&dsi0 {
+- interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&dsi1 {
+- interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&gpio {
+- compatible = "brcm,bcm2711-gpio";
+- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+-
+- gpclk0_gpio49: gpclk0_gpio49 {
+- pin-gpclk {
+- pins = "gpio49";
+- function = "alt1";
+- bias-disable;
+- };
+- };
+- gpclk1_gpio50: gpclk1_gpio50 {
+- pin-gpclk {
+- pins = "gpio50";
+- function = "alt1";
+- bias-disable;
+- };
+- };
+- gpclk2_gpio51: gpclk2_gpio51 {
+- pin-gpclk {
+- pins = "gpio51";
+- function = "alt1";
+- bias-disable;
+- };
+- };
+-
+- i2c0_gpio46: i2c0_gpio46 {
+- pin-sda {
+- function = "alt0";
+- pins = "gpio46";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt0";
+- pins = "gpio47";
+- bias-disable;
+- };
+- };
+- i2c1_gpio46: i2c1_gpio46 {
+- pin-sda {
+- function = "alt1";
+- pins = "gpio46";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt1";
+- pins = "gpio47";
+- bias-disable;
+- };
+- };
+- i2c3_gpio2: i2c3_gpio2 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio2";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio3";
+- bias-disable;
+- };
+- };
+- i2c3_gpio4: i2c3_gpio4 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio4";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio5";
+- bias-disable;
+- };
+- };
+- i2c4_gpio6: i2c4_gpio6 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio6";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio7";
+- bias-disable;
+- };
+- };
+- i2c4_gpio8: i2c4_gpio8 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio8";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio9";
+- bias-disable;
+- };
+- };
+- i2c5_gpio10: i2c5_gpio10 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio10";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio11";
+- bias-disable;
+- };
+- };
+- i2c5_gpio12: i2c5_gpio12 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio12";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio13";
+- bias-disable;
+- };
+- };
+- i2c6_gpio0: i2c6_gpio0 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio0";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio1";
+- bias-disable;
+- };
+- };
+- i2c6_gpio22: i2c6_gpio22 {
+- pin-sda {
+- function = "alt5";
+- pins = "gpio22";
+- bias-pull-up;
+- };
+- pin-scl {
+- function = "alt5";
+- pins = "gpio23";
+- bias-disable;
+- };
+- };
+- i2c_slave_gpio8: i2c_slave_gpio8 {
+- pins-i2c-slave {
+- pins = "gpio8",
+- "gpio9",
+- "gpio10",
+- "gpio11";
+- function = "alt3";
+- };
+- };
+-
+- jtag_gpio48: jtag_gpio48 {
+- pins-jtag {
+- pins = "gpio48",
+- "gpio49",
+- "gpio50",
+- "gpio51",
+- "gpio52",
+- "gpio53";
+- function = "alt4";
+- };
+- };
+-
+- mii_gpio28: mii_gpio28 {
+- pins-mii {
+- pins = "gpio28",
+- "gpio29",
+- "gpio30",
+- "gpio31";
+- function = "alt4";
+- };
+- };
+- mii_gpio36: mii_gpio36 {
+- pins-mii {
+- pins = "gpio36",
+- "gpio37",
+- "gpio38",
+- "gpio39";
+- function = "alt5";
+- };
+- };
+-
+- pcm_gpio50: pcm_gpio50 {
+- pins-pcm {
+- pins = "gpio50",
+- "gpio51",
+- "gpio52",
+- "gpio53";
+- function = "alt2";
+- };
+- };
+-
+- pwm0_0_gpio12: pwm0_0_gpio12 {
+- pin-pwm {
+- pins = "gpio12";
+- function = "alt0";
+- bias-disable;
+- };
+- };
+- pwm0_0_gpio18: pwm0_0_gpio18 {
+- pin-pwm {
+- pins = "gpio18";
+- function = "alt5";
+- bias-disable;
+- };
+- };
+- pwm1_0_gpio40: pwm1_0_gpio40 {
+- pin-pwm {
+- pins = "gpio40";
+- function = "alt0";
+- bias-disable;
+- };
+- };
+- pwm0_1_gpio13: pwm0_1_gpio13 {
+- pin-pwm {
+- pins = "gpio13";
+- function = "alt0";
+- bias-disable;
+- };
+- };
+- pwm0_1_gpio19: pwm0_1_gpio19 {
+- pin-pwm {
+- pins = "gpio19";
+- function = "alt5";
+- bias-disable;
+- };
+- };
+- pwm1_1_gpio41: pwm1_1_gpio41 {
+- pin-pwm {
+- pins = "gpio41";
+- function = "alt0";
+- bias-disable;
+- };
+- };
+- pwm0_1_gpio45: pwm0_1_gpio45 {
+- pin-pwm {
+- pins = "gpio45";
+- function = "alt0";
+- bias-disable;
+- };
+- };
+- pwm0_0_gpio52: pwm0_0_gpio52 {
+- pin-pwm {
+- pins = "gpio52";
+- function = "alt1";
+- bias-disable;
+- };
+- };
+- pwm0_1_gpio53: pwm0_1_gpio53 {
+- pin-pwm {
+- pins = "gpio53";
+- function = "alt1";
+- bias-disable;
+- };
+- };
+-
+- rgmii_gpio35: rgmii_gpio35 {
+- pin-start-stop {
+- pins = "gpio35";
+- function = "alt4";
+- };
+- pin-rx-ok {
+- pins = "gpio36";
+- function = "alt4";
+- };
+- };
+- rgmii_irq_gpio34: rgmii_irq_gpio34 {
+- pin-irq {
+- pins = "gpio34";
+- function = "alt5";
+- };
+- };
+- rgmii_irq_gpio39: rgmii_irq_gpio39 {
+- pin-irq {
+- pins = "gpio39";
+- function = "alt4";
+- };
+- };
+- rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
+- pins-mdio {
+- pins = "gpio28",
+- "gpio29";
+- function = "alt5";
+- };
+- };
+- rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
+- pins-mdio {
+- pins = "gpio37",
+- "gpio38";
+- function = "alt4";
+- };
+- };
+-
+- spi0_gpio46: spi0_gpio46 {
+- pins-spi {
+- pins = "gpio46",
+- "gpio47",
+- "gpio48",
+- "gpio49";
+- function = "alt2";
+- };
+- };
+- spi2_gpio46: spi2_gpio46 {
+- pins-spi {
+- pins = "gpio46",
+- "gpio47",
+- "gpio48",
+- "gpio49",
+- "gpio50";
+- function = "alt5";
+- };
+- };
+- spi3_gpio0: spi3_gpio0 {
+- pins-spi {
+- pins = "gpio0",
+- "gpio1",
+- "gpio2",
+- "gpio3";
+- function = "alt3";
+- };
+- };
+- spi4_gpio4: spi4_gpio4 {
+- pins-spi {
+- pins = "gpio4",
+- "gpio5",
+- "gpio6",
+- "gpio7";
+- function = "alt3";
+- };
+- };
+- spi5_gpio12: spi5_gpio12 {
+- pins-spi {
+- pins = "gpio12",
+- "gpio13",
+- "gpio14",
+- "gpio15";
+- function = "alt3";
+- };
+- };
+- spi6_gpio18: spi6_gpio18 {
+- pins-spi {
+- pins = "gpio18",
+- "gpio19",
+- "gpio20",
+- "gpio21";
+- function = "alt3";
+- };
+- };
+-
+- uart2_gpio0: uart2_gpio0 {
+- pin-tx {
+- pins = "gpio0";
+- function = "alt4";
+- bias-disable;
+- };
+- pin-rx {
+- pins = "gpio1";
+- function = "alt4";
+- bias-pull-up;
+- };
+- };
+- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
+- pin-cts {
+- pins = "gpio2";
+- function = "alt4";
+- bias-pull-up;
+- };
+- pin-rts {
+- pins = "gpio3";
+- function = "alt4";
+- bias-disable;
+- };
+- };
+- uart3_gpio4: uart3_gpio4 {
+- pin-tx {
+- pins = "gpio4";
+- function = "alt4";
+- bias-disable;
+- };
+- pin-rx {
+- pins = "gpio5";
+- function = "alt4";
+- bias-pull-up;
+- };
+- };
+- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
+- pin-cts {
+- pins = "gpio6";
+- function = "alt4";
+- bias-pull-up;
+- };
+- pin-rts {
+- pins = "gpio7";
+- function = "alt4";
+- bias-disable;
+- };
+- };
+- uart4_gpio8: uart4_gpio8 {
+- pin-tx {
+- pins = "gpio8";
+- function = "alt4";
+- bias-disable;
+- };
+- pin-rx {
+- pins = "gpio9";
+- function = "alt4";
+- bias-pull-up;
+- };
+- };
+- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
+- pin-cts {
+- pins = "gpio10";
+- function = "alt4";
+- bias-pull-up;
+- };
+- pin-rts {
+- pins = "gpio11";
+- function = "alt4";
+- bias-disable;
+- };
+- };
+- uart5_gpio12: uart5_gpio12 {
+- pin-tx {
+- pins = "gpio12";
+- function = "alt4";
+- bias-disable;
+- };
+- pin-rx {
+- pins = "gpio13";
+- function = "alt4";
+- bias-pull-up;
+- };
+- };
+- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
+- pin-cts {
+- pins = "gpio14";
+- function = "alt4";
+- bias-pull-up;
+- };
+- pin-rts {
+- pins = "gpio15";
+- function = "alt4";
+- bias-disable;
+- };
+- };
+-};
+-
+-&i2c0 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&i2c1 {
+- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&mailbox {
+- interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&sdhci {
+- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&sdhost {
+- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi {
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi1 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi2 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&system_timer {
+- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&txp {
+- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&uart0 {
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&uart1 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&usb {
+- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&vec {
+- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+-};
+--- a/arch/arm/boot/dts/bcm2838-rpi.dtsi
++++ /dev/null
+@@ -1,25 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-
+-/ {
+- soc {
+- /delete-node/ mailbox@7e00b840;
+- };
+-};
+-
+-&scb {
+- vchiq: mailbox@7e00b840 {
+- compatible = "brcm,bcm2838-vchiq";
+- reg = <0 0x7e00b840 0x3c>;
+- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-};
+-
+-&dma {
+- /* The VPU firmware uses DMA channel 11 for VCHIQ */
+- brcm,dma-channel-mask = <0x1f5>;
+-};
+-
+-&dma40 {
+- /* The VPU firmware DMA channel 11 for VCHIQ */
+- brcm,dma-channel-mask = <0x7000>;
+-};
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ /dev/null
+@@ -1,733 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include "bcm283x.dtsi"
+-
+-#include <dt-bindings/interrupt-controller/arm-gic.h>
+-#include <dt-bindings/soc/bcm2835-pm.h>
+-
+-/ {
+- compatible = "brcm,bcm2838";
+-
+- #address-cells = <2>;
+- #size-cells = <1>;
+-
+- interrupt-parent = <&gicv2>;
+-
+- soc {
+- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
+- <0x7c000000 0x0 0xfc000000 0x02000000>,
+- <0x40000000 0x0 0xff800000 0x00800000>;
+- /* Emulate a contiguous 30-bit address range for DMA */
+- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
+-
+- /delete-node/ interrupt-controller@7e00f300;
+- /delete-node/ v3d@7ec00000;
+-
+- local_intc: local_intc@40000000 {
+- compatible = "brcm,bcm2836-l1-intc";
+- reg = <0x40000000 0x100>;
+- };
+-
+- gicv2: interrupt-controller@40041000 {
+- interrupt-controller;
+- #interrupt-cells = <3>;
+- compatible = "arm,gic-400";
+- reg = <0x40041000 0x1000>,
+- <0x40042000 0x2000>,
+- <0x40044000 0x2000>,
+- <0x40046000 0x2000>;
+- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_HIGH)>;
+- };
+-
+- thermal: thermal@7d5d2200 {
+- compatible = "brcm,avs-tmon-bcm2838";
+- reg = <0x7d5d2200 0x2c>;
+- interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "tmon";
+- clocks = <&clocks BCM2835_CLOCK_TSENS>;
+- #thermal-sensor-cells = <0>;
+- status = "okay";
+- };
+-
+- pm: watchdog@7e100000 {
+- reg = <0x7e100000 0x114>,
+- <0x7e00a000 0x24>,
+- <0x7ec11000 0x20>;
+- };
+-
+- rng@7e104000 {
+- interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- uart2: serial@7e201400 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201400 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart3: serial@7e201600 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201600 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart4: serial@7e201800 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201800 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- uart5: serial@7e201a00 {
+- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
+- reg = <0x7e201a00 0x200>;
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_UART>,
+- <&clocks BCM2835_CLOCK_VPU>;
+- clock-names = "uartclk", "apb_pclk";
+- arm,primecell-periphid = <0x00241011>;
+- status = "disabled";
+- };
+-
+- spi@7e204000 {
+- reg = <0x7e204000 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- spi3: spi@7e204600 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204600 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi4: spi@7e204800 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204800 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi5: spi@7e204a00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204a00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- spi6: spi@7e204c00 {
+- compatible = "brcm,bcm2835-spi";
+- reg = <0x7e204c00 0x0200>;
+- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c3: i2c@7e205600 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205600 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c4: i2c@7e205800 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205800 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c5: i2c@7e205a00 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205a00 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- i2c6: i2c@7e205c00 {
+- compatible = "brcm,bcm2835-i2c";
+- reg = <0x7e205c00 0x200>;
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2835_CLOCK_VPU>;
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+-
+- pwm1: pwm@7e20c800 {
+- compatible = "brcm,bcm2835-pwm";
+- reg = <0x7e20c800 0x28>;
+- clocks = <&clocks BCM2835_CLOCK_PWM>;
+- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
+- assigned-clock-rates = <10000000>;
+- #pwm-cells = <2>;
+- status = "disabled";
+- };
+-
+- emmc2: emmc2@7e340000 {
+- compatible = "brcm,bcm2711-emmc2";
+- status = "okay";
+- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clocks BCM2711_CLOCK_EMMC2>;
+- reg = <0x7e340000 0x100>;
+- };
+-
+- hvs@7e400000 {
+- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+- };
+- };
+-
+- arm-pmu {
+- compatible = "arm,cortex-a72-pmu";
+- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+- };
+-
+- timer {
+- compatible = "arm,armv7-timer";
+- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>,
+- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+- IRQ_TYPE_LEVEL_LOW)>;
+- arm,cpu-registers-not-fw-configured;
+- };
+-
+- cpus: cpus {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
+-
+- cpu0: cpu@0 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <0>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000d8>;
+- };
+-
+- cpu1: cpu@1 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <1>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000e0>;
+- };
+-
+- cpu2: cpu@2 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <2>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000e8>;
+- };
+-
+- cpu3: cpu@3 {
+- device_type = "cpu";
+- compatible = "arm,cortex-a72";
+- reg = <3>;
+- enable-method = "spin-table";
+- cpu-release-addr = <0x0 0x000000f0>;
+- };
+- };
+-
+- v3dbus {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <2>;
+- ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>,
+- <0x40000000 0x0 0xff800000 0x0 0x00800000>;
+- dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>;
+-
+- v3d: v3d@7ec04000 {
+- compatible = "brcm,2711-v3d";
+- reg =
+- <0x7ec00000 0x0 0x4000>,
+- <0x7ec04000 0x0 0x4000>;
+- reg-names = "hub", "core0";
+-
+- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
+- resets = <&pm BCM2835_RESET_V3D>;
+- clocks = <&clocks BCM2835_CLOCK_V3D>;
+- interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+- status = "okay";
+- };
+- };
+-
+- scb: scb {
+- compatible = "simple-bus";
+- #address-cells = <2>;
+- #size-cells = <1>;
+-
+- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
+- <0x0 0x40000000 0x0 0xff800000 0x00800000>,
+- <0x6 0x00000000 0x6 0x00000000 0x40000000>,
+- <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
+- dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
+-
+- pcie_0: pcie@7d500000 {
+- reg = <0x0 0x7d500000 0x9310>,
+- <0x0 0x7e00f300 0x20>;
+- msi-controller;
+- msi-parent = <&pcie_0>;
+- #address-cells = <3>;
+- #interrupt-cells = <1>;
+- #size-cells = <2>;
+- bus-range = <0x0 0x01>;
+- compatible = "brcm,bcm2711b0-pcie", // Safe value
+- "brcm,bcm2711-pcie",
+- "brcm,pci-plat-dev";
+- max-link-speed = <2>;
+- tot-num-pcie = <1>;
+- linux,pci-domain = <0>;
+- interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "pcie", "msi";
+- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 2 &gicv2 GIC_SPI 144
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 3 &gicv2 GIC_SPI 145
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 4 &gicv2 GIC_SPI 146
+- IRQ_TYPE_LEVEL_HIGH>;
+-
+- /* Map outbound accesses from scb:0x6_00000000-03ffffff
+- * to pci:0x0_f8000000-fbffffff
+- */
+- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
+- 0x0 0x04000000>;
+- /* Map inbound accesses from pci:0x0_00000000..ffffffff
+- * to scb:0x0_00000000-ffffffff
+- */
+- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
+- 0x1 0x00000000>;
+- status = "okay";
+- };
+-
+- genet: ethernet@7d580000 {
+- compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
+- reg = <0x0 0x7d580000 0x10000>;
+- #address-cells = <0x1>;
+- #size-cells = <0x1>;
+- interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+-
+- genet_mdio: mdio@e14 {
+- #address-cells = <0x0>;
+- #size-cells = <0x1>;
+- compatible = "brcm,genet-mdio-v5";
+- reg = <0xe14 0x8>;
+- reg-names = "mdio";
+- };
+- };
+-
+- dma40: dma@7e007b00 {
+- compatible = "brcm,bcm2838-dma";
+- reg = <0x0 0x7e007b00 0x400>;
+- interrupts =
+- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
+- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
+- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
+- <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
+- interrupt-names = "dma11",
+- "dma12",
+- "dma13",
+- "dma14";
+- #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x7800>;
+- };
+- /* DMA4 - 40 bit DMA engines */
+-
+- xhci: xhci@7e9c0000 {
+- compatible = "generic-xhci";
+- status = "disabled";
+- reg = <0x0 0x7e9c0000 0x100000>;
+- interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- hevc-decoder@7eb00000 {
+- compatible = "raspberrypi,rpivid-hevc-decoder";
+- reg = <0x0 0x7eb00000 0x10000>;
+- status = "okay";
+- };
+-
+- rpivid-local-intc@7eb10000 {
+- compatible = "raspberrypi,rpivid-local-intc";
+- reg = <0x0 0x7eb10000 0x1000>;
+- status = "okay";
+- interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- h264-decoder@7eb20000 {
+- compatible = "raspberrypi,rpivid-h264-decoder";
+- reg = <0x0 0x7eb20000 0x10000>;
+- status = "okay";
+- };
+-
+- vp9-decoder@7eb30000 {
+- compatible = "raspberrypi,rpivid-vp9-decoder";
+- reg = <0x0 0x7eb30000 0x10000>;
+- status = "okay";
+- };
+- };
+-};
+-
+-&clk_osc {
+- clock-frequency = <54000000>;
+-};
+-
+-&clocks {
+- compatible = "brcm,bcm2711-cprman";
+-};
+-
+-&cpu_thermal {
+- coefficients = <(-487) 410040>;
+-};
+-
+-&dsi0 {
+- interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&dsi1 {
+- interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&gpio {
+- compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio";
+-
+- gpclk0_gpio49: gpclk0_gpio49 {
+- brcm,pins = <49>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- brcm,pull = <BCM2835_PUD_OFF>;
+- };
+- gpclk1_gpio50: gpclk1_gpio50 {
+- brcm,pins = <50>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- brcm,pull = <BCM2835_PUD_OFF>;
+- };
+- gpclk2_gpio51: gpclk2_gpio51 {
+- brcm,pins = <51>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- brcm,pull = <BCM2835_PUD_OFF>;
+- };
+-
+- i2c0_gpio46: i2c0_gpio46 {
+- brcm,pins = <46 47>;
+- brcm,function = <BCM2835_FSEL_ALT0>;
+- };
+- i2c1_gpio46: i2c1_gpio46 {
+- brcm,pins = <46 47>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- };
+- i2c3_gpio2: i2c3_gpio2 {
+- brcm,pins = <2 3>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c3_gpio4: i2c3_gpio4 {
+- brcm,pins = <4 5>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c4_gpio6: i2c4_gpio6 {
+- brcm,pins = <6 7>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c4_gpio8: i2c4_gpio8 {
+- brcm,pins = <8 9>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c5_gpio10: i2c5_gpio10 {
+- brcm,pins = <10 11>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c5_gpio12: i2c5_gpio12 {
+- brcm,pins = <12 13>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c6_gpio0: i2c6_gpio0 {
+- brcm,pins = <0 1>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c6_gpio22: i2c6_gpio22 {
+- brcm,pins = <22 23>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- i2c_slave_gpio8: i2c_slave_gpio8 {
+- brcm,pins = <8 9 10 11>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- jtag_gpio48: jtag_gpio48 {
+- brcm,pins = <48 49 50 51 52 53>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- };
+-
+- mii_gpio28: mii_gpio28 {
+- brcm,pins = <28 29 30 31>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- };
+- mii_gpio36: mii_gpio36 {
+- brcm,pins = <36 37 38 39>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+-
+- pcm_gpio50: pcm_gpio50 {
+- brcm,pins = <50 51 52 53>;
+- brcm,function = <BCM2835_FSEL_ALT2>;
+- };
+-
+- pwm0_gpio52: pwm0_gpio52 {
+- brcm,pins = <52>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- brcm,pull = <BCM2835_PUD_OFF>;
+- };
+- pwm1_gpio53: pwm1_gpio53 {
+- brcm,pins = <53>;
+- brcm,function = <BCM2835_FSEL_ALT1>;
+- brcm,pull = <BCM2835_PUD_OFF>;
+- };
+-
+- /* The following group consists of:
+- * RGMII_START_STOP
+- * RGMII_RX_OK
+- */
+- rgmii_gpio35: rgmii_gpio35 {
+- brcm,pins = <35 36>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- };
+- rgmii_irq_gpio34: rgmii_irq_gpio34 {
+- brcm,pins = <34>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- rgmii_irq_gpio39: rgmii_irq_gpio39 {
+- brcm,pins = <39>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- };
+- rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
+- brcm,pins = <28 29>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
+- brcm,pins = <37 38>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- };
+-
+- spi0_gpio46: spi0_gpio46 {
+- brcm,pins = <46 47 48 49>;
+- brcm,function = <BCM2835_FSEL_ALT2>;
+- };
+- spi2_gpio46: spi2_gpio46 {
+- brcm,pins = <46 47 48 49 50>;
+- brcm,function = <BCM2835_FSEL_ALT5>;
+- };
+- spi3_gpio0: spi3_gpio0 {
+- brcm,pins = <0 1 2 3>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+- spi4_gpio4: spi4_gpio4 {
+- brcm,pins = <4 5 6 7>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+- spi5_gpio12: spi5_gpio12 {
+- brcm,pins = <12 13 14 15>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+- spi6_gpio18: spi6_gpio18 {
+- brcm,pins = <18 19 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT3>;
+- };
+-
+- uart2_gpio0: uart2_gpio0 {
+- brcm,pins = <0 1>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
+- };
+- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
+- brcm,pins = <2 3>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
+- };
+- uart3_gpio4: uart3_gpio4 {
+- brcm,pins = <4 5>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
+- };
+- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
+- brcm,pins = <6 7>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
+- };
+- uart4_gpio8: uart4_gpio8 {
+- brcm,pins = <8 9>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
+- };
+- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
+- brcm,pins = <10 11>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
+- };
+- uart5_gpio12: uart5_gpio12 {
+- brcm,pins = <12 13>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
+- };
+- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
+- brcm,pins = <14 15>;
+- brcm,function = <BCM2835_FSEL_ALT4>;
+- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
+- };
+-};
+-
+-&vec {
+- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&usb {
+- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+- status = "disabled";
+-};
+-
+-&hdmi {
+- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&uart1 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi1 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&spi2 {
+- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&csi0 {
+- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&csi1 {
+- interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&sdhci {
+- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&i2c0 {
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&i2c1 {
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&i2c2 {
+- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&gpio {
+- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&mailbox {
+- interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&rng {
+- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
+-};
+-
+-&sdhost {
+- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&system_timer {
+- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&uart0 {
+- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+-};
+-
+-&dma {
+- reg = <0x7e007000 0xb00>;
+- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
+- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
+- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; /* dmalite 10 */
+- interrupt-names = "dma0",
+- "dma1",
+- "dma2",
+- "dma3",
+- "dma4",
+- "dma5",
+- "dma6",
+- "dma7",
+- "dma8",
+- "dma9",
+- "dma10";
+- brcm,dma-channel-mask = <0x07f5>;
+-};
+-
+-&txp {
+- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+-};
+++ /dev/null
-From 58ac2d4474e531300f9f83773aa4d09e95ee2626 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 12 Jul 2019 11:41:25 +0100
-Subject: [PATCH] pcie-brcmstb: Bounce buffer support is for BCM2711B0
-
-Add a new compatible string to identify BCM2711B0, as later revisions
-don't require the bounce buffer support.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/pci/controller/pcie-brcmstb.c | 31 +++++++++++++++++++++++----
- 1 file changed, 27 insertions(+), 4 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb.c
-+++ b/drivers/pci/controller/pcie-brcmstb.c
-@@ -206,6 +206,8 @@ enum pcie_type {
- BCM7435,
- GENERIC,
- BCM7278,
-+ BCM2711B0,
-+ BCM2711,
- };
-
- struct brcm_window {
-@@ -302,6 +304,20 @@ static const int pcie_offsets[] = {
- [EXT_CFG_DATA] = 0x8000,
- };
-
-+static const struct pcie_cfg_data bcm2711b0_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_128,
-+ .type = BCM2711B0,
-+};
-+
-+static const struct pcie_cfg_data bcm2711_cfg = {
-+ .reg_field_info = pcie_reg_field_info,
-+ .offsets = pcie_offsets,
-+ .max_burst_size = BURST_SIZE_128,
-+ .type = BCM2711,
-+};
-+
- static const struct pcie_cfg_data bcm7435_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-@@ -312,7 +328,7 @@ static const struct pcie_cfg_data bcm743
- static const struct pcie_cfg_data generic_cfg = {
- .reg_field_info = pcie_reg_field_info,
- .offsets = pcie_offsets,
-- .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
-+ .max_burst_size = BURST_SIZE_512,
- .type = GENERIC,
- };
-
-@@ -380,7 +396,7 @@ static unsigned int bounce_buffer = 32*1
- module_param(bounce_buffer, uint, 0644);
- MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
-
--static unsigned int bounce_threshold = 0xc0000000;
-+static unsigned int bounce_threshold;
- module_param(bounce_threshold, uint, 0644);
- MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
-
-@@ -1675,6 +1691,8 @@ static int brcm_pcie_remove(struct platf
- }
-
- static const struct of_device_id brcm_pcie_match[] = {
-+ { .compatible = "brcm,bcm2711b0-pcie", .data = &bcm2711b0_cfg },
-+ { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
- { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
- { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
- { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
-@@ -1731,8 +1749,13 @@ static int brcm_pcie_probe(struct platfo
- if (IS_ERR(base))
- return PTR_ERR(base);
-
-- /* To Do: Add hardware check if this ever gets fixed */
-- if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
-+ if (!bounce_threshold) {
-+ /* PCIe on BCM2711B0 can only address 3GB */
-+ if (pcie->type == BCM2711B0 || pcie->type == GENERIC)
-+ bounce_threshold = 0xc0000000;
-+ }
-+
-+ if (bounce_threshold && (max_pfn > (bounce_threshold/PAGE_SIZE))) {
- int ret;
- ret = brcm_pcie_bounce_init(dev, bounce_buffer,
- (dma_addr_t)bounce_threshold);
--- /dev/null
+From 19a0ac654994661f63f7c9e099ed91a1210af161 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Sun, 6 Oct 2019 15:41:25 +0200
+Subject: [PATCH] ARM: dts: Add minimal Raspberry Pi 4 support
+
+This adds minimal support for the new Raspberry Pi 4 without the
+fancy stuff like GENET, PCIe, xHCI, 40 bit DMA and V3D. The RPi 4 is
+available in 3 different variants (1, 2 and 4 GB RAM), so leave the memory
+size to zero and let the bootloader take care of it. The DWC2 is still
+usable as peripheral via the USB-C port.
+
+Other differences to the Raspberry Pi 3:
+- additional GIC 400 Interrupt controller
+- new thermal IP and HWRNG
+- additional MMC interface (emmc2)
+- additional UART, I2C, SPI and PWM interfaces
+- clock stretching bug in I2C IP has been fixed
+
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Acked-by: Eric Anholt <eric@anholt.net>
+Acked-by: Florian Fanelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 123 +++
+ arch/arm/boot/dts/bcm2711.dtsi | 844 ++++++++++++++++++
+ .../boot/dts/bcm283x-rpi-usb-peripheral.dtsi | 7 +
+ 4 files changed, 975 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+ create mode 100644 arch/arm/boot/dts/bcm2711.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -97,6 +97,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
+ bcm2837-rpi-cm3-io3.dtb \
++ bcm2711-rpi-4-b.dtb \
+ bcm2835-rpi-zero.dtb \
+ bcm2835-rpi-zero-w.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -0,0 +1,123 @@
++// SPDX-License-Identifier: GPL-2.0
++/dts-v1/;
++#include "bcm2711.dtsi"
++#include "bcm2835-rpi.dtsi"
++#include "bcm283x-rpi-usb-peripheral.dtsi"
++
++/ {
++ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
++ model = "Raspberry Pi 4 Model B";
++
++ chosen {
++ /* 8250 auxiliary UART instead of pl011 */
++ stdout-path = "serial1:115200n8";
++ };
++
++ /* Will be filled by the bootloader */
++ memory@0 {
++ device_type = "memory";
++ reg = <0 0 0>;
++ };
++
++ leds {
++ act {
++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
++ };
++
++ pwr {
++ label = "PWR";
++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
++ };
++
++ sd_io_1v8_reg: sd_io_1v8_reg {
++ compatible = "regulator-gpio";
++ regulator-name = "vdd-sd-io";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-settling-time-us = <5000>;
++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
++ states = <1800000 0x1
++ 3300000 0x0>;
++ status = "okay";
++ };
++};
++
++&firmware {
++ expgpio: gpio {
++ compatible = "raspberrypi,firmware-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ gpio-line-names = "BT_ON",
++ "WL_ON",
++ "PWR_LED_OFF",
++ "GLOBAL_RESET",
++ "VDD_SD_IO_SEL",
++ "CAM_GPIO",
++ "",
++ "";
++ status = "okay";
++ };
++};
++
++&pwm1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
++ status = "okay";
++};
++
++/* SDHCI is used to control the SDIO for wireless */
++&sdhci {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_gpio34>;
++ bus-width = <4>;
++ non-removable;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ status = "okay";
++
++ brcmf: wifi@1 {
++ reg = <1>;
++ compatible = "brcm,bcm4329-fmac";
++ };
++};
++
++/* EMMC2 is used to drive the SD card */
++&emmc2 {
++ vqmmc-supply = <&sd_io_1v8_reg>;
++ broken-cd;
++ status = "okay";
++};
++
++/* uart0 communicates with the BT module */
++&uart0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
++ uart-has-rtscts;
++ status = "okay";
++
++ bluetooth {
++ compatible = "brcm,bcm43438-bt";
++ max-speed = <2000000>;
++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++/* uart1 is mapped to the pin header */
++&uart1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart1_gpio14>;
++ status = "okay";
++};
++
++&vchiq {
++ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -0,0 +1,844 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "bcm283x.dtsi"
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/soc/bcm2835-pm.h>
++
++/ {
++ compatible = "brcm,bcm2711";
++
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ interrupt-parent = <&gicv2>;
++
++ soc {
++ /*
++ * Defined ranges:
++ * Common BCM283x peripherals
++ * BCM2711-specific peripherals
++ * ARM-local peripherals
++ */
++ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
++ <0x7c000000 0x0 0xfc000000 0x02000000>,
++ <0x40000000 0x0 0xff800000 0x00800000>;
++ /* Emulate a contiguous 30-bit address range for DMA */
++ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
++
++ /*
++ * This node is the provider for the enable-method for
++ * bringing up secondary cores.
++ */
++ local_intc: local_intc@40000000 {
++ compatible = "brcm,bcm2836-l1-intc";
++ reg = <0x40000000 0x100>;
++ };
++
++ gicv2: interrupt-controller@40041000 {
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ compatible = "arm,gic-400";
++ reg = <0x40041000 0x1000>,
++ <0x40042000 0x2000>,
++ <0x40044000 0x2000>,
++ <0x40046000 0x2000>;
++ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_HIGH)>;
++ };
++
++ dma: dma@7e007000 {
++ compatible = "brcm,bcm2835-dma";
++ reg = <0x7e007000 0xb00>;
++ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
++ /* DMA lite 7 - 10 */
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "dma0",
++ "dma1",
++ "dma2",
++ "dma3",
++ "dma4",
++ "dma5",
++ "dma6",
++ "dma7",
++ "dma8",
++ "dma9",
++ "dma10";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x07f5>;
++ };
++
++ pm: watchdog@7e100000 {
++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
++ #power-domain-cells = <1>;
++ #reset-cells = <1>;
++ reg = <0x7e100000 0x114>,
++ <0x7e00a000 0x24>,
++ <0x7ec11000 0x20>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>,
++ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
++ <&clocks BCM2835_CLOCK_H264>,
++ <&clocks BCM2835_CLOCK_ISP>;
++ clock-names = "v3d", "peri_image", "h264", "isp";
++ system-power-controller;
++ };
++
++ rng@7e104000 {
++ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
++
++ /* RNG is incompatible with brcm,bcm2835-rng */
++ status = "disabled";
++ };
++
++ uart2: serial@7e201400 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201400 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart3: serial@7e201600 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201600 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart4: serial@7e201800 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201800 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ uart5: serial@7e201a00 {
++ compatible = "arm,pl011", "arm,primecell";
++ reg = <0x7e201a00 0x200>;
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_UART>,
++ <&clocks BCM2835_CLOCK_VPU>;
++ clock-names = "uartclk", "apb_pclk";
++ arm,primecell-periphid = <0x00241011>;
++ status = "disabled";
++ };
++
++ spi3: spi@7e204600 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204600 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi4: spi@7e204800 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204800 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi5: spi@7e204a00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204a00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ spi6: spi@7e204c00 {
++ compatible = "brcm,bcm2835-spi";
++ reg = <0x7e204c00 0x0200>;
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c3: i2c@7e205600 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205600 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c4: i2c@7e205800 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205800 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c5: i2c@7e205a00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205a00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c6: i2c@7e205c00 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ reg = <0x7e205c00 0x200>;
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2835_CLOCK_VPU>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ pwm1: pwm@7e20c800 {
++ compatible = "brcm,bcm2835-pwm";
++ reg = <0x7e20c800 0x28>;
++ clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
++ assigned-clock-rates = <10000000>;
++ #pwm-cells = <2>;
++ status = "disabled";
++ };
++
++ emmc2: emmc2@7e340000 {
++ compatible = "brcm,bcm2711-emmc2";
++ reg = <0x7e340000 0x100>;
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
++ status = "disabled";
++ };
++
++ hvs@7e400000 {
++ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
++ };
++ };
++
++ arm-pmu {
++ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
++ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++ };
++
++ timer {
++ compatible = "arm,armv8-timer";
++ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>,
++ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
++ IRQ_TYPE_LEVEL_LOW)>;
++ /* This only applies to the ARMv7 stub */
++ arm,cpu-registers-not-fw-configured;
++ };
++
++ cpus: cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <0>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000d8>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <1>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e0>;
++ };
++
++ cpu2: cpu@2 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <2>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000e8>;
++ };
++
++ cpu3: cpu@3 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a72";
++ reg = <3>;
++ enable-method = "spin-table";
++ cpu-release-addr = <0x0 0x000000f0>;
++ };
++ };
++};
++
++&clk_osc {
++ clock-frequency = <54000000>;
++};
++
++&clocks {
++ compatible = "brcm,bcm2711-cprman";
++};
++
++&cpu_thermal {
++ coefficients = <(-487) 410040>;
++};
++
++&dsi0 {
++ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&dsi1 {
++ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&gpio {
++ compatible = "brcm,bcm2711-gpio";
++ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
++
++ gpclk0_gpio49: gpclk0_gpio49 {
++ pin-gpclk {
++ pins = "gpio49";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ gpclk1_gpio50: gpclk1_gpio50 {
++ pin-gpclk {
++ pins = "gpio50";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ gpclk2_gpio51: gpclk2_gpio51 {
++ pin-gpclk {
++ pins = "gpio51";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++
++ i2c0_gpio46: i2c0_gpio46 {
++ pin-sda {
++ function = "alt0";
++ pins = "gpio46";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt0";
++ pins = "gpio47";
++ bias-disable;
++ };
++ };
++ i2c1_gpio46: i2c1_gpio46 {
++ pin-sda {
++ function = "alt1";
++ pins = "gpio46";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt1";
++ pins = "gpio47";
++ bias-disable;
++ };
++ };
++ i2c3_gpio2: i2c3_gpio2 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio2";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio3";
++ bias-disable;
++ };
++ };
++ i2c3_gpio4: i2c3_gpio4 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio4";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio5";
++ bias-disable;
++ };
++ };
++ i2c4_gpio6: i2c4_gpio6 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio6";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio7";
++ bias-disable;
++ };
++ };
++ i2c4_gpio8: i2c4_gpio8 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio8";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio9";
++ bias-disable;
++ };
++ };
++ i2c5_gpio10: i2c5_gpio10 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio10";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio11";
++ bias-disable;
++ };
++ };
++ i2c5_gpio12: i2c5_gpio12 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio12";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio13";
++ bias-disable;
++ };
++ };
++ i2c6_gpio0: i2c6_gpio0 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio0";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio1";
++ bias-disable;
++ };
++ };
++ i2c6_gpio22: i2c6_gpio22 {
++ pin-sda {
++ function = "alt5";
++ pins = "gpio22";
++ bias-pull-up;
++ };
++ pin-scl {
++ function = "alt5";
++ pins = "gpio23";
++ bias-disable;
++ };
++ };
++ i2c_slave_gpio8: i2c_slave_gpio8 {
++ pins-i2c-slave {
++ pins = "gpio8",
++ "gpio9",
++ "gpio10",
++ "gpio11";
++ function = "alt3";
++ };
++ };
++
++ jtag_gpio48: jtag_gpio48 {
++ pins-jtag {
++ pins = "gpio48",
++ "gpio49",
++ "gpio50",
++ "gpio51",
++ "gpio52",
++ "gpio53";
++ function = "alt4";
++ };
++ };
++
++ mii_gpio28: mii_gpio28 {
++ pins-mii {
++ pins = "gpio28",
++ "gpio29",
++ "gpio30",
++ "gpio31";
++ function = "alt4";
++ };
++ };
++ mii_gpio36: mii_gpio36 {
++ pins-mii {
++ pins = "gpio36",
++ "gpio37",
++ "gpio38",
++ "gpio39";
++ function = "alt5";
++ };
++ };
++
++ pcm_gpio50: pcm_gpio50 {
++ pins-pcm {
++ pins = "gpio50",
++ "gpio51",
++ "gpio52",
++ "gpio53";
++ function = "alt2";
++ };
++ };
++
++ pwm0_0_gpio12: pwm0_0_gpio12 {
++ pin-pwm {
++ pins = "gpio12";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_0_gpio18: pwm0_0_gpio18 {
++ pin-pwm {
++ pins = "gpio18";
++ function = "alt5";
++ bias-disable;
++ };
++ };
++ pwm1_0_gpio40: pwm1_0_gpio40 {
++ pin-pwm {
++ pins = "gpio40";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio13: pwm0_1_gpio13 {
++ pin-pwm {
++ pins = "gpio13";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio19: pwm0_1_gpio19 {
++ pin-pwm {
++ pins = "gpio19";
++ function = "alt5";
++ bias-disable;
++ };
++ };
++ pwm1_1_gpio41: pwm1_1_gpio41 {
++ pin-pwm {
++ pins = "gpio41";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio45: pwm0_1_gpio45 {
++ pin-pwm {
++ pins = "gpio45";
++ function = "alt0";
++ bias-disable;
++ };
++ };
++ pwm0_0_gpio52: pwm0_0_gpio52 {
++ pin-pwm {
++ pins = "gpio52";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++ pwm0_1_gpio53: pwm0_1_gpio53 {
++ pin-pwm {
++ pins = "gpio53";
++ function = "alt1";
++ bias-disable;
++ };
++ };
++
++ rgmii_gpio35: rgmii_gpio35 {
++ pin-start-stop {
++ pins = "gpio35";
++ function = "alt4";
++ };
++ pin-rx-ok {
++ pins = "gpio36";
++ function = "alt4";
++ };
++ };
++ rgmii_irq_gpio34: rgmii_irq_gpio34 {
++ pin-irq {
++ pins = "gpio34";
++ function = "alt5";
++ };
++ };
++ rgmii_irq_gpio39: rgmii_irq_gpio39 {
++ pin-irq {
++ pins = "gpio39";
++ function = "alt4";
++ };
++ };
++ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
++ pins-mdio {
++ pins = "gpio28",
++ "gpio29";
++ function = "alt5";
++ };
++ };
++ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
++ pins-mdio {
++ pins = "gpio37",
++ "gpio38";
++ function = "alt4";
++ };
++ };
++
++ spi0_gpio46: spi0_gpio46 {
++ pins-spi {
++ pins = "gpio46",
++ "gpio47",
++ "gpio48",
++ "gpio49";
++ function = "alt2";
++ };
++ };
++ spi2_gpio46: spi2_gpio46 {
++ pins-spi {
++ pins = "gpio46",
++ "gpio47",
++ "gpio48",
++ "gpio49",
++ "gpio50";
++ function = "alt5";
++ };
++ };
++ spi3_gpio0: spi3_gpio0 {
++ pins-spi {
++ pins = "gpio0",
++ "gpio1",
++ "gpio2",
++ "gpio3";
++ function = "alt3";
++ };
++ };
++ spi4_gpio4: spi4_gpio4 {
++ pins-spi {
++ pins = "gpio4",
++ "gpio5",
++ "gpio6",
++ "gpio7";
++ function = "alt3";
++ };
++ };
++ spi5_gpio12: spi5_gpio12 {
++ pins-spi {
++ pins = "gpio12",
++ "gpio13",
++ "gpio14",
++ "gpio15";
++ function = "alt3";
++ };
++ };
++ spi6_gpio18: spi6_gpio18 {
++ pins-spi {
++ pins = "gpio18",
++ "gpio19",
++ "gpio20",
++ "gpio21";
++ function = "alt3";
++ };
++ };
++
++ uart2_gpio0: uart2_gpio0 {
++ pin-tx {
++ pins = "gpio0";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio1";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
++ pin-cts {
++ pins = "gpio2";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio3";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart3_gpio4: uart3_gpio4 {
++ pin-tx {
++ pins = "gpio4";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio5";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
++ pin-cts {
++ pins = "gpio6";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio7";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart4_gpio8: uart4_gpio8 {
++ pin-tx {
++ pins = "gpio8";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio9";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
++ pin-cts {
++ pins = "gpio10";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio11";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++ uart5_gpio12: uart5_gpio12 {
++ pin-tx {
++ pins = "gpio12";
++ function = "alt4";
++ bias-disable;
++ };
++ pin-rx {
++ pins = "gpio13";
++ function = "alt4";
++ bias-pull-up;
++ };
++ };
++ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
++ pin-cts {
++ pins = "gpio14";
++ function = "alt4";
++ bias-pull-up;
++ };
++ pin-rts {
++ pins = "gpio15";
++ function = "alt4";
++ bias-disable;
++ };
++ };
++};
++
++&i2c0 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&i2c1 {
++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
++ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mailbox {
++ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&sdhci {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&sdhost {
++ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi {
++ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&spi2 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&system_timer {
++ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&txp {
++ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart0 {
++ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&uart1 {
++ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&usb {
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&vec {
++ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
+@@ -0,0 +1,7 @@
++// SPDX-License-Identifier: GPL-2.0
++&usb {
++ dr_mode = "peripheral";
++ g-rx-fifo-size = <256>;
++ g-np-tx-fifo-size = <32>;
++ g-tx-fifo-size = <256 256 512 512 512 768 768>;
++};
+++ /dev/null
-From 8be8dc74799fe7c0e09dfa53aa41e954ffba291c Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Fri, 12 Jul 2019 11:43:03 +0100
-Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string
-
-The BCM2711 PCIe controller has a limited address range in the B0
-silicon, and the driver uses a compatible string to identify the
-limitation. The current Pi 4 firmware will override the compatible
-string if it detects a downstream DTB and it is running on a newer
-revision but set the default value to enable the workaround for
-backwards-compatibility with old firmware.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2838.dtsi | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ b/arch/arm/boot/dts/bcm2838.dtsi
-@@ -314,7 +314,8 @@
- #interrupt-cells = <1>;
- #size-cells = <2>;
- bus-range = <0x0 0x01>;
-- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
-+ compatible = "brcm,bcm2711b0-pcie", // Safe value
-+ "brcm,bcm2711-pcie",
- "brcm,pci-plat-dev";
- max-link-speed = <2>;
- tot-num-pcie = <1>;
+++ /dev/null
-From 3c099a50b3d609206a86896405cfdc8a94cd7aa4 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 29 Jan 2020 11:29:06 +0000
-Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts
-
-Upstream are not going to use the bcm2838 identifier, so begin the
-cleanup by removing the suggested upstream Pi 4 .dts file.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/Makefile | 1 -
- arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 134 --------------------------
- 2 files changed, 135 deletions(-)
- delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -97,7 +97,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2837-rpi-3-b.dtb \
- bcm2837-rpi-3-b-plus.dtb \
- bcm2837-rpi-cm3-io3.dtb \
-- bcm2838-rpi-4-b.dtb \
- bcm2835-rpi-zero.dtb \
- bcm2835-rpi-zero-w.dtb
- dtb-$(CONFIG_ARCH_BCM_5301X) += \
---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
-+++ /dev/null
-@@ -1,134 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/dts-v1/;
--#include "bcm2838.dtsi"
--#include "bcm2835-rpi.dtsi"
--#include "bcm2838-rpi.dtsi"
--
--/ {
-- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
-- model = "Raspberry Pi 4 Model B";
--
-- chosen {
-- /* 8250 auxiliary UART instead of pl011 */
-- stdout-path = "serial1:115200n8";
-- };
--
-- memory@0 {
-- device_type = "memory";
-- reg = <0x0 0x0 0x0>;
-- };
--
-- leds {
-- act {
-- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-- };
--
-- pwr {
-- label = "PWR";
-- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-- };
-- };
--
-- wifi_pwrseq: wifi-pwrseq {
-- compatible = "mmc-pwrseq-simple";
-- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
-- };
--
-- sd_io_1v8_reg: sd_io_1v8_reg {
-- status = "okay";
-- compatible = "regulator-gpio";
-- vin-supply = <&vdd_5v0_reg>;
-- regulator-name = "vdd-sd-io";
-- regulator-min-microvolt = <1800000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-boot-on;
-- regulator-always-on;
-- regulator-settling-time-us = <5000>;
--
-- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-- states = <1800000 0x1
-- 3300000 0x0>;
-- };
--};
--
--&firmware {
-- expgpio: gpio {
-- compatible = "raspberrypi,firmware-gpio";
-- gpio-controller;
-- #gpio-cells = <2>;
-- gpio-line-names = "BT_ON",
-- "WL_ON",
-- "PWR_LED_OFF",
-- "GLOBAL_RESET",
-- "VDD_SD_IO_SEL",
-- "CAM_GPIO",
-- "",
-- "";
-- status = "okay";
-- };
--};
--
--&pwm1 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
-- status = "okay";
--};
--
--/* SDHCI is used to control the SDIO for wireless */
--&sdhci {
-- #address-cells = <1>;
-- #size-cells = <0>;
-- pinctrl-names = "default";
-- pinctrl-0 = <&emmc_gpio34>;
-- status = "okay";
-- bus-width = <4>;
-- non-removable;
-- mmc-pwrseq = <&wifi_pwrseq>;
--
-- brcmf: wifi@1 {
-- reg = <1>;
-- compatible = "brcm,bcm4329-fmac";
-- };
--};
--
--/* EMMC2 is used to drive the SD card */
--&emmc2 {
-- status = "okay";
-- broken-cd;
-- vqmmc-supply = <&sd_io_1v8_reg>;
--};
--
--&genet {
-- phy-handle = <&phy1>;
-- phy-mode = "rgmii-rxid";
-- status = "okay";
--};
--
--&genet_mdio {
-- phy1: ethernet-phy@1 {
-- /* No PHY interrupt */
-- reg = <0x1>;
-- led-modes = <0x00 0x08>; /* link/activity link */
-- };
--};
--
--/* uart0 communicates with the BT module */
--&uart0 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
-- uart-has-rtscts;
-- status = "okay";
--
-- bluetooth {
-- compatible = "brcm,bcm43438-bt";
-- max-speed = <2000000>;
-- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
-- };
--};
--
--/* uart1 is mapped to the pin header */
--&uart1 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart1_gpio14>;
-- status = "okay";
--};
--- /dev/null
+From 4bcb99a967998d255ef009bb0b6880ae99c6f6bf Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 6 Nov 2019 10:59:44 +0100
+Subject: [PATCH] ARM: dts: bcm2711: force CMA into first GB of memory
+
+arm64 places the CMA in ZONE_DMA32, which is not good enough for the
+Raspberry Pi 4 since it contains peripherals that can only address the
+first GB of memory. Explicitly place the CMA into that area.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Acked-by: Stefan Wahren <wahrenst@gmx.net>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm2711.dtsi | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -12,6 +12,26 @@
+
+ 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;
++ };
++ };
++
++
+ soc {
+ /*
+ * Defined ranges:
--- /dev/null
+From 32847947e1d1e1ac2a73c7ea8ad47cca49aef5d4 Mon Sep 17 00:00:00 2001
+From: Stefan Wahren <wahrenst@gmx.net>
+Date: Mon, 11 Nov 2019 20:49:26 +0100
+Subject: [PATCH] ARM: dts: bcm2711-rpi-4: Enable GENET support
+
+This enables the Gigabit Ethernet support on the Raspberry Pi 4.
+The defined PHY mode is equivalent to the default register settings
+in the downstream tree.
+
+Signed-off-by: Matthias Brugger <mbrugger@suse.com>
+Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 17 +++++++++++++++++
+ arch/arm/boot/dts/bcm2711.dtsi | 26 ++++++++++++++++++++++++++
+ 2 files changed, 43 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -19,6 +19,10 @@
+ reg = <0 0 0>;
+ };
+
++ aliases {
++ ethernet0 = &genet;
++ };
++
+ leds {
+ act {
+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+@@ -97,6 +101,19 @@
+ status = "okay";
+ };
+
++&genet {
++ phy-handle = <&phy1>;
++ phy-mode = "rgmii-rxid";
++ status = "okay";
++};
++
++&genet_mdio {
++ phy1: ethernet-phy@1 {
++ /* No PHY interrupt */
++ reg = <0x1>;
++ };
++};
++
+ /* uart0 communicates with the BT module */
+ &uart0 {
+ pinctrl-names = "default";
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -325,6 +325,32 @@
+ cpu-release-addr = <0x0 0x000000f0>;
+ };
+ };
++
++ scb {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <1>;
++
++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
++
++ genet: ethernet@7d580000 {
++ compatible = "brcm,bcm2711-genet-v5";
++ reg = <0x0 0x7d580000 0x10000>;
++ #address-cells = <0x1>;
++ #size-cells = <0x1>;
++ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++
++ genet_mdio: mdio@e14 {
++ compatible = "brcm,genet-mdio-v5";
++ reg = <0xe14 0x8>;
++ reg-names = "mdio";
++ #address-cells = <0x0>;
++ #size-cells = <0x1>;
++ };
++ };
++ };
+ };
+
+ &clk_osc {
+++ /dev/null
-From 66ca4b2544dbd4f10d8f387782f5c7200d1e2167 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 29 Jan 2020 09:35:19 +0000
-Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error
-
-Under some circumstances on BCM283x processors data loss can be
-observed - a single byte missing from the TX output stream. These bytes
-are always the last byte of a batch of 8 written from pl011_tx_chars
-when from_irq is true, meaning that the FIFO full flag is not checked
-before writing.
-
-The transmit optimisation relies on the FIFO being half-empty when the
-TX interrupt is raised. Instrumenting the driver further showed that
-the failure case correlated with the TX FIFO full flag being set at the
-point where the last byte was written to the data register, which
-explains the data loss but not how the FIFO appeared to be prematurely
-full. A possible explanation is that a FIFO write was in flight at the
-time the interrupt was raised, but as yet there is no hypothesis as to
-how this might occur.
-
-In the absence of a clear understanding of the failure mechanism, avoid
-the problem by checking the FIFO levels before writing the last byte of
-the group, which will have minimal performance impact.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- drivers/tty/serial/amba-pl011.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/tty/serial/amba-pl011.c
-+++ b/drivers/tty/serial/amba-pl011.c
-@@ -1444,6 +1444,10 @@ static bool pl011_tx_chars(struct uart_a
- if (likely(from_irq) && count-- == 0)
- break;
-
-+ if (likely(from_irq) && count == 0 &&
-+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
-+ break;
-+
- if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
- break;
-
--- /dev/null
+From 44d7ee4730fbe3c00aba0457489acd0b6e2937c9 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 4 Dec 2019 13:56:33 +0100
+Subject: [PATCH] ARM: dts: bcm2711: fix soc's node dma-ranges
+
+Raspberry Pi's firmware has a feature to select how much memory to
+reserve for its GPU called 'gpu_mem'. The possible values go from 16MB
+to 944MB, with a default of 64MB. This memory resides in the topmost
+part of the lower 1GB memory area and grows bigger expanding towards the
+begging of memory.
+
+It turns out that with low 'gpu_mem' values (16MB and 32MB) the size of
+the memory available to the system in the lower 1GB area can outgrow the
+interconnect's dma-range as its size was selected based on the maximum
+system memory available given the default gpu_mem configuration. This
+makes that memory slice unavailable for DMA. And may cause nasty kernel
+warnings if CMA happens to include it.
+
+Change soc's dma-ranges to really reflect it's HW limitation, which is
+being able to only DMA to the lower 1GB area.
+
+Fixes: 7dbe8c62ceeb ("ARM: dts: Add minimal Raspberry Pi 4 support")
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Phil Elwell <phil@raspberrypi.org>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm2711.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -43,7 +43,7 @@
+ <0x7c000000 0x0 0xfc000000 0x02000000>,
+ <0x40000000 0x0 0xff800000 0x00800000>;
+ /* Emulate a contiguous 30-bit address range for DMA */
+- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
++ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
+
+ /*
+ * This node is the provider for the enable-method for
+++ /dev/null
-From 333c4158645fe8aaacbd644bcdf7bc4c5b93cc26 Mon Sep 17 00:00:00 2001
-From: Tim Gover <990920+timg236@users.noreply.github.com>
-Date: Wed, 15 Jan 2020 11:26:19 +0000
-Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805
-
-The VL805 FW may either be loaded from an SPI EEPROM or alternatively
-loaded directly by the VideoCore firmware. A PCI reset will reset
-the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware
-to be reloaded if an SPI EEPROM is not present.
-
-Use a VideoCore mailbox to trigger the loading of the VL805
-firmware (if necessary) after a PCI reset.
-
-Signed-off-by: Tim Gover <tim.gover@raspberrypi.org>
----
- drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++-
- include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
- 2 files changed, 31 insertions(+), 2 deletions(-)
-
---- a/drivers/usb/host/pci-quirks.c
-+++ b/drivers/usb/host/pci-quirks.c
-@@ -18,7 +18,7 @@
- #include <linux/dmi.h>
- #include "pci-quirks.h"
- #include "xhci-ext-caps.h"
--
-+#include <soc/bcm2835/raspberrypi-firmware.h>
-
- #define UHCI_USBLEGSUP 0xc0 /* legacy support */
- #define UHCI_USBCMD 0 /* command register */
-@@ -634,6 +634,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port)
-
- #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
-
-+/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into
-+ * memory. If run from memory it must be reloaded after a PCI fundmental reset.
-+ * The Raspberry Pi firmware acts as the BIOS in this case.
-+ */
-+static void usb_vl805_init(struct pci_dev *pdev)
-+{
-+#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
-+ struct rpi_firmware *fw;
-+ struct {
-+ u32 dev_addr;
-+ } packet;
-+ int ret;
-+
-+ fw = rpi_firmware_get(NULL);
-+ if (!fw)
-+ return;
-+
-+ packet.dev_addr = (pdev->bus->number << 20) |
-+ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12);
-+
-+ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr);
-+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
-+ &packet, sizeof(packet));
-+#endif
-+}
-+
- #if IS_ENABLED(CONFIG_USB_UHCI_HCD)
-
- /*
-@@ -1222,6 +1248,9 @@ hc_init:
- if (pdev->vendor == PCI_VENDOR_ID_INTEL)
- usb_enable_intel_xhci_ports(pdev);
-
-+ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
-+ usb_vl805_init(pdev);
-+
- op_reg_base = base + XHCI_HC_LENGTH(readl(base));
-
- /* Wait for the host controller to be ready before writing any
---- a/include/soc/bcm2835/raspberrypi-firmware.h
-+++ b/include/soc/bcm2835/raspberrypi-firmware.h
-@@ -95,7 +95,7 @@ enum rpi_firmware_property_tag {
- RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
- RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
- RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
--
-+ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
-
- /* Dispmanx TAGS */
- RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
--- /dev/null
+From b229e7f5a6d21d1b52f3f19fed58bba638714884 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 30 Jan 2020 15:48:00 +0000
+Subject: [PATCH] ARM: dts: Rebuild downstream DTS files
+
+Refactor the tree of downstream DTS files to achieve approximately the
+same end result but wihout modifying upstream files (except for
+bcm2711-rpi-4-b.dts).
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 133 +--------
+ arch/arm/boot/dts/bcm2708.dtsi | 4 +
+ arch/arm/boot/dts/bcm2709.dtsi | 4 +
+ arch/arm/boot/dts/bcm270x-rpi.dtsi | 139 +++++++++
+ arch/arm/boot/dts/bcm270x.dtsi | 98 ++++---
+ arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 13 +
+ arch/arm/boot/dts/bcm2710.dtsi | 4 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 315 ++++++++++++++++++++-
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 222 +++++++++++++++
+ 9 files changed, 766 insertions(+), 166 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm270x-rpi.dtsi
+ create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -1,6 +1,7 @@
+-/* Downstream modifications to bcm2835-rpi.dtsi */
++/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */
+
+ #include "bcm2835-rpi.dtsi"
++#include "bcm270x-rpi.dtsi"
+
+ / {
+ memory@0 {
+@@ -9,147 +10,27 @@
+ };
+
+ aliases {
+- audio = &audio;
+- aux = &aux;
+- sound = &sound;
+- soc = &soc;
+- dma = &dma;
+- intc = &intc;
+- watchdog = &watchdog;
+- random = &random;
+- mailbox = &mailbox;
+- gpio = &gpio;
+- uart0 = &uart0;
+- sdhost = &sdhost;
+- mmc0 = &sdhost;
+- i2s = &i2s;
+- spi0 = &spi0;
+- i2c0 = &i2c0;
+- uart1 = &uart1;
+- spi1 = &spi1;
+- spi2 = &spi2;
+- mmc = &mmc;
+- mmc1 = &mmc;
+- i2c1 = &i2c1;
+ i2c2 = &i2c2;
+- usb = &usb;
+- leds = &leds;
+- fb = &fb;
+- thermal = &thermal;
+- axiperf = &axiperf;
+- };
+-
+- leds: leds {
+- compatible = "gpio-leds";
+- };
+-
+- soc {
+- gpiomem {
+- compatible = "brcm,bcm2835-gpiomem";
+- reg = <0x7e200000 0x1000>;
+- };
+-
+- fb: fb {
+- compatible = "brcm,bcm2708-fb";
+- firmware = <&firmware>;
+- status = "okay";
+- };
+-
+- vcsm: vcsm {
+- compatible = "raspberrypi,bcm2835-vcsm";
+- firmware = <&firmware>;
+- status = "okay";
+- };
+-
+- /* Onboard audio */
+- audio: audio {
+- compatible = "brcm,bcm2835-audio";
+- brcm,pwm-channels = <8>;
+- status = "disabled";
+- };
+-
+- /* External sound card */
+- sound: sound {
+- status = "disabled";
+- };
+ };
+
+ __overrides__ {
+- cache_line_size;
+-
+- uart0 = <&uart0>,"status";
+- uart1 = <&uart1>,"status";
+- i2s = <&i2s>,"status";
+- spi = <&spi0>,"status";
+- i2c0 = <&i2c0>,"status";
+- i2c1 = <&i2c1>,"status";
+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
+- i2c0_baudrate = <&i2c0>,"clock-frequency:0";
+- i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
+-
+- audio = <&audio>,"status";
+- watchdog = <&watchdog>,"status";
+- random = <&random>,"status";
+- sd_overclock = <&sdhost>,"brcm,overclock-50:0";
+- sd_poll_once = <&sdhost>,"non-removable?";
+- sd_force_pio = <&sdhost>,"brcm,force-pio?";
+- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+- sd_debug = <&sdhost>,"brcm,debug";
+- sdio_overclock = <&mmc>,"brcm,overclock-50:0",
+- <&mmcnr>,"brcm,overclock-50:0";
+- axiperf = <&axiperf>,"status";
++ sd_poll_once = <&sdhost>, "non-removable?";
+ };
+ };
+
+-&hdmi {
+- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
+- status = "disabled";
+-};
+-
+-&txp {
+- status = "disabled";
+-};
+-
+-&i2c0 {
+- status = "disabled";
+-};
+-
+-&i2c1 {
+- status = "disabled";
+-};
+-
+-&i2c2 {
+- status = "disabled";
+-};
+-
+-&clocks {
+- firmware = <&firmware>;
+-};
+-
+-&sdhci {
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio48>;
+- bus-width = <4>;
+-};
+-
+-sdhost_pins: &sdhost_gpio48 {
+- /* Add alias */
+-};
+-
+ &sdhost {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdhost_gpio48>;
+- bus-width = <4>;
+- brcm,overclock-50 = <0>;
+- brcm,pio-limit = <1>;
+ status = "okay";
+ };
+
+-&cpu_thermal {
+- /delete-node/ trips;
++&hdmi {
++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
++ status = "disabled";
+ };
+
+-&vec {
++&i2c2 {
+ status = "disabled";
+ };
+--- a/arch/arm/boot/dts/bcm2708.dtsi
++++ b/arch/arm/boot/dts/bcm2708.dtsi
+@@ -8,3 +8,7 @@
+ arm_freq;
+ };
+ };
++
++&vc4 {
++ status = "disabled";
++};
+--- a/arch/arm/boot/dts/bcm2709.dtsi
++++ b/arch/arm/boot/dts/bcm2709.dtsi
+@@ -16,3 +16,7 @@
+ <&v7_cpu3>, "clock-frequency:0";
+ };
+ };
++
++&vc4 {
++ status = "disabled";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi
+@@ -0,0 +1,139 @@
++/* Downstream modifications to bcm2835-rpi.dtsi */
++
++/ {
++ aliases {
++ audio = &audio;
++ aux = &aux;
++ sound = &sound;
++ soc = &soc;
++ dma = &dma;
++ intc = &intc;
++ watchdog = &watchdog;
++ random = &random;
++ mailbox = &mailbox;
++ gpio = &gpio;
++ uart0 = &uart0;
++ uart1 = &uart1;
++ sdhost = &sdhost;
++ mmc = &mmc;
++ mmc1 = &mmc;
++ mmc0 = &sdhost;
++ i2s = &i2s;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ spi0 = &spi0;
++ spi1 = &spi1;
++ spi2 = &spi2;
++ usb = &usb;
++ leds = &leds;
++ fb = &fb;
++ thermal = &thermal;
++ axiperf = &axiperf;
++ };
++
++ /* Define these notional regulators for use by overlays */
++ vdd_3v3_reg: fixedregulator_3v3 {
++ compatible = "regulator-fixed";
++ regulator-always-on;
++ regulator-max-microvolt = <3300000>;
++ regulator-min-microvolt = <3300000>;
++ regulator-name = "3v3";
++ };
++
++ vdd_5v0_reg: fixedregulator_5v0 {
++ compatible = "regulator-fixed";
++ regulator-always-on;
++ regulator-max-microvolt = <5000000>;
++ regulator-min-microvolt = <5000000>;
++ regulator-name = "5v0";
++ };
++
++ leds: leds {
++ compatible = "gpio-leds";
++ };
++
++ soc {
++ gpiomem {
++ compatible = "brcm,bcm2835-gpiomem";
++ reg = <0x7e200000 0x1000>;
++ };
++
++ fb: fb {
++ compatible = "brcm,bcm2708-fb";
++ firmware = <&firmware>;
++ status = "okay";
++ };
++
++ vcsm: vcsm {
++ compatible = "raspberrypi,bcm2835-vcsm";
++ firmware = <&firmware>;
++ status = "okay";
++ };
++
++ /* Onboard audio */
++ audio: audio {
++ compatible = "brcm,bcm2835-audio";
++ brcm,pwm-channels = <8>;
++ status = "disabled";
++ };
++
++ /* External sound card */
++ sound: sound {
++ status = "disabled";
++ };
++ };
++
++ __overrides__ {
++ cache_line_size;
++
++ uart0 = <&uart0>,"status";
++ uart1 = <&uart1>,"status";
++ i2s = <&i2s>,"status";
++ spi = <&spi0>,"status";
++ i2c0 = <&i2c0>,"status";
++ i2c1 = <&i2c1>,"status";
++ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
++ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
++
++ audio = <&audio>,"status";
++ watchdog = <&watchdog>,"status";
++ random = <&random>,"status";
++ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_force_pio = <&sdhost>,"brcm,force-pio?";
++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
++ sd_debug = <&sdhost>,"brcm,debug";
++ sdio_overclock = <&mmc>,"brcm,overclock-50:0",
++ <&mmcnr>,"brcm,overclock-50:0";
++ axiperf = <&axiperf>,"status";
++ };
++};
++
++&txp {
++ status = "disabled";
++};
++
++&i2c0 {
++ status = "disabled";
++};
++
++&i2c1 {
++ status = "disabled";
++};
++
++&clocks {
++ firmware = <&firmware>;
++};
++
++&sdhci {
++ pinctrl-names = "default";
++ pinctrl-0 = <&emmc_gpio48>;
++ bus-width = <4>;
++};
++
++&cpu_thermal {
++ /delete-node/ trips;
++};
++
++&vec {
++ status = "disabled";
++};
+--- a/arch/arm/boot/dts/bcm270x.dtsi
++++ b/arch/arm/boot/dts/bcm270x.dtsi
+@@ -17,32 +17,8 @@
+ /* Add label */
+ };
+
+- gpio@7e200000 { /* gpio */
+- interrupts = <2 17>, <2 18>;
+-
+- dpi_18bit_gpio0: dpi_18bit_gpio0 {
+- brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
+- 12 13 14 15 16 17 18 19
+- 20 21>;
+- brcm,function = <BCM2835_FSEL_ALT2>;
+- };
+- };
+-
+- serial@7e201000 { /* uart0 */
+- /* Enable CTS bug workaround */
+- cts-event-workaround;
+- };
+-
+- i2s@7e203000 { /* i2s */
+- #sound-dai-cells = <0>;
+- reg = <0x7e203000 0x24>;
+- clocks = <&clocks BCM2835_CLOCK_PCM>;
+- };
+-
+ spi0: spi@7e204000 {
+ /* Add label */
+- dmas = <&dma 6>, <&dma 7>;
+- dma-names = "tx", "rx";
+ };
+
+ pixelvalve0: pixelvalve@7e206000 {
+@@ -55,17 +31,6 @@
+ status = "disabled";
+ };
+
+- 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>;
+- status = "disabled";
+- };
+-
+ /delete-node/ sdhci@7e300000;
+
+ sdhci: mmc: mmc@7e300000 {
+@@ -118,6 +83,34 @@
+ status = "disabled";
+ };
+
++ csi0: csi@7e800000 {
++ compatible = "brcm,bcm2835-unicam";
++ reg = <0x7e800000 0x800>,
++ <0x7e802000 0x4>;
++ interrupts = <2 6>;
++ clocks = <&clocks BCM2835_CLOCK_CAM0>;
++ clock-names = "lp";
++ power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #clock-cells = <1>;
++ status = "disabled";
++ };
++
++ csi1: csi@7e801000 {
++ compatible = "brcm,bcm2835-unicam";
++ reg = <0x7e801000 0x800>,
++ <0x7e802004 0x4>;
++ interrupts = <2 7>;
++ clocks = <&clocks BCM2835_CLOCK_CAM1>;
++ clock-names = "lp";
++ power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #clock-cells = <1>;
++ status = "disabled";
++ };
++
+ pixelvalve2: pixelvalve@7e807000 {
+ /* Add label */
+ status = "disabled";
+@@ -160,6 +153,37 @@
+ };
+ };
+
+-&vc4 {
+- status = "disabled";
++&gpio {
++ interrupts = <2 17>, <2 18>;
++
++ dpi_18bit_gpio0: dpi_18bit_gpio0 {
++ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
++ 12 13 14 15 16 17 18 19
++ 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT2>;
++ };
++};
++
++&uart0 {
++ /* Enable CTS bug workaround */
++ cts-event-workaround;
++};
++
++&i2s {
++ #sound-dai-cells = <0>;
++ dmas = <&dma 2>, <&dma 3>;
++ dma-names = "tx", "rx";
++};
++
++&sdhost {
++ dmas = <&dma (13|(1<<29))>;
++ dma-names = "rx-tx";
++ bus-width = <4>;
++ brcm,overclock-50 = <0>;
++ brcm,pio-limit = <1>;
++};
++
++&spi0 {
++ dmas = <&dma 6>, <&dma 7>;
++ dma-names = "tx", "rx";
+ };
+--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
+@@ -170,6 +170,12 @@
+ pinctrl-0 = <&audio_pins>;
+ };
+
++ð_phy {
++ microchip,eee-enabled;
++ microchip,tx-lpi-timer = <600>; /* non-aggressive*/
++ microchip,downshift-after = <2>;
++};
++
+ / {
+ __overrides__ {
+ act_led_gpio = <&act_led>,"gpios:4";
+@@ -179,5 +185,12 @@
+ pwr_led_gpio = <&pwr_led>,"gpios:4";
+ pwr_led_activelow = <&pwr_led>,"gpios:8";
+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ eee = <ð_phy>,"microchip,eee-enabled?";
++ tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0";
++ eth_led0 = <ð_phy>,"microchip,led-modes:0";
++ eth_led1 = <ð_phy>,"microchip,led-modes:4";
++ eth_downshift_after = <ð_phy>,"microchip,downshift-after:0";
++ eth_max_speed = <ð_phy>,"max-speed:0";
+ };
+ };
+--- a/arch/arm/boot/dts/bcm2710.dtsi
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -23,3 +23,7 @@
+ <&cpu3>, "clock-frequency:0";
+ };
+ };
++
++&vc4 {
++ status = "disabled";
++};
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -2,7 +2,6 @@
+ /dts-v1/;
+ #include "bcm2711.dtsi"
+ #include "bcm2835-rpi.dtsi"
+-#include "bcm283x-rpi-usb-peripheral.dtsi"
+
+ / {
+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+@@ -65,8 +64,8 @@
+ "GLOBAL_RESET",
+ "VDD_SD_IO_SEL",
+ "CAM_GPIO",
+- "",
+- "";
++ "SD_PWR_ON",
++ "SD_OC_N";
+ status = "okay";
+ };
+ };
+@@ -138,3 +137,313 @@
+ &vchiq {
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ };
++
++// =============================================
++// Downstream rpi- changes
++
++#include "bcm270x.dtsi"
++#include "bcm2711-rpi.dtsi"
++#include "bcm283x-rpi-csi1-2lane.dtsi"
++
++/ {
++ chosen {
++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
++ };
++
++ aliases {
++ serial0 = &uart1;
++ serial1 = &uart0;
++ mmc0 = &emmc2;
++ mmc1 = &mmcnr;
++ mmc2 = &sdhost;
++ /delete-property/ i2c2;
++ i2c3 = &i2c3;
++ i2c4 = &i2c4;
++ i2c5 = &i2c5;
++ i2c6 = &i2c6;
++ /delete-property/ ethernet;
++ /delete-property/ intc;
++ pcie0 = &pcie_0;
++ };
++
++ /delete-node/ wifi-pwrseq;
++};
++
++&mmcnr {
++ pinctrl-names = "default";
++ pinctrl-0 = <&sdio_pins>;
++ bus-width = <4>;
++ status = "okay";
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pins &bt_pins>;
++ status = "okay";
++
++ /delete-node/ bluetooth;
++};
++
++&uart1 {
++ pinctrl-0 = <&uart1_pins>;
++};
++
++&spi0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
++
++ spidev0: spidev@0{
++ compatible = "spidev";
++ reg = <0>; /* CE0 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ };
++
++ spidev1: spidev@1{
++ compatible = "spidev";
++ reg = <1>; /* CE1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ spi-max-frequency = <125000000>;
++ };
++};
++
++&gpio {
++ spi0_pins: spi0_pins {
++ brcm,pins = <9 10 11>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ spi0_cs_pins: spi0_cs_pins {
++ brcm,pins = <8 7>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi3_pins: spi3_pins {
++ brcm,pins = <1 2 3>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi3_cs_pins: spi3_cs_pins {
++ brcm,pins = <0 24>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi4_pins: spi4_pins {
++ brcm,pins = <5 6 7>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi4_cs_pins: spi4_cs_pins {
++ brcm,pins = <4 25>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi5_pins: spi5_pins {
++ brcm,pins = <13 14 15>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi5_cs_pins: spi5_cs_pins {
++ brcm,pins = <12 26>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ spi6_pins: spi6_pins {
++ brcm,pins = <19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ };
++
++ spi6_cs_pins: spi6_cs_pins {
++ brcm,pins = <18 27>;
++ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
++ };
++
++ i2c0_pins: i2c0 {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2c1_pins: i2c1 {
++ brcm,pins = <2 3>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2c3_pins: i2c3 {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2c4_pins: i2c4 {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2c5_pins: i2c5 {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2c6_pins: i2c6 {
++ brcm,pins = <22 23>;
++ brcm,function = <BCM2835_FSEL_ALT5>;
++ brcm,pull = <BCM2835_PUD_UP>;
++ };
++
++ i2s_pins: i2s {
++ brcm,pins = <18 19 20 21>;
++ brcm,function = <BCM2835_FSEL_ALT0>;
++ };
++
++ sdio_pins: sdio_pins {
++ brcm,pins = <34 35 36 37 38 39>;
++ brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
++ brcm,pull = <0 2 2 2 2 2>;
++ };
++
++ bt_pins: bt_pins {
++ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
++ // to fool pinctrl
++ brcm,function = <0>;
++ brcm,pull = <2>;
++ };
++
++ uart0_pins: uart0_pins {
++ brcm,pins = <32 33>;
++ brcm,function = <BCM2835_FSEL_ALT3>;
++ brcm,pull = <0 2>;
++ };
++
++ uart1_pins: uart1_pins {
++ brcm,pins;
++ brcm,function;
++ brcm,pull;
++ };
++
++ uart2_pins: uart2_pins {
++ brcm,pins = <0 1>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart3_pins: uart3_pins {
++ brcm,pins = <4 5>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart4_pins: uart4_pins {
++ brcm,pins = <8 9>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++
++ uart5_pins: uart5_pins {
++ brcm,pins = <12 13>;
++ brcm,function = <BCM2835_FSEL_ALT4>;
++ brcm,pull = <0 2>;
++ };
++};
++
++&i2c0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2c1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins>;
++ clock-frequency = <100000>;
++};
++
++&i2s {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2s_pins>;
++};
++
++/ {
++ __overrides__ {
++ /delete-property/ i2c2_baudrate;
++ /delete-property/ i2c2_iknowwhatimdoing;
++ };
++};
++
++// =============================================
++// Board specific stuff here
++
++/ {
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++&sdhost {
++ status = "disabled";
++};
++
++&emmc2 {
++ vmmc-supply = <&sd_vcc_reg>;
++};
++
++&phy1 {
++ led-modes = <0x00 0x08>; /* link/activity link */
++};
++
++&gpio {
++ audio_pins: audio_pins {
++ brcm,pins = <40 41>;
++ brcm,function = <4>;
++ };
++};
++
++&leds {
++ act_led: act {
++ label = "led0";
++ linux,default-trigger = "mmc0";
++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
++ };
++
++ pwr_led: pwr {
++ label = "led1";
++ linux,default-trigger = "default-on";
++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
++ };
++};
++
++&pwm1 {
++ status = "disabled";
++};
++
++&audio {
++ pinctrl-names = "default";
++ pinctrl-0 = <&audio_pins>;
++};
++
++/ {
++ __overrides__ {
++ act_led_gpio = <&act_led>,"gpios:4";
++ act_led_activelow = <&act_led>,"gpios:8";
++ act_led_trigger = <&act_led>,"linux,default-trigger";
++
++ pwr_led_gpio = <&pwr_led>,"gpios:4";
++ pwr_led_activelow = <&pwr_led>,"gpios:8";
++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
++
++ eth_led0 = <&phy1>,"led-modes:0";
++ eth_led1 = <&phy1>,"led-modes:4";
++
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -0,0 +1,222 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "bcm270x-rpi.dtsi"
++
++/ {
++ soc {
++ /delete-node/ v3d@7ec00000;
++ /delete-node/ mailbox@7e00b840;
++ };
++
++ __overrides__ {
++ arm_freq;
++ sd_poll_once = <&emmc2>, "non-removable?";
++ };
++
++ v3dbus {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <2>;
++ ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>,
++ <0x40000000 0x0 0xff800000 0x0 0x00800000>;
++ dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>;
++
++ v3d: v3d@7ec04000 {
++ compatible = "brcm,2711-v3d";
++ reg =
++ <0x7ec00000 0x0 0x4000>,
++ <0x7ec04000 0x0 0x4000>;
++ reg-names = "hub", "core0";
++
++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
++ resets = <&pm BCM2835_RESET_V3D>;
++ clocks = <&clocks BCM2835_CLOCK_V3D>;
++ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++ };
++
++ scb: scb {
++ /* Add a label */
++ };
++};
++
++&soc {
++ thermal: thermal@7d5d2200 {
++ compatible = "brcm,avs-tmon-bcm2838";
++ reg = <0x7d5d2200 0x2c>;
++ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "tmon";
++ clocks = <&clocks BCM2835_CLOCK_TSENS>;
++ #thermal-sensor-cells = <0>;
++ status = "okay";
++ };
++
++ vc4: gpu {
++ compatible = "brcm,bcm2835-vc4";
++ status = "disabled";
++ };
++};
++
++&scb {
++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
++ <0x0 0x40000000 0x0 0xff800000 0x00800000>,
++ <0x6 0x00000000 0x6 0x00000000 0x40000000>,
++ <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
++ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
++
++ pcie_0: pcie@7d500000 {
++ reg = <0x0 0x7d500000 0x9310>,
++ <0x0 0x7e00f300 0x20>;
++ msi-controller;
++ msi-parent = <&pcie_0>;
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ bus-range = <0x0 0x01>;
++ compatible = "brcm,bcm2711b0-pcie", // Safe value
++ "brcm,bcm2711-pcie",
++ "brcm,pci-plat-dev";
++ max-link-speed = <2>;
++ tot-num-pcie = <1>;
++ linux,pci-domain = <0>;
++ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 2 &gicv2 GIC_SPI 144
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 3 &gicv2 GIC_SPI 145
++ IRQ_TYPE_LEVEL_HIGH
++ 0 0 0 4 &gicv2 GIC_SPI 146
++ IRQ_TYPE_LEVEL_HIGH>;
++
++ /* Map outbound accesses from scb:0x6_00000000-03ffffff
++ * to pci:0x0_f8000000-fbffffff
++ */
++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
++ 0x0 0x04000000>;
++ /* Map inbound accesses from pci:0x0_00000000..ffffffff
++ * to scb:0x0_00000000-ffffffff
++ */
++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
++ 0x1 0x00000000>;
++ status = "okay";
++ };
++
++ dma40: dma@7e007b00 {
++ compatible = "brcm,bcm2838-dma";
++ reg = <0x0 0x7e007b00 0x400>;
++ interrupts =
++ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
++ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
++ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
++ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
++ interrupt-names = "dma11",
++ "dma12",
++ "dma13",
++ "dma14";
++ #dma-cells = <1>;
++ brcm,dma-channel-mask = <0x7800>;
++ };
++
++ vchiq: mailbox@7e00b840 {
++ compatible = "brcm,bcm2838-vchiq";
++ reg = <0 0x7e00b840 0x3c>;
++ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ xhci: xhci@7e9c0000 {
++ compatible = "generic-xhci";
++ status = "disabled";
++ reg = <0x0 0x7e9c0000 0x100000>;
++ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ hevc-decoder@7eb00000 {
++ compatible = "raspberrypi,rpivid-hevc-decoder";
++ reg = <0x0 0x7eb00000 0x10000>;
++ status = "okay";
++ };
++
++ rpivid-local-intc@7eb10000 {
++ compatible = "raspberrypi,rpivid-local-intc";
++ reg = <0x0 0x7eb10000 0x1000>;
++ status = "okay";
++ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ h264-decoder@7eb20000 {
++ compatible = "raspberrypi,rpivid-h264-decoder";
++ reg = <0x0 0x7eb20000 0x10000>;
++ status = "okay";
++ };
++
++ vp9-decoder@7eb30000 {
++ compatible = "raspberrypi,rpivid-vp9-decoder";
++ reg = <0x0 0x7eb30000 0x10000>;
++ status = "okay";
++ };
++};
++
++&dma {
++ /* The VPU firmware uses DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x1f5>;
++};
++
++&dma40 {
++ /* The VPU firmware DMA channel 11 for VCHIQ */
++ brcm,dma-channel-mask = <0x7000>;
++};
++
++&firmwarekms {
++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&smi {
++ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mmc {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&mmcnr {
++ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&csi0 {
++ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&csi1 {
++ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&random {
++ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
++ status = "okay";
++};
++
++&usb {
++ /* Enable the FIQ support */
++ reg = <0x7e980000 0x10000>,
++ <0x7e00b200 0x200>;
++ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++};
++
++&gpio {
++ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
++};
++
++&cpu_thermal {
++ thermal-sensors = <&thermal>;
++};
++
++&genet {
++ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
++};
+++ /dev/null
-From b058c3c898472ad8799bba29365c3295fdd24970 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Wed, 29 Jan 2020 14:32:51 +0000
-Subject: [PATCH] overlays: Correct the eth_led* colour assignments
-
-See: https://github.com/raspberrypi/firmware/issues/1311
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/overlays/README | 17 +++++++++--------
- 1 file changed, 9 insertions(+), 8 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -109,27 +109,28 @@ Params:
- Legal values are 2, 3, 4, 5 and 0, where
- 0 means never downshift (default 2). Pi3B+ only.
-
-- eth_led0 Set mode of LED0 (usually orange). The legal
-- values are:
-+ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"),
-+ green on Pi4 (default "0").
-+ The legal values are:
-
- Pi3B+
-
-- 0=link/activity 1=link1000/activity (default)
-+ 0=link/activity 1=link1000/activity
- 2=link100/activity 3=link10/activity
- 4=link100/1000/activity 5=link10/1000/activity
- 6=link10/100/activity 14=off 15=on
-
- Pi4
-
-- 0=Speed/Activity (default) 1=Speed
-- 2=Speed/Flash activity 3=FDX
-+ 0=Speed/Activity 1=Speed
-+ 2=Flash activity 3=FDX
- 4=Off 5=On
- 6=Alt 7=Speed/Flash
- 8=Link 9=Activity
-
-- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
-- "6", Pi4 default "8"). See eth_led0 for legal
-- values.
-+ eth_led1 Set mode of LED1 - green on Pi3B (default "6"),
-+ amber on Pi4 (default "8"). See eth_led0 for
-+ legal values.
-
- eth_max_speed Set the maximum speed a link is allowed
- to negotiate. Legal values are 10, 100 and
+++ /dev/null
-From 3ef2bbe381adc17d135f8f9b22a43a242eb80c63 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.org>
-Date: Thu, 30 Jan 2020 09:47:00 +0000
-Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711
-
-The old sdtweak overlay allowed the SD interface to be effectively
-disabled unless there was a card present at boot time, but that
-overlay doesn't work on bcm2711 and has largely been replaced by
-a set of sd_* dtparams (which have the advantage of being board-
-specific.
-
-Add an sd_poll_once dtparam to allow the same functionality on
-all Raspberry Pi boards.
-
-See: https://github.com/raspberrypi/linux/issues/3286
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.org>
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++
- arch/arm/boot/dts/overlays/README | 7 +++++++
- 3 files changed, 10 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -92,6 +92,7 @@
- watchdog = <&watchdog>,"status";
- random = <&random>,"status";
- sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_poll_once = <&sdhost>,"non-removable?";
- sd_force_pio = <&sdhost>,"brcm,force-pio?";
- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
- sd_debug = <&sdhost>,"brcm,debug";
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -363,5 +363,7 @@
-
- eth_led0 = <&phy1>,"led-modes:0";
- eth_led1 = <&phy1>,"led-modes:4";
-+
-+ sd_poll_once = <&emmc2>, "non-removable?";
- };
- };
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -165,6 +165,13 @@ Params:
- sd_overclock Clock (in MHz) to use when the MMC framework
- requests 50MHz
-
-+ sd_poll_once Looks for a card once after booting. Useful
-+ for network booting scenarios to avoid the
-+ overhead of continuous polling. N.B. Using
-+ this option restricts the system to using a
-+ single card per boot (or none at all).
-+ (default off)
-+
- sd_force_pio Disable DMA support for SD driver (default off)
-
- sd_pio_limit Number of blocks above which to use DMA for
--- /dev/null
+From 871370c31c23fcd07ec375a088bd09a0a5a31126 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 31 Jan 2020 09:26:18 +0000
+Subject: [PATCH] staging/vchiq_arm: Fix bcm2711 compatible string
+
+Fixes: "vchiq: Add 36-bit address support"
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -151,7 +151,7 @@ static struct vchiq_drvdata bcm2836_drvd
+ .cache_line_size = 64,
+ };
+
+-static struct vchiq_drvdata bcm2838_drvdata = {
++static struct vchiq_drvdata bcm2711_drvdata = {
+ .cache_line_size = 64,
+ .use_36bit_addrs = true,
+ };
+@@ -3171,7 +3171,7 @@ void vchiq_platform_conn_state_changed(s
+ static const struct of_device_id vchiq_of_match[] = {
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
+- { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
++ { .compatible = "brcm,bcm2711-vchiq", .data = &bcm2711_drvdata },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, vchiq_of_match);
+++ /dev/null
-From fe90ee51b283f7cbbce9980b76b3da8b31d39c60 Mon Sep 17 00:00:00 2001
-From: MikeDK <m.kaplan@evva.com>
-Date: Fri, 31 Jan 2020 10:57:21 +0100
-Subject: [PATCH] overlays: Add ssd1306-spi, ssh1106-spi, ssd-1351-spi
-
-Add overlays for SSD1306, SH1106 and SSD1351 based OLED displays.
-SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in
-1.5 inch RGB OLEDs from AliExpress.
-
-This will load the staging fbtft drivers.
-
-Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
----
- arch/arm/boot/dts/overlays/Makefile | 3 +
- arch/arm/boot/dts/overlays/README | 35 ++++++++
- .../boot/dts/overlays/sh1106-spi-overlay.dts | 84 +++++++++++++++++++
- .../boot/dts/overlays/ssd1306-spi-overlay.dts | 84 +++++++++++++++++++
- .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 ++++++++++++++++++
- 5 files changed, 289 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
- create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- sdhost.dtbo \
- sdio.dtbo \
- sdtweak.dtbo \
-+ sh1106-spi.dtbo \
- smi.dtbo \
- smi-dev.dtbo \
- smi-nand.dtbo \
-@@ -168,6 +169,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- spi6-1cs.dtbo \
- spi6-2cs.dtbo \
- ssd1306.dtbo \
-+ ssd1306-spi.dtbo \
-+ ssd1351-spi.dtbo \
- superaudioboard.dtbo \
- sx150x.dtbo \
- tc358743.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i
- (default on)
-
-
-+Name: sh1106-spi
-+Info: Overlay for SH1106 OLED via SPI using fbtft staging driver.
-+Load: dtoverlay=sh1106-spi,<param>=<val>
-+Params: speed SPI bus speed (default 4000000)
-+ rotate Display rotation (0, 90, 180 or 270; default 0)
-+ fps Delay between frame updates (default 25)
-+ debug Debug output level (0-7; default 0)
-+ dc_pin GPIO pin for D/C (default 24)
-+ reset_pin GPIO pin for RESET (default 25)
-+ height Display height (32 or 64; default 64)
-+
-+
- Name: smi
- Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
- Load: dtoverlay=smi
-@@ -2428,6 +2440,29 @@ Params: address Location
- https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
-
-
-+Name: ssd1306-spi
-+Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver.
-+Load: dtoverlay=ssd1306-spi,<param>=<val>
-+Params: speed SPI bus speed (default 10000000)
-+ rotate Display rotation (0, 90, 180 or 270; default 0)
-+ fps Delay between frame updates (default 25)
-+ debug Debug output level (0-7; default 0)
-+ dc_pin GPIO pin for D/C (default 24)
-+ reset_pin GPIO pin for RESET (default 25)
-+ height Display height (32 or 64; default 64)
-+
-+
-+Name: ssd1351-spi
-+Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver.
-+Load: dtoverlay=ssd1351-spi,<param>=<val>
-+Params: speed SPI bus speed (default 4500000)
-+ rotate Display rotation (0, 90, 180 or 270; default 0)
-+ fps Delay between frame updates (default 25)
-+ debug Debug output level (0-7; default 0)
-+ dc_pin GPIO pin for D/C (default 24)
-+ reset_pin GPIO pin for RESET (default 25)
-+
-+
- Name: superaudioboard
- Info: Configures the SuperAudioBoard sound card
- Load: dtoverlay=superaudioboard,<param>=<val>
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
-@@ -0,0 +1,84 @@
-+/*
-+ * Device Tree overlay for SH1106 based SPI OLED display
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev0>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spidev1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ sh1106_pins: sh1106_pins {
-+ brcm,pins = <25 24>;
-+ brcm,function = <1 1>; /* out out */
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ sh1106: sh1106@0{
-+ compatible = "sinowealth,sh1106";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sh1106_pins>;
-+
-+ spi-max-frequency = <4000000>;
-+ bgr = <0>;
-+ bpp = <1>;
-+ rotate = <0>;
-+ fps = <25>;
-+ buswidth = <8>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ debug = <0>;
-+
-+ sinowealth,height = <64>;
-+ sinowealth,width = <128>;
-+ sinowealth,page-offset = <0>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&sh1106>,"spi-max-frequency:0";
-+ rotate = <&sh1106>,"rotate:0";
-+ fps = <&sh1106>,"fps:0";
-+ debug = <&sh1106>,"debug:0";
-+ dc_pin = <&sh1106>,"dc-gpios:4",
-+ <&sh1106_pins>,"brcm,pins:4";
-+ reset_pin = <&sh1106>,"reset-gpios:4",
-+ <&sh1106_pins>,"brcm,pins:0";
-+ height = <&sh1106>,"sinowealth,height:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
-@@ -0,0 +1,84 @@
-+/*
-+ * Device Tree overlay for SSD1306 based SPI OLED display
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev0>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spidev1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ ssd1306_pins: ssd1306_pins {
-+ brcm,pins = <25 24>;
-+ brcm,function = <1 1>; /* out out */
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ssd1306: ssd1306@0{
-+ compatible = "solomon,ssd1306";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&ssd1306_pins>;
-+
-+ spi-max-frequency = <10000000>;
-+ bgr = <0>;
-+ bpp = <1>;
-+ rotate = <0>;
-+ fps = <25>;
-+ buswidth = <8>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ debug = <0>;
-+
-+ solomon,height = <64>;
-+ solomon,width = <128>;
-+ solomon,page-offset = <0>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&ssd1306>,"spi-max-frequency:0";
-+ rotate = <&ssd1306>,"rotate:0";
-+ fps = <&ssd1306>,"fps:0";
-+ debug = <&ssd1306>,"debug:0";
-+ dc_pin = <&ssd1306>,"dc-gpios:4",
-+ <&ssd1306_pins>,"brcm,pins:4";
-+ reset_pin = <&ssd1306>,"reset-gpios:4",
-+ <&ssd1306_pins>,"brcm,pins:0";
-+ height = <&ssd1306>,"solomon,height:0";
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
-@@ -0,0 +1,83 @@
-+/*
-+ * Device Tree overlay for SSD1351 based SPI OLED display
-+ *
-+ */
-+
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@0 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ fragment@1 {
-+ target = <&spidev0>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@2 {
-+ target = <&spidev1>;
-+ __overlay__ {
-+ status = "disabled";
-+ };
-+ };
-+
-+ fragment@3 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ ssd1351_pins: ssd1351_pins {
-+ brcm,pins = <25 24>;
-+ brcm,function = <1 1>; /* out out */
-+ };
-+ };
-+ };
-+
-+ fragment@4 {
-+ target = <&spi0>;
-+ __overlay__ {
-+ /* needed to avoid dtc warning */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ ssd1351: ssd1351@0{
-+ compatible = "solomon,ssd1351";
-+ reg = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&ssd1351_pins>;
-+
-+ spi-max-frequency = <4500000>;
-+ bgr = <0>;
-+ bpp = <16>;
-+ rotate = <0>;
-+ fps = <25>;
-+ buswidth = <8>;
-+ reset-gpios = <&gpio 25 0>;
-+ dc-gpios = <&gpio 24 0>;
-+ debug = <0>;
-+
-+ solomon,height = <128>;
-+ solomon,width = <128>;
-+ solomon,page-offset = <0>;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ speed = <&ssd1351>,"spi-max-frequency:0";
-+ rotate = <&ssd1351>,"rotate:0";
-+ fps = <&ssd1351>,"fps:0";
-+ debug = <&ssd1351>,"debug:0";
-+ dc_pin = <&ssd1351>,"dc-gpios:4",
-+ <&ssd1351_pins>,"brcm,pins:4";
-+ reset_pin = <&ssd1351>,"reset-gpios:4",
-+ <&ssd1351_pins>,"brcm,pins:0";
-+ };
-+};
--- /dev/null
+From 9367715671c271913278a4abb43276d02ff954d6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 31 Jan 2020 09:33:40 +0000
+Subject: [PATCH] thermal: brcmstb_thermal: Correct SoC name
+
+The Pi 4 SoC is called BCM2711, not BCM2838.
+
+Fixes: "thermal: brcmstb_thermal: Add BCM2838 support"
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/thermal/broadcom/brcmstb_thermal.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/thermal/broadcom/brcmstb_thermal.c
++++ b/drivers/thermal/broadcom/brcmstb_thermal.c
+@@ -290,7 +290,7 @@ static const struct thermal_zone_of_devi
+ .set_trips = brcmstb_set_trips,
+ };
+
+-static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
++static const struct thermal_zone_of_device_ops bcm2711_thermal_of_ops = {
+ .get_temp = brcmstb_get_temp,
+ };
+
+@@ -301,8 +301,8 @@ static const struct brcmstb_thermal_of_d
+ .status_data_shift = 1,
+ };
+
+-static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
+- .of_ops = &bcm2838_thermal_of_ops,
++static const struct brcmstb_thermal_of_data bcm2711_thermal_of_data = {
++ .of_ops = &bcm2711_thermal_of_ops,
+ .status_valid_mask = BIT(10),
+ .status_data_mask = GENMASK(9, 0),
+ .status_data_shift = 0,
+@@ -311,8 +311,8 @@ static const struct brcmstb_thermal_of_d
+ static const struct of_device_id brcmstb_thermal_id_table[] = {
+ { .compatible = "brcm,avs-tmon",
+ .data = &bcm7445_thermal_of_data },
+- { .compatible = "brcm,avs-tmon-bcm2838",
+- .data = &bcm2838_thermal_of_data },
++ { .compatible = "brcm,avs-tmon-bcm2711",
++ .data = &bcm2711_thermal_of_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
--- /dev/null
+From 5eafa5065b2ea2c8d1634f045b85b982393d808a Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 31 Jan 2020 09:36:57 +0000
+Subject: [PATCH] hwrng: iproc-rng200: Correct SoC name
+
+The Pi 4 SoC is called BCM2711, not BCM2838.
+
+Fixes: "hwrng: iproc-rng200: Add BCM2838 support"
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/char/hw_random/Kconfig | 2 +-
+ drivers/char/hw_random/iproc-rng200.c | 11 +++++------
+ 2 files changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -94,7 +94,7 @@ config HW_RANDOM_IPROC_RNG200
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the RNG200
+- hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
++ hardware found on the Broadcom iProc, BCM2711 and STB SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iproc-rng200
+--- a/drivers/char/hw_random/iproc-rng200.c
++++ b/drivers/char/hw_random/iproc-rng200.c
+@@ -174,7 +174,7 @@ static int iproc_rng200_init(struct hwrn
+ return 0;
+ }
+
+-static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
++static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+ {
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+@@ -211,7 +211,7 @@ static int bcm2838_rng200_read(struct hw
+ return num_words * sizeof(u32);
+ }
+
+-static int bcm2838_rng200_init(struct hwrng *rng)
++static int bcm2711_rng200_init(struct hwrng *rng)
+ {
+ struct iproc_rng200_dev *priv = to_rng_priv(rng);
+ uint32_t val;
+@@ -271,9 +271,9 @@ static int iproc_rng200_probe(struct pla
+ priv->rng.name = pdev->name;
+ priv->rng.cleanup = iproc_rng200_cleanup;
+
+- if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
+- priv->rng.init = bcm2838_rng200_init;
+- priv->rng.read = bcm2838_rng200_read;
++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) {
++ priv->rng.init = bcm2711_rng200_init;
++ priv->rng.read = bcm2711_rng200_read;
+ } else {
+ priv->rng.init = iproc_rng200_init;
+ priv->rng.read = iproc_rng200_read;
+@@ -296,7 +296,6 @@ static const struct of_device_id iproc_r
+ { .compatible = "brcm,bcm7211-rng200", },
+ { .compatible = "brcm,bcm7278-rng200", },
+ { .compatible = "brcm,iproc-rng200", },
+- { .compatible = "brcm,bcm2838-rng200"},
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
+++ /dev/null
-From 1257716d9bae9730c43c636046983f5d80c4efc8 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Tue, 4 Feb 2020 13:03:21 +0000
-Subject: [PATCH] overlays: dwc2: Increase RX FIFO size
-
-The previous version of the dwc2 overlay set the RX FIFO size to
-256 4-byte words. This sounds large enough for a 1024 byte packet (the
-largest isochronous high speed packet allowed), but it doesn't take
-into account some extra space needed by the hardware.
-
-Minas Harutyunyan at Synopsys (the source of the DWC OTG design)
-came up with a more correct value, 301, but since there is spare packet
-RAM this can be increased to 558 to allow two packets per frame.
-
-Also update the upstream overlay to match.
-
-See: https://github.com/raspberrypi/linux/issues/3447
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
-@@ -12,7 +12,7 @@
- compatible = "brcm,bcm2835-usb";
- dr_mode = "otg";
- g-np-tx-fifo-size = <32>;
-- g-rx-fifo-size = <256>;
-+ g-rx-fifo-size = <558>;
- g-tx-fifo-size = <512 512 512 512 512 256 256>;
- status = "okay";
- };
---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts
-@@ -123,7 +123,7 @@
- compatible = "brcm,bcm2835-usb";
- dr_mode = "otg";
- g-np-tx-fifo-size = <32>;
-- g-rx-fifo-size = <256>;
-+ g-rx-fifo-size = <558>;
- g-tx-fifo-size = <512 512 512 512 512 256 256>;
- status = "okay";
- };
--- /dev/null
+From 475158d2aab9dc2e8266726f7b026cedfe810619 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 31 Jan 2020 15:24:59 +0000
+Subject: [PATCH] ARM: dts: Correct SoC name
+
+The Pi 4 SoC is called BCM2711, not BCM2838.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -42,7 +42,7 @@
+
+ &soc {
+ thermal: thermal@7d5d2200 {
+- compatible = "brcm,avs-tmon-bcm2838";
++ compatible = "brcm,avs-tmon-bcm2711";
+ reg = <0x7d5d2200 0x2c>;
+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "tmon";
+@@ -106,7 +106,7 @@
+ };
+
+ dma40: dma@7e007b00 {
+- compatible = "brcm,bcm2838-dma";
++ compatible = "brcm,bcm2711-dma";
+ reg = <0x0 0x7e007b00 0x400>;
+ interrupts =
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
+@@ -122,7 +122,7 @@
+ };
+
+ vchiq: mailbox@7e00b840 {
+- compatible = "brcm,bcm2838-vchiq";
++ compatible = "brcm,bcm2711-vchiq";
+ reg = <0 0x7e00b840 0x3c>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ };
+@@ -195,7 +195,7 @@
+ };
+
+ &random {
+- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
++ compatible = "brcm,bcm2711-rng200";
+ status = "okay";
+ };
+
+++ /dev/null
-From 9fa750db2d682fa2c124dae609d05d15f93a5e52 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Tue, 4 Feb 2020 15:22:55 +0000
-Subject: [PATCH] overlays: Fix mcp23017's addr parameter
-
-The addr parameter of the mcp23017 overlay was broken by the addition
-of the noints parameter; splitting the mcp node in two without also
-modifying the second half from the addr parameter would cause the two
-halves to separate. Change the implementation strategy to patch
-fragment 2 (as was originally proposed). This will prevent the
-overlay from being applied at runtime until the "dtoverlay" command
-is improved, but the overlay already has this restriction due to
-fragment 3 so this isn't a step backwards.
-
-See: https://github.com/raspberrypi/linux/issues/3449
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++---------
- 1 file changed, 7 insertions(+), 9 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
-@@ -48,15 +48,13 @@
- };
-
- fragment@4 {
-- target = <&i2c1>;
-- __overlay__ {
-- mcp23017_irq: mcp@20 {
-- #interrupt-cells=<2>;
-- interrupt-parent = <&gpio>;
-- interrupts = <4 2>;
-- interrupt-controller;
-- microchip,irq-mirror;
-- };
-+ target = <&mcp23017>;
-+ mcp23017_irq: __overlay__ {
-+ #interrupt-cells=<2>;
-+ interrupt-parent = <&gpio>;
-+ interrupts = <4 2>;
-+ interrupt-controller;
-+ microchip,irq-mirror;
- };
- };
-
--- /dev/null
+From 1a66f120abddf36eaf2540532ddeb7f7767442c5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Sat, 1 Feb 2020 08:58:11 +0000
+Subject: [PATCH] ARM: dts: Remove CMA allocation from Pi 4 dts
+
+The 5.5 tree includes a patch to disable the CMA command line
+parameter and replace it with properties from a DT node.
+The upstream Pi 4 .dts, now used downstream with modifications,
+includes the "linux,cma" node, but only reserves 32MB which is
+often not enough.
+
+Temporarily remove the "linux,cma" node to reenable the command line
+parameter.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -167,6 +167,10 @@
+ };
+
+ /delete-node/ wifi-pwrseq;
++
++ reserved-memory {
++ /delete-node/ linux,cma;
++ };
+ };
+
+ &mmcnr {
+++ /dev/null
-From 69811ede9ad350beb531082177bdc6da92c7fdb9 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Tue, 4 Feb 2020 16:35:12 +0000
-Subject: [PATCH] SQUASH: Fix spi driver compiler warnings
-
-Squash with "spi: spi-bcm2835: Disable forced software CS"
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/spi/spi-bcm2835.c | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/drivers/spi/spi-bcm2835.c
-+++ b/drivers/spi/spi-bcm2835.c
-@@ -1230,8 +1230,6 @@ static int bcm2835_spi_setup(struct spi_
- {
- struct spi_controller *ctlr = spi->controller;
- struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
-- struct gpio_chip *chip;
-- enum gpio_lookup_flags lflags;
- u32 cs;
-
- /*
+++ /dev/null
-From c6e4343e441558f45df2685b9ed7c13daf7988be Mon Sep 17 00:00:00 2001
-From: Michael Kaplan <m.kaplan@evva.com>
-Date: Wed, 5 Feb 2020 10:27:23 +0100
-Subject: [PATCH] overlays: add hdmi-backlight-hwhack-gpio-overlay
-
-This is a Devicetree overlay for GPIO based backlight on/off capability.
-
-Use this if you have one of those HDMI displays whose backlight cannot be controlled via DPMS over HDMI and plan to do a little soldering to use an RPi gpio pin for on/off switching.
-
-See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
-
-This was tested with a clone of the Waveshare "7 inch HDMI Touch LCD C" where I soldered two mosfets to override the backlight dip-switch.
-When the overlay is loaded, a sysfs backlight node appears which can be used to modify the brightness value (0 or 1), and is even used by DPMS to switch the display backlight off after the configured timeout.
-(On current Raspbian Buster Desktop, it's also possible to wakeup the display via a tap on the touch display :-) )
-
-Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
----
- arch/arm/boot/dts/overlays/Makefile | 1 +
- arch/arm/boot/dts/overlays/README | 14 ++++++
- .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 +++++++++++++++++++
- 3 files changed, 62 insertions(+)
- create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts
-
---- a/arch/arm/boot/dts/overlays/Makefile
-+++ b/arch/arm/boot/dts/overlays/Makefile
-@@ -51,6 +51,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
- gpio-poweroff.dtbo \
- gpio-shutdown.dtbo \
- hd44780-lcd.dtbo \
-+ hdmi-backlight-hwhack-gpio.dtbo \
- hifiberry-amp.dtbo \
- hifiberry-dac.dtbo \
- hifiberry-dacplus.dtbo \
---- a/arch/arm/boot/dts/overlays/README
-+++ b/arch/arm/boot/dts/overlays/README
-@@ -883,6 +883,20 @@ Params: pin_d4 GPIO pin
- display_width Width of the display in characters
-
-
-+Name: hdmi-backlight-hwhack-gpio
-+Info: Devicetree overlay for GPIO based backlight on/off capability.
-+ Use this if you have one of those HDMI displays whose backlight cannot
-+ be controlled via DPMS over HDMI and plan to do a little soldering to
-+ use an RPi gpio pin for on/off switching. See:
-+ https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
-+Load: dtoverlay=hdmi-backlight-hwhack-gpio,<param>=<val>
-+Params: gpio_pin GPIO pin used (default 17)
-+ active_low Set this to 1 if the display backlight is
-+ switched on when the wire goes low.
-+ Leave the default (value 0) if the backlight
-+ expects a high to switch it on.
-+
-+
- Name: hifiberry-amp
- Info: Configures the HifiBerry Amp and Amp+ audio cards
- Load: dtoverlay=hifiberry-amp
---- /dev/null
-+++ b/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts
-@@ -0,0 +1,47 @@
-+/*
-+ * Devicetree overlay for GPIO based backlight on/off capability.
-+ *
-+ * Use this if you have one of those HDMI displays whose backlight cannot be
-+ * controlled via DPMS over HDMI and plan to do a little soldering to use an
-+ * RPi gpio pin for on/off switching.
-+ *
-+ * See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control
-+ *
-+ */
-+/dts-v1/;
-+/plugin/;
-+
-+/ {
-+ compatible = "brcm,bcm2835";
-+
-+ fragment@1 {
-+ target = <&gpio>;
-+ __overlay__ {
-+ hdmi_backlight_hwhack_gpio_pins: hdmi_backlight_hwhack_gpio_pins {
-+ brcm,pins = <17>;
-+ brcm,function = <1>; /* out */
-+ };
-+ };
-+ };
-+
-+ fragment@2 {
-+ target-path = "/";
-+ __overlay__ {
-+ hdmi_backlight_hwhack_gpio: hdmi_backlight_hwhack_gpio {
-+ compatible = "gpio-backlight";
-+
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&hdmi_backlight_hwhack_gpio_pins>;
-+
-+ gpios = <&gpio 17 0>;
-+ default-on;
-+ };
-+ };
-+ };
-+
-+ __overrides__ {
-+ gpio_pin = <&hdmi_backlight_hwhack_gpio>,"gpios:4",
-+ <&hdmi_backlight_hwhack_gpio_pins>,"brcm,pins:0";
-+ active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8";
-+ };
-+};
--- /dev/null
+From 9f93264df7a631132f2dacd150d0cc6cb7d20fc4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 3 Feb 2020 17:30:46 +0000
+Subject: [PATCH] staging: vchiq_arm: Give vchiq children DT nodes
+
+vchiq kernel clients are now instantiated as platform drivers rather
+than using DT, but the children of the vchiq interface may still
+benefit from access to DT properties. Give them the option of a
+a sub-node of the vchiq parent for configuration and to allow
+them to be disabled.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3190,12 +3190,20 @@ vchiq_register_child(struct platform_dev
+ pdevinfo.id = PLATFORM_DEVID_NONE;
+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
+
++ np = of_get_child_by_name(pdev->dev.of_node, name);
++
++ /* Skip the child if it is explicitly disabled */
++ if (np && !of_device_is_available(np))
++ return NULL;
++
+ child = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(child)) {
+ dev_warn(&pdev->dev, "%s not registered\n", name);
+ child = NULL;
+ }
+
++ child->dev.of_node = np;
++
+ /*
+ * We want the dma-ranges etc to be copied from a device with the
+ * correct dma-ranges for the VPU.
+++ /dev/null
-From e90536d721612de6a2619ae6727ee12b56bb2660 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Thu, 30 Jan 2020 11:39:39 +0000
-Subject: [PATCH] ARM: dts: Revert all changes to upstream dts files
-
-With the possible exception of bcm2711* files where there is a name
-clash, we should not be modifying upstream DTS files.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 348 ++------
- arch/arm/boot/dts/bcm2711.dtsi | 888 ++++++++++++++++++++-
- arch/arm/boot/dts/bcm2835-common.dtsi | 131 +++
- arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi-a.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi-b.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi-zero.dts | 1 -
- arch/arm/boot/dts/bcm2835-rpi.dtsi | 37 -
- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 -
- arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 1 -
- arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi | 15 -
- arch/arm/boot/dts/bcm283x.dtsi | 152 +---
- 14 files changed, 1068 insertions(+), 511 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -1,54 +1,57 @@
-+// SPDX-License-Identifier: GPL-2.0
- /dts-v1/;
--
- #include "bcm2711.dtsi"
--#include "bcm2711-rpi.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-+#include "bcm2835-rpi.dtsi"
-+#include "bcm283x-rpi-usb-peripheral.dtsi"
-
- / {
- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
- model = "Raspberry Pi 4 Model B";
-
-- memory@0 {
-- device_type = "memory";
-- reg = <0x0 0x0 0x0>;
-+ chosen {
-+ /* 8250 auxiliary UART instead of pl011 */
-+ stdout-path = "serial1:115200n8";
- };
-
-- chosen {
-- bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
-+ /* Will be filled by the bootloader */
-+ memory@0 {
-+ device_type = "memory";
-+ reg = <0 0 0>;
- };
-
- aliases {
-- serial0 = &uart1;
-- serial1 = &uart0;
-- mmc0 = &emmc2;
-- mmc1 = &mmcnr;
-- mmc2 = &sdhost;
-- i2c3 = &i2c3;
-- i2c4 = &i2c4;
-- i2c5 = &i2c5;
-- i2c6 = &i2c6;
-- /delete-property/ ethernet;
-- /delete-property/ intc;
- ethernet0 = &genet;
-- pcie0 = &pcie_0;
- };
--};
-
--&soc {
-- virtgpio: virtgpio {
-- compatible = "brcm,bcm2835-virtgpio";
-- gpio-controller;
-- #gpio-cells = <2>;
-- firmware = <&firmware>;
-- status = "okay";
-+ leds {
-+ act {
-+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-+ };
-+
-+ pwr {
-+ label = "PWR";
-+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-+ };
- };
--};
-
--&mmcnr {
-- pinctrl-names = "default";
-- pinctrl-0 = <&sdio_pins>;
-- bus-width = <4>;
-- status = "okay";
-+ wifi_pwrseq: wifi-pwrseq {
-+ compatible = "mmc-pwrseq-simple";
-+ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
-+ };
-+
-+ sd_io_1v8_reg: sd_io_1v8_reg {
-+ compatible = "regulator-gpio";
-+ regulator-name = "vdd-sd-io";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ regulator-always-on;
-+ regulator-settling-time-us = <5000>;
-+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-+ states = <1800000 0x1
-+ 3300000 0x0>;
-+ status = "okay";
-+ };
- };
-
- &firmware {
-@@ -68,81 +71,34 @@
- };
- };
-
--&uart0 {
-+&pwm1 {
- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_pins &bt_pins>;
-+ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
- status = "okay";
- };
-
--&uart1 {
-+/* SDHCI is used to control the SDIO for wireless */
-+&sdhci {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
- pinctrl-names = "default";
-- pinctrl-0 = <&uart1_pins>;
-+ pinctrl-0 = <&emmc_gpio34>;
-+ bus-width = <4>;
-+ non-removable;
-+ mmc-pwrseq = <&wifi_pwrseq>;
- status = "okay";
--};
-
--&spi0 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-- cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
--
-- spidev0: spidev@0{
-- compatible = "spidev";
-- reg = <0>; /* CE0 */
-- #address-cells = <1>;
-- #size-cells = <0>;
-- spi-max-frequency = <125000000>;
-- };
--
-- spidev1: spidev@1{
-- compatible = "spidev";
-- reg = <1>; /* CE1 */
-- #address-cells = <1>;
-- #size-cells = <0>;
-- spi-max-frequency = <125000000>;
-- };
--};
--
--// =============================================
--// Board specific stuff here
--
--/ {
--
-- sd_io_1v8_reg: sd_io_1v8_reg {
-- status = "okay";
-- compatible = "regulator-gpio";
-- vin-supply = <&vdd_5v0_reg>;
-- regulator-name = "vdd-sd-io";
-- regulator-min-microvolt = <1800000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-boot-on;
-- regulator-always-on;
-- regulator-settling-time-us = <5000>;
--
-- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-- states = <1800000 0x1
-- 3300000 0x0>;
-+ brcmf: wifi@1 {
-+ reg = <1>;
-+ compatible = "brcm,bcm4329-fmac";
- };
--
-- sd_vcc_reg: sd_vcc_reg {
-- compatible = "regulator-fixed";
-- regulator-name = "vcc-sd";
-- regulator-min-microvolt = <3300000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-boot-on;
-- enable-active-high;
-- gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
-- };
--};
--
--&sdhost {
-- status = "disabled";
- };
-
-+/* EMMC2 is used to drive the SD card */
- &emmc2 {
-- status = "okay";
-- broken-cd;
- vqmmc-supply = <&sd_io_1v8_reg>;
-- vmmc-supply = <&sd_vcc_reg>;
-+ broken-cd;
-+ status = "okay";
- };
-
- &genet {
-@@ -155,200 +111,32 @@
- phy1: ethernet-phy@1 {
- /* No PHY interrupt */
- reg = <0x1>;
-- led-modes = <0x00 0x08>; /* link/activity link */
- };
- };
-
--&leds {
-- act_led: act {
-- label = "led0";
-- linux,default-trigger = "mmc0";
-- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-- };
--
-- pwr_led: pwr {
-- label = "led1";
-- linux,default-trigger = "default-on";
-- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-- };
--};
--
--&audio {
-+/* uart0 communicates with the BT module */
-+&uart0 {
- pinctrl-names = "default";
-- pinctrl-0 = <&audio_pins>;
--};
--
--&sdhost_gpio48 {
-- brcm,pins = <22 23 24 25 26 27>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
--};
--
--&gpio {
-- spi0_pins: spi0_pins {
-- brcm,pins = <9 10 11>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
--
-- spi0_cs_pins: spi0_cs_pins {
-- brcm,pins = <8 7>;
-- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-- };
--
-- spi3_pins: spi3_pins {
-- brcm,pins = <1 2 3>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- spi3_cs_pins: spi3_cs_pins {
-- brcm,pins = <0 24>;
-- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-- };
--
-- spi4_pins: spi4_pins {
-- brcm,pins = <5 6 7>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- spi4_cs_pins: spi4_cs_pins {
-- brcm,pins = <4 25>;
-- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-- };
--
-- spi5_pins: spi5_pins {
-- brcm,pins = <13 14 15>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- spi5_cs_pins: spi5_cs_pins {
-- brcm,pins = <12 26>;
-- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-- };
--
-- spi6_pins: spi6_pins {
-- brcm,pins = <19 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- spi6_cs_pins: spi6_cs_pins {
-- brcm,pins = <18 27>;
-- brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-- };
--
-- i2c0_pins: i2c0 {
-- brcm,pins = <0 1>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2c1_pins: i2c1 {
-- brcm,pins = <2 3>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2c3_pins: i2c3 {
-- brcm,pins = <4 5>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2c4_pins: i2c4 {
-- brcm,pins = <8 9>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2c5_pins: i2c5 {
-- brcm,pins = <12 13>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2c6_pins: i2c6 {
-- brcm,pins = <22 23>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- brcm,pull = <BCM2835_PUD_UP>;
-- };
--
-- i2s_pins: i2s {
-- brcm,pins = <18 19 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
--
-- sdio_pins: sdio_pins {
-- brcm,pins = <34 35 36 37 38 39>;
-- brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
-- brcm,pull = <0 2 2 2 2 2>;
-- };
--
-- bt_pins: bt_pins {
-- brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
-- // to fool pinctrl
-- brcm,function = <0>;
-- brcm,pull = <2>;
-- };
--
-- uart0_pins: uart0_pins {
-- brcm,pins = <32 33>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- brcm,pull = <0 2>;
-- };
--
-- uart1_pins: uart1_pins {
-- brcm,pins;
-- brcm,function;
-- brcm,pull;
-- };
--
-- uart2_pins: uart2_pins {
-- brcm,pins = <0 1>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <0 2>;
-- };
--
-- uart3_pins: uart3_pins {
-- brcm,pins = <4 5>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <0 2>;
-- };
--
-- uart4_pins: uart4_pins {
-- brcm,pins = <8 9>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <0 2>;
-- };
--
-- uart5_pins: uart5_pins {
-- brcm,pins = <12 13>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <0 2>;
-- };
-+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
-+ uart-has-rtscts;
-+ status = "okay";
-
-- audio_pins: audio_pins {
-- brcm,pins = <40 41>;
-- brcm,function = <4>;
-+ bluetooth {
-+ compatible = "brcm,bcm43438-bt";
-+ max-speed = <2000000>;
-+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
- };
- };
-
--&i2c0 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&i2c0_pins>;
-- clock-frequency = <100000>;
--};
--
--&i2c1 {
-+/* uart1 is mapped to the pin header */
-+&uart1 {
- pinctrl-names = "default";
-- pinctrl-0 = <&i2c1_pins>;
-- clock-frequency = <100000>;
--};
--
--&i2c2 {
-- clock-frequency = <100000>;
-+ pinctrl-0 = <&uart1_gpio14>;
-+ status = "okay";
- };
-
--&i2s {
-- pinctrl-names = "default";
-- pinctrl-0 = <&i2s_pins>;
-+&vchiq {
-+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- / {
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -1,44 +1,890 @@
--#include "bcm2838.dtsi"
--#include "bcm270x.dtsi"
-+// SPDX-License-Identifier: GPL-2.0
-+#include "bcm283x.dtsi"
-+
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
-+#include <dt-bindings/soc/bcm2835-pm.h>
-
- / {
-+ compatible = "brcm,bcm2711";
-+
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ 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;
-+ };
-+ };
-+
-+
- soc {
-- /delete-node/ v3d@7ec00000;
-+ /*
-+ * Defined ranges:
-+ * Common BCM283x peripherals
-+ * BCM2711-specific peripherals
-+ * ARM-local peripherals
-+ */
-+ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
-+ <0x7c000000 0x0 0xfc000000 0x02000000>,
-+ <0x40000000 0x0 0xff800000 0x00800000>;
-+ /* Emulate a contiguous 30-bit address range for DMA */
-+ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
-+
-+ /*
-+ * This node is the provider for the enable-method for
-+ * bringing up secondary cores.
-+ */
-+ local_intc: local_intc@40000000 {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ };
-+
-+ gicv2: interrupt-controller@40041000 {
-+ interrupt-controller;
-+ #interrupt-cells = <3>;
-+ compatible = "arm,gic-400";
-+ reg = <0x40041000 0x1000>,
-+ <0x40042000 0x2000>,
-+ <0x40044000 0x2000>,
-+ <0x40046000 0x2000>;
-+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_HIGH)>;
-+ };
-+
-+ dma: dma@7e007000 {
-+ compatible = "brcm,bcm2835-dma";
-+ reg = <0x7e007000 0xb00>;
-+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
-+ /* DMA lite 7 - 10 */
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "dma0",
-+ "dma1",
-+ "dma2",
-+ "dma3",
-+ "dma4",
-+ "dma5",
-+ "dma6",
-+ "dma7",
-+ "dma8",
-+ "dma9",
-+ "dma10";
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x07f5>;
-+ };
-+
-+ pm: watchdog@7e100000 {
-+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-+ #power-domain-cells = <1>;
-+ #reset-cells = <1>;
-+ reg = <0x7e100000 0x114>,
-+ <0x7e00a000 0x24>,
-+ <0x7ec11000 0x20>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>,
-+ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-+ <&clocks BCM2835_CLOCK_H264>,
-+ <&clocks BCM2835_CLOCK_ISP>;
-+ clock-names = "v3d", "peri_image", "h264", "isp";
-+ system-power-controller;
-+ };
-+
-+ rng@7e104000 {
-+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ /* RNG is incompatible with brcm,bcm2835-rng */
-+ status = "disabled";
-+ };
-+
-+ uart2: serial@7e201400 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201400 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart3: serial@7e201600 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201600 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart4: serial@7e201800 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201800 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart5: serial@7e201a00 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201a00 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ spi3: spi@7e204600 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204600 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi4: spi@7e204800 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204800 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi5: spi@7e204a00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204a00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi6: spi@7e204c00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204c00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c3: i2c@7e205600 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205600 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c4: i2c@7e205800 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205800 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c5: i2c@7e205a00 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205a00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c6: i2c@7e205c00 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205c00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ pwm1: pwm@7e20c800 {
-+ compatible = "brcm,bcm2835-pwm";
-+ reg = <0x7e20c800 0x28>;
-+ clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clock-rates = <10000000>;
-+ #pwm-cells = <2>;
-+ status = "disabled";
-+ };
-+
-+ emmc2: emmc2@7e340000 {
-+ compatible = "brcm,bcm2711-emmc2";
-+ reg = <0x7e340000 0x100>;
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
-+ status = "disabled";
-+ };
-+
-+ hvs@7e400000 {
-+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+ };
-+
-+ arm-pmu {
-+ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
-+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
-+ };
-+
-+ timer {
-+ compatible = "arm,armv8-timer";
-+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>;
-+ /* This only applies to the ARMv7 stub */
-+ arm,cpu-registers-not-fw-configured;
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
-+
-+ cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <0>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000d8>;
-+ };
-+
-+ cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <1>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e0>;
-+ };
-+
-+ cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <2>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e8>;
-+ };
-+
-+ cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <3>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000f0>;
-+ };
- };
-
-- __overrides__ {
-- arm_freq;
-+ scb {
-+ compatible = "simple-bus";
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
-+
-+ genet: ethernet@7d580000 {
-+ compatible = "brcm,bcm2711-genet-v5";
-+ reg = <0x0 0x7d580000 0x10000>;
-+ #address-cells = <0x1>;
-+ #size-cells = <0x1>;
-+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+
-+ genet_mdio: mdio@e14 {
-+ compatible = "brcm,genet-mdio-v5";
-+ reg = <0xe14 0x8>;
-+ reg-names = "mdio";
-+ #address-cells = <0x0>;
-+ #size-cells = <0x1>;
-+ };
-+ };
- };
- };
-
--&v3d {
-- status = "disabled";
-+&clk_osc {
-+ clock-frequency = <54000000>;
- };
-
--&firmwarekms {
-- interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+&clocks {
-+ compatible = "brcm,bcm2711-cprman";
- };
-
--&smi {
-- interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+&cpu_thermal {
-+ coefficients = <(-487) 410040>;
- };
-
--&mmc {
-- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+&dsi0 {
-+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&dsi1 {
-+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&gpio {
-+ compatible = "brcm,bcm2711-gpio";
-+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ gpclk0_gpio49: gpclk0_gpio49 {
-+ pin-gpclk {
-+ pins = "gpio49";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ gpclk1_gpio50: gpclk1_gpio50 {
-+ pin-gpclk {
-+ pins = "gpio50";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ gpclk2_gpio51: gpclk2_gpio51 {
-+ pin-gpclk {
-+ pins = "gpio51";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+
-+ i2c0_gpio46: i2c0_gpio46 {
-+ pin-sda {
-+ function = "alt0";
-+ pins = "gpio46";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt0";
-+ pins = "gpio47";
-+ bias-disable;
-+ };
-+ };
-+ i2c1_gpio46: i2c1_gpio46 {
-+ pin-sda {
-+ function = "alt1";
-+ pins = "gpio46";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt1";
-+ pins = "gpio47";
-+ bias-disable;
-+ };
-+ };
-+ i2c3_gpio2: i2c3_gpio2 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio2";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio3";
-+ bias-disable;
-+ };
-+ };
-+ i2c3_gpio4: i2c3_gpio4 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio4";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio5";
-+ bias-disable;
-+ };
-+ };
-+ i2c4_gpio6: i2c4_gpio6 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio6";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio7";
-+ bias-disable;
-+ };
-+ };
-+ i2c4_gpio8: i2c4_gpio8 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio8";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio9";
-+ bias-disable;
-+ };
-+ };
-+ i2c5_gpio10: i2c5_gpio10 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio10";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio11";
-+ bias-disable;
-+ };
-+ };
-+ i2c5_gpio12: i2c5_gpio12 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio12";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio13";
-+ bias-disable;
-+ };
-+ };
-+ i2c6_gpio0: i2c6_gpio0 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio0";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio1";
-+ bias-disable;
-+ };
-+ };
-+ i2c6_gpio22: i2c6_gpio22 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio22";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio23";
-+ bias-disable;
-+ };
-+ };
-+ i2c_slave_gpio8: i2c_slave_gpio8 {
-+ pins-i2c-slave {
-+ pins = "gpio8",
-+ "gpio9",
-+ "gpio10",
-+ "gpio11";
-+ function = "alt3";
-+ };
-+ };
-+
-+ jtag_gpio48: jtag_gpio48 {
-+ pins-jtag {
-+ pins = "gpio48",
-+ "gpio49",
-+ "gpio50",
-+ "gpio51",
-+ "gpio52",
-+ "gpio53";
-+ function = "alt4";
-+ };
-+ };
-+
-+ mii_gpio28: mii_gpio28 {
-+ pins-mii {
-+ pins = "gpio28",
-+ "gpio29",
-+ "gpio30",
-+ "gpio31";
-+ function = "alt4";
-+ };
-+ };
-+ mii_gpio36: mii_gpio36 {
-+ pins-mii {
-+ pins = "gpio36",
-+ "gpio37",
-+ "gpio38",
-+ "gpio39";
-+ function = "alt5";
-+ };
-+ };
-+
-+ pcm_gpio50: pcm_gpio50 {
-+ pins-pcm {
-+ pins = "gpio50",
-+ "gpio51",
-+ "gpio52",
-+ "gpio53";
-+ function = "alt2";
-+ };
-+ };
-+
-+ pwm0_0_gpio12: pwm0_0_gpio12 {
-+ pin-pwm {
-+ pins = "gpio12";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_0_gpio18: pwm0_0_gpio18 {
-+ pin-pwm {
-+ pins = "gpio18";
-+ function = "alt5";
-+ bias-disable;
-+ };
-+ };
-+ pwm1_0_gpio40: pwm1_0_gpio40 {
-+ pin-pwm {
-+ pins = "gpio40";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio13: pwm0_1_gpio13 {
-+ pin-pwm {
-+ pins = "gpio13";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio19: pwm0_1_gpio19 {
-+ pin-pwm {
-+ pins = "gpio19";
-+ function = "alt5";
-+ bias-disable;
-+ };
-+ };
-+ pwm1_1_gpio41: pwm1_1_gpio41 {
-+ pin-pwm {
-+ pins = "gpio41";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio45: pwm0_1_gpio45 {
-+ pin-pwm {
-+ pins = "gpio45";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_0_gpio52: pwm0_0_gpio52 {
-+ pin-pwm {
-+ pins = "gpio52";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio53: pwm0_1_gpio53 {
-+ pin-pwm {
-+ pins = "gpio53";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+
-+ rgmii_gpio35: rgmii_gpio35 {
-+ pin-start-stop {
-+ pins = "gpio35";
-+ function = "alt4";
-+ };
-+ pin-rx-ok {
-+ pins = "gpio36";
-+ function = "alt4";
-+ };
-+ };
-+ rgmii_irq_gpio34: rgmii_irq_gpio34 {
-+ pin-irq {
-+ pins = "gpio34";
-+ function = "alt5";
-+ };
-+ };
-+ rgmii_irq_gpio39: rgmii_irq_gpio39 {
-+ pin-irq {
-+ pins = "gpio39";
-+ function = "alt4";
-+ };
-+ };
-+ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
-+ pins-mdio {
-+ pins = "gpio28",
-+ "gpio29";
-+ function = "alt5";
-+ };
-+ };
-+ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
-+ pins-mdio {
-+ pins = "gpio37",
-+ "gpio38";
-+ function = "alt4";
-+ };
-+ };
-+
-+ spi0_gpio46: spi0_gpio46 {
-+ pins-spi {
-+ pins = "gpio46",
-+ "gpio47",
-+ "gpio48",
-+ "gpio49";
-+ function = "alt2";
-+ };
-+ };
-+ spi2_gpio46: spi2_gpio46 {
-+ pins-spi {
-+ pins = "gpio46",
-+ "gpio47",
-+ "gpio48",
-+ "gpio49",
-+ "gpio50";
-+ function = "alt5";
-+ };
-+ };
-+ spi3_gpio0: spi3_gpio0 {
-+ pins-spi {
-+ pins = "gpio0",
-+ "gpio1",
-+ "gpio2",
-+ "gpio3";
-+ function = "alt3";
-+ };
-+ };
-+ spi4_gpio4: spi4_gpio4 {
-+ pins-spi {
-+ pins = "gpio4",
-+ "gpio5",
-+ "gpio6",
-+ "gpio7";
-+ function = "alt3";
-+ };
-+ };
-+ spi5_gpio12: spi5_gpio12 {
-+ pins-spi {
-+ pins = "gpio12",
-+ "gpio13",
-+ "gpio14",
-+ "gpio15";
-+ function = "alt3";
-+ };
-+ };
-+ spi6_gpio18: spi6_gpio18 {
-+ pins-spi {
-+ pins = "gpio18",
-+ "gpio19",
-+ "gpio20",
-+ "gpio21";
-+ function = "alt3";
-+ };
-+ };
-+
-+ uart2_gpio0: uart2_gpio0 {
-+ pin-tx {
-+ pins = "gpio0";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio1";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
-+ pin-cts {
-+ pins = "gpio2";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio3";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart3_gpio4: uart3_gpio4 {
-+ pin-tx {
-+ pins = "gpio4";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio5";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
-+ pin-cts {
-+ pins = "gpio6";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio7";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart4_gpio8: uart4_gpio8 {
-+ pin-tx {
-+ pins = "gpio8";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio9";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
-+ pin-cts {
-+ pins = "gpio10";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio11";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart5_gpio12: uart5_gpio12 {
-+ pin-tx {
-+ pins = "gpio12";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio13";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
-+ pin-cts {
-+ pins = "gpio14";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio15";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
- };
-
--&mmcnr {
-+&i2c0 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&i2c1 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mailbox {
-+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&sdhci {
- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
- };
-
-+&sdhost {
-+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi {
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi2 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&system_timer {
-+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&txp {
-+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart0 {
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
- &usb {
-- reg = <0x7e980000 0x10000>,
-- <0x7e00b200 0x200>;
-- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
- };
-
--&gpio {
-- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-+&vec {
-+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
- };
---- a/arch/arm/boot/dts/bcm2835-common.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-common.dtsi
-@@ -8,6 +8,47 @@
- interrupt-parent = <&intc>;
-
- soc {
-+ dma: dma@7e007000 {
-+ compatible = "brcm,bcm2835-dma";
-+ reg = <0x7e007000 0xf00>;
-+ interrupts = <1 16>,
-+ <1 17>,
-+ <1 18>,
-+ <1 19>,
-+ <1 20>,
-+ <1 21>,
-+ <1 22>,
-+ <1 23>,
-+ <1 24>,
-+ <1 25>,
-+ <1 26>,
-+ /* dma channel 11-14 share one irq */
-+ <1 27>,
-+ <1 27>,
-+ <1 27>,
-+ <1 27>,
-+ /* unused shared irq for all channels */
-+ <1 28>;
-+ interrupt-names = "dma0",
-+ "dma1",
-+ "dma2",
-+ "dma3",
-+ "dma4",
-+ "dma5",
-+ "dma6",
-+ "dma7",
-+ "dma8",
-+ "dma9",
-+ "dma10",
-+ "dma11",
-+ "dma12",
-+ "dma13",
-+ "dma14",
-+ "dma-shared-all";
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x7f35>;
-+ };
-+
- intc: interrupt-controller@7e00b200 {
- compatible = "brcm,bcm2835-armctrl-ic";
- reg = <0x7e00b200 0x200>;
-@@ -15,6 +56,20 @@
- #interrupt-cells = <2>;
- };
-
-+ pm: watchdog@7e100000 {
-+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-+ #power-domain-cells = <1>;
-+ #reset-cells = <1>;
-+ reg = <0x7e100000 0x114>,
-+ <0x7e00a000 0x24>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>,
-+ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-+ <&clocks BCM2835_CLOCK_H264>,
-+ <&clocks BCM2835_CLOCK_ISP>;
-+ clock-names = "v3d", "peri_image", "h264", "isp";
-+ system-power-controller;
-+ };
-+
- pixelvalve@7e206000 {
- compatible = "brcm,bcm2835-pixelvalve0";
- reg = <0x7e206000 0x100>;
-@@ -35,21 +90,53 @@
- status = "disabled";
- };
-
-+ i2c2: i2c@7e805000 {
-+ compatible = "brcm,bcm2835-i2c";
-+ reg = <0x7e805000 0x1000>;
-+ interrupts = <2 21>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+ };
-+
- pixelvalve@7e807000 {
- compatible = "brcm,bcm2835-pixelvalve2";
- reg = <0x7e807000 0x100>;
- interrupts = <2 10>; /* pixelvalve */
- };
-
-+ hdmi: hdmi@7e902000 {
-+ compatible = "brcm,bcm2835-hdmi";
-+ reg = <0x7e902000 0x600>,
-+ <0x7e808000 0x100>;
-+ interrupts = <2 8>, <2 9>;
-+ ddc = <&i2c2>;
-+ clocks = <&clocks BCM2835_PLLH_PIX>,
-+ <&clocks BCM2835_CLOCK_HSM>;
-+ clock-names = "pixel", "hdmi";
-+ dmas = <&dma 17>;
-+ dma-names = "audio-rx";
-+ status = "disabled";
-+ };
-+
- v3d: v3d@7ec00000 {
- compatible = "brcm,bcm2835-v3d";
- reg = <0x7ec00000 0x1000>;
- interrupts = <1 10>;
- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
- };
-+
-+ vc4: gpu {
-+ compatible = "brcm,bcm2835-vc4";
-+ };
- };
- };
-
-+&cpu_thermal {
-+ thermal-sensors = <&thermal>;
-+};
-+
- &gpio {
- i2c_slave_gpio18: i2c_slave_gpio18 {
- brcm,pins = <18 19 20 21>;
-@@ -60,4 +147,48 @@
- brcm,pins = <4 5 6 12 13>;
- brcm,function = <BCM2835_FSEL_ALT5>;
- };
-+
-+ pwm0_gpio12: pwm0_gpio12 {
-+ brcm,pins = <12>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+ pwm0_gpio18: pwm0_gpio18 {
-+ brcm,pins = <18>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ pwm0_gpio40: pwm0_gpio40 {
-+ brcm,pins = <40>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+ pwm1_gpio13: pwm1_gpio13 {
-+ brcm,pins = <13>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+ pwm1_gpio19: pwm1_gpio19 {
-+ brcm,pins = <19>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ };
-+ pwm1_gpio41: pwm1_gpio41 {
-+ brcm,pins = <41>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+ pwm1_gpio45: pwm1_gpio45 {
-+ brcm,pins = <45>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+};
-+
-+&i2s {
-+ dmas = <&dma 2>, <&dma 3>;
-+ dma-names = "tx", "rx";
-+};
-+
-+&sdhost {
-+ dmas = <&dma 13>;
-+ dma-names = "rx-tx";
-+};
-+
-+&spi {
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
- };
---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
-@@ -3,7 +3,6 @@
- #include "bcm2835.dtsi"
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi-a.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts
-@@ -3,7 +3,6 @@
- #include "bcm2835.dtsi"
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-a", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
-@@ -4,7 +4,6 @@
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
-@@ -4,7 +4,6 @@
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-smsc9512.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
-@@ -4,7 +4,6 @@
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-smsc9512.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-b", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts
-@@ -7,7 +7,6 @@
- #include "bcm2835.dtsi"
- #include "bcm2835-rpi.dtsi"
- #include "bcm283x-rpi-usb-otg.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,model-zero", "brcm,bcm2835";
---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
-@@ -29,22 +29,6 @@
- interrupts = <0 2>;
- };
- };
--
-- vdd_3v3_reg: fixedregulator_3v3 {
-- compatible = "regulator-fixed";
-- regulator-name = "3v3";
-- regulator-min-microvolt = <3300000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-always-on;
-- };
--
-- vdd_5v0_reg: fixedregulator_5v0 {
-- compatible = "regulator-fixed";
-- regulator-name = "5v0";
-- regulator-min-microvolt = <5000000>;
-- regulator-max-microvolt = <5000000>;
-- regulator-always-on;
-- };
- };
-
- &gpio {
-@@ -75,23 +59,10 @@
- clock-frequency = <100000>;
- };
-
--&i2c2 {
-- status = "okay";
--};
--
- &usb {
- power-domains = <&power RPI_POWER_DOMAIN_USB>;
- };
-
--&hdmi {
-- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-- status = "okay";
--};
--
--&v3d {
-- power-domains = <&power RPI_POWER_DOMAIN_V3D>;
--};
--
- &vec {
- power-domains = <&power RPI_POWER_DOMAIN_VEC>;
- status = "okay";
-@@ -104,11 +75,3 @@
- &dsi1 {
- power-domains = <&power RPI_POWER_DOMAIN_DSI1>;
- };
--
--&csi0 {
-- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
--};
--
--&csi1 {
-- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
--};
---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts
-@@ -4,7 +4,6 @@
- #include "bcm2836-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts
-@@ -4,7 +4,6 @@
- #include "bcm2836-rpi.dtsi"
- #include "bcm283x-rpi-smsc9514.dtsi"
- #include "bcm283x-rpi-usb-host.dtsi"
--#include "bcm283x-rpi-csi1-2lane.dtsi"
-
- / {
- compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
---- a/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
-+++ b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
-@@ -29,9 +29,6 @@
- #size-cells = <0x0>;
- eth_phy: ethernet-phy@1 {
- reg = <1>;
-- microchip,eee-enabled;
-- microchip,tx-lpi-timer = <600>; /* non-aggressive*/
-- microchip,downshift-after = <2>;
- microchip,led-modes = <
- LAN78XX_LINK_1000_ACTIVITY
- LAN78XX_LINK_10_100_ACTIVITY
-@@ -42,15 +39,3 @@
- };
- };
- };
--
--
--/ {
-- __overrides__ {
-- eee = <ð_phy>,"microchip,eee-enabled?";
-- tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0";
-- eth_led0 = <ð_phy>,"microchip,led-modes:0";
-- eth_led1 = <ð_phy>,"microchip,led-modes:4";
-- eth_downshift_after = <ð_phy>,"microchip,downshift-after:0";
-- eth_max_speed = <ð_phy>,"max-speed:0";
-- };
--};
---- a/arch/arm/boot/dts/bcm283x.dtsi
-+++ b/arch/arm/boot/dts/bcm283x.dtsi
-@@ -35,8 +35,6 @@
- polling-delay-passive = <0>;
- polling-delay = <1000>;
-
-- thermal-sensors = <&thermal>;
--
- trips {
- cpu-crit {
- temperature = <90000>;
-@@ -72,61 +70,6 @@
- interrupts = <1 11>;
- };
-
-- dma: dma@7e007000 {
-- compatible = "brcm,bcm2835-dma";
-- reg = <0x7e007000 0xf00>;
-- interrupts = <1 16>,
-- <1 17>,
-- <1 18>,
-- <1 19>,
-- <1 20>,
-- <1 21>,
-- <1 22>,
-- <1 23>,
-- <1 24>,
-- <1 25>,
-- <1 26>,
-- /* dma channel 11-14 share one irq */
-- <1 27>,
-- <1 27>,
-- <1 27>,
-- <1 27>,
-- /* unused shared irq for all channels */
-- <1 28>;
-- interrupt-names = "dma0",
-- "dma1",
-- "dma2",
-- "dma3",
-- "dma4",
-- "dma5",
-- "dma6",
-- "dma7",
-- "dma8",
-- "dma9",
-- "dma10",
-- "dma11",
-- "dma12",
-- "dma13",
-- "dma14",
-- "dma-shared-all";
-- #dma-cells = <1>;
-- brcm,dma-channel-mask = <0x7f35>;
-- };
--
-- pm: watchdog@7e100000 {
-- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-- #power-domain-cells = <1>;
-- #reset-cells = <1>;
-- reg = <0x7e100000 0x114>,
-- <0x7e00a000 0x24>;
-- clocks = <&clocks BCM2835_CLOCK_V3D>,
-- <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-- <&clocks BCM2835_CLOCK_H264>,
-- <&clocks BCM2835_CLOCK_ISP>;
-- clock-names = "v3d", "peri_image", "h264", "isp";
-- system-power-controller;
-- };
--
- clocks: cprman@7e101000 {
- compatible = "brcm,bcm2835-cprman";
- #clock-cells = <1>;
-@@ -141,7 +84,7 @@
- <&dsi1 0>, <&dsi1 1>, <&dsi1 2>;
- };
-
-- rng: rng@7e104000 {
-+ rng@7e104000 {
- compatible = "brcm,bcm2835-rng";
- reg = <0x7e104000 0x10>;
- interrupts = <2 29>;
-@@ -269,35 +212,6 @@
- brcm,function = <BCM2835_FSEL_ALT2>;
- };
-
-- pwm0_gpio12: pwm0_gpio12 {
-- brcm,pins = <12>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
-- pwm0_gpio18: pwm0_gpio18 {
-- brcm,pins = <18>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- pwm0_gpio40: pwm0_gpio40 {
-- brcm,pins = <40>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
-- pwm1_gpio13: pwm1_gpio13 {
-- brcm,pins = <13>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
-- pwm1_gpio19: pwm1_gpio19 {
-- brcm,pins = <19>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- pwm1_gpio41: pwm1_gpio41 {
-- brcm,pins = <41>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
-- pwm1_gpio45: pwm1_gpio45 {
-- brcm,pins = <45>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
--
- sdhost_gpio48: sdhost_gpio48 {
- brcm,pins = <48 49 50 51 52 53>;
- brcm,function = <BCM2835_FSEL_ALT0>;
-@@ -379,7 +293,7 @@
- };
-
- uart0: serial@7e201000 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-+ compatible = "arm,pl011", "arm,primecell";
- reg = <0x7e201000 0x200>;
- interrupts = <2 25>;
- clocks = <&clocks BCM2835_CLOCK_UART>,
-@@ -393,8 +307,6 @@
- reg = <0x7e202000 0x100>;
- interrupts = <2 24>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- dmas = <&dma (13|(1<<29))>;
-- dma-names = "rx-tx";
- status = "disabled";
- };
-
-@@ -402,10 +314,6 @@
- compatible = "brcm,bcm2835-i2s";
- reg = <0x7e203000 0x24>;
- clocks = <&clocks BCM2835_CLOCK_PCM>;
--
-- dmas = <&dma 2>,
-- <&dma 3>;
-- dma-names = "tx", "rx";
- status = "disabled";
- };
-
-@@ -414,8 +322,6 @@
- reg = <0x7e204000 0x200>;
- interrupts = <2 22>;
- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- dmas = <&dma 6>, <&dma 7>;
-- dma-names = "tx", "rx";
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
-@@ -540,32 +446,6 @@
- status = "disabled";
- };
-
-- csi0: csi@7e800000 {
-- compatible = "brcm,bcm2835-unicam";
-- reg = <0x7e800000 0x800>,
-- <0x7e802000 0x4>;
-- interrupts = <2 6>;
-- clocks = <&clocks BCM2835_CLOCK_CAM0>;
-- clock-names = "lp";
-- #address-cells = <1>;
-- #size-cells = <0>;
-- #clock-cells = <1>;
-- status = "disabled";
-- };
--
-- csi1: csi@7e801000 {
-- compatible = "brcm,bcm2835-unicam";
-- reg = <0x7e801000 0x800>,
-- <0x7e802004 0x4>;
-- interrupts = <2 7>;
-- clocks = <&clocks BCM2835_CLOCK_CAM1>;
-- clock-names = "lp";
-- #address-cells = <1>;
-- #size-cells = <0>;
-- #clock-cells = <1>;
-- status = "disabled";
-- };
--
- i2c1: i2c@7e804000 {
- compatible = "brcm,bcm2835-i2c";
- reg = <0x7e804000 0x1000>;
-@@ -576,16 +456,6 @@
- status = "disabled";
- };
-
-- i2c2: i2c@7e805000 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e805000 0x1000>;
-- interrupts = <2 21>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
- vec: vec@7e806000 {
- compatible = "brcm,bcm2835-vec";
- reg = <0x7e806000 0x1000>;
-@@ -594,20 +464,6 @@
- status = "disabled";
- };
-
-- hdmi: hdmi@7e902000 {
-- compatible = "brcm,bcm2835-hdmi";
-- reg = <0x7e902000 0x600>,
-- <0x7e808000 0x100>;
-- interrupts = <2 8>, <2 9>;
-- ddc = <&i2c2>;
-- clocks = <&clocks BCM2835_PLLH_PIX>,
-- <&clocks BCM2835_CLOCK_HSM>;
-- clock-names = "pixel", "hdmi";
-- dmas = <&dma 17>;
-- dma-names = "audio-rx";
-- status = "disabled";
-- };
--
- usb: usb@7e980000 {
- compatible = "brcm,bcm2835-usb";
- reg = <0x7e980000 0x10000>;
-@@ -619,10 +475,6 @@
- phys = <&usbphy>;
- phy-names = "usb2-phy";
- };
--
-- vc4: gpu {
-- compatible = "brcm,bcm2835-vc4";
-- };
- };
-
- clocks {
--- /dev/null
+From 79a2c3013a3b2a4304f953a4a55c49c1bc85202b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 3 Feb 2020 17:33:01 +0000
+Subject: [PATCH] staging: vchiq_arm: Add a matching unregister call
+
+All the registered children of vchiq have a corresponding call to
+platform_device_unregister except bcm2835_audio. Fix that.
+
+Fixes: 25c7597af20d ("staging: vchiq_arm: Register a platform device for audio")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+@@ -3293,6 +3293,7 @@ failed_platform_init:
+
+ static int vchiq_remove(struct platform_device *pdev)
+ {
++ platform_device_unregister(bcm2835_audio);
+ platform_device_unregister(bcm2835_camera);
+ platform_device_unregister(bcm2835_codec);
+ platform_device_unregister(vcsm_cma);
+++ /dev/null
-From 134e06abd2d002edfdac3561656ab9e8161b29a3 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 16:53:13 +0000
-Subject: [PATCH] ARM: dts: Clean out downstream BCM2711/2838 files
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 157 -----
- arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 -
- arch/arm/boot/dts/bcm2711.dtsi | 890 --------------------------
- arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 -
- arch/arm/boot/dts/bcm2838.dtsi | 733 ---------------------
- 5 files changed, 1812 deletions(-)
- delete mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
- delete mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
- delete mode 100644 arch/arm/boot/dts/bcm2711.dtsi
- delete mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi
- delete mode 100644 arch/arm/boot/dts/bcm2838.dtsi
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ /dev/null
-@@ -1,157 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/dts-v1/;
--#include "bcm2711.dtsi"
--#include "bcm2835-rpi.dtsi"
--#include "bcm283x-rpi-usb-peripheral.dtsi"
--
--/ {
-- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
-- model = "Raspberry Pi 4 Model B";
--
-- chosen {
-- /* 8250 auxiliary UART instead of pl011 */
-- stdout-path = "serial1:115200n8";
-- };
--
-- /* Will be filled by the bootloader */
-- memory@0 {
-- device_type = "memory";
-- reg = <0 0 0>;
-- };
--
-- aliases {
-- ethernet0 = &genet;
-- };
--
-- leds {
-- act {
-- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-- };
--
-- pwr {
-- label = "PWR";
-- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-- };
-- };
--
-- wifi_pwrseq: wifi-pwrseq {
-- compatible = "mmc-pwrseq-simple";
-- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
-- };
--
-- sd_io_1v8_reg: sd_io_1v8_reg {
-- compatible = "regulator-gpio";
-- regulator-name = "vdd-sd-io";
-- regulator-min-microvolt = <1800000>;
-- regulator-max-microvolt = <3300000>;
-- regulator-boot-on;
-- regulator-always-on;
-- regulator-settling-time-us = <5000>;
-- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-- states = <1800000 0x1
-- 3300000 0x0>;
-- status = "okay";
-- };
--};
--
--&firmware {
-- expgpio: gpio {
-- compatible = "raspberrypi,firmware-gpio";
-- gpio-controller;
-- #gpio-cells = <2>;
-- gpio-line-names = "BT_ON",
-- "WL_ON",
-- "PWR_LED_OFF",
-- "GLOBAL_RESET",
-- "VDD_SD_IO_SEL",
-- "CAM_GPIO",
-- "",
-- "";
-- status = "okay";
-- };
--};
--
--&pwm1 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
-- status = "okay";
--};
--
--/* SDHCI is used to control the SDIO for wireless */
--&sdhci {
-- #address-cells = <1>;
-- #size-cells = <0>;
-- pinctrl-names = "default";
-- pinctrl-0 = <&emmc_gpio34>;
-- bus-width = <4>;
-- non-removable;
-- mmc-pwrseq = <&wifi_pwrseq>;
-- status = "okay";
--
-- brcmf: wifi@1 {
-- reg = <1>;
-- compatible = "brcm,bcm4329-fmac";
-- };
--};
--
--/* EMMC2 is used to drive the SD card */
--&emmc2 {
-- vqmmc-supply = <&sd_io_1v8_reg>;
-- broken-cd;
-- status = "okay";
--};
--
--&genet {
-- phy-handle = <&phy1>;
-- phy-mode = "rgmii-rxid";
-- status = "okay";
--};
--
--&genet_mdio {
-- phy1: ethernet-phy@1 {
-- /* No PHY interrupt */
-- reg = <0x1>;
-- };
--};
--
--/* uart0 communicates with the BT module */
--&uart0 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
-- uart-has-rtscts;
-- status = "okay";
--
-- bluetooth {
-- compatible = "brcm,bcm43438-bt";
-- max-speed = <2000000>;
-- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
-- };
--};
--
--/* uart1 is mapped to the pin header */
--&uart1 {
-- pinctrl-names = "default";
-- pinctrl-0 = <&uart1_gpio14>;
-- status = "okay";
--};
--
--&vchiq {
-- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--/ {
-- __overrides__ {
-- act_led_gpio = <&act_led>,"gpios:4";
-- act_led_activelow = <&act_led>,"gpios:8";
-- act_led_trigger = <&act_led>,"linux,default-trigger";
--
-- pwr_led_gpio = <&pwr_led>,"gpios:4";
-- pwr_led_activelow = <&pwr_led>,"gpios:8";
-- pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
--
-- eth_led0 = <&phy1>,"led-modes:0";
-- eth_led1 = <&phy1>,"led-modes:4";
--
-- sd_poll_once = <&emmc2>, "non-removable?";
-- };
--};
---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
-+++ /dev/null
-@@ -1,7 +0,0 @@
--#include "bcm2708-rpi.dtsi"
--#include "bcm2838-rpi.dtsi"
--
--&v3d {
-- /* Undo the overwriting by bcm270x.dtsi */
-- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
--};
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ /dev/null
-@@ -1,890 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--#include "bcm283x.dtsi"
--
--#include <dt-bindings/interrupt-controller/arm-gic.h>
--#include <dt-bindings/soc/bcm2835-pm.h>
--
--/ {
-- compatible = "brcm,bcm2711";
--
-- #address-cells = <2>;
-- #size-cells = <1>;
--
-- 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;
-- };
-- };
--
--
-- soc {
-- /*
-- * Defined ranges:
-- * Common BCM283x peripherals
-- * BCM2711-specific peripherals
-- * ARM-local peripherals
-- */
-- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
-- <0x7c000000 0x0 0xfc000000 0x02000000>,
-- <0x40000000 0x0 0xff800000 0x00800000>;
-- /* Emulate a contiguous 30-bit address range for DMA */
-- dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
--
-- /*
-- * This node is the provider for the enable-method for
-- * bringing up secondary cores.
-- */
-- local_intc: local_intc@40000000 {
-- compatible = "brcm,bcm2836-l1-intc";
-- reg = <0x40000000 0x100>;
-- };
--
-- gicv2: interrupt-controller@40041000 {
-- interrupt-controller;
-- #interrupt-cells = <3>;
-- compatible = "arm,gic-400";
-- reg = <0x40041000 0x1000>,
-- <0x40042000 0x2000>,
-- <0x40044000 0x2000>,
-- <0x40046000 0x2000>;
-- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_HIGH)>;
-- };
--
-- dma: dma@7e007000 {
-- compatible = "brcm,bcm2835-dma";
-- reg = <0x7e007000 0xb00>;
-- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
-- /* DMA lite 7 - 10 */
-- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
-- interrupt-names = "dma0",
-- "dma1",
-- "dma2",
-- "dma3",
-- "dma4",
-- "dma5",
-- "dma6",
-- "dma7",
-- "dma8",
-- "dma9",
-- "dma10";
-- #dma-cells = <1>;
-- brcm,dma-channel-mask = <0x07f5>;
-- };
--
-- pm: watchdog@7e100000 {
-- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-- #power-domain-cells = <1>;
-- #reset-cells = <1>;
-- reg = <0x7e100000 0x114>,
-- <0x7e00a000 0x24>,
-- <0x7ec11000 0x20>;
-- clocks = <&clocks BCM2835_CLOCK_V3D>,
-- <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-- <&clocks BCM2835_CLOCK_H264>,
-- <&clocks BCM2835_CLOCK_ISP>;
-- clock-names = "v3d", "peri_image", "h264", "isp";
-- system-power-controller;
-- };
--
-- rng@7e104000 {
-- interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
--
-- /* RNG is incompatible with brcm,bcm2835-rng */
-- status = "disabled";
-- };
--
-- uart2: serial@7e201400 {
-- compatible = "arm,pl011", "arm,primecell";
-- reg = <0x7e201400 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart3: serial@7e201600 {
-- compatible = "arm,pl011", "arm,primecell";
-- reg = <0x7e201600 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart4: serial@7e201800 {
-- compatible = "arm,pl011", "arm,primecell";
-- reg = <0x7e201800 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart5: serial@7e201a00 {
-- compatible = "arm,pl011", "arm,primecell";
-- reg = <0x7e201a00 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- spi3: spi@7e204600 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204600 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi4: spi@7e204800 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204800 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi5: spi@7e204a00 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204a00 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi6: spi@7e204c00 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204c00 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c3: i2c@7e205600 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- reg = <0x7e205600 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c4: i2c@7e205800 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- reg = <0x7e205800 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c5: i2c@7e205a00 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- reg = <0x7e205a00 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c6: i2c@7e205c00 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- reg = <0x7e205c00 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- pwm1: pwm@7e20c800 {
-- compatible = "brcm,bcm2835-pwm";
-- reg = <0x7e20c800 0x28>;
-- clocks = <&clocks BCM2835_CLOCK_PWM>;
-- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-- assigned-clock-rates = <10000000>;
-- #pwm-cells = <2>;
-- status = "disabled";
-- };
--
-- emmc2: emmc2@7e340000 {
-- compatible = "brcm,bcm2711-emmc2";
-- reg = <0x7e340000 0x100>;
-- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2711_CLOCK_EMMC2>;
-- status = "disabled";
-- };
--
-- hvs@7e400000 {
-- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-- };
-- };
--
-- arm-pmu {
-- compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
-- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
-- };
--
-- timer {
-- compatible = "arm,armv8-timer";
-- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>;
-- /* This only applies to the ARMv7 stub */
-- arm,cpu-registers-not-fw-configured;
-- };
--
-- cpus: cpus {
-- #address-cells = <1>;
-- #size-cells = <0>;
-- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
--
-- cpu0: cpu@0 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <0>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000d8>;
-- };
--
-- cpu1: cpu@1 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <1>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000e0>;
-- };
--
-- cpu2: cpu@2 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <2>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000e8>;
-- };
--
-- cpu3: cpu@3 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <3>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000f0>;
-- };
-- };
--
-- scb {
-- compatible = "simple-bus";
-- #address-cells = <2>;
-- #size-cells = <1>;
--
-- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
--
-- genet: ethernet@7d580000 {
-- compatible = "brcm,bcm2711-genet-v5";
-- reg = <0x0 0x7d580000 0x10000>;
-- #address-cells = <0x1>;
-- #size-cells = <0x1>;
-- interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-- status = "disabled";
--
-- genet_mdio: mdio@e14 {
-- compatible = "brcm,genet-mdio-v5";
-- reg = <0xe14 0x8>;
-- reg-names = "mdio";
-- #address-cells = <0x0>;
-- #size-cells = <0x1>;
-- };
-- };
-- };
--};
--
--&clk_osc {
-- clock-frequency = <54000000>;
--};
--
--&clocks {
-- compatible = "brcm,bcm2711-cprman";
--};
--
--&cpu_thermal {
-- coefficients = <(-487) 410040>;
--};
--
--&dsi0 {
-- interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&dsi1 {
-- interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&gpio {
-- compatible = "brcm,bcm2711-gpio";
-- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
--
-- gpclk0_gpio49: gpclk0_gpio49 {
-- pin-gpclk {
-- pins = "gpio49";
-- function = "alt1";
-- bias-disable;
-- };
-- };
-- gpclk1_gpio50: gpclk1_gpio50 {
-- pin-gpclk {
-- pins = "gpio50";
-- function = "alt1";
-- bias-disable;
-- };
-- };
-- gpclk2_gpio51: gpclk2_gpio51 {
-- pin-gpclk {
-- pins = "gpio51";
-- function = "alt1";
-- bias-disable;
-- };
-- };
--
-- i2c0_gpio46: i2c0_gpio46 {
-- pin-sda {
-- function = "alt0";
-- pins = "gpio46";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt0";
-- pins = "gpio47";
-- bias-disable;
-- };
-- };
-- i2c1_gpio46: i2c1_gpio46 {
-- pin-sda {
-- function = "alt1";
-- pins = "gpio46";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt1";
-- pins = "gpio47";
-- bias-disable;
-- };
-- };
-- i2c3_gpio2: i2c3_gpio2 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio2";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio3";
-- bias-disable;
-- };
-- };
-- i2c3_gpio4: i2c3_gpio4 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio4";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio5";
-- bias-disable;
-- };
-- };
-- i2c4_gpio6: i2c4_gpio6 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio6";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio7";
-- bias-disable;
-- };
-- };
-- i2c4_gpio8: i2c4_gpio8 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio8";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio9";
-- bias-disable;
-- };
-- };
-- i2c5_gpio10: i2c5_gpio10 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio10";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio11";
-- bias-disable;
-- };
-- };
-- i2c5_gpio12: i2c5_gpio12 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio12";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio13";
-- bias-disable;
-- };
-- };
-- i2c6_gpio0: i2c6_gpio0 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio0";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio1";
-- bias-disable;
-- };
-- };
-- i2c6_gpio22: i2c6_gpio22 {
-- pin-sda {
-- function = "alt5";
-- pins = "gpio22";
-- bias-pull-up;
-- };
-- pin-scl {
-- function = "alt5";
-- pins = "gpio23";
-- bias-disable;
-- };
-- };
-- i2c_slave_gpio8: i2c_slave_gpio8 {
-- pins-i2c-slave {
-- pins = "gpio8",
-- "gpio9",
-- "gpio10",
-- "gpio11";
-- function = "alt3";
-- };
-- };
--
-- jtag_gpio48: jtag_gpio48 {
-- pins-jtag {
-- pins = "gpio48",
-- "gpio49",
-- "gpio50",
-- "gpio51",
-- "gpio52",
-- "gpio53";
-- function = "alt4";
-- };
-- };
--
-- mii_gpio28: mii_gpio28 {
-- pins-mii {
-- pins = "gpio28",
-- "gpio29",
-- "gpio30",
-- "gpio31";
-- function = "alt4";
-- };
-- };
-- mii_gpio36: mii_gpio36 {
-- pins-mii {
-- pins = "gpio36",
-- "gpio37",
-- "gpio38",
-- "gpio39";
-- function = "alt5";
-- };
-- };
--
-- pcm_gpio50: pcm_gpio50 {
-- pins-pcm {
-- pins = "gpio50",
-- "gpio51",
-- "gpio52",
-- "gpio53";
-- function = "alt2";
-- };
-- };
--
-- pwm0_0_gpio12: pwm0_0_gpio12 {
-- pin-pwm {
-- pins = "gpio12";
-- function = "alt0";
-- bias-disable;
-- };
-- };
-- pwm0_0_gpio18: pwm0_0_gpio18 {
-- pin-pwm {
-- pins = "gpio18";
-- function = "alt5";
-- bias-disable;
-- };
-- };
-- pwm1_0_gpio40: pwm1_0_gpio40 {
-- pin-pwm {
-- pins = "gpio40";
-- function = "alt0";
-- bias-disable;
-- };
-- };
-- pwm0_1_gpio13: pwm0_1_gpio13 {
-- pin-pwm {
-- pins = "gpio13";
-- function = "alt0";
-- bias-disable;
-- };
-- };
-- pwm0_1_gpio19: pwm0_1_gpio19 {
-- pin-pwm {
-- pins = "gpio19";
-- function = "alt5";
-- bias-disable;
-- };
-- };
-- pwm1_1_gpio41: pwm1_1_gpio41 {
-- pin-pwm {
-- pins = "gpio41";
-- function = "alt0";
-- bias-disable;
-- };
-- };
-- pwm0_1_gpio45: pwm0_1_gpio45 {
-- pin-pwm {
-- pins = "gpio45";
-- function = "alt0";
-- bias-disable;
-- };
-- };
-- pwm0_0_gpio52: pwm0_0_gpio52 {
-- pin-pwm {
-- pins = "gpio52";
-- function = "alt1";
-- bias-disable;
-- };
-- };
-- pwm0_1_gpio53: pwm0_1_gpio53 {
-- pin-pwm {
-- pins = "gpio53";
-- function = "alt1";
-- bias-disable;
-- };
-- };
--
-- rgmii_gpio35: rgmii_gpio35 {
-- pin-start-stop {
-- pins = "gpio35";
-- function = "alt4";
-- };
-- pin-rx-ok {
-- pins = "gpio36";
-- function = "alt4";
-- };
-- };
-- rgmii_irq_gpio34: rgmii_irq_gpio34 {
-- pin-irq {
-- pins = "gpio34";
-- function = "alt5";
-- };
-- };
-- rgmii_irq_gpio39: rgmii_irq_gpio39 {
-- pin-irq {
-- pins = "gpio39";
-- function = "alt4";
-- };
-- };
-- rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
-- pins-mdio {
-- pins = "gpio28",
-- "gpio29";
-- function = "alt5";
-- };
-- };
-- rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
-- pins-mdio {
-- pins = "gpio37",
-- "gpio38";
-- function = "alt4";
-- };
-- };
--
-- spi0_gpio46: spi0_gpio46 {
-- pins-spi {
-- pins = "gpio46",
-- "gpio47",
-- "gpio48",
-- "gpio49";
-- function = "alt2";
-- };
-- };
-- spi2_gpio46: spi2_gpio46 {
-- pins-spi {
-- pins = "gpio46",
-- "gpio47",
-- "gpio48",
-- "gpio49",
-- "gpio50";
-- function = "alt5";
-- };
-- };
-- spi3_gpio0: spi3_gpio0 {
-- pins-spi {
-- pins = "gpio0",
-- "gpio1",
-- "gpio2",
-- "gpio3";
-- function = "alt3";
-- };
-- };
-- spi4_gpio4: spi4_gpio4 {
-- pins-spi {
-- pins = "gpio4",
-- "gpio5",
-- "gpio6",
-- "gpio7";
-- function = "alt3";
-- };
-- };
-- spi5_gpio12: spi5_gpio12 {
-- pins-spi {
-- pins = "gpio12",
-- "gpio13",
-- "gpio14",
-- "gpio15";
-- function = "alt3";
-- };
-- };
-- spi6_gpio18: spi6_gpio18 {
-- pins-spi {
-- pins = "gpio18",
-- "gpio19",
-- "gpio20",
-- "gpio21";
-- function = "alt3";
-- };
-- };
--
-- uart2_gpio0: uart2_gpio0 {
-- pin-tx {
-- pins = "gpio0";
-- function = "alt4";
-- bias-disable;
-- };
-- pin-rx {
-- pins = "gpio1";
-- function = "alt4";
-- bias-pull-up;
-- };
-- };
-- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
-- pin-cts {
-- pins = "gpio2";
-- function = "alt4";
-- bias-pull-up;
-- };
-- pin-rts {
-- pins = "gpio3";
-- function = "alt4";
-- bias-disable;
-- };
-- };
-- uart3_gpio4: uart3_gpio4 {
-- pin-tx {
-- pins = "gpio4";
-- function = "alt4";
-- bias-disable;
-- };
-- pin-rx {
-- pins = "gpio5";
-- function = "alt4";
-- bias-pull-up;
-- };
-- };
-- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
-- pin-cts {
-- pins = "gpio6";
-- function = "alt4";
-- bias-pull-up;
-- };
-- pin-rts {
-- pins = "gpio7";
-- function = "alt4";
-- bias-disable;
-- };
-- };
-- uart4_gpio8: uart4_gpio8 {
-- pin-tx {
-- pins = "gpio8";
-- function = "alt4";
-- bias-disable;
-- };
-- pin-rx {
-- pins = "gpio9";
-- function = "alt4";
-- bias-pull-up;
-- };
-- };
-- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
-- pin-cts {
-- pins = "gpio10";
-- function = "alt4";
-- bias-pull-up;
-- };
-- pin-rts {
-- pins = "gpio11";
-- function = "alt4";
-- bias-disable;
-- };
-- };
-- uart5_gpio12: uart5_gpio12 {
-- pin-tx {
-- pins = "gpio12";
-- function = "alt4";
-- bias-disable;
-- };
-- pin-rx {
-- pins = "gpio13";
-- function = "alt4";
-- bias-pull-up;
-- };
-- };
-- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
-- pin-cts {
-- pins = "gpio14";
-- function = "alt4";
-- bias-pull-up;
-- };
-- pin-rts {
-- pins = "gpio15";
-- function = "alt4";
-- bias-disable;
-- };
-- };
--};
--
--&i2c0 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&i2c1 {
-- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&mailbox {
-- interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&sdhci {
-- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&sdhost {
-- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&spi {
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&spi1 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&spi2 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&system_timer {
-- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&txp {
-- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&uart0 {
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&uart1 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&usb {
-- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&vec {
-- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
--};
---- a/arch/arm/boot/dts/bcm2838-rpi.dtsi
-+++ /dev/null
-@@ -1,25 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--
--/ {
-- soc {
-- /delete-node/ mailbox@7e00b840;
-- };
--};
--
--&scb {
-- vchiq: mailbox@7e00b840 {
-- compatible = "brcm,bcm2838-vchiq";
-- reg = <0 0x7e00b840 0x3c>;
-- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-- };
--};
--
--&dma {
-- /* The VPU firmware uses DMA channel 11 for VCHIQ */
-- brcm,dma-channel-mask = <0x1f5>;
--};
--
--&dma40 {
-- /* The VPU firmware DMA channel 11 for VCHIQ */
-- brcm,dma-channel-mask = <0x7000>;
--};
---- a/arch/arm/boot/dts/bcm2838.dtsi
-+++ /dev/null
-@@ -1,733 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--#include "bcm283x.dtsi"
--
--#include <dt-bindings/interrupt-controller/arm-gic.h>
--#include <dt-bindings/soc/bcm2835-pm.h>
--
--/ {
-- compatible = "brcm,bcm2838";
--
-- #address-cells = <2>;
-- #size-cells = <1>;
--
-- interrupt-parent = <&gicv2>;
--
-- soc {
-- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
-- <0x7c000000 0x0 0xfc000000 0x02000000>,
-- <0x40000000 0x0 0xff800000 0x00800000>;
-- /* Emulate a contiguous 30-bit address range for DMA */
-- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
--
-- /delete-node/ interrupt-controller@7e00f300;
-- /delete-node/ v3d@7ec00000;
--
-- local_intc: local_intc@40000000 {
-- compatible = "brcm,bcm2836-l1-intc";
-- reg = <0x40000000 0x100>;
-- };
--
-- gicv2: interrupt-controller@40041000 {
-- interrupt-controller;
-- #interrupt-cells = <3>;
-- compatible = "arm,gic-400";
-- reg = <0x40041000 0x1000>,
-- <0x40042000 0x2000>,
-- <0x40044000 0x2000>,
-- <0x40046000 0x2000>;
-- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_HIGH)>;
-- };
--
-- thermal: thermal@7d5d2200 {
-- compatible = "brcm,avs-tmon-bcm2838";
-- reg = <0x7d5d2200 0x2c>;
-- interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
-- interrupt-names = "tmon";
-- clocks = <&clocks BCM2835_CLOCK_TSENS>;
-- #thermal-sensor-cells = <0>;
-- status = "okay";
-- };
--
-- pm: watchdog@7e100000 {
-- reg = <0x7e100000 0x114>,
-- <0x7e00a000 0x24>,
-- <0x7ec11000 0x20>;
-- };
--
-- rng@7e104000 {
-- interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
-- uart2: serial@7e201400 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201400 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart3: serial@7e201600 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201600 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart4: serial@7e201800 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201800 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- uart5: serial@7e201a00 {
-- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
-- reg = <0x7e201a00 0x200>;
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_UART>,
-- <&clocks BCM2835_CLOCK_VPU>;
-- clock-names = "uartclk", "apb_pclk";
-- arm,primecell-periphid = <0x00241011>;
-- status = "disabled";
-- };
--
-- spi@7e204000 {
-- reg = <0x7e204000 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
-- spi3: spi@7e204600 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204600 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi4: spi@7e204800 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204800 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi5: spi@7e204a00 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204a00 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- spi6: spi@7e204c00 {
-- compatible = "brcm,bcm2835-spi";
-- reg = <0x7e204c00 0x0200>;
-- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c3: i2c@7e205600 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205600 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c4: i2c@7e205800 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205800 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c5: i2c@7e205a00 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205a00 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- i2c6: i2c@7e205c00 {
-- compatible = "brcm,bcm2835-i2c";
-- reg = <0x7e205c00 0x200>;
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2835_CLOCK_VPU>;
-- #address-cells = <1>;
-- #size-cells = <0>;
-- status = "disabled";
-- };
--
-- pwm1: pwm@7e20c800 {
-- compatible = "brcm,bcm2835-pwm";
-- reg = <0x7e20c800 0x28>;
-- clocks = <&clocks BCM2835_CLOCK_PWM>;
-- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-- assigned-clock-rates = <10000000>;
-- #pwm-cells = <2>;
-- status = "disabled";
-- };
--
-- emmc2: emmc2@7e340000 {
-- compatible = "brcm,bcm2711-emmc2";
-- status = "okay";
-- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-- clocks = <&clocks BCM2711_CLOCK_EMMC2>;
-- reg = <0x7e340000 0x100>;
-- };
--
-- hvs@7e400000 {
-- interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-- };
-- };
--
-- arm-pmu {
-- compatible = "arm,cortex-a72-pmu";
-- interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
-- };
--
-- timer {
-- compatible = "arm,armv7-timer";
-- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>,
-- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-- IRQ_TYPE_LEVEL_LOW)>;
-- arm,cpu-registers-not-fw-configured;
-- };
--
-- cpus: cpus {
-- #address-cells = <1>;
-- #size-cells = <0>;
-- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
--
-- cpu0: cpu@0 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <0>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000d8>;
-- };
--
-- cpu1: cpu@1 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <1>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000e0>;
-- };
--
-- cpu2: cpu@2 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <2>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000e8>;
-- };
--
-- cpu3: cpu@3 {
-- device_type = "cpu";
-- compatible = "arm,cortex-a72";
-- reg = <3>;
-- enable-method = "spin-table";
-- cpu-release-addr = <0x0 0x000000f0>;
-- };
-- };
--
-- v3dbus {
-- compatible = "simple-bus";
-- #address-cells = <1>;
-- #size-cells = <2>;
-- ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>,
-- <0x40000000 0x0 0xff800000 0x0 0x00800000>;
-- dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>;
--
-- v3d: v3d@7ec04000 {
-- compatible = "brcm,2711-v3d";
-- reg =
-- <0x7ec00000 0x0 0x4000>,
-- <0x7ec04000 0x0 0x4000>;
-- reg-names = "hub", "core0";
--
-- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
-- resets = <&pm BCM2835_RESET_V3D>;
-- clocks = <&clocks BCM2835_CLOCK_V3D>;
-- interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-- status = "okay";
-- };
-- };
--
-- scb: scb {
-- compatible = "simple-bus";
-- #address-cells = <2>;
-- #size-cells = <1>;
--
-- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
-- <0x0 0x40000000 0x0 0xff800000 0x00800000>,
-- <0x6 0x00000000 0x6 0x00000000 0x40000000>,
-- <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
-- dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
--
-- pcie_0: pcie@7d500000 {
-- reg = <0x0 0x7d500000 0x9310>,
-- <0x0 0x7e00f300 0x20>;
-- msi-controller;
-- msi-parent = <&pcie_0>;
-- #address-cells = <3>;
-- #interrupt-cells = <1>;
-- #size-cells = <2>;
-- bus-range = <0x0 0x01>;
-- compatible = "brcm,bcm2711b0-pcie", // Safe value
-- "brcm,bcm2711-pcie",
-- "brcm,pci-plat-dev";
-- max-link-speed = <2>;
-- tot-num-pcie = <1>;
-- linux,pci-domain = <0>;
-- interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-- interrupt-names = "pcie", "msi";
-- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
-- IRQ_TYPE_LEVEL_HIGH
-- 0 0 0 2 &gicv2 GIC_SPI 144
-- IRQ_TYPE_LEVEL_HIGH
-- 0 0 0 3 &gicv2 GIC_SPI 145
-- IRQ_TYPE_LEVEL_HIGH
-- 0 0 0 4 &gicv2 GIC_SPI 146
-- IRQ_TYPE_LEVEL_HIGH>;
--
-- /* Map outbound accesses from scb:0x6_00000000-03ffffff
-- * to pci:0x0_f8000000-fbffffff
-- */
-- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
-- 0x0 0x04000000>;
-- /* Map inbound accesses from pci:0x0_00000000..ffffffff
-- * to scb:0x0_00000000-ffffffff
-- */
-- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
-- 0x1 0x00000000>;
-- status = "okay";
-- };
--
-- genet: ethernet@7d580000 {
-- compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
-- reg = <0x0 0x7d580000 0x10000>;
-- #address-cells = <0x1>;
-- #size-cells = <0x1>;
-- interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-- status = "disabled";
--
-- genet_mdio: mdio@e14 {
-- #address-cells = <0x0>;
-- #size-cells = <0x1>;
-- compatible = "brcm,genet-mdio-v5";
-- reg = <0xe14 0x8>;
-- reg-names = "mdio";
-- };
-- };
--
-- dma40: dma@7e007b00 {
-- compatible = "brcm,bcm2838-dma";
-- reg = <0x0 0x7e007b00 0x400>;
-- interrupts =
-- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
-- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
-- <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
-- interrupt-names = "dma11",
-- "dma12",
-- "dma13",
-- "dma14";
-- #dma-cells = <1>;
-- brcm,dma-channel-mask = <0x7800>;
-- };
-- /* DMA4 - 40 bit DMA engines */
--
-- xhci: xhci@7e9c0000 {
-- compatible = "generic-xhci";
-- status = "disabled";
-- reg = <0x0 0x7e9c0000 0x100000>;
-- interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
-- hevc-decoder@7eb00000 {
-- compatible = "raspberrypi,rpivid-hevc-decoder";
-- reg = <0x0 0x7eb00000 0x10000>;
-- status = "okay";
-- };
--
-- rpivid-local-intc@7eb10000 {
-- compatible = "raspberrypi,rpivid-local-intc";
-- reg = <0x0 0x7eb10000 0x1000>;
-- status = "okay";
-- interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
-- };
--
-- h264-decoder@7eb20000 {
-- compatible = "raspberrypi,rpivid-h264-decoder";
-- reg = <0x0 0x7eb20000 0x10000>;
-- status = "okay";
-- };
--
-- vp9-decoder@7eb30000 {
-- compatible = "raspberrypi,rpivid-vp9-decoder";
-- reg = <0x0 0x7eb30000 0x10000>;
-- status = "okay";
-- };
-- };
--};
--
--&clk_osc {
-- clock-frequency = <54000000>;
--};
--
--&clocks {
-- compatible = "brcm,bcm2711-cprman";
--};
--
--&cpu_thermal {
-- coefficients = <(-487) 410040>;
--};
--
--&dsi0 {
-- interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&dsi1 {
-- interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&gpio {
-- compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio";
--
-- gpclk0_gpio49: gpclk0_gpio49 {
-- brcm,pins = <49>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- brcm,pull = <BCM2835_PUD_OFF>;
-- };
-- gpclk1_gpio50: gpclk1_gpio50 {
-- brcm,pins = <50>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- brcm,pull = <BCM2835_PUD_OFF>;
-- };
-- gpclk2_gpio51: gpclk2_gpio51 {
-- brcm,pins = <51>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- brcm,pull = <BCM2835_PUD_OFF>;
-- };
--
-- i2c0_gpio46: i2c0_gpio46 {
-- brcm,pins = <46 47>;
-- brcm,function = <BCM2835_FSEL_ALT0>;
-- };
-- i2c1_gpio46: i2c1_gpio46 {
-- brcm,pins = <46 47>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- };
-- i2c3_gpio2: i2c3_gpio2 {
-- brcm,pins = <2 3>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c3_gpio4: i2c3_gpio4 {
-- brcm,pins = <4 5>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c4_gpio6: i2c4_gpio6 {
-- brcm,pins = <6 7>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c4_gpio8: i2c4_gpio8 {
-- brcm,pins = <8 9>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c5_gpio10: i2c5_gpio10 {
-- brcm,pins = <10 11>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c5_gpio12: i2c5_gpio12 {
-- brcm,pins = <12 13>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c6_gpio0: i2c6_gpio0 {
-- brcm,pins = <0 1>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c6_gpio22: i2c6_gpio22 {
-- brcm,pins = <22 23>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- i2c_slave_gpio8: i2c_slave_gpio8 {
-- brcm,pins = <8 9 10 11>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- jtag_gpio48: jtag_gpio48 {
-- brcm,pins = <48 49 50 51 52 53>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- };
--
-- mii_gpio28: mii_gpio28 {
-- brcm,pins = <28 29 30 31>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- };
-- mii_gpio36: mii_gpio36 {
-- brcm,pins = <36 37 38 39>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
--
-- pcm_gpio50: pcm_gpio50 {
-- brcm,pins = <50 51 52 53>;
-- brcm,function = <BCM2835_FSEL_ALT2>;
-- };
--
-- pwm0_gpio52: pwm0_gpio52 {
-- brcm,pins = <52>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- brcm,pull = <BCM2835_PUD_OFF>;
-- };
-- pwm1_gpio53: pwm1_gpio53 {
-- brcm,pins = <53>;
-- brcm,function = <BCM2835_FSEL_ALT1>;
-- brcm,pull = <BCM2835_PUD_OFF>;
-- };
--
-- /* The following group consists of:
-- * RGMII_START_STOP
-- * RGMII_RX_OK
-- */
-- rgmii_gpio35: rgmii_gpio35 {
-- brcm,pins = <35 36>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- };
-- rgmii_irq_gpio34: rgmii_irq_gpio34 {
-- brcm,pins = <34>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- rgmii_irq_gpio39: rgmii_irq_gpio39 {
-- brcm,pins = <39>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- };
-- rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
-- brcm,pins = <28 29>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
-- brcm,pins = <37 38>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- };
--
-- spi0_gpio46: spi0_gpio46 {
-- brcm,pins = <46 47 48 49>;
-- brcm,function = <BCM2835_FSEL_ALT2>;
-- };
-- spi2_gpio46: spi2_gpio46 {
-- brcm,pins = <46 47 48 49 50>;
-- brcm,function = <BCM2835_FSEL_ALT5>;
-- };
-- spi3_gpio0: spi3_gpio0 {
-- brcm,pins = <0 1 2 3>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
-- spi4_gpio4: spi4_gpio4 {
-- brcm,pins = <4 5 6 7>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
-- spi5_gpio12: spi5_gpio12 {
-- brcm,pins = <12 13 14 15>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
-- spi6_gpio18: spi6_gpio18 {
-- brcm,pins = <18 19 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT3>;
-- };
--
-- uart2_gpio0: uart2_gpio0 {
-- brcm,pins = <0 1>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-- };
-- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
-- brcm,pins = <2 3>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-- };
-- uart3_gpio4: uart3_gpio4 {
-- brcm,pins = <4 5>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-- };
-- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
-- brcm,pins = <6 7>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-- };
-- uart4_gpio8: uart4_gpio8 {
-- brcm,pins = <8 9>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-- };
-- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
-- brcm,pins = <10 11>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-- };
-- uart5_gpio12: uart5_gpio12 {
-- brcm,pins = <12 13>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_OFF BCM2835_PUD_UP>;
-- };
-- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
-- brcm,pins = <14 15>;
-- brcm,function = <BCM2835_FSEL_ALT4>;
-- brcm,pull = <BCM2835_PUD_UP BCM2835_PUD_OFF>;
-- };
--};
--
--&vec {
-- interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&usb {
-- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-- status = "disabled";
--};
--
--&hdmi {
-- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&uart1 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&spi1 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&spi2 {
-- interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&csi0 {
-- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&csi1 {
-- interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&sdhci {
-- interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&i2c0 {
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&i2c1 {
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&i2c2 {
-- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&gpio {
-- interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&mailbox {
-- interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&rng {
-- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
--};
--
--&sdhost {
-- interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&system_timer {
-- interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&uart0 {
-- interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
--};
--
--&dma {
-- reg = <0x7e007000 0xb00>;
-- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
-- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 7 */
-- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 8 */
-- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, /* dmalite 9 */
-- <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; /* dmalite 10 */
-- interrupt-names = "dma0",
-- "dma1",
-- "dma2",
-- "dma3",
-- "dma4",
-- "dma5",
-- "dma6",
-- "dma7",
-- "dma8",
-- "dma9",
-- "dma10";
-- brcm,dma-channel-mask = <0x07f5>;
--};
--
--&txp {
-- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
--};
--- /dev/null
+From 6c5efcf09c40d37f72692fdbdf6d461abede20f1 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 3 Feb 2020 17:03:29 +0000
+Subject: [PATCH] ARM: dts: Move audio node under the vchiq parent
+
+VCHIQ kernel clients are now instantiated as platform drivers rather
+than using DT, but the children of the vchiq device can optionally be
+given a sub-node of the vchiq parent for configuration and to disable
+them.
+
+Move the existing audio node beneath the vchiq parent, to prevent
+multiple instantiation and unpleasant warnings. Note that the node
+name has to match the module name - "bcm2835_audio".
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm270x-rpi.dtsi | 16 +++++++++-------
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 14 ++++++++++++++
+ 2 files changed, 23 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm270x-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi
+@@ -70,13 +70,6 @@
+ status = "okay";
+ };
+
+- /* Onboard audio */
+- audio: audio {
+- compatible = "brcm,bcm2835-audio";
+- brcm,pwm-channels = <8>;
+- status = "disabled";
+- };
+-
+ /* External sound card */
+ sound: sound {
+ status = "disabled";
+@@ -137,3 +130,12 @@
+ &vec {
+ status = "disabled";
+ };
++
++&vchiq {
++ /* Onboard audio */
++ audio: bcm2835_audio {
++ compatible = "brcm,bcm2835-audio";
++ brcm,pwm-channels = <8>;
++ status = "disabled";
++ };
++};
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -55,6 +55,8 @@
+ compatible = "brcm,bcm2835-vc4";
+ status = "disabled";
+ };
++
++ /delete-node/ audio;
+ };
+
+ &scb {
+@@ -160,6 +162,18 @@
+ };
+ };
+
++&vchiq {
++ /* Onboard audio
++ * This node is replicated because the original from bcm270x-rpi.dtsi
++ * was deleted when the vchiq node was deleted above.
++ */
++ audio: bcm2835_audio {
++ compatible = "brcm,bcm2835-audio";
++ brcm,pwm-channels = <8>;
++ status = "disabled";
++ };
++};
++
+ &dma {
+ /* The VPU firmware uses DMA channel 11 for VCHIQ */
+ brcm,dma-channel-mask = <0x1f5>;
+++ /dev/null
-From 19a0ac654994661f63f7c9e099ed91a1210af161 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Sun, 6 Oct 2019 15:41:25 +0200
-Subject: [PATCH] ARM: dts: Add minimal Raspberry Pi 4 support
-
-This adds minimal support for the new Raspberry Pi 4 without the
-fancy stuff like GENET, PCIe, xHCI, 40 bit DMA and V3D. The RPi 4 is
-available in 3 different variants (1, 2 and 4 GB RAM), so leave the memory
-size to zero and let the bootloader take care of it. The DWC2 is still
-usable as peripheral via the USB-C port.
-
-Other differences to the Raspberry Pi 3:
-- additional GIC 400 Interrupt controller
-- new thermal IP and HWRNG
-- additional MMC interface (emmc2)
-- additional UART, I2C, SPI and PWM interfaces
-- clock stretching bug in I2C IP has been fixed
-
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
-Acked-by: Eric Anholt <eric@anholt.net>
-Acked-by: Florian Fanelli <f.fainelli@gmail.com>
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 123 +++
- arch/arm/boot/dts/bcm2711.dtsi | 844 ++++++++++++++++++
- .../boot/dts/bcm283x-rpi-usb-peripheral.dtsi | 7 +
- 4 files changed, 975 insertions(+)
- create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts
- create mode 100644 arch/arm/boot/dts/bcm2711.dtsi
- create mode 100644 arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -97,6 +97,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
- bcm2837-rpi-3-b.dtb \
- bcm2837-rpi-3-b-plus.dtb \
- bcm2837-rpi-cm3-io3.dtb \
-+ bcm2711-rpi-4-b.dtb \
- bcm2835-rpi-zero.dtb \
- bcm2835-rpi-zero-w.dtb
- dtb-$(CONFIG_ARCH_BCM_5301X) += \
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -0,0 +1,123 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/dts-v1/;
-+#include "bcm2711.dtsi"
-+#include "bcm2835-rpi.dtsi"
-+#include "bcm283x-rpi-usb-peripheral.dtsi"
-+
-+/ {
-+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
-+ model = "Raspberry Pi 4 Model B";
-+
-+ chosen {
-+ /* 8250 auxiliary UART instead of pl011 */
-+ stdout-path = "serial1:115200n8";
-+ };
-+
-+ /* Will be filled by the bootloader */
-+ memory@0 {
-+ device_type = "memory";
-+ reg = <0 0 0>;
-+ };
-+
-+ leds {
-+ act {
-+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-+ };
-+
-+ pwr {
-+ label = "PWR";
-+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-+ };
-+ };
-+
-+ wifi_pwrseq: wifi-pwrseq {
-+ compatible = "mmc-pwrseq-simple";
-+ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
-+ };
-+
-+ sd_io_1v8_reg: sd_io_1v8_reg {
-+ compatible = "regulator-gpio";
-+ regulator-name = "vdd-sd-io";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ regulator-always-on;
-+ regulator-settling-time-us = <5000>;
-+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
-+ states = <1800000 0x1
-+ 3300000 0x0>;
-+ status = "okay";
-+ };
-+};
-+
-+&firmware {
-+ expgpio: gpio {
-+ compatible = "raspberrypi,firmware-gpio";
-+ gpio-controller;
-+ #gpio-cells = <2>;
-+ gpio-line-names = "BT_ON",
-+ "WL_ON",
-+ "PWR_LED_OFF",
-+ "GLOBAL_RESET",
-+ "VDD_SD_IO_SEL",
-+ "CAM_GPIO",
-+ "",
-+ "";
-+ status = "okay";
-+ };
-+};
-+
-+&pwm1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>;
-+ status = "okay";
-+};
-+
-+/* SDHCI is used to control the SDIO for wireless */
-+&sdhci {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&emmc_gpio34>;
-+ bus-width = <4>;
-+ non-removable;
-+ mmc-pwrseq = <&wifi_pwrseq>;
-+ status = "okay";
-+
-+ brcmf: wifi@1 {
-+ reg = <1>;
-+ compatible = "brcm,bcm4329-fmac";
-+ };
-+};
-+
-+/* EMMC2 is used to drive the SD card */
-+&emmc2 {
-+ vqmmc-supply = <&sd_io_1v8_reg>;
-+ broken-cd;
-+ status = "okay";
-+};
-+
-+/* uart0 communicates with the BT module */
-+&uart0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
-+ uart-has-rtscts;
-+ status = "okay";
-+
-+ bluetooth {
-+ compatible = "brcm,bcm43438-bt";
-+ max-speed = <2000000>;
-+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
-+ };
-+};
-+
-+/* uart1 is mapped to the pin header */
-+&uart1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_gpio14>;
-+ status = "okay";
-+};
-+
-+&vchiq {
-+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -0,0 +1,844 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include "bcm283x.dtsi"
-+
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
-+#include <dt-bindings/soc/bcm2835-pm.h>
-+
-+/ {
-+ compatible = "brcm,bcm2711";
-+
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ interrupt-parent = <&gicv2>;
-+
-+ soc {
-+ /*
-+ * Defined ranges:
-+ * Common BCM283x peripherals
-+ * BCM2711-specific peripherals
-+ * ARM-local peripherals
-+ */
-+ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>,
-+ <0x7c000000 0x0 0xfc000000 0x02000000>,
-+ <0x40000000 0x0 0xff800000 0x00800000>;
-+ /* Emulate a contiguous 30-bit address range for DMA */
-+ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
-+
-+ /*
-+ * This node is the provider for the enable-method for
-+ * bringing up secondary cores.
-+ */
-+ local_intc: local_intc@40000000 {
-+ compatible = "brcm,bcm2836-l1-intc";
-+ reg = <0x40000000 0x100>;
-+ };
-+
-+ gicv2: interrupt-controller@40041000 {
-+ interrupt-controller;
-+ #interrupt-cells = <3>;
-+ compatible = "arm,gic-400";
-+ reg = <0x40041000 0x1000>,
-+ <0x40042000 0x2000>,
-+ <0x40044000 0x2000>,
-+ <0x40046000 0x2000>;
-+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_HIGH)>;
-+ };
-+
-+ dma: dma@7e007000 {
-+ compatible = "brcm,bcm2835-dma";
-+ reg = <0x7e007000 0xb00>;
-+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
-+ /* DMA lite 7 - 10 */
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "dma0",
-+ "dma1",
-+ "dma2",
-+ "dma3",
-+ "dma4",
-+ "dma5",
-+ "dma6",
-+ "dma7",
-+ "dma8",
-+ "dma9",
-+ "dma10";
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x07f5>;
-+ };
-+
-+ pm: watchdog@7e100000 {
-+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
-+ #power-domain-cells = <1>;
-+ #reset-cells = <1>;
-+ reg = <0x7e100000 0x114>,
-+ <0x7e00a000 0x24>,
-+ <0x7ec11000 0x20>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>,
-+ <&clocks BCM2835_CLOCK_PERI_IMAGE>,
-+ <&clocks BCM2835_CLOCK_H264>,
-+ <&clocks BCM2835_CLOCK_ISP>;
-+ clock-names = "v3d", "peri_image", "h264", "isp";
-+ system-power-controller;
-+ };
-+
-+ rng@7e104000 {
-+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ /* RNG is incompatible with brcm,bcm2835-rng */
-+ status = "disabled";
-+ };
-+
-+ uart2: serial@7e201400 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201400 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart3: serial@7e201600 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201600 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart4: serial@7e201800 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201800 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ uart5: serial@7e201a00 {
-+ compatible = "arm,pl011", "arm,primecell";
-+ reg = <0x7e201a00 0x200>;
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_UART>,
-+ <&clocks BCM2835_CLOCK_VPU>;
-+ clock-names = "uartclk", "apb_pclk";
-+ arm,primecell-periphid = <0x00241011>;
-+ status = "disabled";
-+ };
-+
-+ spi3: spi@7e204600 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204600 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi4: spi@7e204800 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204800 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi5: spi@7e204a00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204a00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi6: spi@7e204c00 {
-+ compatible = "brcm,bcm2835-spi";
-+ reg = <0x7e204c00 0x0200>;
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c3: i2c@7e205600 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205600 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c4: i2c@7e205800 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205800 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c5: i2c@7e205a00 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205a00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c6: i2c@7e205c00 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ reg = <0x7e205c00 0x200>;
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2835_CLOCK_VPU>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ pwm1: pwm@7e20c800 {
-+ compatible = "brcm,bcm2835-pwm";
-+ reg = <0x7e20c800 0x28>;
-+ clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>;
-+ assigned-clock-rates = <10000000>;
-+ #pwm-cells = <2>;
-+ status = "disabled";
-+ };
-+
-+ emmc2: emmc2@7e340000 {
-+ compatible = "brcm,bcm2711-emmc2";
-+ reg = <0x7e340000 0x100>;
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+ clocks = <&clocks BCM2711_CLOCK_EMMC2>;
-+ status = "disabled";
-+ };
-+
-+ hvs@7e400000 {
-+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+ };
-+
-+ arm-pmu {
-+ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
-+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
-+ };
-+
-+ timer {
-+ compatible = "arm,armv8-timer";
-+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>,
-+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
-+ IRQ_TYPE_LEVEL_LOW)>;
-+ /* This only applies to the ARMv7 stub */
-+ arm,cpu-registers-not-fw-configured;
-+ };
-+
-+ cpus: cpus {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit
-+
-+ cpu0: cpu@0 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <0>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000d8>;
-+ };
-+
-+ cpu1: cpu@1 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <1>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e0>;
-+ };
-+
-+ cpu2: cpu@2 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <2>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000e8>;
-+ };
-+
-+ cpu3: cpu@3 {
-+ device_type = "cpu";
-+ compatible = "arm,cortex-a72";
-+ reg = <3>;
-+ enable-method = "spin-table";
-+ cpu-release-addr = <0x0 0x000000f0>;
-+ };
-+ };
-+};
-+
-+&clk_osc {
-+ clock-frequency = <54000000>;
-+};
-+
-+&clocks {
-+ compatible = "brcm,bcm2711-cprman";
-+};
-+
-+&cpu_thermal {
-+ coefficients = <(-487) 410040>;
-+};
-+
-+&dsi0 {
-+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&dsi1 {
-+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&gpio {
-+ compatible = "brcm,bcm2711-gpio";
-+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
-+
-+ gpclk0_gpio49: gpclk0_gpio49 {
-+ pin-gpclk {
-+ pins = "gpio49";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ gpclk1_gpio50: gpclk1_gpio50 {
-+ pin-gpclk {
-+ pins = "gpio50";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ gpclk2_gpio51: gpclk2_gpio51 {
-+ pin-gpclk {
-+ pins = "gpio51";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+
-+ i2c0_gpio46: i2c0_gpio46 {
-+ pin-sda {
-+ function = "alt0";
-+ pins = "gpio46";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt0";
-+ pins = "gpio47";
-+ bias-disable;
-+ };
-+ };
-+ i2c1_gpio46: i2c1_gpio46 {
-+ pin-sda {
-+ function = "alt1";
-+ pins = "gpio46";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt1";
-+ pins = "gpio47";
-+ bias-disable;
-+ };
-+ };
-+ i2c3_gpio2: i2c3_gpio2 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio2";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio3";
-+ bias-disable;
-+ };
-+ };
-+ i2c3_gpio4: i2c3_gpio4 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio4";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio5";
-+ bias-disable;
-+ };
-+ };
-+ i2c4_gpio6: i2c4_gpio6 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio6";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio7";
-+ bias-disable;
-+ };
-+ };
-+ i2c4_gpio8: i2c4_gpio8 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio8";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio9";
-+ bias-disable;
-+ };
-+ };
-+ i2c5_gpio10: i2c5_gpio10 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio10";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio11";
-+ bias-disable;
-+ };
-+ };
-+ i2c5_gpio12: i2c5_gpio12 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio12";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio13";
-+ bias-disable;
-+ };
-+ };
-+ i2c6_gpio0: i2c6_gpio0 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio0";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio1";
-+ bias-disable;
-+ };
-+ };
-+ i2c6_gpio22: i2c6_gpio22 {
-+ pin-sda {
-+ function = "alt5";
-+ pins = "gpio22";
-+ bias-pull-up;
-+ };
-+ pin-scl {
-+ function = "alt5";
-+ pins = "gpio23";
-+ bias-disable;
-+ };
-+ };
-+ i2c_slave_gpio8: i2c_slave_gpio8 {
-+ pins-i2c-slave {
-+ pins = "gpio8",
-+ "gpio9",
-+ "gpio10",
-+ "gpio11";
-+ function = "alt3";
-+ };
-+ };
-+
-+ jtag_gpio48: jtag_gpio48 {
-+ pins-jtag {
-+ pins = "gpio48",
-+ "gpio49",
-+ "gpio50",
-+ "gpio51",
-+ "gpio52",
-+ "gpio53";
-+ function = "alt4";
-+ };
-+ };
-+
-+ mii_gpio28: mii_gpio28 {
-+ pins-mii {
-+ pins = "gpio28",
-+ "gpio29",
-+ "gpio30",
-+ "gpio31";
-+ function = "alt4";
-+ };
-+ };
-+ mii_gpio36: mii_gpio36 {
-+ pins-mii {
-+ pins = "gpio36",
-+ "gpio37",
-+ "gpio38",
-+ "gpio39";
-+ function = "alt5";
-+ };
-+ };
-+
-+ pcm_gpio50: pcm_gpio50 {
-+ pins-pcm {
-+ pins = "gpio50",
-+ "gpio51",
-+ "gpio52",
-+ "gpio53";
-+ function = "alt2";
-+ };
-+ };
-+
-+ pwm0_0_gpio12: pwm0_0_gpio12 {
-+ pin-pwm {
-+ pins = "gpio12";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_0_gpio18: pwm0_0_gpio18 {
-+ pin-pwm {
-+ pins = "gpio18";
-+ function = "alt5";
-+ bias-disable;
-+ };
-+ };
-+ pwm1_0_gpio40: pwm1_0_gpio40 {
-+ pin-pwm {
-+ pins = "gpio40";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio13: pwm0_1_gpio13 {
-+ pin-pwm {
-+ pins = "gpio13";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio19: pwm0_1_gpio19 {
-+ pin-pwm {
-+ pins = "gpio19";
-+ function = "alt5";
-+ bias-disable;
-+ };
-+ };
-+ pwm1_1_gpio41: pwm1_1_gpio41 {
-+ pin-pwm {
-+ pins = "gpio41";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio45: pwm0_1_gpio45 {
-+ pin-pwm {
-+ pins = "gpio45";
-+ function = "alt0";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_0_gpio52: pwm0_0_gpio52 {
-+ pin-pwm {
-+ pins = "gpio52";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+ pwm0_1_gpio53: pwm0_1_gpio53 {
-+ pin-pwm {
-+ pins = "gpio53";
-+ function = "alt1";
-+ bias-disable;
-+ };
-+ };
-+
-+ rgmii_gpio35: rgmii_gpio35 {
-+ pin-start-stop {
-+ pins = "gpio35";
-+ function = "alt4";
-+ };
-+ pin-rx-ok {
-+ pins = "gpio36";
-+ function = "alt4";
-+ };
-+ };
-+ rgmii_irq_gpio34: rgmii_irq_gpio34 {
-+ pin-irq {
-+ pins = "gpio34";
-+ function = "alt5";
-+ };
-+ };
-+ rgmii_irq_gpio39: rgmii_irq_gpio39 {
-+ pin-irq {
-+ pins = "gpio39";
-+ function = "alt4";
-+ };
-+ };
-+ rgmii_mdio_gpio28: rgmii_mdio_gpio28 {
-+ pins-mdio {
-+ pins = "gpio28",
-+ "gpio29";
-+ function = "alt5";
-+ };
-+ };
-+ rgmii_mdio_gpio37: rgmii_mdio_gpio37 {
-+ pins-mdio {
-+ pins = "gpio37",
-+ "gpio38";
-+ function = "alt4";
-+ };
-+ };
-+
-+ spi0_gpio46: spi0_gpio46 {
-+ pins-spi {
-+ pins = "gpio46",
-+ "gpio47",
-+ "gpio48",
-+ "gpio49";
-+ function = "alt2";
-+ };
-+ };
-+ spi2_gpio46: spi2_gpio46 {
-+ pins-spi {
-+ pins = "gpio46",
-+ "gpio47",
-+ "gpio48",
-+ "gpio49",
-+ "gpio50";
-+ function = "alt5";
-+ };
-+ };
-+ spi3_gpio0: spi3_gpio0 {
-+ pins-spi {
-+ pins = "gpio0",
-+ "gpio1",
-+ "gpio2",
-+ "gpio3";
-+ function = "alt3";
-+ };
-+ };
-+ spi4_gpio4: spi4_gpio4 {
-+ pins-spi {
-+ pins = "gpio4",
-+ "gpio5",
-+ "gpio6",
-+ "gpio7";
-+ function = "alt3";
-+ };
-+ };
-+ spi5_gpio12: spi5_gpio12 {
-+ pins-spi {
-+ pins = "gpio12",
-+ "gpio13",
-+ "gpio14",
-+ "gpio15";
-+ function = "alt3";
-+ };
-+ };
-+ spi6_gpio18: spi6_gpio18 {
-+ pins-spi {
-+ pins = "gpio18",
-+ "gpio19",
-+ "gpio20",
-+ "gpio21";
-+ function = "alt3";
-+ };
-+ };
-+
-+ uart2_gpio0: uart2_gpio0 {
-+ pin-tx {
-+ pins = "gpio0";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio1";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 {
-+ pin-cts {
-+ pins = "gpio2";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio3";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart3_gpio4: uart3_gpio4 {
-+ pin-tx {
-+ pins = "gpio4";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio5";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 {
-+ pin-cts {
-+ pins = "gpio6";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio7";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart4_gpio8: uart4_gpio8 {
-+ pin-tx {
-+ pins = "gpio8";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio9";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 {
-+ pin-cts {
-+ pins = "gpio10";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio11";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+ uart5_gpio12: uart5_gpio12 {
-+ pin-tx {
-+ pins = "gpio12";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ pin-rx {
-+ pins = "gpio13";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ };
-+ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 {
-+ pin-cts {
-+ pins = "gpio14";
-+ function = "alt4";
-+ bias-pull-up;
-+ };
-+ pin-rts {
-+ pins = "gpio15";
-+ function = "alt4";
-+ bias-disable;
-+ };
-+ };
-+};
-+
-+&i2c0 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&i2c1 {
-+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
-+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mailbox {
-+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&sdhci {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&sdhost {
-+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi {
-+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&spi2 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&system_timer {
-+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&txp {
-+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart0 {
-+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&uart1 {
-+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&usb {
-+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&vec {
-+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi
-@@ -0,0 +1,7 @@
-+// SPDX-License-Identifier: GPL-2.0
-+&usb {
-+ dr_mode = "peripheral";
-+ g-rx-fifo-size = <256>;
-+ g-np-tx-fifo-size = <32>;
-+ g-tx-fifo-size = <256 256 512 512 512 768 768>;
-+};
--- /dev/null
+From 9a536b0cb8f83bd979fe274ef0197ece12a3ed09 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Thu, 20 Feb 2020 21:29:56 +0100
+Subject: [PATCH] ASoC: pcm512x: Fix unbalanced regulator enable call
+ in probe error path
+
+commit ac0a68997935c4acb92eaae5ad8982e0bb432d56 upstream.
+
+When we get a clock error during probe we have to call
+regulator_bulk_disable before bailing out, otherwise we trigger
+a warning in regulator_put.
+
+Fix this by using "goto err" like in the error cases above.
+
+Fixes: 5a3af1293194d ("ASoC: pcm512x: Add PCM512x driver")
+Signed-off-by: Matthias Reichl <hias@horus.com>
+Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Link: https://lore.kernel.org/r/20200220202956.29233-1-hias@horus.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ sound/soc/codecs/pcm512x.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/codecs/pcm512x.c
++++ b/sound/soc/codecs/pcm512x.c
+@@ -1564,13 +1564,15 @@ int pcm512x_probe(struct device *dev, st
+ }
+
+ pcm512x->sclk = devm_clk_get(dev, NULL);
+- if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+- return -EPROBE_DEFER;
++ if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) {
++ ret = -EPROBE_DEFER;
++ goto err;
++ }
+ if (!IS_ERR(pcm512x->sclk)) {
+ ret = clk_prepare_enable(pcm512x->sclk);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+- return ret;
++ goto err;
+ }
+ }
+
+++ /dev/null
-From 4bcb99a967998d255ef009bb0b6880ae99c6f6bf Mon Sep 17 00:00:00 2001
-From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
-Date: Wed, 6 Nov 2019 10:59:44 +0100
-Subject: [PATCH] ARM: dts: bcm2711: force CMA into first GB of memory
-
-arm64 places the CMA in ZONE_DMA32, which is not good enough for the
-Raspberry Pi 4 since it contains peripherals that can only address the
-first GB of memory. Explicitly place the CMA into that area.
-
-Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
-Acked-by: Stefan Wahren <wahrenst@gmx.net>
-Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
----
- arch/arm/boot/dts/bcm2711.dtsi | 20 ++++++++++++++++++++
- 1 file changed, 20 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -12,6 +12,26 @@
-
- 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;
-+ };
-+ };
-+
-+
- soc {
- /*
- * Defined ranges:
--- /dev/null
+From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 28 Feb 2020 11:22:40 +0000
+Subject: [PATCH] ARM: dts: overlays: Create custom clocks in /
+
+Change [1] removes the simple-bus compatible string from the "/clocks"
+node, preventing any custom clocks placed there from being initialised.
+Rather than reinstate the compatible string and trigger DT warnings at
+kernel build time, change the overlays to instantiate those clocks under
+the root node ("/").
+
+See: https://github.com/raspberrypi/linux/issues/3481
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+
+[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks")
+---
+ .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +-
+ 5 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
++++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
+@@ -9,7 +9,7 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target-path = "/clocks";
++ target-path = "/";
+ __overlay__ {
+ boss_osc: boss_osc {
+ compatible = "allo,dac-clk";
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -6,7 +6,7 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target-path = "/clocks";
++ target-path = "/";
+ __overlay__ {
+ dacpro_osc: dacpro_osc {
+ compatible = "hifiberry,dacpro-clk";
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -6,7 +6,7 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target-path = "/clocks";
++ target-path = "/";
+ __overlay__ {
+ dacpro_osc: dacpro_osc {
+ compatible = "hifiberry,dacpro-clk";
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -6,7 +6,7 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target-path = "/clocks";
++ target-path = "/";
+ __overlay__ {
+ dacpro_osc: dacpro_osc {
+ compatible = "hifiberry,dacpro-clk";
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+@@ -8,7 +8,7 @@
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+- target-path = "/clocks";
++ target-path = "/";
+ __overlay__ {
+ dachd_osc: pll_dachd_osc {
+ compatible = "hifiberry,dachd-clk";
+++ /dev/null
-From 32847947e1d1e1ac2a73c7ea8ad47cca49aef5d4 Mon Sep 17 00:00:00 2001
-From: Stefan Wahren <wahrenst@gmx.net>
-Date: Mon, 11 Nov 2019 20:49:26 +0100
-Subject: [PATCH] ARM: dts: bcm2711-rpi-4: Enable GENET support
-
-This enables the Gigabit Ethernet support on the Raspberry Pi 4.
-The defined PHY mode is equivalent to the default register settings
-in the downstream tree.
-
-Signed-off-by: Matthias Brugger <mbrugger@suse.com>
-Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
-Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 17 +++++++++++++++++
- arch/arm/boot/dts/bcm2711.dtsi | 26 ++++++++++++++++++++++++++
- 2 files changed, 43 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -19,6 +19,10 @@
- reg = <0 0 0>;
- };
-
-+ aliases {
-+ ethernet0 = &genet;
-+ };
-+
- leds {
- act {
- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-@@ -97,6 +101,19 @@
- status = "okay";
- };
-
-+&genet {
-+ phy-handle = <&phy1>;
-+ phy-mode = "rgmii-rxid";
-+ status = "okay";
-+};
-+
-+&genet_mdio {
-+ phy1: ethernet-phy@1 {
-+ /* No PHY interrupt */
-+ reg = <0x1>;
-+ };
-+};
-+
- /* uart0 communicates with the BT module */
- &uart0 {
- pinctrl-names = "default";
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -325,6 +325,32 @@
- cpu-release-addr = <0x0 0x000000f0>;
- };
- };
-+
-+ scb {
-+ compatible = "simple-bus";
-+ #address-cells = <2>;
-+ #size-cells = <1>;
-+
-+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
-+
-+ genet: ethernet@7d580000 {
-+ compatible = "brcm,bcm2711-genet-v5";
-+ reg = <0x0 0x7d580000 0x10000>;
-+ #address-cells = <0x1>;
-+ #size-cells = <0x1>;
-+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+
-+ genet_mdio: mdio@e14 {
-+ compatible = "brcm,genet-mdio-v5";
-+ reg = <0xe14 0x8>;
-+ reg-names = "mdio";
-+ #address-cells = <0x0>;
-+ #size-cells = <0x1>;
-+ };
-+ };
-+ };
- };
-
- &clk_osc {
--- /dev/null
+From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001
+From: Naushir Patuck <naush@raspberrypi.com>
+Date: Thu, 30 Jan 2020 12:35:44 +0000
+Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when
+ counting transactions
+
+The response block and local state were using u16 and u32 respectively
+to represent transaction id. When the former would wrap, there is a
+mismatch and subsequent transactions will be marked as failures.
+
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
+@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk {
+ /* To be signaled when the response is there */
+ struct completion cmplt;
+
+- u16 id;
++ u32 id;
+ u16 length;
+
+ u8 msg[VC_SM_MAX_MSG_LEN];
+++ /dev/null
-From 44d7ee4730fbe3c00aba0457489acd0b6e2937c9 Mon Sep 17 00:00:00 2001
-From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
-Date: Wed, 4 Dec 2019 13:56:33 +0100
-Subject: [PATCH] ARM: dts: bcm2711: fix soc's node dma-ranges
-
-Raspberry Pi's firmware has a feature to select how much memory to
-reserve for its GPU called 'gpu_mem'. The possible values go from 16MB
-to 944MB, with a default of 64MB. This memory resides in the topmost
-part of the lower 1GB memory area and grows bigger expanding towards the
-begging of memory.
-
-It turns out that with low 'gpu_mem' values (16MB and 32MB) the size of
-the memory available to the system in the lower 1GB area can outgrow the
-interconnect's dma-range as its size was selected based on the maximum
-system memory available given the default gpu_mem configuration. This
-makes that memory slice unavailable for DMA. And may cause nasty kernel
-warnings if CMA happens to include it.
-
-Change soc's dma-ranges to really reflect it's HW limitation, which is
-being able to only DMA to the lower 1GB area.
-
-Fixes: 7dbe8c62ceeb ("ARM: dts: Add minimal Raspberry Pi 4 support")
-Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
-Reviewed-by: Phil Elwell <phil@raspberrypi.org>
-Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
----
- arch/arm/boot/dts/bcm2711.dtsi | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/bcm2711.dtsi
-+++ b/arch/arm/boot/dts/bcm2711.dtsi
-@@ -43,7 +43,7 @@
- <0x7c000000 0x0 0xfc000000 0x02000000>,
- <0x40000000 0x0 0xff800000 0x00800000>;
- /* Emulate a contiguous 30-bit address range for DMA */
-- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
-+ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>;
-
- /*
- * This node is the provider for the enable-method for
--- /dev/null
+From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Fri, 7 Feb 2020 09:51:31 +0000
+Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff
+
+The timeout_ms parameter specifies in milliseconds how long the kernel
+waits for power-down before issuing a WARN. The default value is 3000 ms.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -821,6 +821,8 @@ Params: gpiopin GPIO for
+ input Set if the gpio pin should be configured as
+ an input.
+ export Set to export the configured pin to sysfs
++ timeout_ms Specify (in ms) how long the kernel waits for
++ power-down before issuing a WARN (default 3000).
+
+
+ Name: gpio-shutdown
+--- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
+@@ -32,5 +32,6 @@
+ active_low = <&power_ctrl>,"gpios:8";
+ input = <&power_ctrl>,"input?";
+ export = <&power_ctrl>,"export?";
++ timeout_ms = <&power_ctrl>,"timeout-ms:0";
+ };
+ };
+++ /dev/null
-From b229e7f5a6d21d1b52f3f19fed58bba638714884 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Thu, 30 Jan 2020 15:48:00 +0000
-Subject: [PATCH] ARM: dts: Rebuild downstream DTS files
-
-Refactor the tree of downstream DTS files to achieve approximately the
-same end result but wihout modifying upstream files (except for
-bcm2711-rpi-4-b.dts).
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm2708-rpi.dtsi | 133 +--------
- arch/arm/boot/dts/bcm2708.dtsi | 4 +
- arch/arm/boot/dts/bcm2709.dtsi | 4 +
- arch/arm/boot/dts/bcm270x-rpi.dtsi | 139 +++++++++
- arch/arm/boot/dts/bcm270x.dtsi | 98 ++++---
- arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 13 +
- arch/arm/boot/dts/bcm2710.dtsi | 4 +
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 315 ++++++++++++++++++++-
- arch/arm/boot/dts/bcm2711-rpi.dtsi | 222 +++++++++++++++
- 9 files changed, 766 insertions(+), 166 deletions(-)
- create mode 100644 arch/arm/boot/dts/bcm270x-rpi.dtsi
- create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi
-
---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
-@@ -1,6 +1,7 @@
--/* Downstream modifications to bcm2835-rpi.dtsi */
-+/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */
-
- #include "bcm2835-rpi.dtsi"
-+#include "bcm270x-rpi.dtsi"
-
- / {
- memory@0 {
-@@ -9,147 +10,27 @@
- };
-
- aliases {
-- audio = &audio;
-- aux = &aux;
-- sound = &sound;
-- soc = &soc;
-- dma = &dma;
-- intc = &intc;
-- watchdog = &watchdog;
-- random = &random;
-- mailbox = &mailbox;
-- gpio = &gpio;
-- uart0 = &uart0;
-- sdhost = &sdhost;
-- mmc0 = &sdhost;
-- i2s = &i2s;
-- spi0 = &spi0;
-- i2c0 = &i2c0;
-- uart1 = &uart1;
-- spi1 = &spi1;
-- spi2 = &spi2;
-- mmc = &mmc;
-- mmc1 = &mmc;
-- i2c1 = &i2c1;
- i2c2 = &i2c2;
-- usb = &usb;
-- leds = &leds;
-- fb = &fb;
-- thermal = &thermal;
-- axiperf = &axiperf;
-- };
--
-- leds: leds {
-- compatible = "gpio-leds";
-- };
--
-- soc {
-- gpiomem {
-- compatible = "brcm,bcm2835-gpiomem";
-- reg = <0x7e200000 0x1000>;
-- };
--
-- fb: fb {
-- compatible = "brcm,bcm2708-fb";
-- firmware = <&firmware>;
-- status = "okay";
-- };
--
-- vcsm: vcsm {
-- compatible = "raspberrypi,bcm2835-vcsm";
-- firmware = <&firmware>;
-- status = "okay";
-- };
--
-- /* Onboard audio */
-- audio: audio {
-- compatible = "brcm,bcm2835-audio";
-- brcm,pwm-channels = <8>;
-- status = "disabled";
-- };
--
-- /* External sound card */
-- sound: sound {
-- status = "disabled";
-- };
- };
-
- __overrides__ {
-- cache_line_size;
--
-- uart0 = <&uart0>,"status";
-- uart1 = <&uart1>,"status";
-- i2s = <&i2s>,"status";
-- spi = <&spi0>,"status";
-- i2c0 = <&i2c0>,"status";
-- i2c1 = <&i2c1>,"status";
- i2c2_iknowwhatimdoing = <&i2c2>,"status";
-- i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-- i2c1_baudrate = <&i2c1>,"clock-frequency:0";
- i2c2_baudrate = <&i2c2>,"clock-frequency:0";
--
-- audio = <&audio>,"status";
-- watchdog = <&watchdog>,"status";
-- random = <&random>,"status";
-- sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-- sd_poll_once = <&sdhost>,"non-removable?";
-- sd_force_pio = <&sdhost>,"brcm,force-pio?";
-- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-- sd_debug = <&sdhost>,"brcm,debug";
-- sdio_overclock = <&mmc>,"brcm,overclock-50:0",
-- <&mmcnr>,"brcm,overclock-50:0";
-- axiperf = <&axiperf>,"status";
-+ sd_poll_once = <&sdhost>, "non-removable?";
- };
- };
-
--&hdmi {
-- power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-- status = "disabled";
--};
--
--&txp {
-- status = "disabled";
--};
--
--&i2c0 {
-- status = "disabled";
--};
--
--&i2c1 {
-- status = "disabled";
--};
--
--&i2c2 {
-- status = "disabled";
--};
--
--&clocks {
-- firmware = <&firmware>;
--};
--
--&sdhci {
-- pinctrl-names = "default";
-- pinctrl-0 = <&emmc_gpio48>;
-- bus-width = <4>;
--};
--
--sdhost_pins: &sdhost_gpio48 {
-- /* Add alias */
--};
--
- &sdhost {
- pinctrl-names = "default";
- pinctrl-0 = <&sdhost_gpio48>;
-- bus-width = <4>;
-- brcm,overclock-50 = <0>;
-- brcm,pio-limit = <1>;
- status = "okay";
- };
-
--&cpu_thermal {
-- /delete-node/ trips;
-+&hdmi {
-+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
-+ status = "disabled";
- };
-
--&vec {
-+&i2c2 {
- status = "disabled";
- };
---- a/arch/arm/boot/dts/bcm2708.dtsi
-+++ b/arch/arm/boot/dts/bcm2708.dtsi
-@@ -8,3 +8,7 @@
- arm_freq;
- };
- };
-+
-+&vc4 {
-+ status = "disabled";
-+};
---- a/arch/arm/boot/dts/bcm2709.dtsi
-+++ b/arch/arm/boot/dts/bcm2709.dtsi
-@@ -16,3 +16,7 @@
- <&v7_cpu3>, "clock-frequency:0";
- };
- };
-+
-+&vc4 {
-+ status = "disabled";
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi
-@@ -0,0 +1,139 @@
-+/* Downstream modifications to bcm2835-rpi.dtsi */
-+
-+/ {
-+ aliases {
-+ audio = &audio;
-+ aux = &aux;
-+ sound = &sound;
-+ soc = &soc;
-+ dma = &dma;
-+ intc = &intc;
-+ watchdog = &watchdog;
-+ random = &random;
-+ mailbox = &mailbox;
-+ gpio = &gpio;
-+ uart0 = &uart0;
-+ uart1 = &uart1;
-+ sdhost = &sdhost;
-+ mmc = &mmc;
-+ mmc1 = &mmc;
-+ mmc0 = &sdhost;
-+ i2s = &i2s;
-+ i2c0 = &i2c0;
-+ i2c1 = &i2c1;
-+ spi0 = &spi0;
-+ spi1 = &spi1;
-+ spi2 = &spi2;
-+ usb = &usb;
-+ leds = &leds;
-+ fb = &fb;
-+ thermal = &thermal;
-+ axiperf = &axiperf;
-+ };
-+
-+ /* Define these notional regulators for use by overlays */
-+ vdd_3v3_reg: fixedregulator_3v3 {
-+ compatible = "regulator-fixed";
-+ regulator-always-on;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-min-microvolt = <3300000>;
-+ regulator-name = "3v3";
-+ };
-+
-+ vdd_5v0_reg: fixedregulator_5v0 {
-+ compatible = "regulator-fixed";
-+ regulator-always-on;
-+ regulator-max-microvolt = <5000000>;
-+ regulator-min-microvolt = <5000000>;
-+ regulator-name = "5v0";
-+ };
-+
-+ leds: leds {
-+ compatible = "gpio-leds";
-+ };
-+
-+ soc {
-+ gpiomem {
-+ compatible = "brcm,bcm2835-gpiomem";
-+ reg = <0x7e200000 0x1000>;
-+ };
-+
-+ fb: fb {
-+ compatible = "brcm,bcm2708-fb";
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
-+
-+ vcsm: vcsm {
-+ compatible = "raspberrypi,bcm2835-vcsm";
-+ firmware = <&firmware>;
-+ status = "okay";
-+ };
-+
-+ /* Onboard audio */
-+ audio: audio {
-+ compatible = "brcm,bcm2835-audio";
-+ brcm,pwm-channels = <8>;
-+ status = "disabled";
-+ };
-+
-+ /* External sound card */
-+ sound: sound {
-+ status = "disabled";
-+ };
-+ };
-+
-+ __overrides__ {
-+ cache_line_size;
-+
-+ uart0 = <&uart0>,"status";
-+ uart1 = <&uart1>,"status";
-+ i2s = <&i2s>,"status";
-+ spi = <&spi0>,"status";
-+ i2c0 = <&i2c0>,"status";
-+ i2c1 = <&i2c1>,"status";
-+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
-+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
-+
-+ audio = <&audio>,"status";
-+ watchdog = <&watchdog>,"status";
-+ random = <&random>,"status";
-+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
-+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
-+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
-+ sd_debug = <&sdhost>,"brcm,debug";
-+ sdio_overclock = <&mmc>,"brcm,overclock-50:0",
-+ <&mmcnr>,"brcm,overclock-50:0";
-+ axiperf = <&axiperf>,"status";
-+ };
-+};
-+
-+&txp {
-+ status = "disabled";
-+};
-+
-+&i2c0 {
-+ status = "disabled";
-+};
-+
-+&i2c1 {
-+ status = "disabled";
-+};
-+
-+&clocks {
-+ firmware = <&firmware>;
-+};
-+
-+&sdhci {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&emmc_gpio48>;
-+ bus-width = <4>;
-+};
-+
-+&cpu_thermal {
-+ /delete-node/ trips;
-+};
-+
-+&vec {
-+ status = "disabled";
-+};
---- a/arch/arm/boot/dts/bcm270x.dtsi
-+++ b/arch/arm/boot/dts/bcm270x.dtsi
-@@ -17,32 +17,8 @@
- /* Add label */
- };
-
-- gpio@7e200000 { /* gpio */
-- interrupts = <2 17>, <2 18>;
--
-- dpi_18bit_gpio0: dpi_18bit_gpio0 {
-- brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
-- 12 13 14 15 16 17 18 19
-- 20 21>;
-- brcm,function = <BCM2835_FSEL_ALT2>;
-- };
-- };
--
-- serial@7e201000 { /* uart0 */
-- /* Enable CTS bug workaround */
-- cts-event-workaround;
-- };
--
-- i2s@7e203000 { /* i2s */
-- #sound-dai-cells = <0>;
-- reg = <0x7e203000 0x24>;
-- clocks = <&clocks BCM2835_CLOCK_PCM>;
-- };
--
- spi0: spi@7e204000 {
- /* Add label */
-- dmas = <&dma 6>, <&dma 7>;
-- dma-names = "tx", "rx";
- };
-
- pixelvalve0: pixelvalve@7e206000 {
-@@ -55,17 +31,6 @@
- status = "disabled";
- };
-
-- 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>;
-- status = "disabled";
-- };
--
- /delete-node/ sdhci@7e300000;
-
- sdhci: mmc: mmc@7e300000 {
-@@ -118,6 +83,34 @@
- status = "disabled";
- };
-
-+ csi0: csi@7e800000 {
-+ compatible = "brcm,bcm2835-unicam";
-+ reg = <0x7e800000 0x800>,
-+ <0x7e802000 0x4>;
-+ interrupts = <2 6>;
-+ clocks = <&clocks BCM2835_CLOCK_CAM0>;
-+ clock-names = "lp";
-+ power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ #clock-cells = <1>;
-+ status = "disabled";
-+ };
-+
-+ csi1: csi@7e801000 {
-+ compatible = "brcm,bcm2835-unicam";
-+ reg = <0x7e801000 0x800>,
-+ <0x7e802004 0x4>;
-+ interrupts = <2 7>;
-+ clocks = <&clocks BCM2835_CLOCK_CAM1>;
-+ clock-names = "lp";
-+ power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ #clock-cells = <1>;
-+ status = "disabled";
-+ };
-+
- pixelvalve2: pixelvalve@7e807000 {
- /* Add label */
- status = "disabled";
-@@ -160,6 +153,37 @@
- };
- };
-
--&vc4 {
-- status = "disabled";
-+&gpio {
-+ interrupts = <2 17>, <2 18>;
-+
-+ dpi_18bit_gpio0: dpi_18bit_gpio0 {
-+ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
-+ 12 13 14 15 16 17 18 19
-+ 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT2>;
-+ };
-+};
-+
-+&uart0 {
-+ /* Enable CTS bug workaround */
-+ cts-event-workaround;
-+};
-+
-+&i2s {
-+ #sound-dai-cells = <0>;
-+ dmas = <&dma 2>, <&dma 3>;
-+ dma-names = "tx", "rx";
-+};
-+
-+&sdhost {
-+ dmas = <&dma (13|(1<<29))>;
-+ dma-names = "rx-tx";
-+ bus-width = <4>;
-+ brcm,overclock-50 = <0>;
-+ brcm,pio-limit = <1>;
-+};
-+
-+&spi0 {
-+ dmas = <&dma 6>, <&dma 7>;
-+ dma-names = "tx", "rx";
- };
---- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
-@@ -170,6 +170,12 @@
- pinctrl-0 = <&audio_pins>;
- };
-
-+ð_phy {
-+ microchip,eee-enabled;
-+ microchip,tx-lpi-timer = <600>; /* non-aggressive*/
-+ microchip,downshift-after = <2>;
-+};
-+
- / {
- __overrides__ {
- act_led_gpio = <&act_led>,"gpios:4";
-@@ -179,5 +185,12 @@
- pwr_led_gpio = <&pwr_led>,"gpios:4";
- pwr_led_activelow = <&pwr_led>,"gpios:8";
- pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ eee = <ð_phy>,"microchip,eee-enabled?";
-+ tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0";
-+ eth_led0 = <ð_phy>,"microchip,led-modes:0";
-+ eth_led1 = <ð_phy>,"microchip,led-modes:4";
-+ eth_downshift_after = <ð_phy>,"microchip,downshift-after:0";
-+ eth_max_speed = <ð_phy>,"max-speed:0";
- };
- };
---- a/arch/arm/boot/dts/bcm2710.dtsi
-+++ b/arch/arm/boot/dts/bcm2710.dtsi
-@@ -23,3 +23,7 @@
- <&cpu3>, "clock-frequency:0";
- };
- };
-+
-+&vc4 {
-+ status = "disabled";
-+};
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -2,7 +2,6 @@
- /dts-v1/;
- #include "bcm2711.dtsi"
- #include "bcm2835-rpi.dtsi"
--#include "bcm283x-rpi-usb-peripheral.dtsi"
-
- / {
- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
-@@ -65,8 +64,8 @@
- "GLOBAL_RESET",
- "VDD_SD_IO_SEL",
- "CAM_GPIO",
-- "",
-- "";
-+ "SD_PWR_ON",
-+ "SD_OC_N";
- status = "okay";
- };
- };
-@@ -138,3 +137,313 @@
- &vchiq {
- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
- };
-+
-+// =============================================
-+// Downstream rpi- changes
-+
-+#include "bcm270x.dtsi"
-+#include "bcm2711-rpi.dtsi"
-+#include "bcm283x-rpi-csi1-2lane.dtsi"
-+
-+/ {
-+ chosen {
-+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M";
-+ };
-+
-+ aliases {
-+ serial0 = &uart1;
-+ serial1 = &uart0;
-+ mmc0 = &emmc2;
-+ mmc1 = &mmcnr;
-+ mmc2 = &sdhost;
-+ /delete-property/ i2c2;
-+ i2c3 = &i2c3;
-+ i2c4 = &i2c4;
-+ i2c5 = &i2c5;
-+ i2c6 = &i2c6;
-+ /delete-property/ ethernet;
-+ /delete-property/ intc;
-+ pcie0 = &pcie_0;
-+ };
-+
-+ /delete-node/ wifi-pwrseq;
-+};
-+
-+&mmcnr {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio_pins>;
-+ bus-width = <4>;
-+ status = "okay";
-+};
-+
-+&uart0 {
-+ pinctrl-0 = <&uart0_pins &bt_pins>;
-+ status = "okay";
-+
-+ /delete-node/ bluetooth;
-+};
-+
-+&uart1 {
-+ pinctrl-0 = <&uart1_pins>;
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
-+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
-+
-+ spidev0: spidev@0{
-+ compatible = "spidev";
-+ reg = <0>; /* CE0 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ };
-+
-+ spidev1: spidev@1{
-+ compatible = "spidev";
-+ reg = <1>; /* CE1 */
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ spi-max-frequency = <125000000>;
-+ };
-+};
-+
-+&gpio {
-+ spi0_pins: spi0_pins {
-+ brcm,pins = <9 10 11>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ spi0_cs_pins: spi0_cs_pins {
-+ brcm,pins = <8 7>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi3_pins: spi3_pins {
-+ brcm,pins = <1 2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi3_cs_pins: spi3_cs_pins {
-+ brcm,pins = <0 24>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi4_pins: spi4_pins {
-+ brcm,pins = <5 6 7>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi4_cs_pins: spi4_cs_pins {
-+ brcm,pins = <4 25>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi5_pins: spi5_pins {
-+ brcm,pins = <13 14 15>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi5_cs_pins: spi5_cs_pins {
-+ brcm,pins = <12 26>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ spi6_pins: spi6_pins {
-+ brcm,pins = <19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ };
-+
-+ spi6_cs_pins: spi6_cs_pins {
-+ brcm,pins = <18 27>;
-+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
-+ };
-+
-+ i2c0_pins: i2c0 {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2c1_pins: i2c1 {
-+ brcm,pins = <2 3>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2c3_pins: i2c3 {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2c4_pins: i2c4 {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2c5_pins: i2c5 {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2c6_pins: i2c6 {
-+ brcm,pins = <22 23>;
-+ brcm,function = <BCM2835_FSEL_ALT5>;
-+ brcm,pull = <BCM2835_PUD_UP>;
-+ };
-+
-+ i2s_pins: i2s {
-+ brcm,pins = <18 19 20 21>;
-+ brcm,function = <BCM2835_FSEL_ALT0>;
-+ };
-+
-+ sdio_pins: sdio_pins {
-+ brcm,pins = <34 35 36 37 38 39>;
-+ brcm,function = <BCM2835_FSEL_ALT3>; // alt3 = SD1
-+ brcm,pull = <0 2 2 2 2 2>;
-+ };
-+
-+ bt_pins: bt_pins {
-+ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0
-+ // to fool pinctrl
-+ brcm,function = <0>;
-+ brcm,pull = <2>;
-+ };
-+
-+ uart0_pins: uart0_pins {
-+ brcm,pins = <32 33>;
-+ brcm,function = <BCM2835_FSEL_ALT3>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart1_pins: uart1_pins {
-+ brcm,pins;
-+ brcm,function;
-+ brcm,pull;
-+ };
-+
-+ uart2_pins: uart2_pins {
-+ brcm,pins = <0 1>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart3_pins: uart3_pins {
-+ brcm,pins = <4 5>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart4_pins: uart4_pins {
-+ brcm,pins = <8 9>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+
-+ uart5_pins: uart5_pins {
-+ brcm,pins = <12 13>;
-+ brcm,function = <BCM2835_FSEL_ALT4>;
-+ brcm,pull = <0 2>;
-+ };
-+};
-+
-+&i2c0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2c1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ clock-frequency = <100000>;
-+};
-+
-+&i2s {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ /delete-property/ i2c2_baudrate;
-+ /delete-property/ i2c2_iknowwhatimdoing;
-+ };
-+};
-+
-+// =============================================
-+// Board specific stuff here
-+
-+/ {
-+ sd_vcc_reg: sd_vcc_reg {
-+ compatible = "regulator-fixed";
-+ regulator-name = "vcc-sd";
-+ regulator-min-microvolt = <3300000>;
-+ regulator-max-microvolt = <3300000>;
-+ regulator-boot-on;
-+ enable-active-high;
-+ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
-+ };
-+};
-+
-+&sdhost {
-+ status = "disabled";
-+};
-+
-+&emmc2 {
-+ vmmc-supply = <&sd_vcc_reg>;
-+};
-+
-+&phy1 {
-+ led-modes = <0x00 0x08>; /* link/activity link */
-+};
-+
-+&gpio {
-+ audio_pins: audio_pins {
-+ brcm,pins = <40 41>;
-+ brcm,function = <4>;
-+ };
-+};
-+
-+&leds {
-+ act_led: act {
-+ label = "led0";
-+ linux,default-trigger = "mmc0";
-+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
-+ };
-+
-+ pwr_led: pwr {
-+ label = "led1";
-+ linux,default-trigger = "default-on";
-+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
-+ };
-+};
-+
-+&pwm1 {
-+ status = "disabled";
-+};
-+
-+&audio {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&audio_pins>;
-+};
-+
-+/ {
-+ __overrides__ {
-+ act_led_gpio = <&act_led>,"gpios:4";
-+ act_led_activelow = <&act_led>,"gpios:8";
-+ act_led_trigger = <&act_led>,"linux,default-trigger";
-+
-+ pwr_led_gpio = <&pwr_led>,"gpios:4";
-+ pwr_led_activelow = <&pwr_led>,"gpios:8";
-+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
-+
-+ eth_led0 = <&phy1>,"led-modes:0";
-+ eth_led1 = <&phy1>,"led-modes:4";
-+
-+ };
-+};
---- /dev/null
-+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
-@@ -0,0 +1,222 @@
-+// SPDX-License-Identifier: GPL-2.0
-+#include "bcm270x-rpi.dtsi"
-+
-+/ {
-+ soc {
-+ /delete-node/ v3d@7ec00000;
-+ /delete-node/ mailbox@7e00b840;
-+ };
-+
-+ __overrides__ {
-+ arm_freq;
-+ sd_poll_once = <&emmc2>, "non-removable?";
-+ };
-+
-+ v3dbus {
-+ compatible = "simple-bus";
-+ #address-cells = <1>;
-+ #size-cells = <2>;
-+ ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>,
-+ <0x40000000 0x0 0xff800000 0x0 0x00800000>;
-+ dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>;
-+
-+ v3d: v3d@7ec04000 {
-+ compatible = "brcm,2711-v3d";
-+ reg =
-+ <0x7ec00000 0x0 0x4000>,
-+ <0x7ec04000 0x0 0x4000>;
-+ reg-names = "hub", "core0";
-+
-+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
-+ resets = <&pm BCM2835_RESET_V3D>;
-+ clocks = <&clocks BCM2835_CLOCK_V3D>;
-+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+ };
-+ };
-+
-+ scb: scb {
-+ /* Add a label */
-+ };
-+};
-+
-+&soc {
-+ thermal: thermal@7d5d2200 {
-+ compatible = "brcm,avs-tmon-bcm2838";
-+ reg = <0x7d5d2200 0x2c>;
-+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "tmon";
-+ clocks = <&clocks BCM2835_CLOCK_TSENS>;
-+ #thermal-sensor-cells = <0>;
-+ status = "okay";
-+ };
-+
-+ vc4: gpu {
-+ compatible = "brcm,bcm2835-vc4";
-+ status = "disabled";
-+ };
-+};
-+
-+&scb {
-+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
-+ <0x0 0x40000000 0x0 0xff800000 0x00800000>,
-+ <0x6 0x00000000 0x6 0x00000000 0x40000000>,
-+ <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
-+ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
-+
-+ pcie_0: pcie@7d500000 {
-+ reg = <0x0 0x7d500000 0x9310>,
-+ <0x0 0x7e00f300 0x20>;
-+ msi-controller;
-+ msi-parent = <&pcie_0>;
-+ #address-cells = <3>;
-+ #interrupt-cells = <1>;
-+ #size-cells = <2>;
-+ bus-range = <0x0 0x01>;
-+ compatible = "brcm,bcm2711b0-pcie", // Safe value
-+ "brcm,bcm2711-pcie",
-+ "brcm,pci-plat-dev";
-+ max-link-speed = <2>;
-+ tot-num-pcie = <1>;
-+ linux,pci-domain = <0>;
-+ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "pcie", "msi";
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 2 &gicv2 GIC_SPI 144
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 3 &gicv2 GIC_SPI 145
-+ IRQ_TYPE_LEVEL_HIGH
-+ 0 0 0 4 &gicv2 GIC_SPI 146
-+ IRQ_TYPE_LEVEL_HIGH>;
-+
-+ /* Map outbound accesses from scb:0x6_00000000-03ffffff
-+ * to pci:0x0_f8000000-fbffffff
-+ */
-+ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
-+ 0x0 0x04000000>;
-+ /* Map inbound accesses from pci:0x0_00000000..ffffffff
-+ * to scb:0x0_00000000-ffffffff
-+ */
-+ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
-+ 0x1 0x00000000>;
-+ status = "okay";
-+ };
-+
-+ dma40: dma@7e007b00 {
-+ compatible = "brcm,bcm2838-dma";
-+ reg = <0x0 0x7e007b00 0x400>;
-+ interrupts =
-+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, /* dma4 12 */
-+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, /* dma4 13 */
-+ <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; /* dma4 14 */
-+ interrupt-names = "dma11",
-+ "dma12",
-+ "dma13",
-+ "dma14";
-+ #dma-cells = <1>;
-+ brcm,dma-channel-mask = <0x7800>;
-+ };
-+
-+ vchiq: mailbox@7e00b840 {
-+ compatible = "brcm,bcm2838-vchiq";
-+ reg = <0 0x7e00b840 0x3c>;
-+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ xhci: xhci@7e9c0000 {
-+ compatible = "generic-xhci";
-+ status = "disabled";
-+ reg = <0x0 0x7e9c0000 0x100000>;
-+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ hevc-decoder@7eb00000 {
-+ compatible = "raspberrypi,rpivid-hevc-decoder";
-+ reg = <0x0 0x7eb00000 0x10000>;
-+ status = "okay";
-+ };
-+
-+ rpivid-local-intc@7eb10000 {
-+ compatible = "raspberrypi,rpivid-local-intc";
-+ reg = <0x0 0x7eb10000 0x1000>;
-+ status = "okay";
-+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
-+ };
-+
-+ h264-decoder@7eb20000 {
-+ compatible = "raspberrypi,rpivid-h264-decoder";
-+ reg = <0x0 0x7eb20000 0x10000>;
-+ status = "okay";
-+ };
-+
-+ vp9-decoder@7eb30000 {
-+ compatible = "raspberrypi,rpivid-vp9-decoder";
-+ reg = <0x0 0x7eb30000 0x10000>;
-+ status = "okay";
-+ };
-+};
-+
-+&dma {
-+ /* The VPU firmware uses DMA channel 11 for VCHIQ */
-+ brcm,dma-channel-mask = <0x1f5>;
-+};
-+
-+&dma40 {
-+ /* The VPU firmware DMA channel 11 for VCHIQ */
-+ brcm,dma-channel-mask = <0x7000>;
-+};
-+
-+&firmwarekms {
-+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&smi {
-+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mmc {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&mmcnr {
-+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&csi0 {
-+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&csi1 {
-+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&random {
-+ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
-+ status = "okay";
-+};
-+
-+&usb {
-+ /* Enable the FIQ support */
-+ reg = <0x7e980000 0x10000>,
-+ <0x7e00b200 0x200>;
-+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+};
-+
-+&gpio {
-+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
-+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
-+};
-+
-+&cpu_thermal {
-+ thermal-sensors = <&thermal>;
-+};
-+
-+&genet {
-+ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5";
-+};
--- /dev/null
+From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 6 Feb 2020 12:23:15 +0000
+Subject: [PATCH] of: overlay: Correct symbol path fixups
+
+When symbols from overlays are added to the live tree their paths must
+be rebased. The translated symbol is normally the result of joining
+the fragment-relative path (with a leading "/") to the target path
+(either copied directly from the "target-path" property or resolved
+from the phandle). This translation fails when the target is the root
+node (a common case for Raspberry Pi overlays) because the resulting
+path starts with a double slash. For example, if target-path is "/" and
+the fragment adds a node called "newnode", the label associated with
+that node will be assigned the path "//newnode", which can't be found
+in the tree.
+
+Fix the failure case by explicitly replacing a target path of "/" with
+an empty string.
+
+Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree")
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/of/overlay.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/of/overlay.c
++++ b/drivers/of/overlay.c
+@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy
+ if (!target_path)
+ return NULL;
+ target_path_len = strlen(target_path);
++ if (!strcmp(target_path, "/"))
++ target_path_len = 0;
+
+ new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+ if (!new_prop)
--- /dev/null
+From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 3 Mar 2020 09:43:41 +0000
+Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter
+
+The xtal parameter is targetting the wrong node - fix it.
+
+See: https://github.com/raspberrypi/linux/issues/3156
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
+@@ -32,7 +32,7 @@
+ __overrides__ {
+ int_pin = <&sc16is750>,"interrupts:0";
+ addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name";
+- xtal = <&sc16is750>,"clock-frequency:0";
++ xtal = <&sc16is750_clk>,"clock-frequency:0";
+ };
+
+ };
+++ /dev/null
-From 871370c31c23fcd07ec375a088bd09a0a5a31126 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:26:18 +0000
-Subject: [PATCH] staging/vchiq_arm: Fix bcm2711 compatible string
-
-Fixes: "vchiq: Add 36-bit address support"
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -151,7 +151,7 @@ static struct vchiq_drvdata bcm2836_drvd
- .cache_line_size = 64,
- };
-
--static struct vchiq_drvdata bcm2838_drvdata = {
-+static struct vchiq_drvdata bcm2711_drvdata = {
- .cache_line_size = 64,
- .use_36bit_addrs = true,
- };
-@@ -3171,7 +3171,7 @@ void vchiq_platform_conn_state_changed(s
- static const struct of_device_id vchiq_of_match[] = {
- { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
- { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
-- { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata },
-+ { .compatible = "brcm,bcm2711-vchiq", .data = &bcm2711_drvdata },
- {},
- };
- MODULE_DEVICE_TABLE(of, vchiq_of_match);
+++ /dev/null
-From f498861a16d0b9a189a329080da1aa64d6e9bda7 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:28:57 +0000
-Subject: [PATCH] bcm2835-dma: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "bcm2835-dma: Add proper 40-bit DMA support"
----
- drivers/dma/bcm2835-dma.c | 274 +++++++++++++++++++-------------------
- 1 file changed, 137 insertions(+), 137 deletions(-)
-
---- a/drivers/dma/bcm2835-dma.c
-+++ b/drivers/dma/bcm2835-dma.c
-@@ -38,7 +38,7 @@
- #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
- #define BCM2835_DMA_CHAN_NAME_SIZE 8
- #define BCM2835_DMA_BULK_MASK BIT(0)
--#define BCM2838_DMA_MEMCPY_CHAN 14
-+#define BCM2711_DMA_MEMCPY_CHAN 14
-
- struct bcm2835_dma_cfg_data {
- u32 chan_40bit_mask;
-@@ -70,7 +70,7 @@ struct bcm2835_dma_cb {
- uint32_t pad[2];
- };
-
--struct bcm2838_dma40_scb {
-+struct bcm2711_dma40_scb {
- uint32_t ti;
- uint32_t src;
- uint32_t srci;
-@@ -200,98 +200,98 @@ struct bcm2835_desc {
- #define MAX_LITE_DMA_LEN (SZ_64K - 4)
-
- /* 40-bit DMA support */
--#define BCM2838_DMA40_CS 0x00
--#define BCM2838_DMA40_CB 0x04
--#define BCM2838_DMA40_DEBUG 0x0c
--#define BCM2838_DMA40_TI 0x10
--#define BCM2838_DMA40_SRC 0x14
--#define BCM2838_DMA40_SRCI 0x18
--#define BCM2838_DMA40_DEST 0x1c
--#define BCM2838_DMA40_DESTI 0x20
--#define BCM2838_DMA40_LEN 0x24
--#define BCM2838_DMA40_NEXT_CB 0x28
--#define BCM2838_DMA40_DEBUG2 0x2c
--
--#define BCM2838_DMA40_ACTIVE BIT(0)
--#define BCM2838_DMA40_END BIT(1)
--#define BCM2838_DMA40_INT BIT(2)
--#define BCM2838_DMA40_DREQ BIT(3) /* DREQ state */
--#define BCM2838_DMA40_RD_PAUSED BIT(4) /* Reading is paused */
--#define BCM2838_DMA40_WR_PAUSED BIT(5) /* Writing is paused */
--#define BCM2838_DMA40_DREQ_PAUSED BIT(6) /* Is paused by DREQ flow control */
--#define BCM2838_DMA40_WAITING_FOR_WRITES BIT(7) /* Waiting for last write */
--#define BCM2838_DMA40_ERR BIT(10)
--#define BCM2838_DMA40_QOS(x) (((x) & 0x1f) << 16)
--#define BCM2838_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20)
--#define BCM2838_DMA40_WAIT_FOR_WRITES BIT(28)
--#define BCM2838_DMA40_DISDEBUG BIT(29)
--#define BCM2838_DMA40_ABORT BIT(30)
--#define BCM2838_DMA40_HALT BIT(31)
--#define BCM2838_DMA40_CS_FLAGS(x) (x & (BCM2838_DMA40_QOS(15) | \
-- BCM2838_DMA40_PANIC_QOS(15) | \
-- BCM2838_DMA40_WAIT_FOR_WRITES | \
-- BCM2838_DMA40_DISDEBUG))
-+#define BCM2711_DMA40_CS 0x00
-+#define BCM2711_DMA40_CB 0x04
-+#define BCM2711_DMA40_DEBUG 0x0c
-+#define BCM2711_DMA40_TI 0x10
-+#define BCM2711_DMA40_SRC 0x14
-+#define BCM2711_DMA40_SRCI 0x18
-+#define BCM2711_DMA40_DEST 0x1c
-+#define BCM2711_DMA40_DESTI 0x20
-+#define BCM2711_DMA40_LEN 0x24
-+#define BCM2711_DMA40_NEXT_CB 0x28
-+#define BCM2711_DMA40_DEBUG2 0x2c
-+
-+#define BCM2711_DMA40_ACTIVE BIT(0)
-+#define BCM2711_DMA40_END BIT(1)
-+#define BCM2711_DMA40_INT BIT(2)
-+#define BCM2711_DMA40_DREQ BIT(3) /* DREQ state */
-+#define BCM2711_DMA40_RD_PAUSED BIT(4) /* Reading is paused */
-+#define BCM2711_DMA40_WR_PAUSED BIT(5) /* Writing is paused */
-+#define BCM2711_DMA40_DREQ_PAUSED BIT(6) /* Is paused by DREQ flow control */
-+#define BCM2711_DMA40_WAITING_FOR_WRITES BIT(7) /* Waiting for last write */
-+#define BCM2711_DMA40_ERR BIT(10)
-+#define BCM2711_DMA40_QOS(x) (((x) & 0x1f) << 16)
-+#define BCM2711_DMA40_PANIC_QOS(x) (((x) & 0x1f) << 20)
-+#define BCM2711_DMA40_WAIT_FOR_WRITES BIT(28)
-+#define BCM2711_DMA40_DISDEBUG BIT(29)
-+#define BCM2711_DMA40_ABORT BIT(30)
-+#define BCM2711_DMA40_HALT BIT(31)
-+#define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \
-+ BCM2711_DMA40_PANIC_QOS(15) | \
-+ BCM2711_DMA40_WAIT_FOR_WRITES | \
-+ BCM2711_DMA40_DISDEBUG))
-
- /* Transfer information bits */
--#define BCM2838_DMA40_INTEN BIT(0)
--#define BCM2838_DMA40_TDMODE BIT(1) /* 2D-Mode */
--#define BCM2838_DMA40_WAIT_RESP BIT(2) /* wait for AXI write to be acked */
--#define BCM2838_DMA40_WAIT_RD_RESP BIT(3) /* wait for AXI read to complete */
--#define BCM2838_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */
--#define BCM2838_DMA40_S_DREQ BIT(14) /* enable SREQ for source */
--#define BCM2838_DMA40_D_DREQ BIT(15) /* enable DREQ for destination */
--#define BCM2838_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* add DMA read-wait cycles */
--#define BCM2838_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* add DMA write-wait cycles */
-+#define BCM2711_DMA40_INTEN BIT(0)
-+#define BCM2711_DMA40_TDMODE BIT(1) /* 2D-Mode */
-+#define BCM2711_DMA40_WAIT_RESP BIT(2) /* wait for AXI write to be acked */
-+#define BCM2711_DMA40_WAIT_RD_RESP BIT(3) /* wait for AXI read to complete */
-+#define BCM2711_DMA40_PER_MAP(x) ((x & 31) << 9) /* REQ source */
-+#define BCM2711_DMA40_S_DREQ BIT(14) /* enable SREQ for source */
-+#define BCM2711_DMA40_D_DREQ BIT(15) /* enable DREQ for destination */
-+#define BCM2711_DMA40_S_WAIT(x) ((x & 0xff) << 16) /* add DMA read-wait cycles */
-+#define BCM2711_DMA40_D_WAIT(x) ((x & 0xff) << 24) /* add DMA write-wait cycles */
-
- /* debug register bits */
--#define BCM2838_DMA40_DEBUG_WRITE_ERR BIT(0)
--#define BCM2838_DMA40_DEBUG_FIFO_ERR BIT(1)
--#define BCM2838_DMA40_DEBUG_READ_ERR BIT(2)
--#define BCM2838_DMA40_DEBUG_READ_CB_ERR BIT(3)
--#define BCM2838_DMA40_DEBUG_IN_ON_ERR BIT(8)
--#define BCM2838_DMA40_DEBUG_ABORT_ON_ERR BIT(9)
--#define BCM2838_DMA40_DEBUG_HALT_ON_ERR BIT(10)
--#define BCM2838_DMA40_DEBUG_DISABLE_CLK_GATE BIT(11)
--#define BCM2838_DMA40_DEBUG_RSTATE_SHIFT 14
--#define BCM2838_DMA40_DEBUG_RSTATE_BITS 4
--#define BCM2838_DMA40_DEBUG_WSTATE_SHIFT 18
--#define BCM2838_DMA40_DEBUG_WSTATE_BITS 4
--#define BCM2838_DMA40_DEBUG_RESET BIT(23)
--#define BCM2838_DMA40_DEBUG_ID_SHIFT 24
--#define BCM2838_DMA40_DEBUG_ID_BITS 4
--#define BCM2838_DMA40_DEBUG_VERSION_SHIFT 28
--#define BCM2838_DMA40_DEBUG_VERSION_BITS 4
-+#define BCM2711_DMA40_DEBUG_WRITE_ERR BIT(0)
-+#define BCM2711_DMA40_DEBUG_FIFO_ERR BIT(1)
-+#define BCM2711_DMA40_DEBUG_READ_ERR BIT(2)
-+#define BCM2711_DMA40_DEBUG_READ_CB_ERR BIT(3)
-+#define BCM2711_DMA40_DEBUG_IN_ON_ERR BIT(8)
-+#define BCM2711_DMA40_DEBUG_ABORT_ON_ERR BIT(9)
-+#define BCM2711_DMA40_DEBUG_HALT_ON_ERR BIT(10)
-+#define BCM2711_DMA40_DEBUG_DISABLE_CLK_GATE BIT(11)
-+#define BCM2711_DMA40_DEBUG_RSTATE_SHIFT 14
-+#define BCM2711_DMA40_DEBUG_RSTATE_BITS 4
-+#define BCM2711_DMA40_DEBUG_WSTATE_SHIFT 18
-+#define BCM2711_DMA40_DEBUG_WSTATE_BITS 4
-+#define BCM2711_DMA40_DEBUG_RESET BIT(23)
-+#define BCM2711_DMA40_DEBUG_ID_SHIFT 24
-+#define BCM2711_DMA40_DEBUG_ID_BITS 4
-+#define BCM2711_DMA40_DEBUG_VERSION_SHIFT 28
-+#define BCM2711_DMA40_DEBUG_VERSION_BITS 4
-
- /* Valid only for channels 0 - 3 (11 - 14) */
--#define BCM2838_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
--#define BCM2838_DMA40_CHANIO(base, n) ((base) + BCM2838_DMA_CHAN(n))
-+#define BCM2711_DMA40_CHAN(n) (((n) + 11) << 8) /* Base address */
-+#define BCM2711_DMA40_CHANIO(base, n) ((base) + BCM2711_DMA_CHAN(n))
-
- /* the max dma length for different channels */
- #define MAX_DMA40_LEN SZ_1G
-
--#define BCM2838_DMA40_BURST_LEN(x) ((min(x,16) - 1) << 8)
--#define BCM2838_DMA40_INC BIT(12)
--#define BCM2838_DMA40_SIZE_32 (0 << 13)
--#define BCM2838_DMA40_SIZE_64 (1 << 13)
--#define BCM2838_DMA40_SIZE_128 (2 << 13)
--#define BCM2838_DMA40_SIZE_256 (3 << 13)
--#define BCM2838_DMA40_IGNORE BIT(15)
--#define BCM2838_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */
--
--#define BCM2838_DMA40_MEMCPY_FLAGS \
-- (BCM2838_DMA40_QOS(0) | \
-- BCM2838_DMA40_PANIC_QOS(0) | \
-- BCM2838_DMA40_WAIT_FOR_WRITES | \
-- BCM2838_DMA40_DISDEBUG)
--
--#define BCM2838_DMA40_MEMCPY_XFER_INFO \
-- (BCM2838_DMA40_SIZE_128 | \
-- BCM2838_DMA40_INC | \
-- BCM2838_DMA40_BURST_LEN(16))
-+#define BCM2711_DMA40_BURST_LEN(x) ((min(x,16) - 1) << 8)
-+#define BCM2711_DMA40_INC BIT(12)
-+#define BCM2711_DMA40_SIZE_32 (0 << 13)
-+#define BCM2711_DMA40_SIZE_64 (1 << 13)
-+#define BCM2711_DMA40_SIZE_128 (2 << 13)
-+#define BCM2711_DMA40_SIZE_256 (3 << 13)
-+#define BCM2711_DMA40_IGNORE BIT(15)
-+#define BCM2711_DMA40_STRIDE(x) ((x) << 16) /* For 2D mode */
-+
-+#define BCM2711_DMA40_MEMCPY_FLAGS \
-+ (BCM2711_DMA40_QOS(0) | \
-+ BCM2711_DMA40_PANIC_QOS(0) | \
-+ BCM2711_DMA40_WAIT_FOR_WRITES | \
-+ BCM2711_DMA40_DISDEBUG)
-+
-+#define BCM2711_DMA40_MEMCPY_XFER_INFO \
-+ (BCM2711_DMA40_SIZE_128 | \
-+ BCM2711_DMA40_INC | \
-+ BCM2711_DMA40_BURST_LEN(16))
-
- struct bcm2835_dmadev *memcpy_parent;
- static void __iomem *memcpy_chan;
--static struct bcm2838_dma40_scb *memcpy_scb;
-+static struct bcm2711_dma40_scb *memcpy_scb;
- static dma_addr_t memcpy_scb_dma;
- DEFINE_SPINLOCK(memcpy_lock);
-
-@@ -299,7 +299,7 @@ static const struct bcm2835_dma_cfg_data
- .chan_40bit_mask = 0,
- };
-
--static const struct bcm2835_dma_cfg_data bcm2838_dma_cfg = {
-+static const struct bcm2835_dma_cfg_data bcm2711_dma_cfg = {
- .chan_40bit_mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
- };
-
-@@ -332,27 +332,27 @@ static inline struct bcm2835_desc *to_bc
- return container_of(t, struct bcm2835_desc, vd.tx);
- }
-
--static inline uint32_t to_bcm2838_ti(uint32_t info)
-+static inline uint32_t to_bcm2711_ti(uint32_t info)
- {
-- return ((info & BCM2835_DMA_INT_EN) ? BCM2838_DMA40_INTEN : 0) |
-- ((info & BCM2835_DMA_WAIT_RESP) ? BCM2838_DMA40_WAIT_RESP : 0) |
-+ return ((info & BCM2835_DMA_INT_EN) ? BCM2711_DMA40_INTEN : 0) |
-+ ((info & BCM2835_DMA_WAIT_RESP) ? BCM2711_DMA40_WAIT_RESP : 0) |
- ((info & BCM2835_DMA_S_DREQ) ?
-- (BCM2838_DMA40_S_DREQ | BCM2838_DMA40_WAIT_RD_RESP) : 0) |
-- ((info & BCM2835_DMA_D_DREQ) ? BCM2838_DMA40_D_DREQ : 0) |
-- BCM2838_DMA40_PER_MAP((info >> 16) & 0x1f);
-+ (BCM2711_DMA40_S_DREQ | BCM2711_DMA40_WAIT_RD_RESP) : 0) |
-+ ((info & BCM2835_DMA_D_DREQ) ? BCM2711_DMA40_D_DREQ : 0) |
-+ BCM2711_DMA40_PER_MAP((info >> 16) & 0x1f);
- }
-
--static inline uint32_t to_bcm2838_srci(uint32_t info)
-+static inline uint32_t to_bcm2711_srci(uint32_t info)
- {
-- return ((info & BCM2835_DMA_S_INC) ? BCM2838_DMA40_INC : 0);
-+ return ((info & BCM2835_DMA_S_INC) ? BCM2711_DMA40_INC : 0);
- }
-
--static inline uint32_t to_bcm2838_dsti(uint32_t info)
-+static inline uint32_t to_bcm2711_dsti(uint32_t info)
- {
-- return ((info & BCM2835_DMA_D_INC) ? BCM2838_DMA40_INC : 0);
-+ return ((info & BCM2835_DMA_D_INC) ? BCM2711_DMA40_INC : 0);
- }
-
--static inline uint32_t to_bcm2838_cbaddr(dma_addr_t addr)
-+static inline uint32_t to_bcm2711_cbaddr(dma_addr_t addr)
- {
- BUG_ON(addr & 0x1f);
- return (addr >> 5);
-@@ -412,12 +412,12 @@ static void bcm2835_dma_create_cb_set_le
- }
-
- if (c->is_40bit_channel) {
-- struct bcm2838_dma40_scb *scb =
-- (struct bcm2838_dma40_scb *)control_block;
-+ struct bcm2711_dma40_scb *scb =
-+ (struct bcm2711_dma40_scb *)control_block;
-
- scb->len = cb_len;
- /* add extrainfo bits to ti */
-- scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ scb->ti |= to_bcm2711_ti(finalextrainfo);
- } else {
- control_block->length = cb_len;
- /* add extrainfo bits to info */
-@@ -500,13 +500,13 @@ static struct bcm2835_desc *bcm2835_dma_
- /* fill in the control block */
- control_block = cb_entry->cb;
- if (c->is_40bit_channel) {
-- struct bcm2838_dma40_scb *scb =
-- (struct bcm2838_dma40_scb *)control_block;
-- scb->ti = to_bcm2838_ti(info);
-+ struct bcm2711_dma40_scb *scb =
-+ (struct bcm2711_dma40_scb *)control_block;
-+ scb->ti = to_bcm2711_ti(info);
- scb->src = lower_32_bits(src);
-- scb->srci= upper_32_bits(src) | to_bcm2838_srci(info);
-+ scb->srci= upper_32_bits(src) | to_bcm2711_srci(info);
- scb->dst = lower_32_bits(dst);
-- scb->dsti = upper_32_bits(dst) | to_bcm2838_dsti(info);
-+ scb->dsti = upper_32_bits(dst) | to_bcm2711_dsti(info);
- scb->next_cb = 0;
- } else {
- control_block->info = info;
-@@ -531,7 +531,7 @@ static struct bcm2835_desc *bcm2835_dma_
- /* link this the last controlblock */
- if (frame && c->is_40bit_channel)
- d->cb_list[frame - 1].cb->next =
-- to_bcm2838_cbaddr(cb_entry->paddr);
-+ to_bcm2711_cbaddr(cb_entry->paddr);
- if (frame && !c->is_40bit_channel)
- d->cb_list[frame - 1].cb->next = cb_entry->paddr;
-
-@@ -547,10 +547,10 @@ static struct bcm2835_desc *bcm2835_dma_
-
- /* the last frame requires extra flags */
- if (c->is_40bit_channel) {
-- struct bcm2838_dma40_scb *scb =
-- (struct bcm2838_dma40_scb *)d->cb_list[d->frames-1].cb;
-+ struct bcm2711_dma40_scb *scb =
-+ (struct bcm2711_dma40_scb *)d->cb_list[d->frames-1].cb;
-
-- scb->ti |= to_bcm2838_ti(finalextrainfo);
-+ scb->ti |= to_bcm2711_ti(finalextrainfo);
- } else {
- d->cb_list[d->frames - 1].cb->info |= finalextrainfo;
- }
-@@ -581,18 +581,18 @@ static void bcm2835_dma_fill_cb_chain_wi
- max_len = bcm2835_dma_max_frame_length(c);
- for_each_sg(sgl, sgent, sg_len, i) {
- if (c->is_40bit_channel) {
-- struct bcm2838_dma40_scb *scb =
-- (struct bcm2838_dma40_scb *)cb->cb;
-+ struct bcm2711_dma40_scb *scb =
-+ (struct bcm2711_dma40_scb *)cb->cb;
- for (addr = sg_dma_address(sgent),
- len = sg_dma_len(sgent);
- len > 0;
- addr += scb->len, len -= scb->len, scb++) {
- if (direction == DMA_DEV_TO_MEM) {
- scb->dst = lower_32_bits(addr);
-- scb->dsti = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ scb->dsti = upper_32_bits(addr) | BCM2711_DMA40_INC;
- } else {
- scb->src = lower_32_bits(addr);
-- scb->srci = upper_32_bits(addr) | BCM2838_DMA40_INC;
-+ scb->srci = upper_32_bits(addr) | BCM2711_DMA40_INC;
- }
- scb->len = min(len, max_len);
- }
-@@ -619,7 +619,7 @@ static void bcm2835_dma_abort(struct bcm
- u32 wait_mask = BCM2835_DMA_WAITING_FOR_WRITES;
-
- if (c->is_40bit_channel)
-- wait_mask = BCM2838_DMA40_WAITING_FOR_WRITES;
-+ wait_mask = BCM2711_DMA40_WAITING_FOR_WRITES;
-
- /*
- * A zero control block address means the channel is idle.
-@@ -658,10 +658,10 @@ static void bcm2835_dma_start_desc(struc
- c->desc = d = to_bcm2835_dma_desc(&vd->tx);
-
- if (c->is_40bit_channel) {
-- writel(to_bcm2838_cbaddr(d->cb_list[0].paddr),
-- c->chan_base + BCM2838_DMA40_CB);
-- writel(BCM2838_DMA40_ACTIVE | BCM2838_DMA40_CS_FLAGS(c->dreq),
-- c->chan_base + BCM2838_DMA40_CS);
-+ writel(to_bcm2711_cbaddr(d->cb_list[0].paddr),
-+ c->chan_base + BCM2711_DMA40_CB);
-+ writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_CS_FLAGS(c->dreq),
-+ c->chan_base + BCM2711_DMA40_CS);
- } else {
- writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
- writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
-@@ -694,7 +694,7 @@ static irqreturn_t bcm2835_dma_callback(
- * will remain idle despite the ACTIVE flag being set.
- */
- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE |
-- (c->is_40bit_channel ? BCM2838_DMA40_CS_FLAGS(c->dreq) :
-+ (c->is_40bit_channel ? BCM2711_DMA40_CS_FLAGS(c->dreq) :
- BCM2835_DMA_CS_FLAGS(c->dreq)),
- c->chan_base + BCM2835_DMA_CS);
-
-@@ -799,14 +799,14 @@ static enum dma_status bcm2835_dma_tx_st
- dma_addr_t pos;
-
- if (d->dir == DMA_MEM_TO_DEV && c->is_40bit_channel)
-- pos = readl(c->chan_base + BCM2838_DMA40_SRC) +
-- ((readl(c->chan_base + BCM2838_DMA40_SRCI) &
-+ pos = readl(c->chan_base + BCM2711_DMA40_SRC) +
-+ ((readl(c->chan_base + BCM2711_DMA40_SRCI) &
- 0xff) << 8);
- else if (d->dir == DMA_MEM_TO_DEV && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
- else if (d->dir == DMA_DEV_TO_MEM && c->is_40bit_channel)
-- pos = readl(c->chan_base + BCM2838_DMA40_DEST) +
-- ((readl(c->chan_base + BCM2838_DMA40_DESTI) &
-+ pos = readl(c->chan_base + BCM2711_DMA40_DEST) +
-+ ((readl(c->chan_base + BCM2711_DMA40_DESTI) &
- 0xff) << 8);
- else if (d->dir == DMA_DEV_TO_MEM && !c->is_40bit_channel)
- pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
-@@ -1007,7 +1007,7 @@ static struct dma_async_tx_descriptor *b
-
- /* wrap around into a loop */
- d->cb_list[d->frames - 1].cb->next = c->is_40bit_channel ?
-- to_bcm2838_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-+ to_bcm2711_cbaddr(d->cb_list[0].paddr) : d->cb_list[0].paddr;
-
- return vchan_tx_prep(&c->vc, &d->vd, flags);
- }
-@@ -1095,7 +1095,7 @@ static void bcm2835_dma_free(struct bcm2
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
- }
-
--int bcm2838_dma40_memcpy_init(void)
-+int bcm2711_dma40_memcpy_init(void)
- {
- if (!memcpy_parent)
- return -EPROBE_DEFER;
-@@ -1108,15 +1108,15 @@ int bcm2838_dma40_memcpy_init(void)
-
- return 0;
- }
--EXPORT_SYMBOL(bcm2838_dma40_memcpy_init);
-+EXPORT_SYMBOL(bcm2711_dma40_memcpy_init);
-
--void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
-+void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
- {
-- struct bcm2838_dma40_scb *scb = memcpy_scb;
-+ struct bcm2711_dma40_scb *scb = memcpy_scb;
- unsigned long flags;
-
- if (!scb) {
-- pr_err("bcm2838_dma40_memcpy not initialised!\n");
-+ pr_err("bcm2711_dma40_memcpy not initialised!\n");
- return;
- }
-
-@@ -1124,29 +1124,29 @@ void bcm2838_dma40_memcpy(dma_addr_t dst
-
- scb->ti = 0;
- scb->src = lower_32_bits(src);
-- scb->srci = upper_32_bits(src) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->srci = upper_32_bits(src) | BCM2711_DMA40_MEMCPY_XFER_INFO;
- scb->dst = lower_32_bits(dst);
-- scb->dsti = upper_32_bits(dst) | BCM2838_DMA40_MEMCPY_XFER_INFO;
-+ scb->dsti = upper_32_bits(dst) | BCM2711_DMA40_MEMCPY_XFER_INFO;
- scb->len = size;
- scb->next_cb = 0;
-
-- writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2838_DMA40_CB);
-- writel(BCM2838_DMA40_MEMCPY_FLAGS + BCM2838_DMA40_ACTIVE,
-- memcpy_chan + BCM2838_DMA40_CS);
-+ writel((u32)(memcpy_scb_dma >> 5), memcpy_chan + BCM2711_DMA40_CB);
-+ writel(BCM2711_DMA40_MEMCPY_FLAGS + BCM2711_DMA40_ACTIVE,
-+ memcpy_chan + BCM2711_DMA40_CS);
-
- /* Poll for completion */
-- while (!(readl(memcpy_chan + BCM2838_DMA40_CS) & BCM2838_DMA40_END))
-+ while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END))
- cpu_relax();
-
-- writel(BCM2838_DMA40_END, memcpy_chan + BCM2838_DMA40_CS);
-+ writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS);
-
- spin_unlock_irqrestore(&memcpy_lock, flags);
- }
--EXPORT_SYMBOL(bcm2838_dma40_memcpy);
-+EXPORT_SYMBOL(bcm2711_dma40_memcpy);
-
- static const struct of_device_id bcm2835_dma_of_match[] = {
- { .compatible = "brcm,bcm2835-dma", .data = &bcm2835_dma_cfg },
-- { .compatible = "brcm,bcm2838-dma", .data = &bcm2838_dma_cfg },
-+ { .compatible = "brcm,bcm2711-dma", .data = &bcm2711_dma_cfg },
- {},
- };
- MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
-@@ -1274,9 +1274,9 @@ static int bcm2835_dma_probe(struct plat
-
- /* And possibly one for the 40-bit DMA memcpy API */
- if (chans_available & od->cfg_data->chan_40bit_mask &
-- BIT(BCM2838_DMA_MEMCPY_CHAN)) {
-+ BIT(BCM2711_DMA_MEMCPY_CHAN)) {
- memcpy_parent = od;
-- memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2838_DMA_MEMCPY_CHAN);
-+ memcpy_chan = BCM2835_DMA_CHANIO(base, BCM2711_DMA_MEMCPY_CHAN);
- memcpy_scb = dma_alloc_coherent(memcpy_parent->ddev.dev,
- sizeof(*memcpy_scb),
- &memcpy_scb_dma, GFP_KERNEL);
-@@ -1284,7 +1284,7 @@ static int bcm2835_dma_probe(struct plat
- dev_warn(&pdev->dev,
- "Failed to allocated memcpy scb\n");
-
-- chans_available &= ~BIT(BCM2838_DMA_MEMCPY_CHAN);
-+ chans_available &= ~BIT(BCM2711_DMA_MEMCPY_CHAN);
- }
-
- /* get irqs for each channel that we support */
--- /dev/null
+From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 18:23:01 +0100
+Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper
+
+commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream.
+
+Add of_get_next_dma_parent() helper which is similar to
+__of_get_dma_parent(), but can be used in iterators and decrements the
+ref count on the prior parent.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_
+ return of_node_get(args.np);
+ }
+
++static struct device_node *of_get_next_dma_parent(struct device_node *np)
++{
++ struct device_node *parent;
++
++ parent = __of_get_dma_parent(np);
++ of_node_put(np);
++
++ return parent;
++}
++
+ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
+ {
+ struct device_node *host;
--- /dev/null
+From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 14:47:31 +0100
+Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent"
+
+commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream.
+
+Much like for address translation, when checking for DMA coherence we
+should be sure to walk up the DMA hierarchy, rather than the MMIO one,
+now that we can accommodate them being different.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -1023,7 +1023,7 @@ bool of_dma_is_coherent(struct device_no
+ of_node_put(node);
+ return true;
+ }
+- node = of_get_next_parent(node);
++ node = of_get_next_dma_parent(node);
+ }
+ of_node_put(node);
+ return false;
+++ /dev/null
-From 9367715671c271913278a4abb43276d02ff954d6 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:33:40 +0000
-Subject: [PATCH] thermal: brcmstb_thermal: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "thermal: brcmstb_thermal: Add BCM2838 support"
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/thermal/broadcom/brcmstb_thermal.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/thermal/broadcom/brcmstb_thermal.c
-+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
-@@ -290,7 +290,7 @@ static const struct thermal_zone_of_devi
- .set_trips = brcmstb_set_trips,
- };
-
--static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
-+static const struct thermal_zone_of_device_ops bcm2711_thermal_of_ops = {
- .get_temp = brcmstb_get_temp,
- };
-
-@@ -301,8 +301,8 @@ static const struct brcmstb_thermal_of_d
- .status_data_shift = 1,
- };
-
--static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
-- .of_ops = &bcm2838_thermal_of_ops,
-+static const struct brcmstb_thermal_of_data bcm2711_thermal_of_data = {
-+ .of_ops = &bcm2711_thermal_of_ops,
- .status_valid_mask = BIT(10),
- .status_data_mask = GENMASK(9, 0),
- .status_data_shift = 0,
-@@ -311,8 +311,8 @@ static const struct brcmstb_thermal_of_d
- static const struct of_device_id brcmstb_thermal_id_table[] = {
- { .compatible = "brcm,avs-tmon",
- .data = &bcm7445_thermal_of_data },
-- { .compatible = "brcm,avs-tmon-bcm2838",
-- .data = &bcm2838_thermal_of_data },
-+ { .compatible = "brcm,avs-tmon-bcm2711",
-+ .data = &bcm2711_thermal_of_data },
- {},
- };
- MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+++ /dev/null
-From 5eafa5065b2ea2c8d1634f045b85b982393d808a Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:36:57 +0000
-Subject: [PATCH] hwrng: iproc-rng200: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "hwrng: iproc-rng200: Add BCM2838 support"
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/char/hw_random/Kconfig | 2 +-
- drivers/char/hw_random/iproc-rng200.c | 11 +++++------
- 2 files changed, 6 insertions(+), 7 deletions(-)
-
---- a/drivers/char/hw_random/Kconfig
-+++ b/drivers/char/hw_random/Kconfig
-@@ -94,7 +94,7 @@ config HW_RANDOM_IPROC_RNG200
- default HW_RANDOM
- ---help---
- This driver provides kernel-side support for the RNG200
-- hardware found on the Broadcom iProc, BCM2838 and STB SoCs.
-+ hardware found on the Broadcom iProc, BCM2711 and STB SoCs.
-
- To compile this driver as a module, choose M here: the
- module will be called iproc-rng200
---- a/drivers/char/hw_random/iproc-rng200.c
-+++ b/drivers/char/hw_random/iproc-rng200.c
-@@ -174,7 +174,7 @@ static int iproc_rng200_init(struct hwrn
- return 0;
- }
-
--static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max,
-+static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max,
- bool wait)
- {
- struct iproc_rng200_dev *priv = to_rng_priv(rng);
-@@ -211,7 +211,7 @@ static int bcm2838_rng200_read(struct hw
- return num_words * sizeof(u32);
- }
-
--static int bcm2838_rng200_init(struct hwrng *rng)
-+static int bcm2711_rng200_init(struct hwrng *rng)
- {
- struct iproc_rng200_dev *priv = to_rng_priv(rng);
- uint32_t val;
-@@ -271,9 +271,9 @@ static int iproc_rng200_probe(struct pla
- priv->rng.name = pdev->name;
- priv->rng.cleanup = iproc_rng200_cleanup;
-
-- if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) {
-- priv->rng.init = bcm2838_rng200_init;
-- priv->rng.read = bcm2838_rng200_read;
-+ if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) {
-+ priv->rng.init = bcm2711_rng200_init;
-+ priv->rng.read = bcm2711_rng200_read;
- } else {
- priv->rng.init = iproc_rng200_init;
- priv->rng.read = iproc_rng200_read;
-@@ -296,7 +296,6 @@ static const struct of_device_id iproc_r
- { .compatible = "brcm,bcm7211-rng200", },
- { .compatible = "brcm,bcm7278-rng200", },
- { .compatible = "brcm,iproc-rng200", },
-- { .compatible = "brcm,bcm2838-rng200"},
- {},
- };
- MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
--- /dev/null
+From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Tue, 2 Jul 2019 18:42:39 +0100
+Subject: [PATCH] of: Factor out #{addr,size}-cells parsing
+
+In some cases such as PCI host controllers, we may have a "parent bus"
+which is an OF leaf node, but still need to correctly parse ranges from
+the point of view of that bus. For that, factor out variants of the
+"#addr-cells" and "#size-cells" parsers which do not assume they have a
+device node and thus immediately traverse upwards before reading the
+relevant property.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+[robh: don't make of_bus_n_{addr,size}_cells() public]
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+
+(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a)
+---
+ drivers/of/address.c | 2 ++
+ drivers/of/base.c | 32 ++++++++++++++++++++++----------
+ drivers/of/of_private.h | 14 ++++++++++++++
+ 3 files changed, 38 insertions(+), 10 deletions(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -14,6 +14,8 @@
+ #include <linux/slab.h>
+ #include <linux/string.h>
+
++#include "of_private.h"
++
+ /* Max address size we deal with */
+ #define OF_MAX_ADDR_CELLS 4
+ #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru
+ return np && match && type && !strcmp(match, type);
+ }
+
+-int of_n_addr_cells(struct device_node *np)
++int of_bus_n_addr_cells(struct device_node *np)
+ {
+ u32 cells;
+
+- do {
+- if (np->parent)
+- np = np->parent;
++ for (; np; np = np->parent)
+ if (!of_property_read_u32(np, "#address-cells", &cells))
+ return cells;
+- } while (np->parent);
++
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+ }
++
++int of_n_addr_cells(struct device_node *np)
++{
++ if (np->parent)
++ np = np->parent;
++
++ return of_bus_n_addr_cells(np);
++}
+ EXPORT_SYMBOL(of_n_addr_cells);
+
+-int of_n_size_cells(struct device_node *np)
++int of_bus_n_size_cells(struct device_node *np)
+ {
+ u32 cells;
+
+- do {
+- if (np->parent)
+- np = np->parent;
++ for (; np; np = np->parent)
+ if (!of_property_read_u32(np, "#size-cells", &cells))
+ return cells;
+- } while (np->parent);
++
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+ }
++
++int of_n_size_cells(struct device_node *np)
++{
++ if (np->parent)
++ np = np->parent;
++
++ return of_bus_n_size_cells(np);
++}
+ EXPORT_SYMBOL(of_n_size_cells);
+
+ #ifdef CONFIG_NUMA
+--- a/drivers/of/of_private.h
++++ b/drivers/of/of_private.h
+@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s
+ #define for_each_transaction_entry_reverse(_oft, _te) \
+ list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
+
++extern int of_bus_n_addr_cells(struct device_node *np);
++extern int of_bus_n_size_cells(struct device_node *np);
++
++#ifdef CONFIG_OF_ADDRESS
++extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
++ u64 *paddr, u64 *size);
++#else
++static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
++ u64 *paddr, u64 *size)
++{
++ return -ENODEV;
++}
++#endif
++
+ #endif /* _LINUX_OF_PRIVATE_H */
--- /dev/null
+From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 4 Sep 2019 11:43:30 +0100
+Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes
+ missing 'dma-ranges'
+
+commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream.
+
+'dma-ranges' frequently exists without parent nodes having 'dma-ranges'.
+While this is an error for 'ranges', this is fine because DMA capable
+devices always have a translatable DMA address. Also, with no
+'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with
+no restrictions unless perhaps the device itself has implicit
+restrictions.
+
+Cc: Robin Murphy <robin.murphy@arm.com>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ drivers/of/address.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -519,9 +519,13 @@ static int of_translate_one(struct devic
+ *
+ * As far as we know, this damage only exists on Apple machines, so
+ * This code is only enabled on powerpc. --gcl
++ *
++ * This quirk also applies for 'dma-ranges' which frequently exist in
++ * child nodes without 'dma-ranges' in the parent nodes. --RobH
+ */
+ ranges = of_get_property(parent, rprop, &rlen);
+- if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
++ if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
++ strcmp(rprop, "dma-ranges")) {
+ pr_debug("no ranges; cannot translate\n");
+ return 1;
+ }
+++ /dev/null
-From 900b4ad0814df7dbacb01318bf49af5bab605fa0 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 09:39:40 +0000
-Subject: [PATCH] pcie-brcmstb: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Fixes: "bcm2835-dma: Add proper 40-bit DMA support"
-Fixes: "Ported pcie-brcmstb bounce buffer implementation to ARM64."
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/pci/controller/pcie-brcmstb-bounce.c | 10 +++++-----
- drivers/pci/controller/pcie-brcmstb-bounce64.c | 10 +++++-----
- 2 files changed, 10 insertions(+), 10 deletions(-)
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce.c
-@@ -91,8 +91,8 @@ struct dmabounce_device_info {
-
- static struct dmabounce_device_info *g_dmabounce_device_info;
-
--extern int bcm2838_dma40_memcpy_init(void);
--extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+extern int bcm2711_dma40_memcpy_init(void);
-+extern void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-
- #ifdef STATS
- static ssize_t
-@@ -320,7 +320,7 @@ map_single(struct device *dev, struct sa
-
- if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
- !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-- bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ bcm2711_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
- size);
-
- return buf->safe_dma_addr;
-@@ -338,7 +338,7 @@ unmap_single(struct device *dev, struct
- dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
- (u64)buf->unsafe_dma_addr);
-
-- bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ bcm2711_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
- size);
- }
- return buf->unsafe_dma_addr;
-@@ -476,7 +476,7 @@ int brcm_pcie_bounce_init(struct device
- if (g_dmabounce_device_info)
- return -EBUSY;
-
-- ret = bcm2838_dma40_memcpy_init();
-+ ret = bcm2711_dma40_memcpy_init();
- if (ret)
- return ret;
-
---- a/drivers/pci/controller/pcie-brcmstb-bounce64.c
-+++ b/drivers/pci/controller/pcie-brcmstb-bounce64.c
-@@ -93,8 +93,8 @@ struct dmabounce_device_info {
-
- static struct dmabounce_device_info *g_dmabounce_device_info;
-
--extern int bcm2838_dma40_memcpy_init(void);
--extern void bcm2838_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-+extern int bcm2711_dma40_memcpy_init(void);
-+extern void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size);
-
- #ifdef STATS
- static ssize_t
-@@ -322,7 +322,7 @@ map_single(struct device *dev, struct sa
-
- if ((dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) &&
- !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-- bcm2838_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
-+ bcm2711_dma40_memcpy(buf->safe_dma_addr, buf->unsafe_dma_addr,
- size);
-
- return buf->safe_dma_addr;
-@@ -340,7 +340,7 @@ unmap_single(struct device *dev, struct
- dev_dbg(dev, "unmap: %llx->%llx\n", (u64)buf->safe_dma_addr,
- (u64)buf->unsafe_dma_addr);
-
-- bcm2838_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
-+ bcm2711_dma40_memcpy(buf->unsafe_dma_addr, buf->safe_dma_addr,
- size);
- }
- return buf->unsafe_dma_addr;
-@@ -483,7 +483,7 @@ int brcm_pcie_bounce_init(struct device
- if (g_dmabounce_device_info)
- return -EBUSY;
-
-- ret = bcm2838_dma40_memcpy_init();
-+ ret = bcm2711_dma40_memcpy_init();
- if (ret)
- return ret;
-
+++ /dev/null
-From 475158d2aab9dc2e8266726f7b026cedfe810619 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 31 Jan 2020 15:24:59 +0000
-Subject: [PATCH] ARM: dts: Correct SoC name
-
-The Pi 4 SoC is called BCM2711, not BCM2838.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm2711-rpi.dtsi | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
-@@ -42,7 +42,7 @@
-
- &soc {
- thermal: thermal@7d5d2200 {
-- compatible = "brcm,avs-tmon-bcm2838";
-+ compatible = "brcm,avs-tmon-bcm2711";
- reg = <0x7d5d2200 0x2c>;
- interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "tmon";
-@@ -106,7 +106,7 @@
- };
-
- dma40: dma@7e007b00 {
-- compatible = "brcm,bcm2838-dma";
-+ compatible = "brcm,bcm2711-dma";
- reg = <0x0 0x7e007b00 0x400>;
- interrupts =
- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, /* dma4 11 */
-@@ -122,7 +122,7 @@
- };
-
- vchiq: mailbox@7e00b840 {
-- compatible = "brcm,bcm2838-vchiq";
-+ compatible = "brcm,bcm2711-vchiq";
- reg = <0 0x7e00b840 0x3c>;
- interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
- };
-@@ -195,7 +195,7 @@
- };
-
- &random {
-- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200";
-+ compatible = "brcm,bcm2711-rng200";
- status = "okay";
- };
-
--- /dev/null
+From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 3 Jul 2019 18:42:20 +0100
+Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes
+
+commit 951d48855d86e72e0d6de73440fe09d363168064 upstream.
+
+Since the "dma-ranges" property is only valid for a node representing a
+bus, of_dma_get_range() currently assumes the node passed in is a leaf
+representing a device, and starts the walk from its parent. In cases
+like PCI host controllers on typical FDT systems, however, where the PCI
+endpoints are probed dynamically the initial leaf node represents the
+'bus' itself, and this logic means we fail to consider any "dma-ranges"
+describing the host bridge itself. Rework the logic such that
+of_dma_get_range() also works correctly starting from a bus node
+containing "dma-ranges".
+
+While this does mean "dma-ranges" could incorrectly be in a device leaf
+node, there isn't really any way in this function to ensure that a leaf
+node is or isn't a bus node.
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+[robh: Allow for the bus child node to still be passed in]
+Signed-off-by: Rob Herring <robh@kernel.org>
+Reviewed-by: Robin Murphy <robin.murphy@arm.com>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Tested-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+---
+ drivers/of/address.c | 44 ++++++++++++++++++--------------------------
+ 1 file changed, 18 insertions(+), 26 deletions(-)
+
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node
+ const __be32 *ranges = NULL;
+ int len, naddr, nsize, pna;
+ int ret = 0;
++ bool found_dma_ranges = false;
+ u64 dmaaddr;
+
+- if (!node)
+- return -EINVAL;
+-
+- while (1) {
+- struct device_node *parent;
+-
+- naddr = of_n_addr_cells(node);
+- nsize = of_n_size_cells(node);
+-
+- parent = __of_get_dma_parent(node);
+- of_node_put(node);
+-
+- node = parent;
+- if (!node)
+- break;
+-
++ while (node) {
+ ranges = of_get_property(node, "dma-ranges", &len);
+
+ /* Ignore empty ranges, they imply no translation required */
+ if (ranges && len > 0)
+ break;
+
+- /*
+- * At least empty ranges has to be defined for parent node if
+- * DMA is supported
+- */
+- if (!ranges)
+- break;
++ /* Once we find 'dma-ranges', then a missing one is an error */
++ if (found_dma_ranges && !ranges) {
++ ret = -ENODEV;
++ goto out;
++ }
++ found_dma_ranges = true;
++
++ node = of_get_next_dma_parent(node);
+ }
+
+- if (!ranges) {
++ if (!node || !ranges) {
+ pr_debug("no dma-ranges found for node(%pOF)\n", np);
+ ret = -ENODEV;
+ goto out;
+ }
+
+- len /= sizeof(u32);
+-
++ naddr = of_bus_n_addr_cells(node);
++ nsize = of_bus_n_size_cells(node);
+ pna = of_n_addr_cells(node);
++ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
++ ret = -EINVAL;
++ goto out;
++ }
+
+ /* dma-ranges format:
+ * DMA addr : naddr cells
+@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node
+ * size : nsize cells
+ */
+ dmaaddr = of_read_number(ranges, naddr);
+- *paddr = of_translate_dma_address(np, ranges);
++ *paddr = of_translate_dma_address(node, ranges + naddr);
+ if (*paddr == OF_BAD_ADDR) {
+ pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
+ dma_addr, np);
+++ /dev/null
-From 1a66f120abddf36eaf2540532ddeb7f7767442c5 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Sat, 1 Feb 2020 08:58:11 +0000
-Subject: [PATCH] ARM: dts: Remove CMA allocation from Pi 4 dts
-
-The 5.5 tree includes a patch to disable the CMA command line
-parameter and replace it with properties from a DT node.
-The upstream Pi 4 .dts, now used downstream with modifications,
-includes the "linux,cma" node, but only reserves 32MB which is
-often not enough.
-
-Temporarily remove the "linux,cma" node to reenable the command line
-parameter.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
-@@ -167,6 +167,10 @@
- };
-
- /delete-node/ wifi-pwrseq;
-+
-+ reserved-memory {
-+ /delete-node/ linux,cma;
-+ };
- };
-
- &mmcnr {
--- /dev/null
+From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:43 +0200
+Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of
+ calling max_zone_dma_phys()
+
+commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream.
+
+By the time we call zones_sizes_init() arm64_dma_phys_limit already
+contains the result of max_zone_dma_phys(). We use the variable instead
+of calling the function directly to save some precious cpu time.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/mm/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig
+ unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
+
+ #ifdef CONFIG_ZONE_DMA32
+- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys());
++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
+ #endif
+ max_zone_pfns[ZONE_NORMAL] = max;
+
--- /dev/null
+From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:44 +0200
+Subject: [PATCH] arm64: rename variables used to calculate
+ ZONE_DMA32's size
+
+commit a573cdd7973dedd87e62196c400332896bb236c8 upstream.
+
+Let the name indicate that they are used to calculate ZONE_DMA32's size
+as opposed to ZONE_DMA.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/mm/init.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -56,7 +56,7 @@ EXPORT_SYMBOL(physvirt_offset);
+ struct page *vmemmap __ro_after_init;
+ EXPORT_SYMBOL(vmemmap);
+
+-phys_addr_t arm64_dma_phys_limit __ro_after_init;
++phys_addr_t arm64_dma32_phys_limit __ro_after_init;
+
+ #ifdef CONFIG_KEXEC_CORE
+ /*
+@@ -174,7 +174,7 @@ static void __init reserve_elfcorehdr(vo
+ * currently assumes that for memory starting above 4G, 32-bit devices will
+ * use a DMA offset.
+ */
+-static phys_addr_t __init max_zone_dma_phys(void)
++static phys_addr_t __init max_zone_dma32_phys(void)
+ {
+ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+ return min(offset + (1ULL << 32), memblock_end_of_DRAM());
+@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig
+ unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
+
+ #ifdef CONFIG_ZONE_DMA32
+- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit);
++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
+ #endif
+ max_zone_pfns[ZONE_NORMAL] = max;
+
+@@ -200,16 +200,16 @@ 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_dma = min;
++ unsigned long max_dma32 = min;
+
+ memset(zone_size, 0, sizeof(zone_size));
+
+ /* 4GB maximum for 32-bit only capable devices */
+ #ifdef CONFIG_ZONE_DMA32
+- max_dma = PFN_DOWN(arm64_dma_phys_limit);
+- zone_size[ZONE_DMA32] = max_dma - min;
++ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit);
++ zone_size[ZONE_DMA32] = max_dma32 - min;
+ #endif
+- zone_size[ZONE_NORMAL] = max - max_dma;
++ zone_size[ZONE_NORMAL] = max - max_dma32;
+
+ memcpy(zhole_size, zone_size, sizeof(zhole_size));
+
+@@ -221,14 +221,14 @@ static void __init zone_sizes_init(unsig
+ continue;
+
+ #ifdef CONFIG_ZONE_DMA32
+- if (start < max_dma) {
+- unsigned long dma_end = min(end, max_dma);
++ if (start < max_dma32) {
++ unsigned long dma_end = min(end, max_dma32);
+ zhole_size[ZONE_DMA32] -= dma_end - start;
+ }
+ #endif
+- if (end > max_dma) {
++ if (end > max_dma32) {
+ unsigned long normal_end = min(end, max);
+- unsigned long normal_start = max(start, max_dma);
++ unsigned long normal_start = max(start, max_dma32);
+ zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
+ }
+ }
+@@ -420,9 +420,9 @@ void __init arm64_memblock_init(void)
+
+ /* 4GB maximum for 32-bit only capable devices */
+ if (IS_ENABLED(CONFIG_ZONE_DMA32))
+- arm64_dma_phys_limit = max_zone_dma_phys();
++ arm64_dma32_phys_limit = max_zone_dma32_phys();
+ else
+- arm64_dma_phys_limit = PHYS_MASK + 1;
++ arm64_dma32_phys_limit = PHYS_MASK + 1;
+
+ reserve_crashkernel();
+
+@@ -430,7 +430,7 @@ void __init arm64_memblock_init(void)
+
+ high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+
+- dma_contiguous_reserve(arm64_dma_phys_limit);
++ dma_contiguous_reserve(arm64_dma32_phys_limit);
+ }
+
+ void __init bootmem_init(void)
+@@ -534,7 +534,7 @@ static void __init free_unused_memmap(vo
+ void __init mem_init(void)
+ {
+ if (swiotlb_force == SWIOTLB_FORCE ||
+- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT))
++ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
+ swiotlb_init(1);
+ else
+ swiotlb_force = SWIOTLB_NO_FORCE;
+++ /dev/null
-From 9f93264df7a631132f2dacd150d0cc6cb7d20fc4 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Mon, 3 Feb 2020 17:30:46 +0000
-Subject: [PATCH] staging: vchiq_arm: Give vchiq children DT nodes
-
-vchiq kernel clients are now instantiated as platform drivers rather
-than using DT, but the children of the vchiq interface may still
-benefit from access to DT properties. Give them the option of a
-a sub-node of the vchiq parent for configuration and to allow
-them to be disabled.
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3190,12 +3190,20 @@ vchiq_register_child(struct platform_dev
- pdevinfo.id = PLATFORM_DEVID_NONE;
- pdevinfo.dma_mask = DMA_BIT_MASK(32);
-
-+ np = of_get_child_by_name(pdev->dev.of_node, name);
-+
-+ /* Skip the child if it is explicitly disabled */
-+ if (np && !of_device_is_available(np))
-+ return NULL;
-+
- child = platform_device_register_full(&pdevinfo);
- if (IS_ERR(child)) {
- dev_warn(&pdev->dev, "%s not registered\n", name);
- child = NULL;
- }
-
-+ child->dev.of_node = np;
-+
- /*
- * We want the dma-ranges etc to be copied from a device with the
- * correct dma-ranges for the VPU.
--- /dev/null
+From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:45 +0200
+Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32
+
+commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream.
+
+So far all arm64 devices have supported 32 bit DMA masks for their
+peripherals. This is not true anymore for the Raspberry Pi 4 as most of
+it's peripherals can only address the first GB of memory on a total of
+up to 4 GB.
+
+This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32
+to be addressable with a 32 bit mask. So it was decided to re-introduce
+ZONE_DMA in arm64.
+
+ZONE_DMA will contain the lower 1G of memory, which is currently the
+memory area addressable by any peripheral on an arm64 device.
+ZONE_DMA32 will contain the rest of the 32 bit addressable memory.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/Kconfig | 4 +++
+ arch/arm64/include/asm/page.h | 2 ++
+ arch/arm64/mm/init.c | 54 +++++++++++++++++++++++++----------
+ 3 files changed, 45 insertions(+), 15 deletions(-)
+
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -267,6 +267,10 @@ config GENERIC_CSUM
+ config GENERIC_CALIBRATE_DELAY
+ def_bool y
+
++config ZONE_DMA
++ bool "Support DMA zone" if EXPERT
++ default y
++
+ config ZONE_DMA32
+ bool "Support DMA32 zone" if EXPERT
+ default y
+--- a/arch/arm64/include/asm/page.h
++++ b/arch/arm64/include/asm/page.h
+@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long);
+
+ #include <asm-generic/getorder.h>
+
++#define ARCH_ZONE_DMA_BITS 30
++
+ #endif
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -56,6 +56,13 @@ EXPORT_SYMBOL(physvirt_offset);
+ struct page *vmemmap __ro_after_init;
+ EXPORT_SYMBOL(vmemmap);
+
++/*
++ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of
++ * memory as some devices, namely the Raspberry Pi 4, have peripherals with
++ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32
++ * bit addressable memory area.
++ */
++phys_addr_t arm64_dma_phys_limit __ro_after_init;
+ phys_addr_t arm64_dma32_phys_limit __ro_after_init;
+
+ #ifdef CONFIG_KEXEC_CORE
+@@ -169,15 +176,16 @@ static void __init reserve_elfcorehdr(vo
+ {
+ }
+ #endif /* CONFIG_CRASH_DUMP */
++
+ /*
+- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It
+- * currently assumes that for memory starting above 4G, 32-bit devices will
+- * use a DMA offset.
++ * Return the maximum physical address for a zone with a given address size
++ * limit. It currently assumes that for memory starting above 4G, 32-bit
++ * devices will use a DMA offset.
+ */
+-static phys_addr_t __init max_zone_dma32_phys(void)
++static phys_addr_t __init max_zone_phys(unsigned int zone_bits)
+ {
+- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
+- return min(offset + (1ULL << 32), memblock_end_of_DRAM());
++ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits);
++ return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM());
+ }
+
+ #ifdef CONFIG_NUMA
+@@ -186,6 +194,9 @@ static void __init zone_sizes_init(unsig
+ {
+ unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
+
++#ifdef CONFIG_ZONE_DMA
++ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
++#endif
+ #ifdef CONFIG_ZONE_DMA32
+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
+ #endif
+@@ -201,13 +212,18 @@ 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;
+
+ memset(zone_size, 0, sizeof(zone_size));
+
+- /* 4GB maximum for 32-bit only capable devices */
++#ifdef CONFIG_ZONE_DMA
++ max_dma = 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);
+- zone_size[ZONE_DMA32] = max_dma32 - min;
++ zone_size[ZONE_DMA32] = max_dma32 - max_dma;
+ #endif
+ zone_size[ZONE_NORMAL] = max - max_dma32;
+
+@@ -219,11 +235,17 @@ static void __init zone_sizes_init(unsig
+
+ if (start >= max)
+ continue;
+-
++#ifdef CONFIG_ZONE_DMA
++ if (start < max_dma) {
++ unsigned long dma_end = min_not_zero(end, max_dma);
++ zhole_size[ZONE_DMA] -= dma_end - start;
++ }
++#endif
+ #ifdef CONFIG_ZONE_DMA32
+ if (start < max_dma32) {
+- unsigned long dma_end = min(end, max_dma32);
+- zhole_size[ZONE_DMA32] -= dma_end - start;
++ unsigned long dma32_end = min(end, max_dma32);
++ unsigned long dma32_start = max(start, max_dma);
++ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start;
+ }
+ #endif
+ if (end > max_dma32) {
+@@ -418,9 +440,11 @@ void __init arm64_memblock_init(void)
+
+ early_init_fdt_scan_reserved_mem();
+
+- /* 4GB maximum for 32-bit only capable devices */
++ if (IS_ENABLED(CONFIG_ZONE_DMA))
++ arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS);
++
+ if (IS_ENABLED(CONFIG_ZONE_DMA32))
+- arm64_dma32_phys_limit = max_zone_dma32_phys();
++ arm64_dma32_phys_limit = max_zone_phys(32);
+ else
+ arm64_dma32_phys_limit = PHYS_MASK + 1;
+
+@@ -430,7 +454,7 @@ void __init arm64_memblock_init(void)
+
+ high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
+
+- dma_contiguous_reserve(arm64_dma32_phys_limit);
++ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit);
+ }
+
+ void __init bootmem_init(void)
+@@ -534,7 +558,7 @@ static void __init free_unused_memmap(vo
+ void __init mem_init(void)
+ {
+ if (swiotlb_force == SWIOTLB_FORCE ||
+- max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT))
++ max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit))
+ swiotlb_init(1);
+ else
+ swiotlb_force = SWIOTLB_NO_FORCE;
+++ /dev/null
-From 79a2c3013a3b2a4304f953a4a55c49c1bc85202b Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Mon, 3 Feb 2020 17:33:01 +0000
-Subject: [PATCH] staging: vchiq_arm: Add a matching unregister call
-
-All the registered children of vchiq have a corresponding call to
-platform_device_unregister except bcm2835_audio. Fix that.
-
-Fixes: 25c7597af20d ("staging: vchiq_arm: Register a platform device for audio")
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
-@@ -3293,6 +3293,7 @@ failed_platform_init:
-
- static int vchiq_remove(struct platform_device *pdev)
- {
-+ platform_device_unregister(bcm2835_audio);
- platform_device_unregister(bcm2835_camera);
- platform_device_unregister(bcm2835_codec);
- platform_device_unregister(vcsm_cma);
+++ /dev/null
-From 6c5efcf09c40d37f72692fdbdf6d461abede20f1 Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Mon, 3 Feb 2020 17:03:29 +0000
-Subject: [PATCH] ARM: dts: Move audio node under the vchiq parent
-
-VCHIQ kernel clients are now instantiated as platform drivers rather
-than using DT, but the children of the vchiq device can optionally be
-given a sub-node of the vchiq parent for configuration and to disable
-them.
-
-Move the existing audio node beneath the vchiq parent, to prevent
-multiple instantiation and unpleasant warnings. Note that the node
-name has to match the module name - "bcm2835_audio".
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
----
- arch/arm/boot/dts/bcm270x-rpi.dtsi | 16 +++++++++-------
- arch/arm/boot/dts/bcm2711-rpi.dtsi | 14 ++++++++++++++
- 2 files changed, 23 insertions(+), 7 deletions(-)
-
---- a/arch/arm/boot/dts/bcm270x-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi
-@@ -70,13 +70,6 @@
- status = "okay";
- };
-
-- /* Onboard audio */
-- audio: audio {
-- compatible = "brcm,bcm2835-audio";
-- brcm,pwm-channels = <8>;
-- status = "disabled";
-- };
--
- /* External sound card */
- sound: sound {
- status = "disabled";
-@@ -137,3 +130,12 @@
- &vec {
- status = "disabled";
- };
-+
-+&vchiq {
-+ /* Onboard audio */
-+ audio: bcm2835_audio {
-+ compatible = "brcm,bcm2835-audio";
-+ brcm,pwm-channels = <8>;
-+ status = "disabled";
-+ };
-+};
---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
-+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
-@@ -55,6 +55,8 @@
- compatible = "brcm,bcm2835-vc4";
- status = "disabled";
- };
-+
-+ /delete-node/ audio;
- };
-
- &scb {
-@@ -160,6 +162,18 @@
- };
- };
-
-+&vchiq {
-+ /* Onboard audio
-+ * This node is replicated because the original from bcm270x-rpi.dtsi
-+ * was deleted when the vchiq node was deleted above.
-+ */
-+ audio: bcm2835_audio {
-+ compatible = "brcm,bcm2835-audio";
-+ brcm,pwm-channels = <8>;
-+ status = "disabled";
-+ };
-+};
-+
- &dma {
- /* The VPU firmware uses DMA channel 11 for VCHIQ */
- brcm,dma-channel-mask = <0x1f5>;
--- /dev/null
+From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Wed, 11 Sep 2019 20:25:46 +0200
+Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum
+ zone_type'
+
+commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream.
+
+These zones usage has evolved with time and the comments were outdated.
+This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date
+examples on how they are used on different architectures.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------
+ 1 file changed, 26 insertions(+), 19 deletions(-)
+
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -358,33 +358,40 @@ struct per_cpu_nodestat {
+ #endif /* !__GENERATING_BOUNDS.H */
+
+ enum zone_type {
+-#ifdef CONFIG_ZONE_DMA
+ /*
+- * ZONE_DMA is used when there are devices that are not able
+- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we
+- * carve out the portion of memory that is needed for these devices.
+- * The range is arch specific.
+- *
+- * Some examples
+- *
+- * Architecture Limit
+- * ---------------------------
+- * parisc, ia64, sparc <4G
+- * s390, powerpc <2G
+- * arm Various
+- * alpha Unlimited or 0-16MB.
++ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able
++ * to DMA to all of the addressable memory (ZONE_NORMAL).
++ * On architectures where this area covers the whole 32 bit address
++ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller
++ * DMA addressing constraints. This distinction is important as a 32bit
++ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit
++ * platforms may need both zones as they support peripherals with
++ * different DMA addressing limitations.
++ *
++ * Some examples:
++ *
++ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the
++ * rest of the lower 4G.
++ *
++ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on
++ * the specific device.
++ *
++ * - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the
++ * lower 4G.
++ *
++ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary
++ * depending on the specific device.
+ *
+- * i386, x86_64 and multiple other arches
+- * <16M.
++ * - s390 uses ZONE_DMA fixed to the lower 2G.
++ *
++ * - ia64 and riscv only use ZONE_DMA32.
++ *
++ * - parisc uses neither.
+ */
++#ifdef CONFIG_ZONE_DMA
+ ZONE_DMA,
+ #endif
+ #ifdef CONFIG_ZONE_DMA32
+- /*
+- * x86_64 needs two ZONE_DMAs because it supports devices that are
+- * only able to do DMA to the lower 16M but also 32 bit devices that
+- * can only do DMA areas below 4G.
+- */
+ ZONE_DMA32,
+ #endif
+ /*
+++ /dev/null
-From 9a536b0cb8f83bd979fe274ef0197ece12a3ed09 Mon Sep 17 00:00:00 2001
-From: Matthias Reichl <hias@horus.com>
-Date: Thu, 20 Feb 2020 21:29:56 +0100
-Subject: [PATCH] ASoC: pcm512x: Fix unbalanced regulator enable call
- in probe error path
-
-commit ac0a68997935c4acb92eaae5ad8982e0bb432d56 upstream.
-
-When we get a clock error during probe we have to call
-regulator_bulk_disable before bailing out, otherwise we trigger
-a warning in regulator_put.
-
-Fix this by using "goto err" like in the error cases above.
-
-Fixes: 5a3af1293194d ("ASoC: pcm512x: Add PCM512x driver")
-Signed-off-by: Matthias Reichl <hias@horus.com>
-Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
-Link: https://lore.kernel.org/r/20200220202956.29233-1-hias@horus.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- sound/soc/codecs/pcm512x.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/sound/soc/codecs/pcm512x.c
-+++ b/sound/soc/codecs/pcm512x.c
-@@ -1564,13 +1564,15 @@ int pcm512x_probe(struct device *dev, st
- }
-
- pcm512x->sclk = devm_clk_get(dev, NULL);
-- if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-- return -EPROBE_DEFER;
-+ if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) {
-+ ret = -EPROBE_DEFER;
-+ goto err;
-+ }
- if (!IS_ERR(pcm512x->sclk)) {
- ret = clk_prepare_enable(pcm512x->sclk);
- if (ret != 0) {
- dev_err(dev, "Failed to enable SCLK: %d\n", ret);
-- return ret;
-+ goto err;
- }
- }
-
--- /dev/null
+From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Mon, 28 Oct 2019 11:32:32 -0500
+Subject: [PATCH] resource: Add a resource_list_first_type helper
+
+commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream.
+
+A common pattern is looping over a resource_list just to get a matching
+entry with a specific type. Add resource_list_first_type() helper which
+implements this.
+
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ include/linux/resource_ext.h | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/linux/resource_ext.h
++++ b/include/linux/resource_ext.h
+@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou
+ #define resource_list_for_each_entry_safe(entry, tmp, list) \
+ list_for_each_entry_safe((entry), (tmp), (list), node)
+
++static inline struct resource_entry *
++resource_list_first_type(struct list_head *list, unsigned long type)
++{
++ struct resource_entry *entry;
++
++ resource_list_for_each_entry(entry, list) {
++ if (resource_type(entry->res) == type)
++ return entry;
++ }
++ return NULL;
++}
++
+ #endif /* _LINUX_RESOURCE_EXT_H */
+++ /dev/null
-From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001
-From: Phil Elwell <phil@raspberrypi.com>
-Date: Fri, 28 Feb 2020 11:22:40 +0000
-Subject: [PATCH] ARM: dts: overlays: Create custom clocks in /
-
-Change [1] removes the simple-bus compatible string from the "/clocks"
-node, preventing any custom clocks placed there from being initialised.
-Rather than reinstate the compatible string and trigger DT warnings at
-kernel build time, change the overlays to instantiate those clocks under
-the root node ("/").
-
-See: https://github.com/raspberrypi/linux/issues/3481
-
-Signed-off-by: Phil Elwell <phil@raspberrypi.com>
-
-[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks")
----
- .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
- arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +-
- 5 files changed, 5 insertions(+), 5 deletions(-)
-
---- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts
-@@ -9,7 +9,7 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target-path = "/clocks";
-+ target-path = "/";
- __overlay__ {
- boss_osc: boss_osc {
- compatible = "allo,dac-clk";
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
-@@ -6,7 +6,7 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target-path = "/clocks";
-+ target-path = "/";
- __overlay__ {
- dacpro_osc: dacpro_osc {
- compatible = "hifiberry,dacpro-clk";
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
-@@ -6,7 +6,7 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target-path = "/clocks";
-+ target-path = "/";
- __overlay__ {
- dacpro_osc: dacpro_osc {
- compatible = "hifiberry,dacpro-clk";
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
-@@ -6,7 +6,7 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target-path = "/clocks";
-+ target-path = "/";
- __overlay__ {
- dacpro_osc: dacpro_osc {
- compatible = "hifiberry,dacpro-clk";
---- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
-+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
-@@ -8,7 +8,7 @@
- compatible = "brcm,bcm2835";
-
- fragment@0 {
-- target-path = "/clocks";
-+ target-path = "/";
- __overlay__ {
- dachd_osc: pll_dachd_osc {
- compatible = "hifiberry,dachd-clk";
--- /dev/null
+From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Mon, 14 Oct 2019 20:31:03 +0200
+Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable
+
+commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream.
+
+Some architectures, notably ARM, are interested in tweaking this
+depending on their runtime DMA addressing limitations.
+
+Acked-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+---
+ arch/arm64/include/asm/page.h | 2 --
+ arch/arm64/mm/init.c | 9 +++++++--
+ arch/powerpc/include/asm/page.h | 9 ---------
+ arch/powerpc/mm/mem.c | 20 +++++++++++++++-----
+ arch/s390/include/asm/page.h | 2 --
+ arch/s390/mm/init.c | 1 +
+ include/linux/dma-direct.h | 2 ++
+ kernel/dma/direct.c | 13 ++++++-------
+ 8 files changed, 31 insertions(+), 27 deletions(-)
+
+--- a/arch/arm64/include/asm/page.h
++++ b/arch/arm64/include/asm/page.h
+@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long);
+
+ #include <asm-generic/getorder.h>
+
+-#define ARCH_ZONE_DMA_BITS 30
+-
+ #endif
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -20,6 +20,7 @@
+ #include <linux/sort.h>
+ #include <linux/of.h>
+ #include <linux/of_fdt.h>
++#include <linux/dma-direct.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dma-contiguous.h>
+ #include <linux/efi.h>
+@@ -41,6 +42,8 @@
+ #include <asm/tlb.h>
+ #include <asm/alternative.h>
+
++#define ARM64_ZONE_DMA_BITS 30
++
+ /*
+ * We need to be able to catch inadvertent references to memstart_addr
+ * that occur (potentially in generic code) before arm64_memblock_init()
+@@ -440,8 +443,10 @@ void __init arm64_memblock_init(void)
+
+ early_init_fdt_scan_reserved_mem();
+
+- if (IS_ENABLED(CONFIG_ZONE_DMA))
+- arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS);
++ if (IS_ENABLED(CONFIG_ZONE_DMA)) {
++ zone_dma_bits = ARM64_ZONE_DMA_BITS;
++ arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS);
++ }
+
+ if (IS_ENABLED(CONFIG_ZONE_DMA32))
+ arm64_dma32_phys_limit = max_zone_phys(32);
+--- a/arch/powerpc/include/asm/page.h
++++ b/arch/powerpc/include/asm/page.h
+@@ -334,13 +334,4 @@ struct vm_area_struct;
+ #endif /* __ASSEMBLY__ */
+ #include <asm/slice.h>
+
+-/*
+- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks.
+- */
+-#ifdef CONFIG_PPC32
+-#define ARCH_ZONE_DMA_BITS 30
+-#else
+-#define ARCH_ZONE_DMA_BITS 31
+-#endif
+-
+ #endif /* _ASM_POWERPC_PAGE_H */
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -31,6 +31,7 @@
+ #include <linux/slab.h>
+ #include <linux/vmalloc.h>
+ #include <linux/memremap.h>
++#include <linux/dma-direct.h>
+
+ #include <asm/pgalloc.h>
+ #include <asm/prom.h>
+@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi
+ * everything else. GFP_DMA32 page allocations automatically fall back to
+ * ZONE_DMA.
+ *
+- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to
+- * inform the generic DMA mapping code. 32-bit only devices (if not handled
+- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get
+- * otherwise served by ZONE_DMA.
++ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the
++ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU
++ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by
++ * ZONE_DMA.
+ */
+ static unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+@@ -259,9 +260,18 @@ void __init paging_init(void)
+ printk(KERN_DEBUG "Memory hole size: %ldMB\n",
+ (long int)((top_of_ram - total_ram) >> 20));
+
++ /*
++ * Allow 30-bit DMA for very limited Broadcom wifi chips on many
++ * powerbooks.
++ */
++ if (IS_ENABLED(CONFIG_PPC32))
++ zone_dma_bits = 30;
++ else
++ zone_dma_bits = 31;
++
+ #ifdef CONFIG_ZONE_DMA
+ max_zone_pfns[ZONE_DMA] = min(max_low_pfn,
+- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT));
++ 1UL << (zone_dma_bits - PAGE_SHIFT));
+ #endif
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ #ifdef CONFIG_HIGHMEM
+--- a/arch/s390/include/asm/page.h
++++ b/arch/s390/include/asm/page.h
+@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+-#define ARCH_ZONE_DMA_BITS 31
+-
+ #include <asm-generic/memory_model.h>
+ #include <asm-generic/getorder.h>
+
+--- a/arch/s390/mm/init.c
++++ b/arch/s390/mm/init.c
+@@ -118,6 +118,7 @@ void __init paging_init(void)
+
+ sparse_memory_present_with_active_regions(MAX_NUMNODES);
+ sparse_init();
++ zone_dma_bits = 31;
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -8,6 +8,8 @@
+
+ static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+
++extern unsigned int zone_dma_bits;
++
+ #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
+ #include <asm/dma-direct.h>
+ #else
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -16,12 +16,11 @@
+ #include <linux/swiotlb.h>
+
+ /*
+- * Most architectures use ZONE_DMA for the first 16 Megabytes, but
+- * some use it for entirely different regions:
++ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it
++ * it for entirely different regions. In that case the arch code needs to
++ * override the variable below for dma-direct to work properly.
+ */
+-#ifndef ARCH_ZONE_DMA_BITS
+-#define ARCH_ZONE_DMA_BITS 24
+-#endif
++unsigned int zone_dma_bits __ro_after_init = 24;
+
+ static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size)
+ {
+@@ -69,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_ma
+ * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
+ * zones.
+ */
+- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
++ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
+ return GFP_DMA;
+ if (*phys_mask <= DMA_BIT_MASK(32))
+ return GFP_DMA32;
+@@ -395,7 +394,7 @@ int dma_direct_supported(struct device *
+ u64 min_mask;
+
+ if (IS_ENABLED(CONFIG_ZONE_DMA))
+- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS);
++ min_mask = DMA_BIT_MASK(zone_dma_bits);
+ else
+ min_mask = DMA_BIT_MASK(30);
+
--- /dev/null
+From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Thu, 7 Nov 2019 16:06:45 +0100
+Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation
+
+commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream.
+
+The devices found behind this PCIe chip have unusual DMA mapping
+constraints as there is an AMBA interconnect placed in between them and
+the different PCI endpoints. The offset between physical memory
+addresses and AMBA's view is provided by reading a PCI config register,
+which is saved and used whenever DMA mapping is needed.
+
+It turns out that this DMA setup can be represented by properly setting
+'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device
+enable fixup. And ultimately allows us to get rid of this device's
+custom DMA functions.
+
+Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is
+moved to avoid warnings whenever CONFIG_PM is not enabled.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/x86/Kconfig | 1 -
+ arch/x86/include/asm/device.h | 3 -
+ arch/x86/include/asm/dma-direct.h | 9 --
+ arch/x86/pci/sta2x11-fixup.c | 135 ++++++------------------------
+ 4 files changed, 26 insertions(+), 122 deletions(-)
+ delete mode 100644 arch/x86/include/asm/dma-direct.h
+
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE
+ config STA2X11
+ bool "STA2X11 Companion Chip Support"
+ depends on X86_32_NON_STANDARD && PCI
+- select ARCH_HAS_PHYS_TO_DMA
+ select SWIOTLB
+ select MFD_STA2X11
+ select GPIOLIB
+--- a/arch/x86/include/asm/device.h
++++ b/arch/x86/include/asm/device.h
+@@ -6,9 +6,6 @@ struct dev_archdata {
+ #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
+ void *iommu; /* hook for IOMMU specific extension */
+ #endif
+-#ifdef CONFIG_STA2X11
+- bool is_sta2x11;
+-#endif
+ };
+
+ #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
+--- a/arch/x86/include/asm/dma-direct.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-#ifndef ASM_X86_DMA_DIRECT_H
+-#define ASM_X86_DMA_DIRECT_H 1
+-
+-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
+-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr);
+-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr);
+-
+-#endif /* ASM_X86_DMA_DIRECT_H */
+--- a/arch/x86/pci/sta2x11-fixup.c
++++ b/arch/x86/pci/sta2x11-fixup.c
+@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin
+ };
+
+ struct sta2x11_mapping {
+- u32 amba_base;
+ int is_suspended;
+ struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS];
+ };
+@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci
+ return pdev->bus->number - instance->bus0;
+ }
+
+-static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
+-{
+- struct sta2x11_instance *instance;
+- int ep;
+-
+- instance = sta2x11_pdev_to_instance(pdev);
+- if (!instance)
+- return NULL;
+- ep = sta2x11_pdev_to_ep(pdev);
+- return instance->map + ep;
+-}
+-
+ /* This is exported, as some devices need to access the MFD registers */
+ struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev)
+ {
+@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins
+ }
+ EXPORT_SYMBOL(sta2x11_get_instance);
+
+-
+-/**
+- * p2a - Translate physical address to STA2x11 AMBA address,
+- * used for DMA transfers to STA2x11
+- * @p: Physical address
+- * @pdev: PCI device (must be hosted within the connext)
+- */
+-static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev)
+-{
+- struct sta2x11_mapping *map;
+- dma_addr_t a;
+-
+- map = sta2x11_pdev_to_mapping(pdev);
+- a = p + map->amba_base;
+- return a;
+-}
+-
+-/**
+- * a2p - Translate STA2x11 AMBA address to physical address
+- * used for DMA transfers from STA2x11
+- * @a: STA2x11 AMBA address
+- * @pdev: PCI device (must be hosted within the connext)
+- */
+-static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev)
+-{
+- struct sta2x11_mapping *map;
+- dma_addr_t p;
+-
+- map = sta2x11_pdev_to_mapping(pdev);
+- p = a - map->amba_base;
+- return p;
+-}
+-
+ /* At setup time, we use our own ops if the device is a ConneXt one */
+ static void sta2x11_setup_pdev(struct pci_dev *pdev)
+ {
+@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc
+
+ if (!instance) /* either a sta2x11 bridge or another ST device */
+ return;
+- pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+- pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+- pdev->dev.archdata.is_sta2x11 = true;
+
+ /* We must enable all devices as master, for audio DMA to work */
+ pci_set_master(pdev);
+@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc
+ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev);
+
+ /*
+- * The following three functions are exported (used in swiotlb: FIXME)
+- */
+-/**
+- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it)
+- * @dev: device for a PCI device
+- * @addr: DMA address
+- * @size: DMA size
+- */
+-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+- struct sta2x11_mapping *map;
+-
+- if (!dev->archdata.is_sta2x11) {
+- if (!dev->dma_mask)
+- return false;
+- return addr + size - 1 <= *dev->dma_mask;
+- }
+-
+- map = sta2x11_pdev_to_mapping(to_pci_dev(dev));
+-
+- if (!map || (addr < map->amba_base))
+- return false;
+- if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) {
+- return false;
+- }
+-
+- return true;
+-}
+-
+-/**
+- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device
+- * @dev: device for a PCI device
+- * @paddr: Physical address
+- */
+-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+-{
+- if (!dev->archdata.is_sta2x11)
+- return paddr;
+- return p2a(paddr, to_pci_dev(dev));
+-}
+-
+-/**
+- * dma_to_phys - Return the physical address used for this STA2x11 DMA address
+- * @dev: device for a PCI device
+- * @daddr: STA2x11 AMBA DMA address
+- */
+-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
+-{
+- if (!dev->archdata.is_sta2x11)
+- return daddr;
+- return a2p(daddr, to_pci_dev(dev));
+-}
+-
+-
+-/*
+ * At boot we must set up the mappings for the pcie-to-amba bridge.
+ * It involves device access, and the same happens at suspend/resume time
+ */
+@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device
+ /* At probe time, enable mapping for each endpoint, using the pdev */
+ static void sta2x11_map_ep(struct pci_dev *pdev)
+ {
+- struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
++ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev);
++ struct device *dev = &pdev->dev;
++ u32 amba_base, max_amba_addr;
+ int i;
+
+- if (!map)
++ if (!instance)
+ return;
+- pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base);
++
++ pci_read_config_dword(pdev, AHB_BASE(0), &amba_base);
++ max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1;
++
++ dev->dma_pfn_offset = PFN_DOWN(-amba_base);
++
++ dev->bus_dma_mask = max_amba_addr;
++ pci_set_consistent_dma_mask(pdev, max_amba_addr);
++ pci_set_dma_mask(pdev, max_amba_addr);
+
+ /* Configure AHB mapping */
+ pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0);
+@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de
+
+ dev_info(&pdev->dev,
+ "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n",
+- sta2x11_pdev_to_ep(pdev), map->amba_base,
+- map->amba_base + STA2X11_AMBA_SIZE - 1);
++ sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr);
+ }
+ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep);
+
+ #ifdef CONFIG_PM /* Some register values must be saved and restored */
+
++static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
++{
++ struct sta2x11_instance *instance;
++ int ep;
++
++ instance = sta2x11_pdev_to_instance(pdev);
++ if (!instance)
++ return NULL;
++ ep = sta2x11_pdev_to_ep(pdev);
++ return instance->map + ep;
++}
++
+ static void suspend_mapping(struct pci_dev *pdev)
+ {
+ struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
--- /dev/null
+From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001
+From: Rob Herring <robh@kernel.org>
+Date: Wed, 30 Oct 2019 17:30:57 -0500
+Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers
+
+Extend devm_of_pci_get_host_bridge_resources() and
+pci_parse_request_of_pci_ranges() helpers to also parse the inbound
+addresses from DT 'dma-ranges' and populate a resource list with the
+translated addresses. This will help ensure 'dma-ranges' is always
+parsed in a consistent way.
+
+Tested-by: Srinath Mannam <srinath.mannam@broadcom.com>
+Tested-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com> # for AArdvark
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Srinath Mannam <srinath.mannam@broadcom.com>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+Acked-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Jingoo Han <jingoohan1@gmail.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Toan Le <toan@os.amperecomputing.com>
+Cc: Ley Foon Tan <lftan@altera.com>
+Cc: Tom Joseph <tjoseph@cadence.com>
+Cc: Ray Jui <rjui@broadcom.com>
+Cc: Scott Branden <sbranden@broadcom.com>
+Cc: bcm-kernel-feedback-list@broadcom.com
+Cc: Ryder Lee <ryder.lee@mediatek.com>
+Cc: Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
+Cc: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Cc: Simon Horman <horms@verge.net.au>
+Cc: Shawn Lin <shawn.lin@rock-chips.com>
+Cc: Heiko Stuebner <heiko@sntech.de>
+Cc: Michal Simek <michal.simek@xilinx.com>
+Cc: rfi@lists.rocketboards.org
+Cc: linux-mediatek@lists.infradead.org
+Cc: linux-renesas-soc@vger.kernel.org
+Cc: linux-rockchip@lists.infradead.org
+(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc)
+---
+ .../pci/controller/dwc/pcie-designware-host.c | 8 +--
+ drivers/pci/controller/pci-aardvark.c | 3 +-
+ drivers/pci/controller/pci-ftpci100.c | 4 +-
+ drivers/pci/controller/pci-host-common.c | 2 +-
+ drivers/pci/controller/pci-v3-semi.c | 8 +--
+ drivers/pci/controller/pci-versatile.c | 3 +-
+ drivers/pci/controller/pci-xgene.c | 4 +-
+ drivers/pci/controller/pcie-altera.c | 5 +-
+ drivers/pci/controller/pcie-cadence-host.c | 2 +-
+ drivers/pci/controller/pcie-iproc-platform.c | 4 +-
+ drivers/pci/controller/pcie-mediatek.c | 4 +-
+ drivers/pci/controller/pcie-mobiveil.c | 4 +-
+ drivers/pci/controller/pcie-rcar.c | 3 +-
+ drivers/pci/controller/pcie-rockchip-host.c | 4 +-
+ drivers/pci/controller/pcie-xilinx-nwl.c | 4 +-
+ drivers/pci/controller/pcie-xilinx.c | 4 +-
+ drivers/pci/of.c | 61 ++++++++++++++++---
+ drivers/pci/pci.h | 8 ++-
+ include/linux/pci.h | 9 ++-
+ 19 files changed, 96 insertions(+), 48 deletions(-)
+
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -343,12 +343,8 @@ int dw_pcie_host_init(struct pcie_port *
+ if (!bridge)
+ return -ENOMEM;
+
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+- &bridge->windows, &pp->io_base);
+- if (ret)
+- return ret;
+-
+- ret = devm_request_pci_bus_resources(dev, &bridge->windows);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (ret)
+ return ret;
+
+--- a/drivers/pci/controller/pci-aardvark.c
++++ b/drivers/pci/controller/pci-aardvark.c
+@@ -1023,7 +1023,8 @@ static int advk_pcie_probe(struct platfo
+ return ret;
+ }
+
+- ret = advk_pcie_parse_request_of_pci_ranges(pcie);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, &bus);
+ if (ret) {
+ dev_err(dev, "Failed to parse resources\n");
+ return ret;
+--- a/drivers/pci/controller/pci-ftpci100.c
++++ b/drivers/pci/controller/pci-ftpci100.c
+@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat
+ if (IS_ERR(p->base))
+ return PTR_ERR(p->base);
+
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+- &res, &io_base);
++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
++ &host->dma_ranges, NULL);
+ if (ret)
+ return ret;
+
+--- a/drivers/pci/controller/pci-host-common.c
++++ b/drivers/pci/controller/pci-host-common.c
+@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci
+ struct pci_config_window *cfg;
+
+ /* Parse our PCI ranges and request their resources */
+- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+ if (err)
+ return ERR_PTR(err);
+
+--- a/drivers/pci/controller/pci-v3-semi.c
++++ b/drivers/pci/controller/pci-v3-semi.c
+@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_
+ if (IS_ERR(v3->config_base))
+ return PTR_ERR(v3->config_base);
+
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+- &io_base);
+- if (ret)
+- return ret;
+-
+- ret = devm_request_pci_bus_resources(dev, &res);
++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows,
++ &host->dma_ranges, NULL);
+ if (ret)
+ return ret;
+
+--- a/drivers/pci/controller/pci-versatile.c
++++ b/drivers/pci/controller/pci-versatile.c
+@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl
+ if (IS_ERR(versatile_cfg_base[1]))
+ return PTR_ERR(versatile_cfg_base[1]);
+
+- ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ NULL, NULL);
+ if (ret)
+ return ret;
+
+--- a/drivers/pci/controller/pci-xgene.c
++++ b/drivers/pci/controller/pci-xgene.c
+@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf
+ if (ret)
+ return ret;
+
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+- &iobase);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (ret)
+ return ret;
+
+--- a/drivers/pci/controller/pcie-altera.c
++++ b/drivers/pci/controller/pcie-altera.c
+@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat
+ return ret;
+ }
+
+- INIT_LIST_HEAD(&pcie->resources);
+-
+- ret = altera_pcie_parse_request_of_pci_ranges(pcie);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (ret) {
+ dev_err(dev, "Failed add resources\n");
+ return ret;
+--- a/drivers/pci/controller/pcie-cadence-host.c
++++ b/drivers/pci/controller/pcie-cadence-host.c
+@@ -211,7 +211,7 @@ static int cdns_pcie_host_init(struct de
+ int err;
+
+ /* Parse our PCI ranges and request their resources */
+- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+ if (err)
+ return err;
+
+--- a/drivers/pci/controller/pcie-iproc-platform.c
++++ b/drivers/pci/controller/pcie-iproc-platform.c
+@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct
+ if (IS_ERR(pcie->phy))
+ return PTR_ERR(pcie->phy);
+
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources,
+- &iobase);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (ret) {
+ dev_err(dev, "unable to get PCI host bridge resources\n");
+ return ret;
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci
+ resource_size_t io_base;
+ int err;
+
+- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+- windows, &io_base);
++ err = pci_parse_request_of_pci_ranges(dev, windows,
++ &host->dma_ranges, &bus);
+ if (err)
+ return err;
+
+--- a/drivers/pci/controller/pcie-mobiveil.c
++++ b/drivers/pci/controller/pcie-mobiveil.c
+@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl
+ INIT_LIST_HEAD(&pcie->resources);
+
+ /* parse the host bridge base addresses from the device tree file */
+- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+- &pcie->resources, &iobase);
++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (ret) {
+ dev_err(dev, "Getting bridge resources failed\n");
+ return ret;
+--- a/drivers/pci/controller/pcie-rcar.c
++++ b/drivers/pci/controller/pcie-rcar.c
+@@ -1143,7 +1143,8 @@ static int rcar_pcie_probe(struct platfo
+ pcie->dev = dev;
+ platform_set_drvdata(pdev, pcie);
+
+- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
++ err = pci_parse_request_of_pci_ranges(dev, &pcie->resources,
++ &bridge->dma_ranges, NULL);
+ if (err)
+ goto err_free_bridge;
+
+--- a/drivers/pci/controller/pcie-rockchip-host.c
++++ b/drivers/pci/controller/pcie-rockchip-host.c
+@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl
+ if (err < 0)
+ goto err_deinit_port;
+
+- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+- &res, &io_base);
++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, &bus_res);
+ if (err)
+ goto err_remove_irq_domain;
+
+--- a/drivers/pci/controller/pcie-xilinx-nwl.c
++++ b/drivers/pci/controller/pcie-xilinx-nwl.c
+@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor
+ return err;
+ }
+
+- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+- &iobase);
++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (err) {
+ dev_err(dev, "Getting bridge resources failed\n");
+ return err;
+--- a/drivers/pci/controller/pcie-xilinx.c
++++ b/drivers/pci/controller/pcie-xilinx.c
+@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat
+ return err;
+ }
+
+- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
+- &iobase);
++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
+ if (err) {
+ dev_err(dev, "Getting bridge resources failed\n");
+ return err;
+--- a/drivers/pci/of.c
++++ b/drivers/pci/of.c
+@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl
+ */
+ int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+- struct list_head *resources, resource_size_t *io_base)
++ struct list_head *resources,
++ struct list_head *ib_resources,
++ resource_size_t *io_base)
+ {
+ struct device_node *dev_node = dev->of_node;
+ struct resource *res, tmp_res;
+ struct resource *bus_range;
+ struct of_pci_range range;
+ struct of_pci_range_parser parser;
+- char range_type[4];
++ const char *range_type;
+ int err;
+
+ if (io_base)
+@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource
+ for_each_of_pci_range(&parser, &range) {
+ /* Read next ranges element */
+ if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
+- snprintf(range_type, 4, " IO");
++ range_type = "IO";
+ else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
+- snprintf(range_type, 4, "MEM");
++ range_type = "MEM";
+ else
+- snprintf(range_type, 4, "err");
+- dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n",
++ range_type = "err";
++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n",
+ range_type, range.cpu_addr,
+ range.cpu_addr + range.size - 1, range.pci_addr);
+
+@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource
+ pci_add_resource_offset(resources, res, res->start - range.pci_addr);
+ }
+
++ /* Check for dma-ranges property */
++ if (!ib_resources)
++ return 0;
++ err = of_pci_dma_range_parser_init(&parser, dev_node);
++ if (err)
++ return 0;
++
++ dev_dbg(dev, "Parsing dma-ranges property...\n");
++ for_each_of_pci_range(&parser, &range) {
++ struct resource_entry *entry;
++ /*
++ * If we failed translation or got a zero-sized region
++ * then skip this range
++ */
++ if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) ||
++ range.cpu_addr == OF_BAD_ADDR || range.size == 0)
++ continue;
++
++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n",
++ "IB MEM", range.cpu_addr,
++ range.cpu_addr + range.size - 1, range.pci_addr);
++
++
++ err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
++ if (err)
++ continue;
++
++ res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
++ if (!res) {
++ err = -ENOMEM;
++ goto failed;
++ }
++
++ /* Keep the resource list sorted */
++ resource_list_for_each_entry(entry, ib_resources)
++ if (entry->res->start > res->start)
++ break;
++
++ pci_add_resource_offset(&entry->node, res,
++ res->start - range.pci_addr);
++ }
++
+ return 0;
+
+ failed:
+@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p
+
+ int pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
++ struct list_head *ib_resources,
+ struct resource **bus_range)
+ {
+ int err, res_valid = 0;
+@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru
+ struct resource_entry *win, *tmp;
+
+ INIT_LIST_HEAD(resources);
++ if (ib_resources)
++ INIT_LIST_HEAD(ib_resources);
+ err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
+- &iobase);
++ ib_resources, &iobase);
+ if (err)
+ return err;
+
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -636,11 +636,15 @@ static inline void pci_release_bus_of_no
+ #if defined(CONFIG_OF_ADDRESS)
+ int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+- struct list_head *resources, resource_size_t *io_base);
++ struct list_head *resources,
++ struct list_head *ib_resources,
++ resource_size_t *io_base);
+ #else
+ static inline int devm_of_pci_get_host_bridge_resources(struct device *dev,
+ unsigned char busno, unsigned char bus_max,
+- struct list_head *resources, resource_size_t *io_base)
++ struct list_head *resources,
++ struct list_head *ib_resources,
++ resource_size_t *io_base)
+ {
+ return -EINVAL;
+ }
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -2278,6 +2278,7 @@ struct irq_domain;
+ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus);
+ int pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
++ struct list_head *ib_resources,
+ struct resource **bus_range);
+
+ /* Arch may override this (weak) */
+@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n
+ #else /* CONFIG_OF */
+ static inline struct irq_domain *
+ pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
+-static inline int pci_parse_request_of_pci_ranges(struct device *dev,
+- struct list_head *resources,
+- struct resource **bus_range)
++static inline int
++pci_parse_request_of_pci_ranges(struct device *dev,
++ struct list_head *resources,
++ struct list_head *ib_resources,
++ struct resource **bus_range)
+ {
+ return -EINVAL;
+ }
--- /dev/null
+From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 12 Nov 2019 17:06:04 +0100
+Subject: [PATCH] dma-direct: unify the dma_capable definitions
+
+commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream.
+
+Currently each architectures that wants to override dma_to_phys and
+phys_to_dma also has to provide dma_capable. But there isn't really
+any good reason for that. powerpc and mips just have copies of the
+generic one minus the latests fix, and the arm one was the inspiration
+for said fix, but misses the bus_dma_mask handling.
+Make all architectures use the generic version instead.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+---
+ arch/arm/include/asm/dma-direct.h | 19 -------------------
+ arch/mips/include/asm/dma-direct.h | 8 --------
+ arch/powerpc/include/asm/dma-direct.h | 9 ---------
+ include/linux/dma-direct.h | 2 +-
+ 4 files changed, 1 insertion(+), 37 deletions(-)
+
+--- a/arch/arm/include/asm/dma-direct.h
++++ b/arch/arm/include/asm/dma-direct.h
+@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys(
+ return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset;
+ }
+
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+- u64 limit, mask;
+-
+- if (!dev->dma_mask)
+- return 0;
+-
+- mask = *dev->dma_mask;
+-
+- limit = (mask + 1) & ~mask;
+- if (limit && size > limit)
+- return 0;
+-
+- if ((addr | (addr + size - 1)) & ~mask)
+- return 0;
+-
+- return 1;
+-}
+-
+ #endif /* ASM_ARM_DMA_DIRECT_H */
+--- a/arch/mips/include/asm/dma-direct.h
++++ b/arch/mips/include/asm/dma-direct.h
+@@ -2,14 +2,6 @@
+ #ifndef _MIPS_DMA_DIRECT_H
+ #define _MIPS_DMA_DIRECT_H 1
+
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+- if (!dev->dma_mask)
+- return false;
+-
+- return addr + size - 1 <= *dev->dma_mask;
+-}
+-
+ dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr);
+ phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr);
+
+--- a/arch/powerpc/include/asm/dma-direct.h
++++ b/arch/powerpc/include/asm/dma-direct.h
+@@ -2,15 +2,6 @@
+ #ifndef ASM_POWERPC_DMA_DIRECT_H
+ #define ASM_POWERPC_DMA_DIRECT_H 1
+
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+- if (!dev->dma_mask)
+- return false;
+-
+- return addr + size - 1 <=
+- min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+-}
+-
+ static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+ {
+ if (!dev)
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys(
+
+ return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT);
+ }
++#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+
+ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+ {
+@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de
+
+ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+ }
+-#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+
+ #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ bool force_dma_unencrypted(struct device *dev);
--- /dev/null
+From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 12 Nov 2019 17:07:43 +0100
+Subject: [PATCH] dma-direct: avoid a forward declaration for
+ phys_to_dma
+
+Move dma_capable down a bit so that we don't need a forward declaration
+for phys_to_dma.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2)
+---
+ include/linux/dma-direct.h | 30 ++++++++++++++----------------
+ 1 file changed, 14 insertions(+), 16 deletions(-)
+
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -6,8 +6,6 @@
+ #include <linux/memblock.h> /* for min_low_pfn */
+ #include <linux/mem_encrypt.h>
+
+-static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+-
+ extern unsigned int zone_dma_bits;
+
+ #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA
+@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys(
+ }
+ #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
+
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+-{
+- dma_addr_t end = addr + size - 1;
+-
+- if (!dev->dma_mask)
+- return false;
+-
+- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
+- min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+- return false;
+-
+- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
+-}
+-
+ #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ bool force_dma_unencrypted(struct device *dev);
+ #else
+@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st
+ return __sme_clr(__dma_to_phys(dev, daddr));
+ }
+
++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
++{
++ dma_addr_t end = addr + size - 1;
++
++ if (!dev->dma_mask)
++ return false;
++
++ if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
++ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
++ return false;
++
++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
++}
++
+ u64 dma_direct_get_required_mask(struct device *dev);
+ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp, unsigned long attrs);
--- /dev/null
+From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 19 Nov 2019 17:38:58 +0100
+Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the
+ min_low_pfn check
+
+commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream.
+
+The valid memory address check in dma_capable only makes sense when mapping
+normal memory, not when using dma_map_resource to map a device resource.
+Add a new boolean argument to dma_capable to exclude that check for the
+dma_map_resource case.
+
+Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses")
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+---
+ arch/x86/kernel/amd_gart_64.c | 4 ++--
+ drivers/xen/swiotlb-xen.c | 4 ++--
+ include/linux/dma-direct.h | 5 +++--
+ kernel/dma/direct.c | 4 ++--
+ kernel/dma/swiotlb.c | 2 +-
+ 5 files changed, 10 insertions(+), 9 deletions(-)
+
+--- a/arch/x86/kernel/amd_gart_64.c
++++ b/arch/x86/kernel/amd_gart_64.c
+@@ -185,13 +185,13 @@ static void iommu_full(struct device *de
+ static inline int
+ need_iommu(struct device *dev, unsigned long addr, size_t size)
+ {
+- return force_iommu || !dma_capable(dev, addr, size);
++ return force_iommu || !dma_capable(dev, addr, size, true);
+ }
+
+ static inline int
+ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
+ {
+- return !dma_capable(dev, addr, size);
++ return !dma_capable(dev, addr, size, true);
+ }
+
+ /* Map a single continuous physical area into the IOMMU.
+--- a/drivers/xen/swiotlb-xen.c
++++ b/drivers/xen/swiotlb-xen.c
+@@ -375,7 +375,7 @@ static dma_addr_t xen_swiotlb_map_page(s
+ * we can safely return the device addr and not worry about bounce
+ * buffering it.
+ */
+- if (dma_capable(dev, dev_addr, size) &&
++ if (dma_capable(dev, dev_addr, size, true) &&
+ !range_straddles_page_boundary(phys, size) &&
+ !xen_arch_need_swiotlb(dev, phys, dev_addr) &&
+ swiotlb_force != SWIOTLB_FORCE)
+@@ -397,7 +397,7 @@ static dma_addr_t xen_swiotlb_map_page(s
+ /*
+ * Ensure that the address returned is DMA'ble
+ */
+- if (unlikely(!dma_capable(dev, dev_addr, size))) {
++ if (unlikely(!dma_capable(dev, dev_addr, size, true))) {
+ swiotlb_tbl_unmap_single(dev, map, size, size, dir,
+ attrs | DMA_ATTR_SKIP_CPU_SYNC);
+ return DMA_MAPPING_ERROR;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st
+ return __sme_clr(__dma_to_phys(dev, daddr));
+ }
+
+-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size,
++ bool is_ram)
+ {
+ dma_addr_t end = addr + size - 1;
+
+ if (!dev->dma_mask)
+ return false;
+
+- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
++ if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) &&
+ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+ return false;
+
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -325,7 +325,7 @@ static inline bool dma_direct_possible(s
+ size_t size)
+ {
+ return swiotlb_force != SWIOTLB_FORCE &&
+- dma_capable(dev, dma_addr, size);
++ dma_capable(dev, dma_addr, size, true);
+ }
+
+ dma_addr_t dma_direct_map_page(struct device *dev, struct page *page,
+@@ -374,7 +374,7 @@ dma_addr_t dma_direct_map_resource(struc
+ {
+ dma_addr_t dma_addr = paddr;
+
+- if (unlikely(!dma_capable(dev, dma_addr, size))) {
++ if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
+ report_addr(dev, dma_addr, size);
+ return DMA_MAPPING_ERROR;
+ }
+--- a/kernel/dma/swiotlb.c
++++ b/kernel/dma/swiotlb.c
+@@ -678,7 +678,7 @@ bool swiotlb_map(struct device *dev, phy
+
+ /* Ensure that the address returned is DMA'ble */
+ *dma_addr = __phys_to_dma(dev, *phys);
+- if (unlikely(!dma_capable(dev, *dma_addr, size))) {
++ if (unlikely(!dma_capable(dev, *dma_addr, size, true))) {
+ swiotlb_tbl_unmap_single(dev, *phys, size, size, dir,
+ attrs | DMA_ATTR_SKIP_CPU_SYNC);
+ return false;
--- /dev/null
+From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Thu, 21 Nov 2019 10:26:44 +0100
+Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit
+
+commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream.
+
+Using a mask to represent bus DMA constraints has a set of limitations.
+The biggest one being it can only hold a power of two (minus one). The
+DMA mapping code is already aware of this and treats dev->bus_dma_mask
+as a limit. This quirk is already used by some architectures although
+still rare.
+
+With the introduction of the Raspberry Pi 4 we've found a new contender
+for the use of bus DMA limits, as its PCIe bus can only address the
+lower 3GB of memory (of a total of 4GB). This is impossible to represent
+with a mask. To make things worse the device-tree code rounds non power
+of two bus DMA limits to the next power of two, which is unacceptable in
+this case.
+
+In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all
+over the tree and treat it as such. Note that dev->bus_dma_limit should
+contain the higher accessible DMA address.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Reviewed-by: Robin Murphy <robin.murphy@arm.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ arch/mips/pci/fixup-sb1250.c | 16 ++++++++--------
+ arch/powerpc/sysdev/fsl_pci.c | 6 +++---
+ arch/x86/kernel/pci-dma.c | 2 +-
+ arch/x86/mm/mem_encrypt.c | 2 +-
+ arch/x86/pci/sta2x11-fixup.c | 2 +-
+ drivers/acpi/arm64/iort.c | 20 +++++++-------------
+ drivers/ata/ahci.c | 2 +-
+ drivers/iommu/dma-iommu.c | 3 +--
+ drivers/of/device.c | 9 +++++----
+ include/linux/device.h | 6 +++---
+ include/linux/dma-direct.h | 2 +-
+ include/linux/dma-mapping.h | 2 +-
+ kernel/dma/direct.c | 27 +++++++++++++--------------
+ 13 files changed, 46 insertions(+), 53 deletions(-)
+
+--- a/arch/mips/pci/fixup-sb1250.c
++++ b/arch/mips/pci/fixup-sb1250.c
+@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI
+
+ /*
+ * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit
+- * bus, so we set the bus's DMA mask accordingly. However the HT link
++ * bus, so we set the bus's DMA limit accordingly. However the HT link
+ * down the artificial PCI-HT bridge supports 40-bit addressing and the
+ * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus
+ * width, so we record the PCI-HT bridge's secondary and subordinate bus
+- * numbers and do not set the mask for devices present in the inclusive
++ * numbers and do not set the limit for devices present in the inclusive
+ * range of those.
+ */
+-struct sb1250_bus_dma_mask_exclude {
++struct sb1250_bus_dma_limit_exclude {
+ bool set;
+ unsigned char start;
+ unsigned char end;
+ };
+
+-static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data)
++static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data)
+ {
+- struct sb1250_bus_dma_mask_exclude *exclude = data;
++ struct sb1250_bus_dma_limit_exclude *exclude = data;
+ bool exclude_this;
+ bool ht_bridge;
+
+@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc
+ exclude->start, exclude->end);
+ } else {
+ dev_dbg(&dev->dev, "disabling DAC for device");
+- dev->dev.bus_dma_mask = DMA_BIT_MASK(32);
++ dev->dev.bus_dma_limit = DMA_BIT_MASK(32);
+ }
+
+ return 0;
+@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc
+
+ static void quirk_sb1250_pci_dac(struct pci_dev *dev)
+ {
+- struct sb1250_bus_dma_mask_exclude exclude = { .set = false };
++ struct sb1250_bus_dma_limit_exclude exclude = { .set = false };
+
+- pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude);
++ pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude);
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
+ quirk_sb1250_pci_dac);
+--- a/arch/powerpc/sysdev/fsl_pci.c
++++ b/arch/powerpc/sysdev/fsl_pci.c
+@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st
+ {
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+- pdev->dev.bus_dma_mask =
+- hose->dma_window_base_cur + hose->dma_window_size;
++ pdev->dev.bus_dma_limit =
++ hose->dma_window_base_cur + hose->dma_window_size - 1;
+ }
+
+ static void setup_swiotlb_ops(struct pci_controller *hose)
+@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct
+ * mapping that allows addressing any RAM address from across PCI.
+ */
+ if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) {
+- dev->bus_dma_mask = 0;
++ dev->bus_dma_limit = 0;
+ dev->archdata.dma_offset = pci64_dma_offset;
+ }
+ }
+--- a/arch/x86/kernel/pci-dma.c
++++ b/arch/x86/kernel/pci-dma.c
+@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init);
+
+ static int via_no_dac_cb(struct pci_dev *pdev, void *data)
+ {
+- pdev->dev.bus_dma_mask = DMA_BIT_MASK(32);
++ pdev->dev.bus_dma_limit = DMA_BIT_MASK(32);
+ return 0;
+ }
+
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device
+ if (sme_active()) {
+ u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask));
+ u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask,
+- dev->bus_dma_mask);
++ dev->bus_dma_limit);
+
+ if (dma_dev_mask <= dma_enc_mask)
+ return true;
+--- a/arch/x86/pci/sta2x11-fixup.c
++++ b/arch/x86/pci/sta2x11-fixup.c
+@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de
+
+ dev->dma_pfn_offset = PFN_DOWN(-amba_base);
+
+- dev->bus_dma_mask = max_amba_addr;
++ dev->bus_dma_limit = max_amba_addr;
+ pci_set_consistent_dma_mask(pdev, max_amba_addr);
+ pci_set_dma_mask(pdev, max_amba_addr);
+
+--- a/drivers/acpi/arm64/iort.c
++++ b/drivers/acpi/arm64/iort.c
+@@ -1057,8 +1057,8 @@ static int rc_dma_get_range(struct devic
+ */
+ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+ {
+- u64 mask, dmaaddr = 0, size = 0, offset = 0;
+- int ret, msb;
++ u64 end, mask, dmaaddr = 0, size = 0, offset = 0;
++ int ret;
+
+ /*
+ * If @dev is expected to be DMA-capable then the bus code that created
+@@ -1085,19 +1085,13 @@ void iort_dma_setup(struct device *dev,
+ }
+
+ if (!ret) {
+- msb = fls64(dmaaddr + size - 1);
+ /*
+- * Round-up to the power-of-two mask or set
+- * the mask to the whole 64-bit address space
+- * in case the DMA region covers the full
+- * memory window.
++ * Limit coherent and dma mask based on size retrieved from
++ * firmware.
+ */
+- mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1;
+- /*
+- * Limit coherent and dma mask based on size
+- * retrieved from firmware.
+- */
+- dev->bus_dma_mask = mask;
++ end = dmaaddr + size - 1;
++ mask = DMA_BIT_MASK(ilog2(end) + 1);
++ dev->bus_dma_limit = end;
+ dev->coherent_dma_mask = mask;
+ *dev->dma_mask = mask;
+ }
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -899,7 +899,7 @@ static int ahci_configure_dma_masks(stru
+ * value, don't extend it here. This happens on STA2X11, for example.
+ *
+ * XXX: manipulating the DMA mask from platform code is completely
+- * bogus, platform code should use dev->bus_dma_mask instead..
++ * bogus, platform code should use dev->bus_dma_limit instead..
+ */
+ if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
+ return 0;
+--- a/drivers/iommu/dma-iommu.c
++++ b/drivers/iommu/dma-iommu.c
+@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s
+ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+ iova_len = roundup_pow_of_two(iova_len);
+
+- if (dev->bus_dma_mask)
+- dma_limit &= dev->bus_dma_mask;
++ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit);
+
+ if (domain->geometry.force_aperture)
+ dma_limit = min(dma_limit, domain->geometry.aperture_end);
+--- a/drivers/of/device.c
++++ b/drivers/of/device.c
+@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev,
+ bool coherent;
+ unsigned long offset;
+ const struct iommu_ops *iommu;
+- u64 mask;
++ u64 mask, end;
+
+ ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
+ if (ret < 0) {
+@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev,
+ * Limit coherent and dma mask based on size and default mask
+ * set by the driver.
+ */
+- mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1);
++ end = dma_addr + size - 1;
++ mask = DMA_BIT_MASK(ilog2(end) + 1);
+ dev->coherent_dma_mask &= mask;
+ *dev->dma_mask &= mask;
+- /* ...but only set bus mask if we found valid dma-ranges earlier */
++ /* ...but only set bus limit if we found valid dma-ranges earlier */
+ if (!ret)
+- dev->bus_dma_mask = mask;
++ dev->bus_dma_limit = end;
+
+ coherent = of_dma_is_coherent(np);
+ dev_dbg(dev, "device is%sdma coherent\n",
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -1186,8 +1186,8 @@ struct dev_links_info {
+ * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
+ * hardware supports 64-bit addresses for consistent allocations
+ * such descriptors.
+- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA
+- * limit than the device itself supports.
++ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller
++ * DMA limit than the device itself supports.
+ * @dma_pfn_offset: offset of DMA memory range relatively of RAM
+ * @dma_parms: A low level driver may set these to teach IOMMU code about
+ * segment limitations.
+@@ -1270,7 +1270,7 @@ struct device {
+ not all hardware supports
+ 64 bit addresses for consistent
+ allocations such descriptors. */
+- u64 bus_dma_mask; /* upstream dma_mask constraint */
++ u64 bus_dma_limit; /* upstream dma constraint */
+ unsigned long dma_pfn_offset;
+
+ struct device_dma_parameters *dma_parms;
+--- a/include/linux/dma-direct.h
++++ b/include/linux/dma-direct.h
+@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de
+ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn)))
+ return false;
+
+- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask);
++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit);
+ }
+
+ u64 dma_direct_get_required_mask(struct device *dev);
+--- a/include/linux/dma-mapping.h
++++ b/include/linux/dma-mapping.h
+@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co
+ */
+ static inline bool dma_addressing_limited(struct device *dev)
+ {
+- return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) <
++ return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) <
+ dma_get_required_mask(dev);
+ }
+
+--- a/kernel/dma/direct.c
++++ b/kernel/dma/direct.c
+@@ -26,10 +26,10 @@ static void report_addr(struct device *d
+ {
+ if (!dev->dma_mask) {
+ dev_err_once(dev, "DMA map on device without dma_mask\n");
+- } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) {
++ } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) {
+ dev_err_once(dev,
+- "overflow %pad+%zu of DMA mask %llx bus mask %llx\n",
+- &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask);
++ "overflow %pad+%zu of DMA mask %llx bus limit %llx\n",
++ &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit);
+ }
+ WARN_ON_ONCE(1);
+ }
+@@ -50,15 +50,14 @@ u64 dma_direct_get_required_mask(struct
+ }
+
+ static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
+- u64 *phys_mask)
++ u64 *phys_limit)
+ {
+- if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask)
+- dma_mask = dev->bus_dma_mask;
++ u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit);
+
+ if (force_dma_unencrypted(dev))
+- *phys_mask = __dma_to_phys(dev, dma_mask);
++ *phys_limit = __dma_to_phys(dev, dma_limit);
+ else
+- *phys_mask = dma_to_phys(dev, dma_mask);
++ *phys_limit = dma_to_phys(dev, dma_limit);
+
+ /*
+ * Optimistically try the zone that the physical address mask falls
+@@ -68,9 +67,9 @@ static gfp_t __dma_direct_optimal_gfp_ma
+ * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
+ * zones.
+ */
+- if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits))
++ if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits))
+ return GFP_DMA;
+- if (*phys_mask <= DMA_BIT_MASK(32))
++ if (*phys_limit <= DMA_BIT_MASK(32))
+ return GFP_DMA32;
+ return 0;
+ }
+@@ -78,7 +77,7 @@ static gfp_t __dma_direct_optimal_gfp_ma
+ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
+ {
+ return phys_to_dma_direct(dev, phys) + size - 1 <=
+- min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask);
++ min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit);
+ }
+
+ struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
+@@ -87,7 +86,7 @@ struct page *__dma_direct_alloc_pages(st
+ size_t alloc_size = PAGE_ALIGN(size);
+ int node = dev_to_node(dev);
+ struct page *page = NULL;
+- u64 phys_mask;
++ u64 phys_limit;
+
+ if (attrs & DMA_ATTR_NO_WARN)
+ gfp |= __GFP_NOWARN;
+@@ -95,7 +94,7 @@ struct page *__dma_direct_alloc_pages(st
+ /* we always manually zero the memory once we are done: */
+ gfp &= ~__GFP_ZERO;
+ gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
+- &phys_mask);
++ &phys_limit);
+ page = dma_alloc_contiguous(dev, alloc_size, gfp);
+ if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+ dma_free_contiguous(dev, page, alloc_size);
+@@ -109,7 +108,7 @@ again:
+ page = NULL;
+
+ if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+- phys_mask < DMA_BIT_MASK(64) &&
++ phys_limit < DMA_BIT_MASK(64) &&
+ !(gfp & (GFP_DMA32 | GFP_DMA))) {
+ gfp |= GFP_DMA32;
+ goto again;
--- /dev/null
+From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Mon, 16 Dec 2019 12:01:08 +0100
+Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller
+
+commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream.
+
+This enables bcm2711's PCIe bus, which is hardwired to a VIA
+Technologies XHCI USB 3.0 controller.
+
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++-
+ 1 file changed, 30 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2711.dtsi
++++ b/arch/arm/boot/dts/bcm2711.dtsi
+@@ -331,7 +331,36 @@
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>;
++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>,
++ <0x6 0x00000000 0x6 0x00000000 0x40000000>;
++
++ pcie0: pcie@7d500000 {
++ compatible = "brcm,bcm2711-pcie";
++ reg = <0x0 0x7d500000 0x9310>;
++ device_type = "pci";
++ #address-cells = <3>;
++ #interrupt-cells = <1>;
++ #size-cells = <2>;
++ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "pcie", "msi";
++ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
++ IRQ_TYPE_LEVEL_HIGH>;
++ msi-controller;
++ msi-parent = <&pcie0>;
++
++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
++ 0x0 0x04000000>;
++ /*
++ * The wrapper around the PCIe block has a bug
++ * preventing it from accessing beyond the first 3GB of
++ * memory.
++ */
++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
++ 0x0 0xc0000000>;
++ brcm,enable-ssc;
++ };
+
+ genet: ethernet@7d580000 {
+ compatible = "brcm,bcm2711-genet-v5";
--- /dev/null
+From 4d9470c29736bf81bdb0d21da24cf350b1e99402 Mon Sep 17 00:00:00 2001
+From: Jim Quinlan <james.quinlan@broadcom.com>
+Date: Mon, 16 Dec 2019 12:01:09 +0100
+Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller
+ driver
+
+commit c0452137034bda8f686dd9a2e167949bfffd6776 upstream.
+
+This adds a basic driver for Broadcom's STB PCIe controller, for now
+aimed at Raspberry Pi 4's SoC, bcm2711.
+
+Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
+Co-developed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+[lorenzo.pieralisi@arm.com: updated brcm_pcie_get_rc_bar2_size_and_offset()according to https://lore.kernel.org/linux-pci/be8ddb33a7360af1815cf686f77f3f0913d02be3.camel@suse.de]
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+Reviewed-by: Jeremy Linton <jeremy.linton@arm.com>
+---
+ drivers/pci/controller/Kconfig | 8 +
+ drivers/pci/controller/Makefile | 1 +
+ drivers/pci/controller/pcie-brcmstb.c | 755 ++++++++++++++++++++++++++
+ 3 files changed, 764 insertions(+)
+ create mode 100644 drivers/pci/controller/pcie-brcmstb.c
+
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -281,6 +281,14 @@ config VMD
+ To compile this driver as a module, choose M here: the
+ module will be called vmd.
+
++config PCIE_BRCMSTB
++ tristate "Broadcom Brcmstb PCIe host controller"
++ depends on ARCH_BCM2835 || COMPILE_TEST
++ depends on OF
++ help
++ Say Y here to enable PCIe host controller support for
++ Broadcom STB based SoCs, like the Raspberry Pi 4.
++
+ config PCI_HYPERV_INTERFACE
+ tristate "Hyper-V PCI Interface"
+ depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_VMD) += vmd.o
++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y += dwc/
+
+--- /dev/null
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -0,0 +1,755 @@
++// SPDX-License-Identifier: GPL-2.0+
++/* Copyright (C) 2009 - 2019 Broadcom */
++
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/compiler.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/irqdomain.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/log2.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/pci.h>
++#include <linux/printk.h>
++#include <linux/sizes.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include "../pci.h"
++
++/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
++#define BRCM_PCIE_CAP_REGS 0x00ac
++
++/* Broadcom STB PCIe Register Offsets */
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188
++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
++#define PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN 0x0
++
++#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
++#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
++
++#define PCIE_RC_DL_MDIO_ADDR 0x1100
++#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
++#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
++
++#define PCIE_MISC_MISC_CTRL 0x4008
++#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
++#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0
++#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
++#define PCIE_MEM_WIN0_LO(win) \
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
++#define PCIE_MEM_WIN0_HI(win) \
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4)
++
++#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
++#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
++
++#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
++#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
++#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
++
++#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
++#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
++
++#define PCIE_MISC_PCIE_CTRL 0x4064
++#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
++
++#define PCIE_MISC_PCIE_STATUS 0x4068
++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
++#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
++#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
++#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
++#define PCIE_MEM_WIN0_BASE_LIMIT(win) \
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff
++#define PCIE_MEM_WIN0_BASE_HI(win) \
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8)
++
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
++#define PCIE_MEM_WIN0_LIMIT_HI(win) \
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
++
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
++
++#define PCIE_MSI_INTR2_STATUS 0x4500
++#define PCIE_MSI_INTR2_CLR 0x4508
++#define PCIE_MSI_INTR2_MASK_SET 0x4510
++#define PCIE_MSI_INTR2_MASK_CLR 0x4514
++
++#define PCIE_EXT_CFG_DATA 0x8000
++
++#define PCIE_EXT_CFG_INDEX 0x9000
++#define PCIE_EXT_BUSNUM_SHIFT 20
++#define PCIE_EXT_SLOT_SHIFT 15
++#define PCIE_EXT_FUNC_SHIFT 12
++
++#define PCIE_RGR1_SW_INIT_1 0x9210
++#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
++#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2
++
++/* PCIe parameters */
++#define BRCM_NUM_PCIE_OUT_WINS 0x4
++
++/* MDIO registers */
++#define MDIO_PORT0 0x0
++#define MDIO_DATA_MASK 0x7fffffff
++#define MDIO_PORT_MASK 0xf0000
++#define MDIO_REGAD_MASK 0xffff
++#define MDIO_CMD_MASK 0xfff00000
++#define MDIO_CMD_READ 0x1
++#define MDIO_CMD_WRITE 0x0
++#define MDIO_DATA_DONE_MASK 0x80000000
++#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0)
++#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1)
++#define SSC_REGS_ADDR 0x1100
++#define SET_ADDR_OFFSET 0x1f
++#define SSC_CNTL_OFFSET 0x2
++#define SSC_CNTL_OVRD_EN_MASK 0x8000
++#define SSC_CNTL_OVRD_VAL_MASK 0x4000
++#define SSC_STATUS_OFFSET 0x1
++#define SSC_STATUS_SSC_MASK 0x400
++#define SSC_STATUS_PLL_LOCK_MASK 0x800
++
++/* Internal PCIe Host Controller Information.*/
++struct brcm_pcie {
++ struct device *dev;
++ void __iomem *base;
++ struct clk *clk;
++ struct pci_bus *root_bus;
++ struct device_node *np;
++ bool ssc;
++ int gen;
++};
++
++/*
++ * This is to convert the size of the inbound "BAR" region to the
++ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
++ */
++static int brcm_pcie_encode_ibar_size(u64 size)
++{
++ int log2_in = ilog2(size);
++
++ if (log2_in >= 12 && log2_in <= 15)
++ /* Covers 4KB to 32KB (inclusive) */
++ return (log2_in - 12) + 0x1c;
++ else if (log2_in >= 16 && log2_in <= 35)
++ /* Covers 64KB to 32GB, (inclusive) */
++ return log2_in - 15;
++ /* Something is awry so disable */
++ return 0;
++}
++
++static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd)
++{
++ u32 pkt = 0;
++
++ pkt |= FIELD_PREP(MDIO_PORT_MASK, port);
++ pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad);
++ pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd);
++
++ return pkt;
++}
++
++/* negative return value indicates error */
++static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val)
++{
++ int tries;
++ u32 data;
++
++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ),
++ base + PCIE_RC_DL_MDIO_ADDR);
++ readl(base + PCIE_RC_DL_MDIO_ADDR);
++
++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) {
++ udelay(10);
++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA);
++ }
++
++ *val = FIELD_GET(MDIO_DATA_MASK, data);
++ return MDIO_RD_DONE(data) ? 0 : -EIO;
++}
++
++/* negative return value indicates error */
++static int brcm_pcie_mdio_write(void __iomem *base, u8 port,
++ u8 regad, u16 wrdata)
++{
++ int tries;
++ u32 data;
++
++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE),
++ base + PCIE_RC_DL_MDIO_ADDR);
++ readl(base + PCIE_RC_DL_MDIO_ADDR);
++ writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA);
++
++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) {
++ udelay(10);
++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA);
++ }
++
++ return MDIO_WT_DONE(data) ? 0 : -EIO;
++}
++
++/*
++ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative
++ * return value indicates error.
++ */
++static int brcm_pcie_set_ssc(struct brcm_pcie *pcie)
++{
++ int pll, ssc;
++ int ret;
++ u32 tmp;
++
++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET,
++ SSC_REGS_ADDR);
++ if (ret < 0)
++ return ret;
++
++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0,
++ SSC_CNTL_OFFSET, &tmp);
++ if (ret < 0)
++ return ret;
++
++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_EN_MASK);
++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK);
++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0,
++ SSC_CNTL_OFFSET, tmp);
++ if (ret < 0)
++ return ret;
++
++ usleep_range(1000, 2000);
++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0,
++ SSC_STATUS_OFFSET, &tmp);
++ if (ret < 0)
++ return ret;
++
++ ssc = FIELD_GET(SSC_STATUS_SSC_MASK, tmp);
++ pll = FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp);
++
++ return ssc && pll ? 0 : -EIO;
++}
++
++/* Limits operation to a specific generation (1, 2, or 3) */
++static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen)
++{
++ u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++ u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++
++ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
++ writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
++
++ lnkctl2 = (lnkctl2 & ~0xf) | gen;
++ writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
++}
++
++static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
++ unsigned int win, u64 cpu_addr,
++ u64 pcie_addr, u64 size)
++{
++ u32 cpu_addr_mb_high, limit_addr_mb_high;
++ phys_addr_t cpu_addr_mb, limit_addr_mb;
++ int high_addr_shift;
++ u32 tmp;
++
++ /* Set the base of the pcie_addr window */
++ writel(lower_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_LO(win));
++ writel(upper_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_HI(win));
++
++ /* Write the addr base & limit lower bits (in MBs) */
++ cpu_addr_mb = cpu_addr / SZ_1M;
++ limit_addr_mb = (cpu_addr + size - 1) / SZ_1M;
++
++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win));
++ u32p_replace_bits(&tmp, cpu_addr_mb,
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK);
++ u32p_replace_bits(&tmp, limit_addr_mb,
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK);
++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win));
++
++ /* Write the cpu & limit addr upper bits */
++ high_addr_shift =
++ HWEIGHT32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK);
++
++ cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift;
++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_HI(win));
++ u32p_replace_bits(&tmp, cpu_addr_mb_high,
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK);
++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_HI(win));
++
++ limit_addr_mb_high = limit_addr_mb >> high_addr_shift;
++ tmp = readl(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
++ u32p_replace_bits(&tmp, limit_addr_mb_high,
++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK);
++ writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
++}
++
++/* The controller is capable of serving in both RC and EP roles */
++static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ u32 val = readl(base + PCIE_MISC_PCIE_STATUS);
++
++ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val);
++}
++
++static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
++{
++ u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS);
++ u32 dla = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val);
++ u32 plu = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val);
++
++ return dla && plu;
++}
++
++/* Configuration space read/write support */
++static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
++{
++ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
++ | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
++ | (busnr << PCIE_EXT_BUSNUM_SHIFT)
++ | (reg & ~3);
++}
++
++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
++ int where)
++{
++ struct brcm_pcie *pcie = bus->sysdata;
++ void __iomem *base = pcie->base;
++ int idx;
++
++ /* Accesses to the RC go right to the RC registers if slot==0 */
++ if (pci_is_root_bus(bus))
++ return PCI_SLOT(devfn) ? NULL : base + where;
++
++ /* For devices, write to the config space index register */
++ idx = brcm_pcie_cfg_index(bus->number, devfn, 0);
++ writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
++ return base + PCIE_EXT_CFG_DATA + where;
++}
++
++static struct pci_ops brcm_pcie_ops = {
++ .map_bus = brcm_pcie_map_conf,
++ .read = pci_generic_config_read,
++ .write = pci_generic_config_write,
++};
++
++static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val)
++{
++ u32 tmp;
++
++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK);
++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
++}
++
++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val)
++{
++ u32 tmp;
++
++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1);
++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK);
++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1);
++}
++
++static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
++ u64 *rc_bar2_size,
++ u64 *rc_bar2_offset)
++{
++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
++ struct device *dev = pcie->dev;
++ struct resource_entry *entry;
++
++ entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
++ if (!entry)
++ return -ENODEV;
++
++
++ /*
++ * The controller expects the inbound window offset to be calculated as
++ * the difference between PCIe's address space and CPU's. The offset
++ * provided by the firmware is calculated the opposite way, so we
++ * negate it.
++ */
++ *rc_bar2_offset = -entry->offset;
++ *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start);
++
++ /*
++ * We validate the inbound memory view even though we should trust
++ * whatever the device-tree provides. This is because of an HW issue on
++ * early Raspberry Pi 4's revisions (bcm2711). It turns out its
++ * firmware has to dynamically edit dma-ranges due to a bug on the
++ * PCIe controller integration, which prohibits any access above the
++ * lower 3GB of memory. Given this, we decided to keep the dma-ranges
++ * in check, avoiding hard to debug device-tree related issues in the
++ * future:
++ *
++ * The PCIe host controller by design must set the inbound viewport to
++ * be a contiguous arrangement of all of the system's memory. In
++ * addition, its size mut be a power of two. To further complicate
++ * matters, the viewport must start on a pcie-address that is aligned
++ * on a multiple of its size. If a portion of the viewport does not
++ * represent system memory -- e.g. 3GB of memory requires a 4GB
++ * viewport -- we can map the outbound memory in or after 3GB and even
++ * though the viewport will overlap the outbound memory the controller
++ * will know to send outbound memory downstream and everything else
++ * upstream.
++ *
++ * For example:
++ *
++ * - The best-case scenario, memory up to 3GB, is to place the inbound
++ * region in the first 4GB of pcie-space, as some legacy devices can
++ * only address 32bits. We would also like to put the MSI under 4GB
++ * as well, since some devices require a 32bit MSI target address.
++ *
++ * - If the system memory is 4GB or larger we cannot start the inbound
++ * region at location 0 (since we have to allow some space for
++ * outbound memory @ 3GB). So instead it will start at the 1x
++ * multiple of its size
++ */
++ if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
++ (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
++ dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
++ *rc_bar2_size, *rc_bar2_offset);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int brcm_pcie_setup(struct brcm_pcie *pcie)
++{
++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
++ u64 rc_bar2_offset, rc_bar2_size;
++ void __iomem *base = pcie->base;
++ struct device *dev = pcie->dev;
++ struct resource_entry *entry;
++ unsigned int scb_size_val;
++ bool ssc_good = false;
++ struct resource *res;
++ int num_out_wins = 0;
++ u16 nlw, cls, lnksta;
++ int i, ret;
++ u32 tmp;
++
++ /* Reset the bridge */
++ brcm_pcie_bridge_sw_init_set(pcie, 1);
++
++ usleep_range(100, 200);
++
++ /* Take the bridge out of reset */
++ brcm_pcie_bridge_sw_init_set(pcie, 0);
++
++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK;
++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++ /* Wait for SerDes to be stable */
++ usleep_range(100, 200);
++
++ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
++ u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128,
++ PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
++ writel(tmp, base + PCIE_MISC_MISC_CTRL);
++
++ ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
++ &rc_bar2_offset);
++ if (ret)
++ return ret;
++
++ tmp = lower_32_bits(rc_bar2_offset);
++ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size),
++ PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK);
++ writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO);
++ writel(upper_32_bits(rc_bar2_offset),
++ base + PCIE_MISC_RC_BAR2_CONFIG_HI);
++
++ scb_size_val = rc_bar2_size ?
++ ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */
++ tmp = readl(base + PCIE_MISC_MISC_CTRL);
++ u32p_replace_bits(&tmp, scb_size_val,
++ PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
++ writel(tmp, base + PCIE_MISC_MISC_CTRL);
++
++ /* disable the PCIe->GISB memory window (RC_BAR1) */
++ tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO);
++ tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK;
++ writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO);
++
++ /* disable the PCIe->SCB memory window (RC_BAR3) */
++ tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO);
++ tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;
++ writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO);
++
++ /* Mask all interrupts since we are not handling any yet */
++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET);
++
++ /* clear any interrupts we find on boot */
++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR);
++
++ if (pcie->gen)
++ brcm_pcie_set_gen(pcie, pcie->gen);
++
++ /* Unassert the fundamental reset */
++ brcm_pcie_perst_set(pcie, 0);
++
++ /*
++ * Give the RC/EP time to wake up, before trying to configure RC.
++ * Intermittently check status for link-up, up to a total of 100ms.
++ */
++ for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5)
++ msleep(5);
++
++ if (!brcm_pcie_link_up(pcie)) {
++ dev_err(dev, "link down\n");
++ return -ENODEV;
++ }
++
++ if (!brcm_pcie_rc_mode(pcie)) {
++ dev_err(dev, "PCIe misconfigured; is in EP mode\n");
++ return -EINVAL;
++ }
++
++ resource_list_for_each_entry(entry, &bridge->windows) {
++ res = entry->res;
++
++ if (resource_type(res) != IORESOURCE_MEM)
++ continue;
++
++ if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) {
++ dev_err(pcie->dev, "too many outbound wins\n");
++ return -EINVAL;
++ }
++
++ brcm_pcie_set_outbound_win(pcie, num_out_wins, res->start,
++ res->start - entry->offset,
++ resource_size(res));
++ num_out_wins++;
++ }
++
++ /*
++ * For config space accesses on the RC, show the right class for
++ * a PCIe-PCIe bridge (the default setting is to be EP mode).
++ */
++ tmp = readl(base + PCIE_RC_CFG_PRIV1_ID_VAL3);
++ u32p_replace_bits(&tmp, 0x060400,
++ PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK);
++ writel(tmp, base + PCIE_RC_CFG_PRIV1_ID_VAL3);
++
++ if (pcie->ssc) {
++ ret = brcm_pcie_set_ssc(pcie);
++ if (ret == 0)
++ ssc_good = true;
++ else
++ dev_err(dev, "failed attempt to enter ssc mode\n");
++ }
++
++ lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
++ cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta);
++ nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
++ dev_info(dev, "link up, %s x%u %s\n",
++ PCIE_SPEED2STR(cls + PCI_SPEED_133MHz_PCIX_533),
++ nlw, ssc_good ? "(SSC)" : "(!SSC)");
++
++ /* PCIe->SCB endian mode for BAR */
++ tmp = readl(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
++ u32p_replace_bits(&tmp, PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN,
++ PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
++ writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
++
++ /*
++ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
++ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
++ */
++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++
++ return 0;
++}
++
++/* L23 is a low-power PCIe link state */
++static void brcm_pcie_enter_l23(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ int l23, i;
++ u32 tmp;
++
++ /* Assert request for L23 */
++ tmp = readl(base + PCIE_MISC_PCIE_CTRL);
++ u32p_replace_bits(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK);
++ writel(tmp, base + PCIE_MISC_PCIE_CTRL);
++
++ /* Wait up to 36 msec for L23 */
++ tmp = readl(base + PCIE_MISC_PCIE_STATUS);
++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp);
++ for (i = 0; i < 15 && !l23; i++) {
++ usleep_range(2000, 2400);
++ tmp = readl(base + PCIE_MISC_PCIE_STATUS);
++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK,
++ tmp);
++ }
++
++ if (!l23)
++ dev_err(pcie->dev, "failed to enter low-power link state\n");
++}
++
++static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
++{
++ void __iomem *base = pcie->base;
++ int tmp;
++
++ if (brcm_pcie_link_up(pcie))
++ brcm_pcie_enter_l23(pcie);
++ /* Assert fundamental reset */
++ brcm_pcie_perst_set(pcie, 1);
++
++ /* Deassert request for L23 in case it was asserted */
++ tmp = readl(base + PCIE_MISC_PCIE_CTRL);
++ u32p_replace_bits(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK);
++ writel(tmp, base + PCIE_MISC_PCIE_CTRL);
++
++ /* Turn off SerDes */
++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
++
++ /* Shutdown PCIe bridge */
++ brcm_pcie_bridge_sw_init_set(pcie, 1);
++}
++
++static void __brcm_pcie_remove(struct brcm_pcie *pcie)
++{
++ brcm_pcie_turn_off(pcie);
++ clk_disable_unprepare(pcie->clk);
++ clk_put(pcie->clk);
++}
++
++static int brcm_pcie_remove(struct platform_device *pdev)
++{
++ struct brcm_pcie *pcie = platform_get_drvdata(pdev);
++
++ pci_stop_root_bus(pcie->root_bus);
++ pci_remove_root_bus(pcie->root_bus);
++ __brcm_pcie_remove(pcie);
++
++ return 0;
++}
++
++static int brcm_pcie_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct pci_host_bridge *bridge;
++ struct brcm_pcie *pcie;
++ struct pci_bus *child;
++ struct resource *res;
++ int ret;
++
++ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
++ if (!bridge)
++ return -ENOMEM;
++
++ pcie = pci_host_bridge_priv(bridge);
++ pcie->dev = &pdev->dev;
++ pcie->np = np;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ pcie->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(pcie->base))
++ return PTR_ERR(pcie->base);
++
++ pcie->clk = devm_clk_get_optional(&pdev->dev, "sw_pcie");
++ if (IS_ERR(pcie->clk))
++ return PTR_ERR(pcie->clk);
++
++ ret = of_pci_get_max_link_speed(np);
++ pcie->gen = (ret < 0) ? 0 : ret;
++
++ pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
++
++ ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows,
++ &bridge->dma_ranges, NULL);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(pcie->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "could not enable clock\n");
++ return ret;
++ }
++
++ ret = brcm_pcie_setup(pcie);
++ if (ret)
++ goto fail;
++
++ bridge->dev.parent = &pdev->dev;
++ bridge->busnr = 0;
++ bridge->ops = &brcm_pcie_ops;
++ bridge->sysdata = pcie;
++ bridge->map_irq = of_irq_parse_and_map_pci;
++ bridge->swizzle_irq = pci_common_swizzle;
++
++ ret = pci_scan_root_bus_bridge(bridge);
++ if (ret < 0) {
++ dev_err(pcie->dev, "Scanning root bridge failed\n");
++ goto fail;
++ }
++
++ pci_assign_unassigned_bus_resources(bridge->bus);
++ list_for_each_entry(child, &bridge->bus->children, node)
++ pcie_bus_configure_settings(child);
++ pci_bus_add_devices(bridge->bus);
++ platform_set_drvdata(pdev, pcie);
++ pcie->root_bus = bridge->bus;
++
++ return 0;
++fail:
++ __brcm_pcie_remove(pcie);
++ return ret;
++}
++
++static const struct of_device_id brcm_pcie_match[] = {
++ { .compatible = "brcm,bcm2711-pcie" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, brcm_pcie_match);
++
++static struct platform_driver brcm_pcie_driver = {
++ .probe = brcm_pcie_probe,
++ .remove = brcm_pcie_remove,
++ .driver = {
++ .name = "brcm-pcie",
++ .of_match_table = brcm_pcie_match,
++ },
++};
++module_platform_driver(brcm_pcie_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
++MODULE_AUTHOR("Broadcom");
--- /dev/null
+From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001
+From: Jim Quinlan <james.quinlan@broadcom.com>
+Date: Mon, 16 Dec 2019 12:01:10 +0100
+Subject: [PATCH] PCI: brcmstb: Add MSI support
+
+commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream.
+
+This adds MSI support to the Broadcom STB PCIe host controller. The MSI
+controller is physically located within the PCIe block, however, there
+is no reason why the MSI controller could not be moved elsewhere in the
+future. MSIX is not supported by the HW.
+
+Since the internal Brcmstb MSI controller is intertwined with the PCIe
+controller, it is not its own platform device but rather part of the
+PCIe platform device.
+
+Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
+Co-developed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Andrew Murray <andrew.murray@arm.com>
+---
+ drivers/pci/controller/Kconfig | 1 +
+ drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++-
+ 2 files changed, 262 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -285,6 +285,7 @@ config PCIE_BRCMSTB
+ tristate "Broadcom Brcmstb PCIe host controller"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on OF
++ depends on PCI_MSI_IRQ_DOMAIN
+ help
+ Say Y here to enable PCIe host controller support for
+ Broadcom STB based SoCs, like the Raspberry Pi 4.
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -2,6 +2,7 @@
+ /* Copyright (C) 2009 - 2019 Broadcom */
+
+ #include <linux/bitfield.h>
++#include <linux/bitops.h>
+ #include <linux/clk.h>
+ #include <linux/compiler.h>
+ #include <linux/delay.h>
+@@ -9,11 +10,13 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/ioport.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/kernel.h>
+ #include <linux/list.h>
+ #include <linux/log2.h>
+ #include <linux/module.h>
++#include <linux/msi.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_pci.h>
+@@ -67,6 +70,12 @@
+ #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
+ #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
+
++#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
++#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
++
++#define PCIE_MISC_MSI_DATA_CONFIG 0x404c
++#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540
++
+ #define PCIE_MISC_PCIE_CTRL 0x4064
+ #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
+
+@@ -114,6 +123,11 @@
+
+ /* PCIe parameters */
+ #define BRCM_NUM_PCIE_OUT_WINS 0x4
++#define BRCM_INT_PCI_MSI_NR 32
++
++/* MSI target adresses */
++#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
++#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
+
+ /* MDIO registers */
+ #define MDIO_PORT0 0x0
+@@ -135,6 +149,19 @@
+ #define SSC_STATUS_SSC_MASK 0x400
+ #define SSC_STATUS_PLL_LOCK_MASK 0x800
+
++struct brcm_msi {
++ struct device *dev;
++ void __iomem *base;
++ struct device_node *np;
++ struct irq_domain *msi_domain;
++ struct irq_domain *inner_domain;
++ struct mutex lock; /* guards the alloc/free operations */
++ u64 target_addr;
++ int irq;
++ /* used indicates which MSI interrupts have been alloc'd */
++ unsigned long used;
++};
++
+ /* Internal PCIe Host Controller Information.*/
+ struct brcm_pcie {
+ struct device *dev;
+@@ -144,6 +171,8 @@ struct brcm_pcie {
+ struct device_node *np;
+ bool ssc;
+ int gen;
++ u64 msi_target_addr;
++ struct brcm_msi *msi;
+ };
+
+ /*
+@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s
+ writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
+ }
+
++static struct irq_chip brcm_msi_irq_chip = {
++ .name = "BRCM STB PCIe MSI",
++ .irq_ack = irq_chip_ack_parent,
++ .irq_mask = pci_msi_mask_irq,
++ .irq_unmask = pci_msi_unmask_irq,
++};
++
++static struct msi_domain_info brcm_msi_domain_info = {
++ /* Multi MSI is supported by the controller, but not by this driver */
++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
++ .chip = &brcm_msi_irq_chip,
++};
++
++static void brcm_pcie_msi_isr(struct irq_desc *desc)
++{
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ unsigned long status, virq;
++ struct brcm_msi *msi;
++ struct device *dev;
++ u32 bit;
++
++ chained_irq_enter(chip, desc);
++ msi = irq_desc_get_handler_data(desc);
++ dev = msi->dev;
++
++ status = readl(msi->base + PCIE_MSI_INTR2_STATUS);
++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
++ virq = irq_find_mapping(msi->inner_domain, bit);
++ if (virq)
++ generic_handle_irq(virq);
++ else
++ dev_dbg(dev, "unexpected MSI\n");
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
++{
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
++
++ msg->address_lo = lower_32_bits(msi->target_addr);
++ msg->address_hi = upper_32_bits(msi->target_addr);
++ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq;
++}
++
++static int brcm_msi_set_affinity(struct irq_data *irq_data,
++ const struct cpumask *mask, bool force)
++{
++ return -EINVAL;
++}
++
++static void brcm_msi_ack_irq(struct irq_data *data)
++{
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
++
++ writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR);
++}
++
++
++static struct irq_chip brcm_msi_bottom_irq_chip = {
++ .name = "BRCM STB MSI",
++ .irq_compose_msi_msg = brcm_msi_compose_msi_msg,
++ .irq_set_affinity = brcm_msi_set_affinity,
++ .irq_ack = brcm_msi_ack_irq,
++};
++
++static int brcm_msi_alloc(struct brcm_msi *msi)
++{
++ int hwirq;
++
++ mutex_lock(&msi->lock);
++ hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0);
++ mutex_unlock(&msi->lock);
++
++ return hwirq;
++}
++
++static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
++{
++ mutex_lock(&msi->lock);
++ bitmap_release_region(&msi->used, hwirq, 0);
++ mutex_unlock(&msi->lock);
++}
++
++static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
++ unsigned int nr_irqs, void *args)
++{
++ struct brcm_msi *msi = domain->host_data;
++ int hwirq;
++
++ hwirq = brcm_msi_alloc(msi);
++
++ if (hwirq < 0)
++ return hwirq;
++
++ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq,
++ &brcm_msi_bottom_irq_chip, domain->host_data,
++ handle_edge_irq, NULL, NULL);
++ return 0;
++}
++
++static void brcm_irq_domain_free(struct irq_domain *domain,
++ unsigned int virq, unsigned int nr_irqs)
++{
++ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
++ struct brcm_msi *msi = irq_data_get_irq_chip_data(d);
++
++ brcm_msi_free(msi, d->hwirq);
++}
++
++static const struct irq_domain_ops msi_domain_ops = {
++ .alloc = brcm_irq_domain_alloc,
++ .free = brcm_irq_domain_free,
++};
++
++static int brcm_allocate_domains(struct brcm_msi *msi)
++{
++ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);
++ struct device *dev = msi->dev;
++
++ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
++ &msi_domain_ops, msi);
++ if (!msi->inner_domain) {
++ dev_err(dev, "failed to create IRQ domain\n");
++ return -ENOMEM;
++ }
++
++ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
++ &brcm_msi_domain_info,
++ msi->inner_domain);
++ if (!msi->msi_domain) {
++ dev_err(dev, "failed to create MSI domain\n");
++ irq_domain_remove(msi->inner_domain);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void brcm_free_domains(struct brcm_msi *msi)
++{
++ irq_domain_remove(msi->msi_domain);
++ irq_domain_remove(msi->inner_domain);
++}
++
++static void brcm_msi_remove(struct brcm_pcie *pcie)
++{
++ struct brcm_msi *msi = pcie->msi;
++
++ if (!msi)
++ return;
++ irq_set_chained_handler(msi->irq, NULL);
++ irq_set_handler_data(msi->irq, NULL);
++ brcm_free_domains(msi);
++}
++
++static void brcm_msi_set_regs(struct brcm_msi *msi)
++{
++ writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR);
++
++ /*
++ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
++ * enable, which we set to 1.
++ */
++ writel(lower_32_bits(msi->target_addr) | 0x1,
++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
++ writel(upper_32_bits(msi->target_addr),
++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
++
++ writel(PCIE_MISC_MSI_DATA_CONFIG_VAL,
++ msi->base + PCIE_MISC_MSI_DATA_CONFIG);
++}
++
++static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
++{
++ struct brcm_msi *msi;
++ int irq, ret;
++ struct device *dev = pcie->dev;
++
++ irq = irq_of_parse_and_map(dev->of_node, 1);
++ if (irq <= 0) {
++ dev_err(dev, "cannot map MSI interrupt\n");
++ return -ENODEV;
++ }
++
++ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
++ if (!msi)
++ return -ENOMEM;
++
++ mutex_init(&msi->lock);
++ msi->dev = dev;
++ msi->base = pcie->base;
++ msi->np = pcie->np;
++ msi->target_addr = pcie->msi_target_addr;
++ msi->irq = irq;
++
++ ret = brcm_allocate_domains(msi);
++ if (ret)
++ return ret;
++
++ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi);
++
++ brcm_msi_set_regs(msi);
++ pcie->msi = msi;
++
++ return 0;
++}
++
+ /* The controller is capable of serving in both RC and EP roles */
+ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
+ {
+@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p
+ PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK);
+ writel(tmp, base + PCIE_MISC_MISC_CTRL);
+
++ /*
++ * We ideally want the MSI target address to be located in the 32bit
++ * addressable memory area. Some devices might depend on it. This is
++ * possible either when the inbound window is located above the lower
++ * 4GB or when the inbound area is smaller than 4GB (taking into
++ * account the rounding-up we're forced to perform).
++ */
++ if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G)
++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
++ else
++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
++
+ /* disable the PCIe->GISB memory window (RC_BAR1) */
+ tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO);
+ tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK;
+@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br
+
+ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
+ {
++ brcm_msi_remove(pcie);
+ brcm_pcie_turn_off(pcie);
+ clk_disable_unprepare(pcie->clk);
+ clk_put(pcie->clk);
+@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf
+
+ static int brcm_pcie_probe(struct platform_device *pdev)
+ {
+- struct device_node *np = pdev->dev.of_node;
++ struct device_node *np = pdev->dev.of_node, *msi_np;
+ struct pci_host_bridge *bridge;
+ struct brcm_pcie *pcie;
+ struct pci_bus *child;
+@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo
+ if (ret)
+ goto fail;
+
++ msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
++ if (pci_msi_enabled() && msi_np == pcie->np) {
++ ret = brcm_pcie_enable_msi(pcie);
++ if (ret) {
++ dev_err(pcie->dev, "probe of internal MSI failed");
++ goto fail;
++ }
++ }
++
+ bridge->dev.parent = &pdev->dev;
+ bridge->busnr = 0;
+ bridge->ops = &brcm_pcie_ops;
--- /dev/null
+From 39192141aa16809323c24d8910e3a63488f7f55d Mon Sep 17 00:00:00 2001
+From: Marek Szyprowski <m.szyprowski@samsung.com>
+Date: Thu, 27 Feb 2020 12:51:46 +0100
+Subject: [PATCH] PCI: brcmstb: Fix build on 32bit ARM platforms with
+ older compilers
+
+commit 73a7a271b3eee7b83f29b13866163776f1cbef89 upstream.
+
+Some older compilers have no implementation for the helper for 64-bit
+unsigned division/modulo, so linking pcie-brcmstb driver causes the
+"undefined reference to `__aeabi_uldivmod'" error.
+
+*rc_bar2_size is always a power of two, because it is calculated as:
+"1ULL << fls64(entry->res->end - entry->res->start)", so the modulo
+operation in the subsequent check can be replaced by a simple logical
+AND with a proper mask.
+
+Link: https://lore.kernel.org/r/20200227115146.24515-1-m.szyprowski@samsung.com
+Fixes: c0452137034b ("PCI: brcmstb: Add Broadcom STB PCIe host controller driver")
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/controller/pcie-brcmstb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_
+ * outbound memory @ 3GB). So instead it will start at the 1x
+ * multiple of its size
+ */
+- if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
++ if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) ||
+ (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
+ dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
+ *rc_bar2_size, *rc_bar2_offset);
--- /dev/null
+From 5e9b9f246802f492e7740ab2589aa8c81df5ef20 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 2 Mar 2020 15:05:25 +0000
+Subject: [PATCH] bcm2711-rpi.dtsi: Use upstream pcie node
+
+Now that the upstream bcm2711 DT has a pcie DT node there's no need to
+define one downstream.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +-
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 41 ---------------------------
+ 2 files changed, 1 insertion(+), 42 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -163,7 +163,7 @@
+ i2c6 = &i2c6;
+ /delete-property/ ethernet;
+ /delete-property/ intc;
+- pcie0 = &pcie_0;
++ pcie0 = &pcie0;
+ };
+
+ /delete-node/ wifi-pwrseq;
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -66,47 +66,6 @@
+ <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
+ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
+
+- pcie_0: pcie@7d500000 {
+- reg = <0x0 0x7d500000 0x9310>,
+- <0x0 0x7e00f300 0x20>;
+- msi-controller;
+- msi-parent = <&pcie_0>;
+- #address-cells = <3>;
+- #interrupt-cells = <1>;
+- #size-cells = <2>;
+- bus-range = <0x0 0x01>;
+- compatible = "brcm,bcm2711b0-pcie", // Safe value
+- "brcm,bcm2711-pcie",
+- "brcm,pci-plat-dev";
+- max-link-speed = <2>;
+- tot-num-pcie = <1>;
+- linux,pci-domain = <0>;
+- interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+- interrupt-names = "pcie", "msi";
+- interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 2 &gicv2 GIC_SPI 144
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 3 &gicv2 GIC_SPI 145
+- IRQ_TYPE_LEVEL_HIGH
+- 0 0 0 4 &gicv2 GIC_SPI 146
+- IRQ_TYPE_LEVEL_HIGH>;
+-
+- /* Map outbound accesses from scb:0x6_00000000-03ffffff
+- * to pci:0x0_f8000000-fbffffff
+- */
+- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000
+- 0x0 0x04000000>;
+- /* Map inbound accesses from pci:0x0_00000000..ffffffff
+- * to scb:0x0_00000000-ffffffff
+- */
+- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000
+- 0x1 0x00000000>;
+- status = "okay";
+- };
+-
+ dma40: dma@7e007b00 {
+ compatible = "brcm,bcm2711-dma";
+ reg = <0x0 0x7e007b00 0x400>;
--- /dev/null
+From a3ceeebaaa66e6786490e850b5019808da3785c0 Mon Sep 17 00:00:00 2001
+From: Andrey Konovalov <andrey.konovalov@linaro.org>
+Date: Mon, 20 Jan 2020 05:15:57 -0300
+Subject: [PATCH] media: dt-bindings: media: i2c: Add IMX219 CMOS
+ sensor binding
+
+Commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream.
+(Currently on linux-media/master, queued for 5.7)
+
+Add YAML device tree binding for IMX219 CMOS image sensor, and
+the relevant MAINTAINERS entries.
+
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+---
+ .../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++
+ MAINTAINERS | 8 ++
+ 2 files changed, 122 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml
+@@ -0,0 +1,114 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/media/i2c/imx219.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
++
++maintainers:
++ - Dave Stevenson <dave.stevenson@raspberrypi.com>
++
++description: |-
++ The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor
++ with an active array size of 3280H x 2464V. It is programmable through
++ I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet.
++ Image data is sent through MIPI CSI-2, which is configured as either 2 or
++ 4 data lanes.
++
++properties:
++ compatible:
++ const: sony,imx219
++
++ reg:
++ description: I2C device address
++ maxItems: 1
++
++ clocks:
++ maxItems: 1
++
++ VDIG-supply:
++ description:
++ Digital I/O voltage supply, 1.8 volts
++
++ VANA-supply:
++ description:
++ Analog voltage supply, 2.8 volts
++
++ VDDL-supply:
++ description:
++ Digital core voltage supply, 1.2 volts
++
++ reset-gpios:
++ description: |-
++ Reference to the GPIO connected to the xclr pin, if any.
++ Must be released (set high) after all supplies are applied.
++
++ # See ../video-interfaces.txt for more details
++ port:
++ type: object
++ properties:
++ endpoint:
++ type: object
++ properties:
++ data-lanes:
++ description: |-
++ The sensor supports either two-lane, or four-lane operation.
++ If this property is omitted four-lane operation is assumed.
++ For two-lane operation the property must be set to <1 2>.
++ items:
++ - const: 1
++ - const: 2
++
++ clock-noncontinuous:
++ type: boolean
++ description: |-
++ MIPI CSI-2 clock is non-continuous if this property is present,
++ otherwise it's continuous.
++
++ link-frequencies:
++ allOf:
++ - $ref: /schemas/types.yaml#/definitions/uint64-array
++ description:
++ Allowed data bus frequencies.
++
++ required:
++ - link-frequencies
++
++required:
++ - compatible
++ - reg
++ - clocks
++ - VANA-supply
++ - VDIG-supply
++ - VDDL-supply
++ - port
++
++additionalProperties: false
++
++examples:
++ - |
++ i2c0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ imx219: sensor@10 {
++ compatible = "sony,imx219";
++ reg = <0x10>;
++ clocks = <&imx219_clk>;
++ VANA-supply = <&imx219_vana>; /* 2.8v */
++ VDIG-supply = <&imx219_vdig>; /* 1.8v */
++ VDDL-supply = <&imx219_vddl>; /* 1.2v */
++
++ port {
++ imx219_0: endpoint {
++ remote-endpoint = <&csi1_ep>;
++ data-lanes = <1 2>;
++ clock-noncontinuous;
++ link-frequencies = /bits/ 64 <456000000>;
++ };
++ };
++ };
++ };
++
++...
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -15142,6 +15142,14 @@ S: Maintained
+ F: drivers/media/i2c/imx214.c
+ F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
+
++SONY IMX219 SENSOR DRIVER
++M: Dave Stevenson <dave.stevenson@raspberrypi.com>
++L: linux-media@vger.kernel.org
++T: git git://linuxtv.org/media_tree.git
++S: Maintained
++F: drivers/media/i2c/imx219.c
++F: Documentation/devicetree/bindings/media/i2c/imx219.yaml
++
+ SONY IMX258 SENSOR DRIVER
+ M: Sakari Ailus <sakari.ailus@linux.intel.com>
+ L: linux-media@vger.kernel.org
--- /dev/null
+From 5cd8c4efeb46ce1ef370dd3012a7951ba430b58f Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Mon, 20 Jan 2020 05:15:58 -0300
+Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor
+
+Commit 1283b3b8f82b9004fbb94398cade5c8e797a2c8d upstream.
+(Currently on linux-media/master, queued for 5.7)
+
+Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
+Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
+currently only supports 2 lanes.
+8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
+@ 30fps are currently supported.
+
+[Sakari Ailus: make imx219_check_hwcfg static]
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+---
+ drivers/media/i2c/Kconfig | 11 +
+ drivers/media/i2c/Makefile | 1 +
+ drivers/media/i2c/imx219.c | 1312 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1324 insertions(+)
+ create mode 100644 drivers/media/i2c/imx219.c
+
+--- a/drivers/media/i2c/Kconfig
++++ b/drivers/media/i2c/Kconfig
+@@ -578,6 +578,17 @@ config VIDEO_IMX214
+ To compile this driver as a module, choose M here: the
+ module will be called imx214.
+
++config VIDEO_IMX219
++ tristate "Sony IMX219 sensor support"
++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
++ select V4L2_FWNODE
++ help
++ This is a Video4Linux2 sensor driver for the Sony
++ IMX219 camera.
++
++ To compile this driver as a module, choose M here: the
++ module will be called imx219.
++
+ config VIDEO_IMX258
+ tristate "Sony IMX258 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+--- a/drivers/media/i2c/Makefile
++++ b/drivers/media/i2c/Makefile
+@@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v76
+ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
+ obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
+ obj-$(CONFIG_VIDEO_IMX214) += imx214.o
++obj-$(CONFIG_VIDEO_IMX219) += imx219.o
+ obj-$(CONFIG_VIDEO_IMX258) += imx258.o
+ obj-$(CONFIG_VIDEO_IMX274) += imx274.o
+ obj-$(CONFIG_VIDEO_IMX319) += imx319.o
+--- /dev/null
++++ b/drivers/media/i2c/imx219.c
+@@ -0,0 +1,1312 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * A V4L2 driver for Sony IMX219 cameras.
++ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
++ *
++ * Based on Sony imx258 camera driver
++ * Copyright (C) 2018 Intel Corporation
++ *
++ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
++ * Copyright 2018 Qtechnology A/S
++ *
++ * Flip handling taken from the Sony IMX319 driver.
++ * Copyright (C) 2018 Intel Corporation
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/clkdev.h>
++#include <linux/delay.h>
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <linux/regulator/consumer.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-fwnode.h>
++#include <media/v4l2-mediabus.h>
++#include <asm/unaligned.h>
++
++#define IMX219_REG_VALUE_08BIT 1
++#define IMX219_REG_VALUE_16BIT 2
++
++#define IMX219_REG_MODE_SELECT 0x0100
++#define IMX219_MODE_STANDBY 0x00
++#define IMX219_MODE_STREAMING 0x01
++
++/* Chip ID */
++#define IMX219_REG_CHIP_ID 0x0000
++#define IMX219_CHIP_ID 0x0219
++
++/* External clock frequency is 24.0M */
++#define IMX219_XCLK_FREQ 24000000
++
++/* Pixel rate is fixed at 182.4M for all the modes */
++#define IMX219_PIXEL_RATE 182400000
++
++#define IMX219_DEFAULT_LINK_FREQ 456000000
++
++/* V_TIMING internal */
++#define IMX219_REG_VTS 0x0160
++#define IMX219_VTS_15FPS 0x0dc6
++#define IMX219_VTS_30FPS_1080P 0x06e3
++#define IMX219_VTS_30FPS_BINNED 0x06e3
++#define IMX219_VTS_MAX 0xffff
++
++#define IMX219_VBLANK_MIN 4
++
++/*Frame Length Line*/
++#define IMX219_FLL_MIN 0x08a6
++#define IMX219_FLL_MAX 0xffff
++#define IMX219_FLL_STEP 1
++#define IMX219_FLL_DEFAULT 0x0c98
++
++/* HBLANK control - read only */
++#define IMX219_PPL_DEFAULT 3448
++
++/* Exposure control */
++#define IMX219_REG_EXPOSURE 0x015a
++#define IMX219_EXPOSURE_MIN 4
++#define IMX219_EXPOSURE_STEP 1
++#define IMX219_EXPOSURE_DEFAULT 0x640
++#define IMX219_EXPOSURE_MAX 65535
++
++/* Analog gain control */
++#define IMX219_REG_ANALOG_GAIN 0x0157
++#define IMX219_ANA_GAIN_MIN 0
++#define IMX219_ANA_GAIN_MAX 232
++#define IMX219_ANA_GAIN_STEP 1
++#define IMX219_ANA_GAIN_DEFAULT 0x0
++
++/* Digital gain control */
++#define IMX219_REG_DIGITAL_GAIN 0x0158
++#define IMX219_DGTL_GAIN_MIN 0x0100
++#define IMX219_DGTL_GAIN_MAX 0x0fff
++#define IMX219_DGTL_GAIN_DEFAULT 0x0100
++#define IMX219_DGTL_GAIN_STEP 1
++
++#define IMX219_REG_ORIENTATION 0x0172
++
++/* Test Pattern Control */
++#define IMX219_REG_TEST_PATTERN 0x0600
++#define IMX219_TEST_PATTERN_DISABLE 0
++#define IMX219_TEST_PATTERN_SOLID_COLOR 1
++#define IMX219_TEST_PATTERN_COLOR_BARS 2
++#define IMX219_TEST_PATTERN_GREY_COLOR 3
++#define IMX219_TEST_PATTERN_PN9 4
++
++/* Test pattern colour components */
++#define IMX219_REG_TESTP_RED 0x0602
++#define IMX219_REG_TESTP_GREENR 0x0604
++#define IMX219_REG_TESTP_BLUE 0x0606
++#define IMX219_REG_TESTP_GREENB 0x0608
++#define IMX219_TESTP_COLOUR_MIN 0
++#define IMX219_TESTP_COLOUR_MAX 0x03ff
++#define IMX219_TESTP_COLOUR_STEP 1
++#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX
++#define IMX219_TESTP_GREENR_DEFAULT 0
++#define IMX219_TESTP_BLUE_DEFAULT 0
++#define IMX219_TESTP_GREENB_DEFAULT 0
++
++struct imx219_reg {
++ u16 address;
++ u8 val;
++};
++
++struct imx219_reg_list {
++ unsigned int num_of_regs;
++ const struct imx219_reg *regs;
++};
++
++/* Mode : resolution and related config&values */
++struct imx219_mode {
++ /* Frame width */
++ unsigned int width;
++ /* Frame height */
++ unsigned int height;
++
++ /* V-timing */
++ unsigned int vts_def;
++
++ /* Default register values */
++ struct imx219_reg_list reg_list;
++};
++
++/*
++ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
++ * driver.
++ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
++ */
++static const struct imx219_reg mode_3280x2464_regs[] = {
++ {0x0100, 0x00},
++ {0x30eb, 0x0c},
++ {0x30eb, 0x05},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0164, 0x00},
++ {0x0165, 0x00},
++ {0x0166, 0x0c},
++ {0x0167, 0xcf},
++ {0x0168, 0x00},
++ {0x0169, 0x00},
++ {0x016a, 0x09},
++ {0x016b, 0x9f},
++ {0x016c, 0x0c},
++ {0x016d, 0xd0},
++ {0x016e, 0x09},
++ {0x016f, 0xa0},
++ {0x0170, 0x01},
++ {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},
++ {0x0624, 0x0c},
++ {0x0625, 0xd0},
++ {0x0626, 0x09},
++ {0x0627, 0xa0},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const struct imx219_reg mode_1920_1080_regs[] = {
++ {0x0100, 0x00},
++ {0x30eb, 0x05},
++ {0x30eb, 0x0c},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++ {0x0164, 0x02},
++ {0x0165, 0xa8},
++ {0x0166, 0x0a},
++ {0x0167, 0x27},
++ {0x0168, 0x02},
++ {0x0169, 0xb4},
++ {0x016a, 0x06},
++ {0x016b, 0xeb},
++ {0x016c, 0x07},
++ {0x016d, 0x80},
++ {0x016e, 0x04},
++ {0x016f, 0x38},
++ {0x0170, 0x01},
++ {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},
++ {0x0624, 0x07},
++ {0x0625, 0x80},
++ {0x0626, 0x04},
++ {0x0627, 0x38},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const struct imx219_reg mode_1640_1232_regs[] = {
++ {0x0100, 0x00},
++ {0x30eb, 0x0c},
++ {0x30eb, 0x05},
++ {0x300a, 0xff},
++ {0x300b, 0xff},
++ {0x30eb, 0x05},
++ {0x30eb, 0x09},
++ {0x0114, 0x01},
++ {0x0128, 0x00},
++ {0x012a, 0x18},
++ {0x012b, 0x00},
++ {0x0164, 0x00},
++ {0x0165, 0x00},
++ {0x0166, 0x0c},
++ {0x0167, 0xcf},
++ {0x0168, 0x00},
++ {0x0169, 0x00},
++ {0x016a, 0x09},
++ {0x016b, 0x9f},
++ {0x016c, 0x06},
++ {0x016d, 0x68},
++ {0x016e, 0x04},
++ {0x016f, 0xd0},
++ {0x0170, 0x01},
++ {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},
++ {0x0624, 0x06},
++ {0x0625, 0x68},
++ {0x0626, 0x04},
++ {0x0627, 0xd0},
++ {0x455e, 0x00},
++ {0x471e, 0x4b},
++ {0x4767, 0x0f},
++ {0x4750, 0x14},
++ {0x4540, 0x00},
++ {0x47b4, 0x14},
++ {0x4713, 0x30},
++ {0x478b, 0x10},
++ {0x478f, 0x10},
++ {0x4793, 0x10},
++ {0x4797, 0x0e},
++ {0x479b, 0x0e},
++ {0x0162, 0x0d},
++ {0x0163, 0x78},
++};
++
++static const char * const imx219_test_pattern_menu[] = {
++ "Disabled",
++ "Color Bars",
++ "Solid Color",
++ "Grey Color Bars",
++ "PN9"
++};
++
++static const int imx219_test_pattern_val[] = {
++ IMX219_TEST_PATTERN_DISABLE,
++ IMX219_TEST_PATTERN_COLOR_BARS,
++ IMX219_TEST_PATTERN_SOLID_COLOR,
++ IMX219_TEST_PATTERN_GREY_COLOR,
++ IMX219_TEST_PATTERN_PN9,
++};
++
++/* regulator supplies */
++static const char * const imx219_supply_name[] = {
++ /* Supplies can be enabled in any order */
++ "VANA", /* Analog (2.8V) supply */
++ "VDIG", /* Digital Core (1.8V) supply */
++ "VDDL", /* IF (1.2V) supply */
++};
++
++#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
++
++/*
++ * 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 + <time to initialize the sensor register over I2C>)
++ * where
++ * t4 is fixed, and is max 200uS,
++ * t5 is fixed, and is 6000uS,
++ * t6 depends on the sensor external clock, and is max 32000 clock periods.
++ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
++ * So for any acceptable external clock t6 is always within the range of
++ * 1185 to 5333 uS, and is always less than t5.
++ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
++ * initialize the sensor over I2C, and then exit the software standby.
++ *
++ * This start-up time can be optimized a bit more, if we start the writes
++ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
++ * initialization over I2C may complete before (t4+t5) expires, and we must
++ * ensure that capture is not started before (t4+t5).
++ *
++ * This delay doesn't account for the power supply startup time. If needed,
++ * this should be taken care of via the regulator framework. E.g. in the
++ * case of DT for regulator-fixed one should define the startup-delay-us
++ * property.
++ */
++#define IMX219_XCLR_MIN_DELAY_US 6200
++#define IMX219_XCLR_DELAY_RANGE_US 1000
++
++/* Mode configs */
++static const struct imx219_mode supported_modes[] = {
++ {
++ /* 8MPix 15fps mode */
++ .width = 3280,
++ .height = 2464,
++ .vts_def = IMX219_VTS_15FPS,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
++ .regs = mode_3280x2464_regs,
++ },
++ },
++ {
++ /* 1080P 30fps cropped */
++ .width = 1920,
++ .height = 1080,
++ .vts_def = IMX219_VTS_30FPS_1080P,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
++ .regs = mode_1920_1080_regs,
++ },
++ },
++ {
++ /* 2x2 binned 30fps mode */
++ .width = 1640,
++ .height = 1232,
++ .vts_def = IMX219_VTS_30FPS_BINNED,
++ .reg_list = {
++ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
++ .regs = mode_1640_1232_regs,
++ },
++ },
++};
++
++struct imx219 {
++ struct v4l2_subdev sd;
++ struct media_pad pad;
++
++ struct clk *xclk; /* system clock to IMX219 */
++ u32 xclk_freq;
++
++ struct gpio_desc *reset_gpio;
++ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
++
++ struct v4l2_ctrl_handler ctrl_handler;
++ /* V4L2 Controls */
++ struct v4l2_ctrl *pixel_rate;
++ struct v4l2_ctrl *exposure;
++ struct v4l2_ctrl *vflip;
++ struct v4l2_ctrl *hflip;
++ struct v4l2_ctrl *vblank;
++ struct v4l2_ctrl *hblank;
++
++ /* Current mode */
++ const struct imx219_mode *mode;
++
++ /*
++ * Mutex for serialized access:
++ * Protect sensor module set pad format and start/stop streaming safely.
++ */
++ struct mutex mutex;
++
++ /* Streaming on/off */
++ bool streaming;
++};
++
++static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
++{
++ return container_of(_sd, struct imx219, sd);
++}
++
++/* Read registers up to 2 at a time */
++static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ struct i2c_msg msgs[2];
++ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
++ u8 data_buf[4] = { 0, };
++ int ret;
++
++ if (len > 4)
++ return -EINVAL;
++
++ /* Write register address */
++ msgs[0].addr = client->addr;
++ msgs[0].flags = 0;
++ msgs[0].len = ARRAY_SIZE(addr_buf);
++ msgs[0].buf = addr_buf;
++
++ /* Read data from register */
++ msgs[1].addr = client->addr;
++ msgs[1].flags = I2C_M_RD;
++ msgs[1].len = len;
++ msgs[1].buf = &data_buf[4 - len];
++
++ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
++ if (ret != ARRAY_SIZE(msgs))
++ return -EIO;
++
++ *val = get_unaligned_be32(data_buf);
++
++ return 0;
++}
++
++/* Write registers up to 2 at a time */
++static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ u8 buf[6];
++
++ if (len > 4)
++ return -EINVAL;
++
++ put_unaligned_be16(reg, buf);
++ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
++ if (i2c_master_send(client, buf, len + 2) != len + 2)
++ return -EIO;
++
++ return 0;
++}
++
++/* Write a list of registers */
++static int imx219_write_regs(struct imx219 *imx219,
++ const struct imx219_reg *regs, u32 len)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ unsigned int i;
++ int ret;
++
++ for (i = 0; i < len; i++) {
++ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
++ if (ret) {
++ dev_err_ratelimited(&client->dev,
++ "Failed to write reg 0x%4.4x. error = %d\n",
++ regs[i].address, ret);
++
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/* Get bayer order based on flip setting. */
++static u32 imx219_get_format_code(struct imx219 *imx219)
++{
++ /*
++ * Only one bayer order is supported.
++ * It depends on the flip settings.
++ */
++ static const u32 codes[2][2] = {
++ { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
++ { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
++ };
++
++ lockdep_assert_held(&imx219->mutex);
++ return codes[imx219->vflip->val][imx219->hflip->val];
++}
++
++static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ struct v4l2_mbus_framefmt *try_fmt =
++ v4l2_subdev_get_try_format(sd, fh->pad, 0);
++
++ mutex_lock(&imx219->mutex);
++
++ /* Initialize try_fmt */
++ try_fmt->width = supported_modes[0].width;
++ try_fmt->height = supported_modes[0].height;
++ try_fmt->code = imx219_get_format_code(imx219);
++ try_fmt->field = V4L2_FIELD_NONE;
++
++ mutex_unlock(&imx219->mutex);
++
++ return 0;
++}
++
++static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct imx219 *imx219 =
++ container_of(ctrl->handler, struct imx219, ctrl_handler);
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++
++ if (ctrl->id == V4L2_CID_VBLANK) {
++ int exposure_max, exposure_def;
++
++ /* Update max exposure while meeting expected vblanking */
++ exposure_max = imx219->mode->height + ctrl->val - 4;
++ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++ exposure_max : IMX219_EXPOSURE_DEFAULT;
++ __v4l2_ctrl_modify_range(imx219->exposure,
++ imx219->exposure->minimum,
++ exposure_max, imx219->exposure->step,
++ exposure_def);
++ }
++
++ /*
++ * Applying V4L2 control value only happens
++ * when power is up for streaming
++ */
++ if (pm_runtime_get_if_in_use(&client->dev) == 0)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_ANALOGUE_GAIN:
++ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
++ IMX219_REG_VALUE_08BIT, ctrl->val);
++ break;
++ case V4L2_CID_EXPOSURE:
++ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_DIGITAL_GAIN:
++ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN:
++ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
++ IMX219_REG_VALUE_16BIT,
++ imx219_test_pattern_val[ctrl->val]);
++ break;
++ case V4L2_CID_HFLIP:
++ case V4L2_CID_VFLIP:
++ ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
++ imx219->hflip->val |
++ imx219->vflip->val << 1);
++ break;
++ case V4L2_CID_VBLANK:
++ ret = imx219_write_reg(imx219, IMX219_REG_VTS,
++ IMX219_REG_VALUE_16BIT,
++ imx219->mode->height + ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN_RED:
++ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN_GREENR:
++ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN_BLUE:
++ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ case V4L2_CID_TEST_PATTERN_GREENB:
++ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
++ IMX219_REG_VALUE_16BIT, ctrl->val);
++ break;
++ default:
++ dev_info(&client->dev,
++ "ctrl(id:0x%x,val:0x%x) is not handled\n",
++ ctrl->id, ctrl->val);
++ ret = -EINVAL;
++ break;
++ }
++
++ pm_runtime_put(&client->dev);
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
++ .s_ctrl = imx219_set_ctrl,
++};
++
++static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++
++ /*
++ * Only one bayer order is supported (though it depends on the flip
++ * settings)
++ */
++ if (code->index > 0)
++ return -EINVAL;
++
++ code->code = imx219_get_format_code(imx219);
++
++ return 0;
++}
++
++static int imx219_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++
++ if (fse->index >= ARRAY_SIZE(supported_modes))
++ return -EINVAL;
++
++ if (fse->code != imx219_get_format_code(imx219))
++ return -EINVAL;
++
++ fse->min_width = supported_modes[fse->index].width;
++ fse->max_width = fse->min_width;
++ fse->min_height = supported_modes[fse->index].height;
++ fse->max_height = fse->min_height;
++
++ return 0;
++}
++
++static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
++{
++ fmt->colorspace = V4L2_COLORSPACE_SRGB;
++ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
++ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
++ fmt->colorspace,
++ fmt->ycbcr_enc);
++ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
++}
++
++static void imx219_update_pad_format(struct imx219 *imx219,
++ const struct imx219_mode *mode,
++ struct v4l2_subdev_format *fmt)
++{
++ fmt->format.width = mode->width;
++ fmt->format.height = mode->height;
++ fmt->format.code = imx219_get_format_code(imx219);
++ fmt->format.field = V4L2_FIELD_NONE;
++
++ imx219_reset_colorspace(&fmt->format);
++}
++
++static int __imx219_get_pad_format(struct imx219 *imx219,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
++ struct v4l2_mbus_framefmt *try_fmt =
++ v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
++ /* update the code which could change due to vflip or hflip: */
++ try_fmt->code = imx219_get_format_code(imx219);
++ fmt->format = *try_fmt;
++ } else {
++ imx219_update_pad_format(imx219, imx219->mode, fmt);
++ }
++
++ return 0;
++}
++
++static int imx219_get_pad_format(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret;
++
++ mutex_lock(&imx219->mutex);
++ ret = __imx219_get_pad_format(imx219, cfg, fmt);
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++}
++
++static int imx219_set_pad_format(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *fmt)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ const struct imx219_mode *mode;
++ struct v4l2_mbus_framefmt *framefmt;
++ int exposure_max, exposure_def, hblank;
++
++ mutex_lock(&imx219->mutex);
++
++ /* Bayer order varies with flips */
++ fmt->format.code = imx219_get_format_code(imx219);
++
++ mode = v4l2_find_nearest_size(supported_modes,
++ ARRAY_SIZE(supported_modes),
++ width, height,
++ fmt->format.width, fmt->format.height);
++ imx219_update_pad_format(imx219, mode, fmt);
++ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
++ framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
++ *framefmt = fmt->format;
++ } else if (imx219->mode != mode) {
++ imx219->mode = mode;
++ /* Update limits and set FPS to default */
++ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
++ IMX219_VTS_MAX - mode->height, 1,
++ mode->vts_def - mode->height);
++ __v4l2_ctrl_s_ctrl(imx219->vblank,
++ mode->vts_def - mode->height);
++ /* Update max exposure while meeting expected vblanking */
++ exposure_max = mode->vts_def - 4;
++ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++ exposure_max : IMX219_EXPOSURE_DEFAULT;
++ __v4l2_ctrl_modify_range(imx219->exposure,
++ imx219->exposure->minimum,
++ exposure_max, imx219->exposure->step,
++ exposure_def);
++ /*
++ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
++ * depends on mode->width only, and is not changeble in any
++ * way other than changing the mode.
++ */
++ hblank = IMX219_PPL_DEFAULT - mode->width;
++ __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
++ hblank);
++ }
++
++ mutex_unlock(&imx219->mutex);
++
++ return 0;
++}
++
++static int imx219_start_streaming(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ const struct imx219_reg_list *reg_list;
++ int ret;
++
++ /* Apply default values of current mode */
++ reg_list = &imx219->mode->reg_list;
++ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
++ if (ret) {
++ dev_err(&client->dev, "%s failed to set mode\n", __func__);
++ return ret;
++ }
++
++ /* Apply customized values from user */
++ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
++ if (ret)
++ return ret;
++
++ /* set stream on register */
++ return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
++}
++
++static void imx219_stop_streaming(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++
++ /* set stream off register */
++ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
++ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
++ if (ret)
++ dev_err(&client->dev, "%s failed to set stream\n", __func__);
++}
++
++static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct imx219 *imx219 = to_imx219(sd);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret = 0;
++
++ mutex_lock(&imx219->mutex);
++ if (imx219->streaming == enable) {
++ mutex_unlock(&imx219->mutex);
++ return 0;
++ }
++
++ if (enable) {
++ ret = pm_runtime_get_sync(&client->dev);
++ if (ret < 0) {
++ pm_runtime_put_noidle(&client->dev);
++ goto err_unlock;
++ }
++
++ /*
++ * Apply default & customized values
++ * and then start streaming.
++ */
++ ret = imx219_start_streaming(imx219);
++ if (ret)
++ goto err_rpm_put;
++ } else {
++ imx219_stop_streaming(imx219);
++ pm_runtime_put(&client->dev);
++ }
++
++ imx219->streaming = enable;
++
++ /* vflip and hflip cannot change during streaming */
++ __v4l2_ctrl_grab(imx219->vflip, enable);
++ __v4l2_ctrl_grab(imx219->hflip, enable);
++
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++
++err_rpm_put:
++ pm_runtime_put(&client->dev);
++err_unlock:
++ mutex_unlock(&imx219->mutex);
++
++ return ret;
++}
++
++/* Power/clock management functions */
++static int imx219_power_on(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret;
++
++ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
++ imx219->supplies);
++ if (ret) {
++ dev_err(&client->dev, "%s: failed to enable regulators\n",
++ __func__);
++ return ret;
++ }
++
++ ret = clk_prepare_enable(imx219->xclk);
++ if (ret) {
++ dev_err(&client->dev, "%s: failed to enable clock\n",
++ __func__);
++ goto reg_off;
++ }
++
++ gpiod_set_value_cansleep(imx219->reset_gpio, 1);
++ usleep_range(IMX219_XCLR_MIN_DELAY_US,
++ IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
++
++ return 0;
++
++reg_off:
++ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
++
++ return ret;
++}
++
++static int imx219_power_off(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++
++ gpiod_set_value_cansleep(imx219->reset_gpio, 0);
++ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
++ clk_disable_unprepare(imx219->xclk);
++
++ return 0;
++}
++
++static int __maybe_unused imx219_suspend(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++
++ if (imx219->streaming)
++ imx219_stop_streaming(imx219);
++
++ return 0;
++}
++
++static int __maybe_unused imx219_resume(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++ int ret;
++
++ if (imx219->streaming) {
++ ret = imx219_start_streaming(imx219);
++ if (ret)
++ goto error;
++ }
++
++ return 0;
++
++error:
++ imx219_stop_streaming(imx219);
++ imx219->streaming = 0;
++
++ return ret;
++}
++
++static int imx219_get_regulators(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ unsigned int i;
++
++ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
++ imx219->supplies[i].supply = imx219_supply_name[i];
++
++ return devm_regulator_bulk_get(&client->dev,
++ IMX219_NUM_SUPPLIES,
++ imx219->supplies);
++}
++
++/* Verify chip ID */
++static int imx219_identify_module(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ int ret;
++ u32 val;
++
++ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
++ IMX219_REG_VALUE_16BIT, &val);
++ if (ret) {
++ dev_err(&client->dev, "failed to read chip id %x\n",
++ IMX219_CHIP_ID);
++ return ret;
++ }
++
++ if (val != IMX219_CHIP_ID) {
++ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
++ IMX219_CHIP_ID, val);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_subdev_core_ops imx219_core_ops = {
++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
++ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
++};
++
++static const struct v4l2_subdev_video_ops imx219_video_ops = {
++ .s_stream = imx219_set_stream,
++};
++
++static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
++ .enum_mbus_code = imx219_enum_mbus_code,
++ .get_fmt = imx219_get_pad_format,
++ .set_fmt = imx219_set_pad_format,
++ .enum_frame_size = imx219_enum_frame_size,
++};
++
++static const struct v4l2_subdev_ops imx219_subdev_ops = {
++ .core = &imx219_core_ops,
++ .video = &imx219_video_ops,
++ .pad = &imx219_pad_ops,
++};
++
++static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
++ .open = imx219_open,
++};
++
++/* Initialize control handlers */
++static int imx219_init_controls(struct imx219 *imx219)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
++ struct v4l2_ctrl_handler *ctrl_hdlr;
++ unsigned int height = imx219->mode->height;
++ int exposure_max, exposure_def, hblank;
++ int i, ret;
++
++ ctrl_hdlr = &imx219->ctrl_handler;
++ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
++ if (ret)
++ return ret;
++
++ mutex_init(&imx219->mutex);
++ ctrl_hdlr->lock = &imx219->mutex;
++
++ /* By default, PIXEL_RATE is read only */
++ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_PIXEL_RATE,
++ IMX219_PIXEL_RATE,
++ IMX219_PIXEL_RATE, 1,
++ IMX219_PIXEL_RATE);
++
++ /* Initial vblank/hblank/exposure parameters based on current mode */
++ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
++ IMX219_VTS_MAX - height, 1,
++ imx219->mode->vts_def - height);
++ hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
++ imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_HBLANK, hblank, hblank,
++ 1, hblank);
++ if (imx219->hblank)
++ imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
++ exposure_max = imx219->mode->vts_def - 4;
++ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
++ exposure_max : IMX219_EXPOSURE_DEFAULT;
++ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_EXPOSURE,
++ IMX219_EXPOSURE_MIN, exposure_max,
++ IMX219_EXPOSURE_STEP,
++ exposure_def);
++
++ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
++ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
++ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
++
++ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
++ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
++ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
++
++ imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ if (imx219->hflip)
++ imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
++
++ imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ if (imx219->vflip)
++ imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
++
++ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_TEST_PATTERN,
++ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
++ 0, 0, imx219_test_pattern_menu);
++ for (i = 0; i < 4; i++) {
++ /*
++ * The assumption is that
++ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
++ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
++ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
++ */
++ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
++ V4L2_CID_TEST_PATTERN_RED + i,
++ IMX219_TESTP_COLOUR_MIN,
++ IMX219_TESTP_COLOUR_MAX,
++ IMX219_TESTP_COLOUR_STEP,
++ IMX219_TESTP_COLOUR_MAX);
++ /* The "Solid color" pattern is white by default */
++ }
++
++ if (ctrl_hdlr->error) {
++ ret = ctrl_hdlr->error;
++ dev_err(&client->dev, "%s control init failed (%d)\n",
++ __func__, ret);
++ goto error;
++ }
++
++ imx219->sd.ctrl_handler = ctrl_hdlr;
++
++ return 0;
++
++error:
++ v4l2_ctrl_handler_free(ctrl_hdlr);
++ mutex_destroy(&imx219->mutex);
++
++ return ret;
++}
++
++static void imx219_free_controls(struct imx219 *imx219)
++{
++ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
++ mutex_destroy(&imx219->mutex);
++}
++
++static int imx219_check_hwcfg(struct device *dev)
++{
++ struct fwnode_handle *endpoint;
++ struct v4l2_fwnode_endpoint ep_cfg = {
++ .bus_type = V4L2_MBUS_CSI2_DPHY
++ };
++ int ret = -EINVAL;
++
++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
++ if (!endpoint) {
++ dev_err(dev, "endpoint node not found\n");
++ return -EINVAL;
++ }
++
++ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
++ dev_err(dev, "could not parse endpoint\n");
++ goto error_out;
++ }
++
++ /* Check the number of MIPI CSI2 data lanes */
++ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
++ dev_err(dev, "only 2 data lanes are currently supported\n");
++ goto error_out;
++ }
++
++ /* Check the link frequency set in device tree */
++ if (!ep_cfg.nr_of_link_frequencies) {
++ dev_err(dev, "link-frequency property not found in DT\n");
++ goto error_out;
++ }
++
++ if (ep_cfg.nr_of_link_frequencies != 1 ||
++ ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
++ dev_err(dev, "Link frequency not supported: %lld\n",
++ ep_cfg.link_frequencies[0]);
++ goto error_out;
++ }
++
++ ret = 0;
++
++error_out:
++ v4l2_fwnode_endpoint_free(&ep_cfg);
++ fwnode_handle_put(endpoint);
++
++ return ret;
++}
++
++static int imx219_probe(struct i2c_client *client)
++{
++ struct device *dev = &client->dev;
++ struct imx219 *imx219;
++ int ret;
++
++ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
++ if (!imx219)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
++
++ /* Check the hardware configuration in device tree */
++ if (imx219_check_hwcfg(dev))
++ return -EINVAL;
++
++ /* Get system clock (xclk) */
++ imx219->xclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(imx219->xclk)) {
++ dev_err(dev, "failed to get xclk\n");
++ return PTR_ERR(imx219->xclk);
++ }
++
++ imx219->xclk_freq = clk_get_rate(imx219->xclk);
++ if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
++ dev_err(dev, "xclk frequency not supported: %d Hz\n",
++ imx219->xclk_freq);
++ return -EINVAL;
++ }
++
++ ret = imx219_get_regulators(imx219);
++ if (ret) {
++ dev_err(dev, "failed to get regulators\n");
++ return ret;
++ }
++
++ /* Request optional enable pin */
++ imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
++ GPIOD_OUT_HIGH);
++
++ /*
++ * The sensor must be powered for imx219_identify_module()
++ * to be able to read the CHIP_ID register
++ */
++ ret = imx219_power_on(dev);
++ if (ret)
++ return ret;
++
++ ret = imx219_identify_module(imx219);
++ if (ret)
++ goto error_power_off;
++
++ /* Set default mode to max resolution */
++ imx219->mode = &supported_modes[0];
++
++ ret = imx219_init_controls(imx219);
++ if (ret)
++ goto error_power_off;
++
++ /* Initialize subdev */
++ imx219->sd.internal_ops = &imx219_internal_ops;
++ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
++
++ /* Initialize source pad */
++ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
++
++ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
++ if (ret) {
++ dev_err(dev, "failed to init entity pads: %d\n", ret);
++ goto error_handler_free;
++ }
++
++ ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
++ if (ret < 0) {
++ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
++ goto error_media_entity;
++ }
++
++ /* Enable runtime PM and turn off the device */
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++ pm_runtime_idle(dev);
++
++ return 0;
++
++error_media_entity:
++ media_entity_cleanup(&imx219->sd.entity);
++
++error_handler_free:
++ imx219_free_controls(imx219);
++
++error_power_off:
++ imx219_power_off(dev);
++
++ return ret;
++}
++
++static int imx219_remove(struct i2c_client *client)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(client);
++ struct imx219 *imx219 = to_imx219(sd);
++
++ v4l2_async_unregister_subdev(sd);
++ media_entity_cleanup(&sd->entity);
++ imx219_free_controls(imx219);
++
++ pm_runtime_disable(&client->dev);
++ if (!pm_runtime_status_suspended(&client->dev))
++ imx219_power_off(&client->dev);
++ pm_runtime_set_suspended(&client->dev);
++
++ return 0;
++}
++
++static const struct of_device_id imx219_dt_ids[] = {
++ { .compatible = "sony,imx219" },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, imx219_dt_ids);
++
++static const struct dev_pm_ops imx219_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
++ SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
++};
++
++static struct i2c_driver imx219_i2c_driver = {
++ .driver = {
++ .name = "imx219",
++ .of_match_table = imx219_dt_ids,
++ .pm = &imx219_pm_ops,
++ },
++ .probe_new = imx219_probe,
++ .remove = imx219_remove,
++};
++
++module_i2c_driver(imx219_i2c_driver);
++
++MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com");
++MODULE_DESCRIPTION("Sony IMX219 sensor driver");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From eae83133532e44adae2f632b2168119a4c7249a2 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 11 Mar 2020 12:07:57 +0000
+Subject: [PATCH] overlays: imx219: Correct link frequency to match the
+ upstream driver
+
+The upstream driver is checking the link frequency parameter, and
+the overlay had the wrong value.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/imx219-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/imx219-overlay.dts
++++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts
+@@ -40,7 +40,7 @@
+ data-lanes = <1 2>;
+ clock-noncontinuous;
+ link-frequencies =
+- /bits/ 64 <297000000>;
++ /bits/ 64 <456000000>;
+ };
+ };
+ };
--- /dev/null
+From 61113c5463166d734dc6560574f5fb1536bae795 Mon Sep 17 00:00:00 2001
+From: Nataliya Korovkina <malus.brandywine@gmail.com>
+Date: Thu, 12 Mar 2020 17:22:53 -0400
+Subject: [PATCH] Kbuild: Allow .dtbo overlays to be built, adjust.
+
+This is adjustment to commit
+d368ceaacdccd7732dc97d1d7987bdf7149d62e3 "kbuild: Allow .dtbo overlays to be built piecemeal"
+
+prepare3 target has gone from mainline tree in branch 5.4.y
+
+Signed-off-by: Nataliya Korovkina <malus.brandywine@gmail.com>
+---
+ Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -1238,7 +1238,7 @@ ifneq ($(dtstree),)
+ %.dtb: include/config/kernel.release scripts_dtc
+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
+
+-%.dtbo: prepare3 scripts_dtc
++%.dtbo: include/config/kernel.release scripts_dtc
+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
+
+ PHONY += dtbs dtbs_install dt_binding_check
--- /dev/null
+From 23f717168dc55f69ad517d3ab5f412d04a5afc0e Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.org>
+Date: Wed, 15 Jan 2020 13:40:38 +0000
+Subject: [PATCH] media: ov5647: Fix return codes from
+ ov5647_write/ov5647_read functions.
+
+Previously they were returning positive non-zero codes for success,
+which were getting passed up the call stack. Since release 4.19,
+do_dentry_open (fs/open.c) has been catching these and flagging an
+error. (So this driver has been broken since that date.)
+
+Fixes: 3c2472a [media] media: i2c: Add support for OV5647 sensor
+Signed-off-by: David Plowman <david.plowman@raspberrypi.org>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -214,9 +214,18 @@ static int ov5647_write(struct v4l2_subd
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = i2c_master_send(client, data, 3);
+- if (ret < 0)
++ /*
++ * Writing the wrong number of bytes also needs to be flagged as an
++ * error. Success needs to produce a 0 return code.
++ */
++ if (ret == 3) {
++ ret = 0;
++ } else {
+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+ __func__, reg);
++ if (ret >= 0)
++ ret = -EINVAL;
++ }
+
+ return ret;
+ }
+@@ -228,16 +237,31 @@ static int ov5647_read(struct v4l2_subde
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = i2c_master_send(client, data_w, 2);
+- if (ret < 0) {
++ /*
++ * A negative return code, or sending the wrong number of bytes, both
++ * count as an error.
++ */
++ if (ret != 2) {
+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+ __func__, reg);
++ if (ret >= 0)
++ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, val, 1);
+- if (ret < 0)
++ /*
++ * The only return value indicating success is 1. Anything else, even
++ * a non-negative value, indicates something went wrong.
++ */
++ if (ret == 1) {
++ ret = 0;
++ } else {
+ dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
++ if (ret >= 0)
++ ret = -EINVAL;
++ }
+
+ return ret;
+ }
--- /dev/null
+From 9e584d9de3387588bf455d3c45ec6a092bfa4266 Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:30:53 +0000
+Subject: [PATCH] media: ov5647: Add basic support for multiple sensor
+ modes.
+
+Specifically:
+
+Added a structure ov5647_mode and a list of supported_modes (though no
+actual new modes as yet). The state object points to the "current mode".
+
+ov5647_enum_mbus_code, ov5647_enum_frame_size, ov5647_set_fmt and
+ov5647_get_fmt all needed upgrading to cope with multiple modes.
+
+__sensor_init (which writes all the registers) is now called by
+ov5647_stream_on (once the mode is known) rather than by
+ov5647_sensor_power.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 268 ++++++++++++++++++++++++++++---------
+ 1 file changed, 202 insertions(+), 66 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -86,13 +86,17 @@ struct regval_list {
+ u8 data;
+ };
+
++struct ov5647_mode {
++ struct v4l2_mbus_framefmt format;
++ struct regval_list *reg_list;
++ unsigned int num_regs;
++};
++
+ struct ov5647 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct mutex lock;
+- struct v4l2_mbus_framefmt format;
+- unsigned int width;
+- unsigned int height;
++ const struct ov5647_mode *mode;
+ int power_count;
+ struct clk *xclk;
+ struct gpio_desc *pwdn;
+@@ -207,6 +211,32 @@ static struct regval_list ov5647_640x480
+ {0x0100, 0x01},
+ };
+
++static struct ov5647_mode supported_modes_8bit[] = {
++ /*
++ * Original 8-bit VGA mode
++ * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image.
++ */
++ {
++ {
++ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .field = V4L2_FIELD_NONE,
++ .width = 640,
++ .height = 480
++ },
++ ov5647_640x480,
++ ARRAY_SIZE(ov5647_640x480)
++ },
++ /* more modes below here... */
++};
++
++static struct ov5647_mode supported_modes_10bit[] = {
++ /* no 10-bit modes yet */
++};
++
++/* Use original 8-bit VGA mode as default. */
++#define OV5647_DEFAULT_MODE (&supported_modes_8bit[0])
++
+ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+ {
+ int ret;
+@@ -293,12 +323,55 @@ static int ov5647_set_virtual_channel(st
+ return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
+ }
+
++static int __sensor_init(struct v4l2_subdev *sd)
++{
++ int ret;
++ u8 resetval, rdval;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov5647 *state = to_state(sd);
++
++ ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
++ if (ret < 0)
++ return ret;
++
++ ret = ov5647_write_array(sd, state->mode->reg_list,
++ state->mode->num_regs);
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor default regs error\n");
++ return ret;
++ }
++
++ ret = ov5647_set_virtual_channel(sd, 0);
++ if (ret < 0)
++ return ret;
++
++ ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
++ if (ret < 0)
++ return ret;
++
++ if (!(resetval & 0x01)) {
++ dev_err(&client->dev, "Device was in SW standby");
++ ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
+ static int ov5647_stream_on(struct v4l2_subdev *sd)
+ {
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5647 *ov5647 = to_state(sd);
+ u8 val = MIPI_CTRL00_BUS_IDLE;
+ int ret;
+
++ ret = __sensor_init(sd);
++ if (ret < 0) {
++ dev_err(&client->dev, "sensor_init failed\n");
++ return ret;
++ }
++
+ if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
+ val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+ MIPI_CTRL00_LINE_SYNC_ENABLE;
+@@ -347,44 +420,6 @@ static int set_sw_standby(struct v4l2_su
+ return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
+ }
+
+-static int __sensor_init(struct v4l2_subdev *sd)
+-{
+- int ret;
+- u8 resetval, rdval;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+- ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
+- if (ret < 0)
+- return ret;
+-
+- ret = ov5647_write_array(sd, ov5647_640x480,
+- ARRAY_SIZE(ov5647_640x480));
+- if (ret < 0) {
+- dev_err(&client->dev, "write sensor default regs error\n");
+- return ret;
+- }
+-
+- ret = ov5647_set_virtual_channel(sd, 0);
+- if (ret < 0)
+- return ret;
+-
+- ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
+- if (ret < 0)
+- return ret;
+-
+- if (!(resetval & 0x01)) {
+- dev_err(&client->dev, "Device was in SW standby");
+- ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
+- if (ret < 0)
+- return ret;
+- }
+-
+- /*
+- * stream off to make the clock lane into LP-11 state.
+- */
+- return ov5647_stream_off(sd);
+-}
+-
+ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
+ {
+ int ret = 0;
+@@ -408,7 +443,7 @@ static int ov5647_sensor_power(struct v4
+ }
+
+ ret = ov5647_write_array(sd, sensor_oe_enable_regs,
+- ARRAY_SIZE(sensor_oe_enable_regs));
++ ARRAY_SIZE(sensor_oe_enable_regs));
+ if (ret < 0) {
+ clk_disable_unprepare(ov5647->xclk);
+ dev_err(&client->dev,
+@@ -416,7 +451,10 @@ static int ov5647_sensor_power(struct v4
+ goto out;
+ }
+
+- ret = __sensor_init(sd);
++ /*
++ * Ensure streaming off to make clock lane go into LP-11 state.
++ */
++ ret = ov5647_stream_off(sd);
+ if (ret < 0) {
+ clk_disable_unprepare(ov5647->xclk);
+ dev_err(&client->dev,
+@@ -427,7 +465,7 @@ static int ov5647_sensor_power(struct v4
+ dev_dbg(&client->dev, "OV5647 power off\n");
+
+ ret = ov5647_write_array(sd, sensor_oe_disable_regs,
+- ARRAY_SIZE(sensor_oe_disable_regs));
++ ARRAY_SIZE(sensor_oe_disable_regs));
+
+ if (ret < 0)
+ dev_dbg(&client->dev, "disable oe failed\n");
+@@ -489,10 +527,19 @@ static const struct v4l2_subdev_core_ops
+
+ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
+ {
++ struct ov5647 *state = to_state(sd);
++ int ret = 0;
++
++ mutex_lock(&state->lock);
++
+ if (enable)
+- return ov5647_stream_on(sd);
++ ret = ov5647_stream_on(sd);
+ else
+- return ov5647_stream_off(sd);
++ ret = ov5647_stream_off(sd);
++
++ mutex_unlock(&state->lock);
++
++ return ret;
+ }
+
+ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
+@@ -503,38 +550,127 @@ static int ov5647_enum_mbus_code(struct
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+ {
+- if (code->index > 0)
++ if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit))
++ code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
++ else if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit) == 0 &&
++ ARRAY_SIZE(supported_modes_10bit))
++ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++ else if (code->index == 1 && ARRAY_SIZE(supported_modes_8bit) &&
++ ARRAY_SIZE(supported_modes_10bit))
++ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
++ else
+ return -EINVAL;
+
+- code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
++ return 0;
++}
++
++static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct ov5647_mode *mode = NULL;
++
++ if (fse->code == MEDIA_BUS_FMT_SBGGR8_1X8) {
++ if (fse->index >= ARRAY_SIZE(supported_modes_8bit))
++ return -EINVAL;
++ mode = &supported_modes_8bit[fse->index];
++ } else if (fse->code == MEDIA_BUS_FMT_SBGGR10_1X10) {
++ if (fse->index >= ARRAY_SIZE(supported_modes_10bit))
++ return -EINVAL;
++ mode = &supported_modes_10bit[fse->index];
++ } else {
++ return -EINVAL;
++ }
++
++ fse->min_width = mode->format.width;
++ fse->max_width = fse->min_width;
++ fse->min_height = mode->format.height;
++ fse->max_height = fse->min_height;
++
++ return 0;
++}
++
++static int ov5647_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *fmt = &format->format;
++ struct ov5647 *state = to_state(sd);
++ struct v4l2_mbus_framefmt *framefmt;
++ const struct ov5647_mode *mode_8bit, *mode_10bit, *mode = NULL;
++
++ if (format->pad != 0)
++ return -EINVAL;
++
++ mutex_lock(&state->lock);
++
++ /*
++ * Try to respect any given pixel format, otherwise try for a 10-bit
++ * mode.
++ */
++ mode_8bit = v4l2_find_nearest_size(supported_modes_8bit,
++ ARRAY_SIZE(supported_modes_8bit),
++ format.width, format.height,
++ format->format.width,
++ format->format.height);
++ mode_10bit = v4l2_find_nearest_size(supported_modes_10bit,
++ ARRAY_SIZE(supported_modes_10bit),
++ format.width, format.height,
++ format->format.width,
++ format->format.height);
++ if (format->format.code == MEDIA_BUS_FMT_SBGGR8_1X8 && mode_8bit)
++ mode = mode_8bit;
++ else if (format->format.code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
++ mode_10bit)
++ mode = mode_10bit;
++ else if (mode_10bit)
++ mode = mode_10bit;
++ else
++ mode = mode_8bit;
++
++ if (!mode)
++ return -EINVAL;
++
++ *fmt = mode->format;
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
++ framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
++ *framefmt = format->format;
++ } else {
++ state->mode = mode;
++ }
++
++ mutex_unlock(&state->lock);
+
+ return 0;
+ }
+
+-static int ov5647_set_get_fmt(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_format *format)
++static int ov5647_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
+ {
+ struct v4l2_mbus_framefmt *fmt = &format->format;
++ struct ov5647 *state = to_state(sd);
+
+ if (format->pad != 0)
+ return -EINVAL;
+
+- /* Only one format is supported, so return that */
+- memset(fmt, 0, sizeof(*fmt));
+- fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+- fmt->colorspace = V4L2_COLORSPACE_SRGB;
+- fmt->field = V4L2_FIELD_NONE;
+- fmt->width = 640;
+- fmt->height = 480;
++ mutex_lock(&state->lock);
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ *fmt = *v4l2_subdev_get_try_format(sd, cfg, format->pad);
++ else
++ *fmt = state->mode->format;
++
++ mutex_unlock(&state->lock);
+
+ return 0;
+ }
+
+ static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
+ .enum_mbus_code = ov5647_enum_mbus_code,
+- .set_fmt = ov5647_set_get_fmt,
+- .get_fmt = ov5647_set_get_fmt,
++ .set_fmt = ov5647_set_fmt,
++ .get_fmt = ov5647_get_fmt,
++ .enum_frame_size = ov5647_enum_frame_size,
+ };
+
+ static const struct v4l2_subdev_ops ov5647_subdev_ops = {
+@@ -580,18 +716,15 @@ static int ov5647_open(struct v4l2_subde
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_rect *crop =
+ v4l2_subdev_get_try_crop(sd, fh->pad, 0);
++ struct ov5647 *state = to_state(sd);
+
+ crop->left = OV5647_COLUMN_START_DEF;
+ crop->top = OV5647_ROW_START_DEF;
+ crop->width = OV5647_WINDOW_WIDTH_DEF;
+ crop->height = OV5647_WINDOW_HEIGHT_DEF;
+
+- format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+-
+- format->width = OV5647_WINDOW_WIDTH_DEF;
+- format->height = OV5647_WINDOW_HEIGHT_DEF;
+- format->field = V4L2_FIELD_NONE;
+- format->colorspace = V4L2_COLORSPACE_SRGB;
++ /* Set the default format to the same as the sensor. */
++ *format = state->mode->format;
+
+ return 0;
+ }
+@@ -660,6 +793,9 @@ static int ov5647_probe(struct i2c_clien
+
+ mutex_init(&sensor->lock);
+
++ /* Set the default mode before we init the subdev */
++ sensor->mode = OV5647_DEFAULT_MODE;
++
+ sd = &sensor->sd;
+ v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
+ sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
--- /dev/null
+From d9d333b717f220439868edd533994f2709b3a95f Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:23 +0000
+Subject: [PATCH] media: ov5647: Add V4L2 controls for analogue gain,
+ exposure and AWB
+
+Added basic v4l2_ctrl_handler infrastructure (there was none
+previously).
+
+Added controls to let AWB/AEC/AGC run in the sensor's auto mode or
+manually. Also controls to set exposure (in lines) and analogue gain
+(as a register code) from user code.
+
+Also delete registers (just the one) from the VGA mode register set
+that are now controlled by the new V4L2 controls.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 175 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 174 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -29,11 +29,13 @@
+ #include <linux/of_graph.h>
+ #include <linux/slab.h>
+ #include <linux/videodev2.h>
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-fwnode.h>
+ #include <media/v4l2-image-sizes.h>
+ #include <media/v4l2-mediabus.h>
+
++
+ #define SENSOR_NAME "ov5647"
+
+ /*
+@@ -53,9 +55,16 @@
+ #define OV5647_REG_CHIPID_H 0x300A
+ #define OV5647_REG_CHIPID_L 0x300B
+ #define OV5640_REG_PAD_OUT 0x300D
++#define OV5647_REG_EXP_HI 0x3500
++#define OV5647_REG_EXP_MID 0x3501
++#define OV5647_REG_EXP_LO 0x3502
++#define OV5647_REG_AEC_AGC 0x3503
++#define OV5647_REG_GAIN_HI 0x350A
++#define OV5647_REG_GAIN_LO 0x350B
+ #define OV5647_REG_FRAME_OFF_NUMBER 0x4202
+ #define OV5647_REG_MIPI_CTRL00 0x4800
+ #define OV5647_REG_MIPI_CTRL14 0x4814
++#define OV5647_REG_AWB 0x5001
+
+ #define REG_TERM 0xfffe
+ #define VAL_TERM 0xfe
+@@ -101,6 +110,7 @@ struct ov5647 {
+ struct clk *xclk;
+ struct gpio_desc *pwdn;
+ unsigned int flags;
++ struct v4l2_ctrl_handler ctrls;
+ };
+
+ static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+@@ -135,7 +145,6 @@ static struct regval_list ov5647_640x480
+ {0x3612, 0x59},
+ {0x3618, 0x00},
+ {0x5000, 0x06},
+- {0x5001, 0x01},
+ {0x5002, 0x41},
+ {0x5003, 0x08},
+ {0x5a00, 0x08},
+@@ -372,6 +381,11 @@ static int ov5647_stream_on(struct v4l2_
+ return ret;
+ }
+
++ /* Apply customized values from user when stream starts */
++ ret = __v4l2_ctrl_handler_setup(sd->ctrl_handler);
++ if (ret)
++ return ret;
++
+ if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)
+ val |= MIPI_CTRL00_CLOCK_LANE_GATE |
+ MIPI_CTRL00_LINE_SYNC_ENABLE;
+@@ -753,6 +767,120 @@ static int ov5647_parse_dt(struct device
+ return ret;
+ }
+
++static int ov5647_s_auto_white_balance(struct v4l2_subdev *sd, u32 val)
++{
++ /* non-zero turns on AWB */
++ return ov5647_write(sd, OV5647_REG_AWB, val ? 1 : 0);
++}
++
++static int ov5647_s_autogain(struct v4l2_subdev *sd, u32 val)
++{
++ int ret;
++ u8 reg;
++
++ /* non-zero turns on AGC by clearing bit 1 */
++ ret = ov5647_read(sd, OV5647_REG_AEC_AGC, ®);
++ if (ret == 0)
++ ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
++ val ? reg & ~2 : reg | 2);
++
++ return ret;
++}
++
++static int ov5647_s_exposure_auto(struct v4l2_subdev *sd, u32 val)
++{
++ int ret;
++ u8 reg;
++
++ /* Everything except V4L2_EXPOSURE_MANUAL turns on AEC by
++ * clearing bit 0
++ */
++ ret = ov5647_read(sd, OV5647_REG_AEC_AGC, ®);
++ if (ret == 0)
++ ret = ov5647_write(sd, OV5647_REG_AEC_AGC,
++ val == V4L2_EXPOSURE_MANUAL ?
++ reg | 1 : reg & ~1);
++
++ return ret;
++}
++
++static int ov5647_s_analogue_gain(struct v4l2_subdev *sd, u32 val)
++{
++ int ret;
++
++ /* 10 bits of gain, 2 in the high register */
++ ret = ov5647_write(sd, OV5647_REG_GAIN_HI, (val >> 8) & 3);
++ if (ret == 0)
++ ret = ov5647_write(sd, OV5647_REG_GAIN_LO, val & 0xff);
++
++ return ret;
++}
++
++static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val)
++{
++ int ret;
++
++ /* Sensor has 20 bits, but the bottom 4 bits are fractions of a line
++ * which we leave as zero (and don't receive in "val").
++ */
++ ret = ov5647_write(sd, OV5647_REG_EXP_HI, (val >> 12) & 0xf);
++ if (ret == 0)
++ ov5647_write(sd, OV5647_REG_EXP_MID, (val >> 4) & 0xff);
++ if (ret == 0)
++ ov5647_write(sd, OV5647_REG_EXP_LO, (val & 0xf) << 4);
++
++ return ret;
++}
++
++static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct ov5647 *state = container_of(ctrl->handler,
++ struct ov5647, ctrls);
++ struct v4l2_subdev *sd = &state->sd;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret = 0;
++
++ /* v4l2_ctrl_lock() locks our own mutex */
++
++ /*
++ * If the device is not powered up by the host driver do
++ * not apply any controls to H/W at this time. Instead
++ * the controls will be restored right after power-up.
++ */
++ if (state->power_count == 0)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUTO_WHITE_BALANCE:
++ ret = ov5647_s_auto_white_balance(sd, ctrl->val);
++ break;
++ case V4L2_CID_AUTOGAIN:
++ ret = ov5647_s_autogain(sd, ctrl->val);
++ break;
++ case V4L2_CID_EXPOSURE_AUTO:
++ ret = ov5647_s_exposure_auto(sd, ctrl->val);
++ break;
++ case V4L2_CID_ANALOGUE_GAIN:
++ ret = ov5647_s_analogue_gain(sd, ctrl->val);
++ break;
++ case V4L2_CID_EXPOSURE:
++ ret = ov5647_s_exposure(sd, ctrl->val);
++ break;
++ default:
++ dev_info(&client->dev,
++ "ctrl(id:0x%x,val:0x%x) is not handled\n",
++ ctrl->id, ctrl->val);
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ov5647_ctrl_ops = {
++ .s_ctrl = ov5647_s_ctrl,
++};
++
+ static int ov5647_probe(struct i2c_client *client)
+ {
+ struct device *dev = &client->dev;
+@@ -761,6 +889,7 @@ static int ov5647_probe(struct i2c_clien
+ struct v4l2_subdev *sd;
+ struct device_node *np = client->dev.of_node;
+ u32 xclk_freq;
++ struct v4l2_ctrl *ctrl;
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+@@ -793,6 +922,48 @@ static int ov5647_probe(struct i2c_clien
+
+ mutex_init(&sensor->lock);
+
++ /* Initialise controls. */
++ v4l2_ctrl_handler_init(&sensor->ctrls, 3);
++ v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++ V4L2_CID_AUTOGAIN,
++ 0, /* min */
++ 1, /* max */
++ 1, /* step */
++ 1); /* default */
++ v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++ V4L2_CID_AUTO_WHITE_BALANCE,
++ 0, /* min */
++ 1, /* max */
++ 1, /* step */
++ 1); /* default */
++ v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
++ V4L2_CID_EXPOSURE_AUTO,
++ V4L2_EXPOSURE_MANUAL, /* max */
++ 0, /* skip_mask */
++ V4L2_EXPOSURE_AUTO); /* default */
++ ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++ V4L2_CID_EXPOSURE,
++ 4, /* min lines */
++ 65535, /* max lines (4+8+4 bits)*/
++ 1, /* step */
++ 1000); /* default number of lines */
++ ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
++ ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN,
++ 16, /* min, 16 = 1.0x */
++ 1023, /* max (10 bits) */
++ 1, /* step */
++ 32); /* default, 32 = 2.0x */
++ ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
++
++ if (sensor->ctrls.error) {
++ ret = sensor->ctrls.error;
++ dev_err(&client->dev, "%s control init failed (%d)\n",
++ __func__, ret);
++ goto error;
++ }
++ sensor->sd.ctrl_handler = &sensor->ctrls;
++
+ /* Set the default mode before we init the subdev */
+ sensor->mode = OV5647_DEFAULT_MODE;
+
+@@ -828,6 +999,7 @@ static int ov5647_probe(struct i2c_clien
+ error:
+ media_entity_cleanup(&sd->entity);
+ mutex_remove:
++ v4l2_ctrl_handler_free(&sensor->ctrls);
+ mutex_destroy(&sensor->lock);
+ return ret;
+ }
+@@ -839,6 +1011,7 @@ static int ov5647_remove(struct i2c_clie
+
+ v4l2_async_unregister_subdev(&ov5647->sd);
+ media_entity_cleanup(&ov5647->sd.entity);
++ v4l2_ctrl_handler_free(&ov5647->ctrls);
+ v4l2_device_unregister_subdev(sd);
+ mutex_destroy(&ov5647->lock);
+
--- /dev/null
+From 28c0004a54ce9b2c5862b38408952583b07458f9 Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:28 +0000
+Subject: [PATCH] media: ov5647: Add extra 10-bit sensor modes.
+
+The 8-bit VGA mode remains, we add the following 10-bit modes:
+
+Mode 0: 2592x1944 full resolution.
+
+Mode 1: 1920x1080 full resolution, but centre-cropped.
+(This mode achieves 30fps, mode 0 does not.)
+
+Mode 2: 1296x972 full field-of-view 2x2 binned mode.
+
+Mode 3: VGA full field of view mode.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 463 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 452 insertions(+), 11 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -111,6 +111,7 @@ struct ov5647 {
+ struct gpio_desc *pwdn;
+ unsigned int flags;
+ struct v4l2_ctrl_handler ctrls;
++ bool write_mode_regs;
+ };
+
+ static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+@@ -130,7 +131,7 @@ static struct regval_list sensor_oe_enab
+ {0x3002, 0xe4},
+ };
+
+-static struct regval_list ov5647_640x480[] = {
++static struct regval_list ov5647_640x480_8bit[] = {
+ {0x0100, 0x00},
+ {0x0103, 0x01},
+ {0x3034, 0x08},
+@@ -220,9 +221,378 @@ static struct regval_list ov5647_640x480
+ {0x0100, 0x01},
+ };
+
++static struct regval_list ov5647_2592x1944_10bit[] = {
++ {0x0100, 0x00},
++ {0x0103, 0x01},
++ {0x3034, 0x1a},
++ {0x3035, 0x21},
++ {0x3036, 0x69},
++ {0x303c, 0x11},
++ {0x3106, 0xf5},
++ {0x3821, 0x06},
++ {0x3820, 0x00},
++ {0x3827, 0xec},
++ {0x370c, 0x03},
++ {0x3612, 0x5b},
++ {0x3618, 0x04},
++ {0x5000, 0x06},
++ {0x5002, 0x41},
++ {0x5003, 0x08},
++ {0x5a00, 0x08},
++ {0x3000, 0x00},
++ {0x3001, 0x00},
++ {0x3002, 0x00},
++ {0x3016, 0x08},
++ {0x3017, 0xe0},
++ {0x3018, 0x44},
++ {0x301c, 0xf8},
++ {0x301d, 0xf0},
++ {0x3a18, 0x00},
++ {0x3a19, 0xf8},
++ {0x3c01, 0x80},
++ {0x3b07, 0x0c},
++ {0x380c, 0x0b},
++ {0x380d, 0x1c},
++ {0x380e, 0x07},
++ {0x380f, 0xb0},
++ {0x3814, 0x11},
++ {0x3815, 0x11},
++ {0x3708, 0x64},
++ {0x3709, 0x12},
++ {0x3808, 0x0a},
++ {0x3809, 0x20},
++ {0x380a, 0x07},
++ {0x380b, 0x98},
++ {0x3800, 0x00},
++ {0x3801, 0x00},
++ {0x3802, 0x00},
++ {0x3803, 0x00},
++ {0x3804, 0x0a},
++ {0x3805, 0x3f},
++ {0x3806, 0x07},
++ {0x3807, 0xa3},
++ {0x3811, 0x10},
++ {0x3813, 0x06},
++ {0x3630, 0x2e},
++ {0x3632, 0xe2},
++ {0x3633, 0x23},
++ {0x3634, 0x44},
++ {0x3636, 0x06},
++ {0x3620, 0x64},
++ {0x3621, 0xe0},
++ {0x3600, 0x37},
++ {0x3704, 0xa0},
++ {0x3703, 0x5a},
++ {0x3715, 0x78},
++ {0x3717, 0x01},
++ {0x3731, 0x02},
++ {0x370b, 0x60},
++ {0x3705, 0x1a},
++ {0x3f05, 0x02},
++ {0x3f06, 0x10},
++ {0x3f01, 0x0a},
++ {0x3a08, 0x01},
++ {0x3a09, 0x28},
++ {0x3a0a, 0x00},
++ {0x3a0b, 0xf6},
++ {0x3a0d, 0x08},
++ {0x3a0e, 0x06},
++ {0x3a0f, 0x58},
++ {0x3a10, 0x50},
++ {0x3a1b, 0x58},
++ {0x3a1e, 0x50},
++ {0x3a11, 0x60},
++ {0x3a1f, 0x28},
++ {0x4001, 0x02},
++ {0x4004, 0x04},
++ {0x4000, 0x09},
++ {0x4837, 0x19},
++ {0x4800, 0x24},
++ {0x3503, 0x03},
++ {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_1080p30_10bit[] = {
++ {0x0100, 0x00},
++ {0x0103, 0x01},
++ {0x3034, 0x1a},
++ {0x3035, 0x21},
++ {0x3036, 0x62},
++ {0x303c, 0x11},
++ {0x3106, 0xf5},
++ {0x3821, 0x06},
++ {0x3820, 0x00},
++ {0x3827, 0xec},
++ {0x370c, 0x03},
++ {0x3612, 0x5b},
++ {0x3618, 0x04},
++ {0x5000, 0x06},
++ {0x5002, 0x41},
++ {0x5003, 0x08},
++ {0x5a00, 0x08},
++ {0x3000, 0x00},
++ {0x3001, 0x00},
++ {0x3002, 0x00},
++ {0x3016, 0x08},
++ {0x3017, 0xe0},
++ {0x3018, 0x44},
++ {0x301c, 0xf8},
++ {0x301d, 0xf0},
++ {0x3a18, 0x00},
++ {0x3a19, 0xf8},
++ {0x3c01, 0x80},
++ {0x3b07, 0x0c},
++ {0x380c, 0x09},
++ {0x380d, 0x70},
++ {0x380e, 0x04},
++ {0x380f, 0x50},
++ {0x3814, 0x11},
++ {0x3815, 0x11},
++ {0x3708, 0x64},
++ {0x3709, 0x12},
++ {0x3808, 0x07},
++ {0x3809, 0x80},
++ {0x380a, 0x04},
++ {0x380b, 0x38},
++ {0x3800, 0x01},
++ {0x3801, 0x5c},
++ {0x3802, 0x01},
++ {0x3803, 0xb2},
++ {0x3804, 0x08},
++ {0x3805, 0xe3},
++ {0x3806, 0x05},
++ {0x3807, 0xf1},
++ {0x3811, 0x04},
++ {0x3813, 0x02},
++ {0x3630, 0x2e},
++ {0x3632, 0xe2},
++ {0x3633, 0x23},
++ {0x3634, 0x44},
++ {0x3636, 0x06},
++ {0x3620, 0x64},
++ {0x3621, 0xe0},
++ {0x3600, 0x37},
++ {0x3704, 0xa0},
++ {0x3703, 0x5a},
++ {0x3715, 0x78},
++ {0x3717, 0x01},
++ {0x3731, 0x02},
++ {0x370b, 0x60},
++ {0x3705, 0x1a},
++ {0x3f05, 0x02},
++ {0x3f06, 0x10},
++ {0x3f01, 0x0a},
++ {0x3a08, 0x01},
++ {0x3a09, 0x4b},
++ {0x3a0a, 0x01},
++ {0x3a0b, 0x13},
++ {0x3a0d, 0x04},
++ {0x3a0e, 0x03},
++ {0x3a0f, 0x58},
++ {0x3a10, 0x50},
++ {0x3a1b, 0x58},
++ {0x3a1e, 0x50},
++ {0x3a11, 0x60},
++ {0x3a1f, 0x28},
++ {0x4001, 0x02},
++ {0x4004, 0x04},
++ {0x4000, 0x09},
++ {0x4837, 0x19},
++ {0x4800, 0x34},
++ {0x3503, 0x03},
++ {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_2x2binned_10bit[] = {
++ {0x0100, 0x00},
++ {0x0103, 0x01},
++ {0x3034, 0x1A},
++ {0x3035, 0x21},
++ {0x3036, 0x62},
++ {0x303C, 0x11},
++ {0x3106, 0xF5},
++ {0x3827, 0xEC},
++ {0x370C, 0x03},
++ {0x3612, 0x59},
++ {0x3618, 0x00},
++ {0x5000, 0x06},
++ {0x5002, 0x41},
++ {0x5003, 0x08},
++ {0x5A00, 0x08},
++ {0x3000, 0x00},
++ {0x3001, 0x00},
++ {0x3002, 0x00},
++ {0x3016, 0x08},
++ {0x3017, 0xE0},
++ {0x3018, 0x44},
++ {0x301C, 0xF8},
++ {0x301D, 0xF0},
++ {0x3A18, 0x00},
++ {0x3A19, 0xF8},
++ {0x3C01, 0x80},
++ {0x3B07, 0x0C},
++ {0x3800, 0x00},
++ {0x3801, 0x00},
++ {0x3802, 0x00},
++ {0x3803, 0x00},
++ {0x3804, 0x0A},
++ {0x3805, 0x3F},
++ {0x3806, 0x07},
++ {0x3807, 0xA3},
++ {0x3808, 0x05},
++ {0x3809, 0x10},
++ {0x380A, 0x03},
++ {0x380B, 0xCC},
++ {0x380C, 0x07},
++ {0x380D, 0x68},
++ {0x3811, 0x0c},
++ {0x3813, 0x06},
++ {0x3814, 0x31},
++ {0x3815, 0x31},
++ {0x3630, 0x2E},
++ {0x3632, 0xE2},
++ {0x3633, 0x23},
++ {0x3634, 0x44},
++ {0x3636, 0x06},
++ {0x3620, 0x64},
++ {0x3621, 0xE0},
++ {0x3600, 0x37},
++ {0x3704, 0xA0},
++ {0x3703, 0x5A},
++ {0x3715, 0x78},
++ {0x3717, 0x01},
++ {0x3731, 0x02},
++ {0x370B, 0x60},
++ {0x3705, 0x1A},
++ {0x3F05, 0x02},
++ {0x3F06, 0x10},
++ {0x3F01, 0x0A},
++ {0x3A08, 0x01},
++ {0x3A09, 0x28},
++ {0x3A0A, 0x00},
++ {0x3A0B, 0xF6},
++ {0x3A0D, 0x08},
++ {0x3A0E, 0x06},
++ {0x3A0F, 0x58},
++ {0x3A10, 0x50},
++ {0x3A1B, 0x58},
++ {0x3A1E, 0x50},
++ {0x3A11, 0x60},
++ {0x3A1F, 0x28},
++ {0x4001, 0x02},
++ {0x4004, 0x04},
++ {0x4000, 0x09},
++ {0x4837, 0x16},
++ {0x4800, 0x24},
++ {0x3503, 0x03},
++ {0x3820, 0x41},
++ {0x3821, 0x07},
++ {0x380E, 0x05},
++ {0x380F, 0x9B},
++ {0x350A, 0x00},
++ {0x350B, 0x10},
++ {0x3500, 0x00},
++ {0x3501, 0x1A},
++ {0x3502, 0xF0},
++ {0x3212, 0xA0},
++ {0x0100, 0x01},
++};
++
++static struct regval_list ov5647_640x480_10bit[] = {
++ {0x0100, 0x00},
++ {0x0103, 0x01},
++ {0x3035, 0x11},
++ {0x3036, 0x46},
++ {0x303c, 0x11},
++ {0x3821, 0x07},
++ {0x3820, 0x41},
++ {0x370c, 0x03},
++ {0x3612, 0x59},
++ {0x3618, 0x00},
++ {0x5000, 0x06},
++ {0x5003, 0x08},
++ {0x5a00, 0x08},
++ {0x3000, 0xff},
++ {0x3001, 0xff},
++ {0x3002, 0xff},
++ {0x301d, 0xf0},
++ {0x3a18, 0x00},
++ {0x3a19, 0xf8},
++ {0x3c01, 0x80},
++ {0x3b07, 0x0c},
++ {0x380c, 0x07},
++ {0x380d, 0x3c},
++ {0x380e, 0x01},
++ {0x380f, 0xf8},
++ {0x3814, 0x35},
++ {0x3815, 0x35},
++ {0x3708, 0x64},
++ {0x3709, 0x52},
++ {0x3808, 0x02},
++ {0x3809, 0x80},
++ {0x380a, 0x01},
++ {0x380b, 0xe0},
++ {0x3800, 0x00},
++ {0x3801, 0x10},
++ {0x3802, 0x00},
++ {0x3803, 0x00},
++ {0x3804, 0x0a},
++ {0x3805, 0x2f},
++ {0x3806, 0x07},
++ {0x3807, 0x9f},
++ {0x3630, 0x2e},
++ {0x3632, 0xe2},
++ {0x3633, 0x23},
++ {0x3634, 0x44},
++ {0x3620, 0x64},
++ {0x3621, 0xe0},
++ {0x3600, 0x37},
++ {0x3704, 0xa0},
++ {0x3703, 0x5a},
++ {0x3715, 0x78},
++ {0x3717, 0x01},
++ {0x3731, 0x02},
++ {0x370b, 0x60},
++ {0x3705, 0x1a},
++ {0x3f05, 0x02},
++ {0x3f06, 0x10},
++ {0x3f01, 0x0a},
++ {0x3a08, 0x01},
++ {0x3a09, 0x2e},
++ {0x3a0a, 0x00},
++ {0x3a0b, 0xfb},
++ {0x3a0d, 0x02},
++ {0x3a0e, 0x01},
++ {0x3a0f, 0x58},
++ {0x3a10, 0x50},
++ {0x3a1b, 0x58},
++ {0x3a1e, 0x50},
++ {0x3a11, 0x60},
++ {0x3a1f, 0x28},
++ {0x4001, 0x02},
++ {0x4004, 0x02},
++ {0x4000, 0x09},
++ {0x3000, 0x00},
++ {0x3001, 0x00},
++ {0x3002, 0x00},
++ {0x3017, 0xe0},
++ {0x301c, 0xfc},
++ {0x3636, 0x06},
++ {0x3016, 0x08},
++ {0x3827, 0xec},
++ {0x3018, 0x44},
++ {0x3035, 0x21},
++ {0x3106, 0xf5},
++ {0x3034, 0x1a},
++ {0x301c, 0xf8},
++ {0x4800, 0x34},
++ {0x3503, 0x03},
++ {0x0100, 0x01},
++};
++
+ static struct ov5647_mode supported_modes_8bit[] = {
+ /*
+- * Original 8-bit VGA mode
++ * MODE 0: Original 8-bit VGA mode.
+ * Uncentred crop (top left quarter) from 2x2 binned 1296x972 image.
+ */
+ {
+@@ -233,14 +603,70 @@ static struct ov5647_mode supported_mode
+ .width = 640,
+ .height = 480
+ },
+- ov5647_640x480,
+- ARRAY_SIZE(ov5647_640x480)
++ ov5647_640x480_8bit,
++ ARRAY_SIZE(ov5647_640x480_8bit)
+ },
+- /* more modes below here... */
+ };
+
+ static struct ov5647_mode supported_modes_10bit[] = {
+- /* no 10-bit modes yet */
++ /*
++ * MODE 0: 2592x1944 full resolution full FOV 10-bit mode.
++ */
++ {
++ {
++ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .field = V4L2_FIELD_NONE,
++ .width = 2592,
++ .height = 1944
++ },
++ ov5647_2592x1944_10bit,
++ ARRAY_SIZE(ov5647_2592x1944_10bit)
++ },
++ /*
++ * MODE 1: 1080p30 10-bit mode.
++ * Full resolution centre-cropped down to 1080p.
++ */
++ {
++ {
++ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .field = V4L2_FIELD_NONE,
++ .width = 1920,
++ .height = 1080
++ },
++ ov5647_1080p30_10bit,
++ ARRAY_SIZE(ov5647_1080p30_10bit)
++ },
++ /*
++ * MODE 2: 2x2 binned full FOV 10-bit mode.
++ */
++ {
++ {
++ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .field = V4L2_FIELD_NONE,
++ .width = 1296,
++ .height = 972
++ },
++ ov5647_2x2binned_10bit,
++ ARRAY_SIZE(ov5647_2x2binned_10bit)
++ },
++ /*
++ * MODE 3: 10-bit VGA full FOV mode 60fps.
++ * 2x2 binned and subsampled down to VGA.
++ */
++ {
++ {
++ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
++ .colorspace = V4L2_COLORSPACE_SRGB,
++ .field = V4L2_FIELD_NONE,
++ .width = 640,
++ .height = 480
++ },
++ ov5647_640x480_10bit,
++ ARRAY_SIZE(ov5647_640x480_10bit)
++ },
+ };
+
+ /* Use original 8-bit VGA mode as default. */
+@@ -343,11 +769,14 @@ static int __sensor_init(struct v4l2_sub
+ if (ret < 0)
+ return ret;
+
+- ret = ov5647_write_array(sd, state->mode->reg_list,
+- state->mode->num_regs);
+- if (ret < 0) {
+- dev_err(&client->dev, "write sensor default regs error\n");
+- return ret;
++ if (state->write_mode_regs) {
++ ret = ov5647_write_array(sd, state->mode->reg_list,
++ state->mode->num_regs);
++ if (ret < 0) {
++ dev_err(&client->dev, "write sensor default regs error\n");
++ return ret;
++ }
++ state->write_mode_regs = false;
+ }
+
+ ret = ov5647_set_virtual_channel(sd, 0);
+@@ -475,6 +904,9 @@ static int ov5647_sensor_power(struct v4
+ "Camera not available, check Power\n");
+ goto out;
+ }
++
++ /* Write out the register set over I2C on stream-on. */
++ ov5647->write_mode_regs = true;
+ } else if (!on && ov5647->power_count == 1) {
+ dev_dbg(&client->dev, "OV5647 power off\n");
+
+@@ -650,6 +1082,12 @@ static int ov5647_set_fmt(struct v4l2_su
+ framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ *framefmt = format->format;
+ } else {
++ /*
++ * If we have changed modes, write the I2C register list on
++ * a stream_on().
++ */
++ if (state->mode != mode)
++ state->write_mode_regs = true;
+ state->mode = mode;
+ }
+
+@@ -967,6 +1405,9 @@ static int ov5647_probe(struct i2c_clien
+ /* Set the default mode before we init the subdev */
+ sensor->mode = OV5647_DEFAULT_MODE;
+
++ /* Write out the register set over I2C on stream-on. */
++ sensor->write_mode_regs = true;
++
+ sd = &sensor->sd;
+ v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
+ sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
--- /dev/null
+From 8bc19baeeca276374bed2d2ec95029d34fd93d7d Mon Sep 17 00:00:00 2001
+From: David Plowman <david.plowman@raspberrypi.com>
+Date: Wed, 29 Jan 2020 15:31:32 +0000
+Subject: [PATCH] media: ov5647: change defaults to better match raw
+ camera applications.
+
+Specifically:
+
+* AWB is now off by default.
+
+* AEC/AGC is also off by default.
+
+* The default mode is changed to the 10-bit 2x2 binned mode.
+
+AWB and AEC/AGC can be re-enabled using the usual V4L2 controls. The
+original 8-bit mode will be respected if an application requests the
+8-bit format.
+
+Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
+Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
+---
+ drivers/media/i2c/ov5647.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/media/i2c/ov5647.c
++++ b/drivers/media/i2c/ov5647.c
+@@ -669,8 +669,8 @@ static struct ov5647_mode supported_mode
+ },
+ };
+
+-/* Use original 8-bit VGA mode as default. */
+-#define OV5647_DEFAULT_MODE (&supported_modes_8bit[0])
++/* Use 2x2 binned 10-bit mode as default. */
++#define OV5647_DEFAULT_MODE (&supported_modes_10bit[2])
+
+ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+ {
+@@ -1367,18 +1367,18 @@ static int ov5647_probe(struct i2c_clien
+ 0, /* min */
+ 1, /* max */
+ 1, /* step */
+- 1); /* default */
++ 0); /* default */
+ v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, /* min */
+ 1, /* max */
+ 1, /* step */
+- 1); /* default */
++ 0); /* default */
+ v4l2_ctrl_new_std_menu(&sensor->ctrls, &ov5647_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO,
+ V4L2_EXPOSURE_MANUAL, /* max */
+ 0, /* skip_mask */
+- V4L2_EXPOSURE_AUTO); /* default */
++ V4L2_EXPOSURE_MANUAL); /* default */
+ ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ 4, /* min lines */
--- /dev/null
+From c0b2ca6abdde60a111fd6d3257be78c7f44e16ff Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime@cerno.tech>
+Date: Thu, 26 Dec 2019 15:44:31 +0100
+Subject: [PATCH] drm/vc4: fkms: Change crtc_state structure name to
+ avoid conflict
+
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -260,7 +260,7 @@ static inline struct vc4_crtc *to_vc4_cr
+ return container_of(crtc, struct vc4_crtc, base);
+ }
+
+-struct vc4_crtc_state {
++struct fkms_crtc_state {
+ struct drm_crtc_state base;
+
+ struct {
+@@ -271,10 +271,10 @@ struct vc4_crtc_state {
+ } margins;
+ };
+
+-static inline struct vc4_crtc_state *
+-to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++static inline struct fkms_crtc_state *
++to_fkms_crtc_state(struct drm_crtc_state *crtc_state)
+ {
+- return (struct vc4_crtc_state *)crtc_state;
++ return (struct fkms_crtc_state *)crtc_state;
+ }
+
+ struct vc4_fkms_encoder {
+@@ -410,7 +410,7 @@ static void vc4_fkms_crtc_get_margins(st
+ unsigned int *left, unsigned int *right,
+ unsigned int *top, unsigned int *bottom)
+ {
+- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct fkms_crtc_state *vc4_state = to_fkms_crtc_state(state);
+ struct drm_connector_state *conn_state;
+ struct drm_connector *conn;
+ int i;
+@@ -423,7 +423,7 @@ static void vc4_fkms_crtc_get_margins(st
+ /* We have to interate over all new connector states because
+ * vc4_fkms_crtc_get_margins() might be called before
+ * vc4_fkms_crtc_atomic_check() which means margins info in
+- * vc4_crtc_state might be outdated.
++ * fkms_crtc_state might be outdated.
+ */
+ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
+ if (conn_state->crtc != state->crtc)
+@@ -1068,7 +1068,7 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
+- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct fkms_crtc_state *vc4_state = to_fkms_crtc_state(state);
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ int i;
+@@ -1178,13 +1178,13 @@ static int vc4_page_flip(struct drm_crtc
+ static struct drm_crtc_state *
+ vc4_crtc_duplicate_state(struct drm_crtc *crtc)
+ {
+- struct vc4_crtc_state *vc4_state, *old_vc4_state;
++ struct fkms_crtc_state *vc4_state, *old_vc4_state;
+
+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+ if (!vc4_state)
+ return NULL;
+
+- old_vc4_state = to_vc4_crtc_state(crtc->state);
++ old_vc4_state = to_fkms_crtc_state(crtc->state);
+ vc4_state->margins = old_vc4_state->margins;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
--- /dev/null
+From 0d392a430d7dc84d8654972e9dbfa4d13009d3e8 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 24 Jan 2020 14:22:06 +0000
+Subject: [PATCH] drm/fourcc: Add packed 10bit YUV 4:2:0 format
+
+Adds a format that is 3 10bit YUV 4:2:0 samples packed into
+a 32bit work (with 2 spare bits).
+
+Supported on Broadcom BCM2711 chips.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/drm_fourcc.c | 3 +++
+ include/uapi/drm/drm_fourcc.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/gpu/drm/drm_fourcc.c
++++ b/drivers/gpu/drm/drm_fourcc.c
+@@ -274,6 +274,9 @@ const struct drm_format_info *__drm_form
+ { .format = DRM_FORMAT_YUV420_10BIT, .depth = 0,
+ .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
+ .is_yuv = true },
++ { .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2,
++ .char_per_block = { 4, 4, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 },
++ .hsub = 2, .vsub = 2, .is_yuv = true},
+ };
+
+ unsigned int i;
+--- a/include/uapi/drm/drm_fourcc.h
++++ b/include/uapi/drm/drm_fourcc.h
+@@ -266,6 +266,13 @@ extern "C" {
+ #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */
+
+ /*
++ * 2 plane YCbCr MSB aligned, 3 pixels packed into 4 bytes.
++ * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian
++ * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian
++ */
++#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */
++
++/*
+ * 3 plane YCbCr
+ * index 0: Y plane, [7:0] Y
+ * index 1: Cb plane, [7:0] Cb
+@@ -593,6 +600,10 @@ extern "C" {
+ * and UV. Some SAND-using hardware stores UV in a separate tiled
+ * image from Y to reduce the column height, which is not supported
+ * with these modifiers.
++ *
++ * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also
++ * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes
++ * wide, but as this is a 10 bpp format that translates to 96 pixels.
+ */
+
+ #define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \
--- /dev/null
+From 531d3d5c89825bade52f4257d264bbb06775a6fa Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Fri, 24 Jan 2020 14:24:33 +0000
+Subject: [PATCH] drm/vc4: Add DRM_FORMAT_P030 support to firmware-kms
+
+Adds support for this format which is 3 10bit samples packed into
+4 bytes, as used by the HEVC codec block.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 21 ++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc_image_types.h | 4 ++++
+ 2 files changed, 24 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -216,6 +216,10 @@ static const struct vc_image_format {
+ .vc_image = VC_IMAGE_YUV420SP,
+ .is_vu = 1,
+ },
++ {
++ .drm = DRM_FORMAT_P030,
++ .vc_image = VC_IMAGE_YUV10COL,
++ },
+ };
+
+ static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
+@@ -622,7 +626,15 @@ static int vc4_plane_to_mb(struct drm_pl
+ }
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+- mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ switch (mb->plane.vc_image_type) {
++ case VC_IMAGE_YUV420SP:
++ mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
++ break;
++ /* VC_IMAGE_YUV10COL could be included in here, but it is only
++ * valid as a SAND128 format, so the table at the top will have
++ * already set the correct format.
++ */
++ }
+ /* Note that the column pitch is passed across in lines, not
+ * bytes.
+ */
+@@ -707,6 +719,13 @@ static bool vc4_fkms_format_mod_supporte
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
+ return true;
+ 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_NV21:
+--- a/drivers/gpu/drm/vc4/vc_image_types.h
++++ b/drivers/gpu/drm/vc4/vc_image_types.h
+@@ -139,6 +139,10 @@ enum {
+ VC_IMAGE_YUV_UV_16,
+ /* YUV4:2:0 with U,V in side-by-side format */
+ VC_IMAGE_YUV420_S,
++ /* 10-bit YUV 420 column image format */
++ VC_IMAGE_YUV10COL,
++ /* 32-bpp, 10-bit R/G/B, 2-bit Alpha */
++ VC_IMAGE_RGBA1010102,
+
+ VC_IMAGE_MAX, /* bounds for error checking */
+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,