patches-6.12: bcm27xx: refresh patch set

The patches were generated from the RPi repo with the following command:
git format-patch v6.12.5..rpi-6.12.y

Then used update_kernel.sh to rebase against 6.12.5.

Removed wireless drivers, Github workflows, and defconfigs patches.
The following was used to flag potential patches to exclude:

ls|grep -i brcm
ls|grep -i github
ls|grep -i config
ls|grep -i readme

Also helpful to grep for keywords in patches to manually inspect
like: grep defconfig *.patch

Signed-off-by: John Audia <therealgraysky@proton.me>
This commit is contained in:
John Audia 2024-12-16 11:04:14 -05:00
parent 3bb0365112
commit f59f26ed47
690 changed files with 295008 additions and 0 deletions

View File

@ -0,0 +1,22 @@
From 99b87b80f2e12dfecaa0d63267769203ebb04d04 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 20 Apr 2020 13:41:10 +0100
Subject: [PATCH 004/697] Revert "spi: spidev: Fix CS polarity if GPIO
descriptors are used"
This reverts commit 83b2a8fe43bda0c11981ad6afa5dd0104d78be28.
---
drivers/spi/spidev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -428,7 +428,7 @@ spidev_ioctl(struct file *filp, unsigned
}
if (ctlr->use_gpio_descriptors && spi_get_csgpiod(spi, 0))
- tmp |= SPI_CS_HIGH;
+ { /*tmp |= SPI_CS_HIGH;*/ }
tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = tmp & SPI_MODE_USER_MASK;

View File

@ -0,0 +1,29 @@
From d1f6582242f7b5ee85a46b10c496957ee38e62b5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 7 Mar 2022 16:18:55 +0000
Subject: [PATCH 005/697] Revert "net: bcmgenet: Request APD, DLL disable and
IDDQ-SR"
This reverts commit c3a4c69360ab43560f212eed326c9d8bde35b14c, which
broke rebooting when network booting.
See: https://github.com/raspberrypi/rpi-eeprom/issues/417
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/net/ethernet/broadcom/genet/bcmmii.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -304,9 +304,7 @@ int bcmgenet_mii_probe(struct net_device
struct device_node *dn = kdev->of_node;
phy_interface_t phy_iface = priv->phy_interface;
struct phy_device *phydev;
- u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE |
- PHY_BRCM_DIS_TXCRXC_NOENRGY |
- PHY_BRCM_IDDQ_SUSPEND;
+ u32 phy_flags = 0;
int ret;
/* Communicate the integrated PHY revision */

View File

@ -0,0 +1,69 @@
From f7aff06f3804aef99910922397bf196cfaa5479e Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Mon, 31 Jul 2023 13:47:10 +0100
Subject: [PATCH 006/697] Revert "Revert "xhci: add quirk for host controllers
that don't update endpoint DCS""
This reverts commit 5bef4b3cb95a5b883dfec8b3ffc0d671323d55bb.
We don't agree with upstream revert so undo it.
---
drivers/usb/host/xhci-pci.c | 4 +++-
drivers/usb/host/xhci-ring.c | 23 ++++++++++++++++++++++-
2 files changed, 25 insertions(+), 2 deletions(-)
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -424,8 +424,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)
+ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) {
xhci->quirks |= XHCI_LPM_SUPPORT;
+ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
+ }
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) {
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -637,8 +637,11 @@ static int xhci_move_dequeue_past_td(str
struct xhci_ring *ep_ring;
struct xhci_command *cmd;
struct xhci_segment *new_seg;
+ struct xhci_segment *halted_seg = NULL;
union xhci_trb *new_deq;
int new_cycle;
+ union xhci_trb *halted_trb;
+ int index = 0;
dma_addr_t addr;
u64 hw_dequeue;
bool cycle_found = false;
@@ -657,7 +660,25 @@ static int xhci_move_dequeue_past_td(str
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
new_seg = ep_ring->deq_seg;
new_deq = ep_ring->dequeue;
- new_cycle = 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, td, 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];
+ new_cycle = halted_trb->generic.field[3] & 0x1;
+ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
+ (u8)(hw_dequeue & 0x1), index, new_cycle);
+ } else {
+ new_cycle = hw_dequeue & 0x1;
+ }
/*
* We want to find the pointer, segment and cycle state of the new trb

View File

@ -0,0 +1,156 @@
From faa6f87df4d488431743607a8158f15bdcb2afdd Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Fri, 2 Feb 2024 13:04:00 +0000
Subject: [PATCH 007/697] Revert "PCI: brcmstb: Configure HW CLKREQ# mode
appropriate for downstream device"
This reverts commit e2596dcf1e9dfd5904d50f796c19b03c94a3b8b4.
---
drivers/pci/controller/pcie-brcmstb.c | 100 +++-----------------------
1 file changed, 10 insertions(+), 90 deletions(-)
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -48,9 +48,6 @@
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
-#define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8
-#define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8
-
#define PCIE_RC_DL_MDIO_ADDR 0x1100
#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
@@ -127,12 +124,9 @@
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
-#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK 0x200000
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
-#define PCIE_CLKREQ_MASK \
- (PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK | \
- PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK)
+
#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac
#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_EN_MASK BIT(0)
@@ -1187,93 +1181,13 @@ static int brcm_pcie_setup(struct brcm_p
return 0;
}
-/*
- * This extends the timeout period for an access to an internal bus. This
- * access timeout may occur during L1SS sleep periods, even without the
- * presence of a PCIe access.
- */
-static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie)
-{
- /* TIMEOUT register is two registers before RGR1_SW_INIT_1 */
- const unsigned int REG_OFFSET = PCIE_RGR1_SW_INIT_1(pcie) - 8;
- u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */
-
- /* 7712 does not have this (RGR1) timer */
- if (pcie->soc_base == BCM7712)
- return;
-
- /* Each unit in timeout register is 1/216,000,000 seconds */
- writel(216 * timeout_us, pcie->base + REG_OFFSET);
-}
-
-static void brcm_config_clkreq(struct brcm_pcie *pcie)
-{
- static const char err_msg[] = "invalid 'brcm,clkreq-mode' DT string\n";
- const char *mode = "default";
- u32 clkreq_cntl;
- int ret, tmp;
-
- ret = of_property_read_string(pcie->np, "brcm,clkreq-mode", &mode);
- if (ret && ret != -EINVAL) {
- dev_err(pcie->dev, err_msg);
- mode = "safe";
- }
-
- /* Start out assuming safe mode (both mode bits cleared) */
- clkreq_cntl = readl(pcie->base + HARD_DEBUG(pcie));
- clkreq_cntl &= ~PCIE_CLKREQ_MASK;
-
- if (strcmp(mode, "no-l1ss") == 0) {
- /*
- * "no-l1ss" -- Provides Clock Power Management, L0s, and
- * L1, but cannot provide L1 substate (L1SS) power
- * savings. If the downstream device connected to the RC is
- * L1SS capable AND the OS enables L1SS, all PCIe traffic
- * may abruptly halt, potentially hanging the system.
- */
- clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
- /*
- * We want to un-advertise L1 substates because if the OS
- * tries to configure the controller into using L1 substate
- * power savings it may fail or hang when the RC HW is in
- * "no-l1ss" mode.
- */
- tmp = readl(pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP);
- u32p_replace_bits(&tmp, 2, PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK);
- writel(tmp, pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP);
-
- } else if (strcmp(mode, "default") == 0) {
- /*
- * "default" -- Provides L0s, L1, and L1SS, but not
- * compliant to provide Clock Power Management;
- * specifically, may not be able to meet the Tclron max
- * timing of 400ns as specified in "Dynamic Clock Control",
- * section 3.2.5.2.2 of the PCIe spec. This situation is
- * atypical and should happen only with older devices.
- */
- clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK;
- brcm_extend_rbus_timeout(pcie);
-
- } else {
- /*
- * "safe" -- No power savings; refclk is driven by RC
- * unconditionally.
- */
- if (strcmp(mode, "safe") != 0)
- dev_err(pcie->dev, err_msg);
- mode = "safe";
- }
- writel(clkreq_cntl, pcie->base + HARD_DEBUG(pcie));
-
- dev_info(pcie->dev, "clkreq-mode set to %s\n", mode);
-}
-
static int brcm_pcie_start_link(struct brcm_pcie *pcie)
{
struct device *dev = pcie->dev;
void __iomem *base = pcie->base;
u16 nlw, cls, lnksta;
bool ssc_good = false;
+ u32 tmp;
int ret, i;
/* Unassert the fundamental reset */
@@ -1300,8 +1214,6 @@ static int brcm_pcie_start_link(struct b
return -ENODEV;
}
- brcm_config_clkreq(pcie);
-
if (pcie->gen)
brcm_pcie_set_gen(pcie, pcie->gen);
@@ -1320,6 +1232,14 @@ static int brcm_pcie_start_link(struct b
pci_speed_string(pcie_link_speed[cls]), nlw,
ssc_good ? "(SSC)" : "(!SSC)");
+ /*
+ * 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;
}

View File

@ -0,0 +1,52 @@
From fee8daf3147a30ddbfe2ac759ee5b7481bace2ca Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Wed, 31 Jan 2024 19:47:39 +0000
Subject: [PATCH 008/697] Revert "ARM: dts: bcm2711: Add BCM2711 xHCI support"
This reverts commit 522c35e08b53f157ad3e51848caa861b258001e4.
---
arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi | 5 -----
arch/arm/boot/dts/broadcom/bcm2711.dtsi | 14 --------------
2 files changed, 19 deletions(-)
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "bcm2835-rpi.dtsi"
-#include <dt-bindings/power/raspberrypi-power.h>
#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
/ {
@@ -101,7 +100,3 @@
&vchiq {
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
};
-
-&xhci {
- power-domains = <&power RPI_POWER_DOMAIN_USB>;
-};
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -604,20 +604,6 @@
};
};
- xhci: usb@7e9c0000 {
- compatible = "brcm,bcm2711-xhci", "brcm,xhci-brcm-v2";
- reg = <0x0 0x7e9c0000 0x100000>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
- /* DWC2 and this IP block share the same USB PHY,
- * enabling both at the same time results in lockups.
- * So keep this node disabled and let the bootloader
- * decide which interface should be enabled.
- */
- status = "disabled";
- };
-
v3d: gpu@7ec00000 {
compatible = "brcm,2711-v3d";
reg = <0x0 0x7ec00000 0x4000>,

View File

@ -0,0 +1,26 @@
From 3063c20ced293f1f214fa77b71adac0ce3385d81 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 28 Mar 2024 16:16:37 +0000
Subject: [PATCH 009/697] Revert "usb: phy: generic: Get the vbus supply"
This reverts commit 03e607cbb2931374db1825f371e9c7f28526d3f4.
---
drivers/usb/phy/phy-generic.c | 7 -------
1 file changed, 7 deletions(-)
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -256,13 +256,6 @@ int usb_phy_gen_create_phy(struct device
return dev_err_probe(dev, PTR_ERR(nop->vcc),
"could not get vcc regulator\n");
- nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus");
- if (PTR_ERR(nop->vbus_draw) == -ENODEV)
- nop->vbus_draw = NULL;
- if (IS_ERR(nop->vbus_draw))
- return dev_err_probe(dev, PTR_ERR(nop->vbus_draw),
- "could not get vbus regulator\n");
-
nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";

View File

@ -0,0 +1,102 @@
From c1d90b3d7f207b203d8f8b32e02dbd1d7636cb6a Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Thu, 7 Apr 2022 18:23:07 +0100
Subject: [PATCH 010/697] raspberrypi-firmware: Update mailbox commands
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
include/soc/bcm2835/raspberrypi-firmware.h | 28 +++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -36,6 +36,8 @@ struct rpi_firmware_property_tag_header
enum rpi_firmware_property_tag {
RPI_FIRMWARE_PROPERTY_END = 0,
RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
+ RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
+ RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003,
RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
@@ -71,6 +73,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,
@@ -89,8 +92,11 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
- RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
+ RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00038049,
+ RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 0x00030050,
RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
+ RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064,
+ RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064,
RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066,
/* Dispmanx TAGS */
@@ -105,9 +111,16 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e,
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,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
@@ -116,22 +129,33 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d,
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008,
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d,
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
+ RPI_FIRMWARE_SET_PLANE = 0x00048015,
+ 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,
};
@@ -155,6 +179,8 @@ enum rpi_firmware_clk_id {
RPI_FIRMWARE_NUM_CLK_ID,
};
+#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64
+
/**
* struct rpi_firmware_clk_rate_request - Firmware Request for a rate
* @id: ID of the clock being queried

View File

@ -0,0 +1,24 @@
From fce77d9309edd4d813e45ea2868a6a3307787193 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 7 Jan 2021 16:30:55 +0000
Subject: [PATCH 011/697] drm/atomic: Don't fixup modes that haven't been reset
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/drm_atomic_helper.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -444,6 +444,11 @@ mode_fixup(struct drm_atomic_state *stat
new_crtc_state =
drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
+ if (!new_crtc_state->mode_changed &&
+ !new_crtc_state->connectors_changed) {
+ continue;
+ }
+
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call ->mode_fixup twice.

View File

@ -0,0 +1,30 @@
From 6030529dd021bc882eb9ade9eec009c77c40316e Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 2 Nov 2021 16:01:36 +0000
Subject: [PATCH 012/697] drm: Check whether the gamma lut has changed before
updating
drm_crtc_legacy_gamma_set updates the gamma_lut blob unconditionally,
which leads to unnecessary reprogramming of hardware.
Check whether the blob contents has actually changed before
signalling that it has been updated.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/drm_color_mgmt.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -330,7 +330,9 @@ static int drm_crtc_legacy_gamma_set(str
replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
use_gamma_lut ? NULL : blob);
replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
- replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
+ if (!crtc_state->gamma_lut || !crtc_state->gamma_lut->data ||
+ memcmp(crtc_state->gamma_lut->data, blob_data, blob->length))
+ replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
use_gamma_lut ? blob : NULL);
crtc_state->color_mgmt_changed |= replaced;

View File

@ -0,0 +1,76 @@
From 4d523d624f8ac39c56c431d411750c11492d5dbe Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 17 Dec 2021 13:36:52 +0000
Subject: [PATCH 013/697] drm/dsi: Document the meaning and spec references for
MIPI_DSI_MODE_*
The MIPI_DSI_MODE_* flags have fairly terse descriptions and no reference
to the DSI specification as to their exact meaning. Usage has therefore
been rather fluid.
Extend the descriptions and provide references to the part of the
MIPI DSI specification regarding what they mean.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
include/drm/drm_mipi_dsi.h | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -114,29 +114,43 @@ struct mipi_dsi_host *of_find_mipi_dsi_h
/* DSI mode flags */
-/* video mode */
+/* Video mode display.
+ * Not set denotes a command mode display.
+ */
#define MIPI_DSI_MODE_VIDEO BIT(0)
-/* video burst mode */
+/* Video burst mode.
+ * Link frequency to be configured via platform configuration.
+ * This should always be set in conjunction with MIPI_DSI_MODE_VIDEO.
+ * (DSI spec V1.1 8.11.4)
+ */
#define MIPI_DSI_MODE_VIDEO_BURST BIT(1)
-/* video pulse mode */
+/* Video pulse mode.
+ * Not set denotes sync event mode. (DSI spec V1.1 8.11.2)
+ */
#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2)
-/* enable auto vertical count mode */
+/* Enable auto vertical count mode */
#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3)
-/* enable hsync-end packets in vsync-pulse and v-porch area */
+/* Enable hsync-end packets in vsync-pulse and v-porch area */
#define MIPI_DSI_MODE_VIDEO_HSE BIT(4)
-/* disable hfront-porch area */
+/* Transmit NULL packets or LP mode during hfront-porch area.
+ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1)
+ */
#define MIPI_DSI_MODE_VIDEO_NO_HFP BIT(5)
-/* disable hback-porch area */
+/* Transmit NULL packets or LP mode during hback-porch area.
+ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1)
+ */
#define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6)
-/* disable hsync-active area */
+/* Transmit NULL packets or LP mode during hsync-active area.
+ * Not set denotes sending a blanking packet instead. (DSI spec V1.1 8.11.1)
+ */
#define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7)
-/* flush display FIFO on vsync pulse */
+/* Flush display FIFO on vsync pulse */
#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
-/* disable EoT packets in HS mode */
+/* Disable EoT packets in HS mode. (DSI spec V1.1 8.1) */
#define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9)
-/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
+/* Device supports non-continuous clock behavior (DSI spec V1.1 5.6.1) */
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
-/* transmit data in low power */
+/* Transmit data in low power */
#define MIPI_DSI_MODE_LPM BIT(11)
/* transmit data ending at the same time for all lanes within one hsync */
#define MIPI_DSI_HS_PKT_END_ALIGNED BIT(12)

View File

@ -0,0 +1,25 @@
From 5be301d72c1923bf6fbcf43f6dea728f50702cee Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 20 Jan 2022 17:29:36 +0000
Subject: [PATCH 014/697] drm/bridge: tc358762: Ignore EPROBE_DEFER when
logging errors
mipi_dsi_attach can fail due to resources not being available
yet, therefore do not log error messages should they occur.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/bridge/tc358762.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/gpu/drm/bridge/tc358762.c
+++ b/drivers/gpu/drm/bridge/tc358762.c
@@ -294,7 +294,7 @@ static int tc358762_probe(struct mipi_ds
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
drm_bridge_remove(&ctx->bridge);
- dev_err(dev, "failed to attach dsi\n");
+ dev_err_probe(dev, ret, "failed to attach dsi\n");
}
return ret;

View File

@ -0,0 +1,170 @@
From d234bb9caf5309340b7afdb7e8bf6f8ae346eab8 Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Wed, 26 Jan 2022 15:58:13 +0000
Subject: [PATCH 015/697] drm: Add chroma siting properties
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 14 +++++++++
drivers/gpu/drm/drm_atomic_uapi.c | 8 +++++
drivers/gpu/drm/drm_color_mgmt.c | 36 +++++++++++++++++++++++
include/drm/drm_color_mgmt.h | 3 ++
include/drm/drm_plane.h | 35 ++++++++++++++++++++--
5 files changed, 94 insertions(+), 2 deletions(-)
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -267,6 +267,20 @@ void __drm_atomic_helper_plane_state_res
plane_state->color_range = val;
}
+ if (plane->chroma_siting_h_property) {
+ if (!drm_object_property_get_default_value(&plane->base,
+ plane->chroma_siting_h_property,
+ &val))
+ plane_state->chroma_siting_h = val;
+ }
+
+ if (plane->chroma_siting_v_property) {
+ if (!drm_object_property_get_default_value(&plane->base,
+ plane->chroma_siting_v_property,
+ &val))
+ plane_state->chroma_siting_v = val;
+ }
+
if (plane->zpos_property) {
if (!drm_object_property_get_default_value(&plane->base,
plane->zpos_property,
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -538,6 +538,10 @@ static int drm_atomic_plane_set_property
state->color_encoding = val;
} else if (property == plane->color_range_property) {
state->color_range = val;
+ } else if (property == plane->chroma_siting_h_property) {
+ state->chroma_siting_h = val;
+ } else if (property == plane->chroma_siting_v_property) {
+ state->chroma_siting_v = val;
} else if (property == config->prop_fb_damage_clips) {
ret = drm_property_replace_blob_from_id(dev,
&state->fb_damage_clips,
@@ -620,6 +624,10 @@ drm_atomic_plane_get_property(struct drm
*val = state->color_encoding;
} else if (property == plane->color_range_property) {
*val = state->color_range;
+ } else if (property == plane->chroma_siting_h_property) {
+ *val = state->chroma_siting_h;
+ } else if (property == plane->chroma_siting_v_property) {
+ *val = state->chroma_siting_v;
} else if (property == config->prop_fb_damage_clips) {
*val = (state->fb_damage_clips) ?
state->fb_damage_clips->base.id : 0;
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -591,6 +591,42 @@ int drm_plane_create_color_properties(st
EXPORT_SYMBOL(drm_plane_create_color_properties);
/**
+ * drm_plane_create_chroma_siting_properties - chroma siting related plane properties
+ * @plane: plane object
+ *
+ * Create and attach plane specific CHROMA_SITING
+ * properties to @plane.
+ */
+int drm_plane_create_chroma_siting_properties(struct drm_plane *plane,
+ int32_t default_chroma_siting_h,
+ int32_t default_chroma_siting_v)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_property *prop;
+
+ prop = drm_property_create_range(dev, 0, "CHROMA_SITING_H",
+ 0, 1<<16);
+ if (!prop)
+ return -ENOMEM;
+ plane->chroma_siting_h_property = prop;
+ drm_object_attach_property(&plane->base, prop, default_chroma_siting_h);
+
+ prop = drm_property_create_range(dev, 0, "CHROMA_SITING_V",
+ 0, 1<<16);
+ if (!prop)
+ return -ENOMEM;
+ plane->chroma_siting_v_property = prop;
+ drm_object_attach_property(&plane->base, prop, default_chroma_siting_v);
+
+ if (plane->state) {
+ plane->state->chroma_siting_h = default_chroma_siting_h;
+ plane->state->chroma_siting_v = default_chroma_siting_v;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(drm_plane_create_chroma_siting_properties);
+
+/**
* drm_color_lut_check - check validity of lookup table
* @lut: property blob containing LUT to check
* @tests: bitmask of tests to run
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -91,6 +91,9 @@ int drm_plane_create_color_properties(st
enum drm_color_encoding default_encoding,
enum drm_color_range default_range);
+int drm_plane_create_chroma_siting_properties(struct drm_plane *plane,
+ int32_t default_chroma_siting_h, int32_t default_chroma_siting_v);
+
/**
* enum drm_color_lut_tests - hw-specific LUT tests to perform
*
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -184,6 +184,24 @@ struct drm_plane_state {
enum drm_color_range color_range;
/**
+ * @chroma_siting_h:
+ *
+ * Location of chroma samples horizontally compared to luma
+ * 0 means chroma is sited with left luma
+ * 0x8000 is interstitial. 0x10000 is sited with right luma
+ */
+ int32_t chroma_siting_h;
+
+ /**
+ * @chroma_siting_v:
+ *
+ * Location of chroma samples vertically compared to luma
+ * 0 means chroma is sited with top luma
+ * 0x8000 is interstitial. 0x10000 is sited with bottom luma
+ */
+ int32_t chroma_siting_v;
+
+ /**
* @fb_damage_clips:
*
* Blob representing damage (area in plane framebuffer that changed
@@ -783,9 +801,22 @@ struct drm_plane {
struct drm_property *hotspot_y_property;
/**
- * @kmsg_panic: Used to register a panic notifier for this plane
+ * @chroma_siting_h_property:
+ *
+ * Optional "CHROMA_SITING_H" property for specifying
+ * chroma siting for YUV formats.
+ * See drm_plane_create_chroma_siting_properties().
+ */
+ struct drm_property *chroma_siting_h_property;
+
+ /**
+ * @chroma_siting_v_property:
+ *
+ * Optional "CHROMA_SITING_V" property for specifying
+ * chroma siting for YUV formats.
+ * See drm_plane_create_chroma_siting_properties().
*/
- struct kmsg_dumper kmsg_panic;
+ struct drm_property *chroma_siting_v_property;
};
#define obj_to_plane(x) container_of(x, struct drm_plane, base)

View File

@ -0,0 +1,121 @@
From fa34363447ef39ae5b02c350ae2650cd4c1308f6 Mon Sep 17 00:00:00 2001
From: Daniel Vetter <daniel.vetter@ffwll.ch>
Date: Fri, 23 Oct 2020 14:39:23 +0200
Subject: [PATCH 016/697] drm/atomic-helpers: remove legacy_cursor_update hacks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The stuff never really worked, and leads to lots of fun because it
out-of-order frees atomic states. Which upsets KASAN, among other
things.
For async updates we now have a more solid solution with the
->atomic_async_check and ->atomic_async_commit hooks. Support for that
for msm and vc4 landed. nouveau and i915 have their own commit
routines, doing something similar.
For everyone else it's probably better to remove the use-after-free
bug, and encourage folks to use the async support instead. The
affected drivers which register a legacy cursor plane and don't either
use the new async stuff or their own commit routine are: amdgpu,
atmel, mediatek, qxl, rockchip, sti, sun4i, tegra, virtio, and vmwgfx.
Inspired by an amdgpu bug report.
v2: Drop RFC, I think with amdgpu converted over to use
atomic_async_check/commit done in
commit 674e78acae0dfb4beb56132e41cbae5b60f7d662
Author: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Date: Wed Dec 5 14:59:07 2018 -0500
drm/amd/display: Add fast path for cursor plane updates
we don't have any driver anymore where we have userspace expecting
solid legacy cursor support _and_ they are using the atomic helpers in
their fully glory. So we can retire this.
v3: Paper over msm and i915 regression. The complete_all is the only
thing missing afaict.
v4: Rebased on recent kernel, added extra link for vc4 bug.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199425
Link: https://lore.kernel.org/all/20220221134155.125447-9-maxime@cerno.tech/
Cc: mikita.lipski@amd.com
Cc: Michel Dänzer <michel@daenzer.net>
Cc: harry.wentland@amd.com
Cc: Rob Clark <robdclark@gmail.com>
Cc: "Kazlauskas, Nicholas" <nicholas.kazlauskas@amd.com>
Tested-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/drm_atomic_helper.c | 13 -------------
drivers/gpu/drm/i915/display/intel_display.c | 13 +++++++++++++
drivers/gpu/drm/msm/msm_atomic.c | 2 ++
3 files changed, 15 insertions(+), 13 deletions(-)
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1656,13 +1656,6 @@ drm_atomic_helper_wait_for_vblanks(struc
int i, ret;
unsigned int crtc_mask = 0;
- /*
- * Legacy cursor ioctls are completely unsynced, and userspace
- * relies on that (by doing tons of cursor updates).
- */
- if (old_state->legacy_cursor_update)
- return;
-
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
if (!new_crtc_state->active)
continue;
@@ -2311,12 +2304,6 @@ int drm_atomic_helper_setup_commit(struc
complete_all(&commit->flip_done);
continue;
}
-
- /* Legacy cursor updates are fully unsynced. */
- if (state->legacy_cursor_update) {
- complete_all(&commit->flip_done);
- continue;
- }
if (!new_crtc_state->event) {
commit->event = kzalloc(sizeof(*commit->event),
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7648,6 +7648,19 @@ int intel_atomic_commit(struct drm_devic
state->base.legacy_cursor_update = false;
}
+ /*
+ * FIXME: Cut over to (async) commit helpers instead of hand-rolling
+ * everything.
+ */
+ if (state->base.legacy_cursor_update) {
+ struct intel_crtc_state *new_crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
+ complete_all(&new_crtc_state->uapi.commit->flip_done);
+ }
+
ret = intel_atomic_prepare_commit(state);
if (ret) {
drm_dbg_atomic(&dev_priv->drm,
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -242,6 +242,8 @@ void msm_atomic_commit_tail(struct drm_a
/* async updates are limited to single-crtc updates: */
WARN_ON(crtc_mask != drm_crtc_mask(async_crtc));
+ complete_all(&async_crtc->state->commit->flip_done);
+
/*
* Start timer if we don't already have an update pending
* on this crtc:

View File

@ -0,0 +1,60 @@
From 5350800c62c07a2f1e90332039a09d3be55b960b Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 1 Apr 2022 17:10:37 +0100
Subject: [PATCH 017/697] drm/atomic: If margins are updated, update all
planes.
Margins may be implemented by scaling the planes, but as there
is no way of intercepting the set_property for a standard property,
and all planes are checked in drm_atomic_check_only before the
connectors, there's now way to add the planes into the state
from the driver.
If the margin properties change, add all corresponding planes to
the state.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/gpu/drm/drm_atomic_uapi.c | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -679,6 +679,7 @@ static int drm_atomic_connector_set_prop
{
struct drm_device *dev = connector->dev;
struct drm_mode_config *config = &dev->mode_config;
+ bool margins_updated = false;
bool replaced = false;
int ret;
@@ -707,12 +708,16 @@ static int drm_atomic_connector_set_prop
state->tv.subconnector = val;
} else if (property == config->tv_left_margin_property) {
state->tv.margins.left = val;
+ margins_updated = true;
} else if (property == config->tv_right_margin_property) {
state->tv.margins.right = val;
+ margins_updated = true;
} else if (property == config->tv_top_margin_property) {
state->tv.margins.top = val;
+ margins_updated = true;
} else if (property == config->tv_bottom_margin_property) {
state->tv.margins.bottom = val;
+ margins_updated = true;
} else if (property == config->legacy_tv_mode_property) {
state->tv.legacy_mode = val;
} else if (property == config->tv_mode_property) {
@@ -797,6 +802,12 @@ static int drm_atomic_connector_set_prop
return -EINVAL;
}
+ if (margins_updated && state->crtc) {
+ ret = drm_atomic_add_affected_planes(state->state, state->crtc);
+
+ return ret;
+ }
+
return 0;
}

View File

@ -0,0 +1,24 @@
From 4cdcf8e2c3eb6acfce367b06f0e3a82529ad8a20 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime@cerno.tech>
Date: Mon, 6 Jun 2022 11:02:16 +0200
Subject: [PATCH 018/697] arm64: setup: Fix build warning
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
arch/arm64/kernel/setup.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -214,9 +214,9 @@ static void __init request_standard_reso
size_t res_size;
kernel_code.start = __pa_symbol(_stext);
- kernel_code.end = __pa_symbol(__init_begin - 1);
+ kernel_code.end = __pa_symbol(__init_begin) - 1;
kernel_data.start = __pa_symbol(_sdata);
- kernel_data.end = __pa_symbol(_end - 1);
+ kernel_data.end = __pa_symbol(_end) - 1;
insert_resource(&iomem_resource, &kernel_code);
insert_resource(&iomem_resource, &kernel_data);

View File

@ -0,0 +1,25 @@
From 0c982a65617ddab7a80b88d8293022f657857ae4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 9 Sep 2019 15:49:56 +0100
Subject: [PATCH 021/697] 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
@@ -153,7 +153,7 @@ static int raspberrypi_clock_property(st
struct raspberrypi_firmware_prop msg = {
.id = cpu_to_le32(data->id),
.val = cpu_to_le32(*val),
- .disable_turbo = cpu_to_le32(1),
+ .disable_turbo = cpu_to_le32(0),
};
int ret;

View File

@ -0,0 +1,70 @@
From e0060fa6ffa45d46235ba9565b26619e8e0c2367 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime@cerno.tech>
Date: Mon, 11 Jul 2022 15:58:36 +0200
Subject: [PATCH 022/697] clk: bcm: rpi: Create helper to retrieve private data
The RaspberryPi firmware clocks driver uses in several instances a
container_of to retrieve the struct raspberrypi_clk_data from a pointer
to struct clk_hw. Let's create a small function to avoid duplicating it
all over the place.
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/clk/bcm/clk-raspberrypi.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -56,6 +56,12 @@ struct raspberrypi_clk_data {
struct raspberrypi_clk *rpi;
};
+static inline
+const struct raspberrypi_clk_data *clk_hw_to_data(const struct clk_hw *hw)
+{
+ return container_of(hw, struct raspberrypi_clk_data, hw);
+}
+
struct raspberrypi_clk_variant {
bool export;
char *clkdev;
@@ -168,8 +174,7 @@ static int raspberrypi_clock_property(st
static int raspberrypi_fw_is_prepared(struct clk_hw *hw)
{
- struct raspberrypi_clk_data *data =
- container_of(hw, struct raspberrypi_clk_data, hw);
+ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
@@ -186,8 +191,7 @@ static int raspberrypi_fw_is_prepared(st
static unsigned long raspberrypi_fw_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- struct raspberrypi_clk_data *data =
- container_of(hw, struct raspberrypi_clk_data, hw);
+ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 val = 0;
int ret;
@@ -203,8 +207,7 @@ static unsigned long raspberrypi_fw_get_
static int raspberrypi_fw_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
- struct raspberrypi_clk_data *data =
- container_of(hw, struct raspberrypi_clk_data, hw);
+ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
struct raspberrypi_clk *rpi = data->rpi;
u32 _rate = rate;
int ret;
@@ -221,8 +224,7 @@ static int raspberrypi_fw_set_rate(struc
static int raspberrypi_fw_dumb_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
- struct raspberrypi_clk_data *data =
- container_of(hw, struct raspberrypi_clk_data, hw);
+ const struct raspberrypi_clk_data *data = clk_hw_to_data(hw);
struct raspberrypi_clk_variant *variant = data->variant;
/*

View File

@ -0,0 +1,85 @@
From 23af1bc548742e8d20a57ae703c5646c7f70e20a Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Tue, 12 Apr 2022 20:07:20 +0100
Subject: [PATCH 023/697] clk-raspberrypi: Add ISP to exported clocks
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
clk-raspberrypi: Enable minimize for all firmware clocks
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
clk: bcm: rpi: Add disp clock
BCM2712 has an extra clock exposed by the firmware called DISP, and used
by (at least) the HVS. Let's add it to the list of clocks to register in
Linux.
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
clk: bcm: rpi: Add the BCM283x pixel clock.
The clk-bcm2835 handling of the pixel clock does not function
correctly when the HDMI power domain is disabled.
The firmware supports it correctly, so add it to the
firmware clock driver.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/clk/bcm/clk-raspberrypi.c | 14 ++++++++++++++
include/soc/bcm2835/raspberrypi-firmware.h | 1 +
2 files changed, 15 insertions(+)
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
@@ -34,6 +34,7 @@ static char *rpi_firmware_clk_names[] =
[RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc",
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb",
[RPI_FIRMWARE_VEC_CLK_ID] = "vec",
+ [RPI_FIRMWARE_DISP_CLK_ID] = "disp",
};
#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0)
@@ -117,18 +118,31 @@ raspberrypi_clk_variants[RPI_FIRMWARE_NU
},
[RPI_FIRMWARE_V3D_CLK_ID] = {
.export = true,
+ .minimize = true,
},
[RPI_FIRMWARE_PIXEL_CLK_ID] = {
.export = true,
+ .minimize = true,
},
[RPI_FIRMWARE_HEVC_CLK_ID] = {
.export = true,
+ .minimize = true,
+ },
+ [RPI_FIRMWARE_ISP_CLK_ID] = {
+ .export = true,
+ .minimize = true,
},
[RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = {
.export = true,
+ .minimize = true,
},
[RPI_FIRMWARE_VEC_CLK_ID] = {
.export = true,
+ .minimize = true,
+ },
+ [RPI_FIRMWARE_DISP_CLK_ID] = {
+ .export = true,
+ .minimize = true,
},
};
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -176,6 +176,7 @@ enum rpi_firmware_clk_id {
RPI_FIRMWARE_M2MC_CLK_ID,
RPI_FIRMWARE_PIXEL_BVB_CLK_ID,
RPI_FIRMWARE_VEC_CLK_ID,
+ RPI_FIRMWARE_DISP_CLK_ID,
RPI_FIRMWARE_NUM_CLK_ID,
};

View File

@ -0,0 +1,83 @@
From cee2529d24e48051fff96a9f2d4740f5c3661f7e Mon Sep 17 00:00:00 2001
From: Martin Sperl <kernel@martin.sperl.org>
Date: Fri, 2 Sep 2016 16:45:27 +0100
Subject: [PATCH 024/697] clk: clk-bcm2835: Register the clocks early during
the boot process
so that special/critical clocks can get enabled early on in the
boot process avoiding the risk of disabling a clock, pll_divider
or pll when a claiming driver fails to install propperly - maybe it needs to defer.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
clk: clk-bcm2835: Use %zd when printing size_t
The debug text for how many clocks have been registered
uses "%d" with a size_t. Correct it to "%zd".
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
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>
clk-bcm2835: use subsys_initcall for the clock driver when IMA is enabled
Co-authored-by: Davide Scovotto <scovottodavide@gmail.com>
Co-developed-by: Davide Scovotto <scovottodavide@gmail.com>
Signed-off-by: Davide Scovotto <scovottodavide@gmail.com>
Signed-off-by: Alberto Solavagione <albertosolavagione30@gmail.com>
---
drivers/clk/bcm/clk-bcm2835.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -2319,8 +2319,15 @@ static int bcm2835_clk_probe(struct plat
if (ret)
return ret;
- return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
&cprman->onecell);
+ if (ret)
+ return ret;
+
+ /* note that we have registered all the clocks */
+ dev_dbg(dev, "registered %zd clocks\n", asize);
+
+ return 0;
}
static const struct cprman_plat_data cprman_bcm2835_plat_data = {
@@ -2346,7 +2353,15 @@ static struct platform_driver bcm2835_cl
.probe = bcm2835_clk_probe,
};
-builtin_platform_driver(bcm2835_clk_driver);
+static int __init __bcm2835_clk_driver_init(void)
+{
+ return platform_driver_register(&bcm2835_clk_driver);
+}
+#ifdef CONFIG_IMA
+subsys_initcall(__bcm2835_clk_driver_init);
+#else
+postcore_initcall(__bcm2835_clk_driver_init);
+#endif
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("BCM2835 clock driver");

View File

@ -0,0 +1,28 @@
From 4333d849f06982afd3a6633e51afe448224305a5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 13 Feb 2017 17:20:08 +0000
Subject: [PATCH 025/697] clk-bcm2835: Mark used PLLs and dividers CRITICAL
The VPU configures and relies on several PLLs and dividers. Mark all
enabled dividers and their PLLs as CRITICAL to prevent the kernel from
switching them off.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/clk/bcm/clk-bcm2835.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1407,6 +1407,11 @@ bcm2835_register_pll_divider(struct bcm2
divider->div.hw.init = &init;
divider->div.table = NULL;
+ if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) {
+ init.flags |= CLK_IS_CRITICAL;
+ divider->div.flags |= CLK_IS_CRITICAL;
+ }
+
divider->cprman = cprman;
divider->data = divider_data;

View File

@ -0,0 +1,118 @@
From f9d8149791e2cbe06cf656182c53ee29f5cd9972 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 13 Feb 2017 17:20:08 +0000
Subject: [PATCH 026/697] clk-bcm2835: Add claim-clocks property
The claim-clocks property can be used to prevent PLLs and dividers
from being marked as critical. It contains a vector of clock IDs,
as defined by dt-bindings/clock/bcm2835.h.
Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and
PLLH_PIX for the vc4_kms_v3d driver.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/clk/bcm/clk-bcm2835.c | 43 +++++++++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1335,6 +1335,8 @@ static const struct clk_ops bcm2835_vpu_
.debug_init = bcm2835_clock_debug_init,
};
+static bool bcm2835_clk_is_claimed(const char *name);
+
static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
const void *data)
{
@@ -1352,6 +1354,9 @@ static struct clk_hw *bcm2835_register_p
init.ops = &bcm2835_pll_clk_ops;
init.flags = pll_data->flags | CLK_IGNORE_UNUSED;
+ if (!bcm2835_clk_is_claimed(pll_data->name))
+ init.flags |= CLK_IS_CRITICAL;
+
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return NULL;
@@ -1408,8 +1413,10 @@ bcm2835_register_pll_divider(struct bcm2
divider->div.table = NULL;
if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) {
- init.flags |= CLK_IS_CRITICAL;
- divider->div.flags |= CLK_IS_CRITICAL;
+ if (!bcm2835_clk_is_claimed(divider_data->source_pll))
+ init.flags |= CLK_IS_CRITICAL;
+ if (!bcm2835_clk_is_claimed(divider_data->name))
+ divider->div.flags |= CLK_IS_CRITICAL;
}
divider->cprman = cprman;
@@ -1466,6 +1473,15 @@ static struct clk_hw *bcm2835_register_c
init.flags = clock_data->flags | CLK_IGNORE_UNUSED;
/*
+ * Some GPIO clocks for ethernet/wifi PLLs are marked as
+ * critical (since some platforms use them), but if the
+ * firmware didn't have them turned on then they clearly
+ * aren't actually critical.
+ */
+ if ((cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE) == 0)
+ init.flags &= ~CLK_IS_CRITICAL;
+
+ /*
* Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
* rate changes on at least of the parents.
*/
@@ -2245,6 +2261,8 @@ static const struct bcm2835_clk_desc clk
.ctl_reg = CM_PERIICTL),
};
+static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)];
+
/*
* Permanently take a reference on the parent of the SDRAM clock.
*
@@ -2264,6 +2282,19 @@ static int bcm2835_mark_sdc_parent_criti
return clk_prepare_enable(parent);
}
+static bool bcm2835_clk_is_claimed(const char *name)
+{
+ 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];
+ }
+
+ return false;
+}
+
static int bcm2835_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2273,6 +2304,7 @@ static int bcm2835_clk_probe(struct plat
const size_t asize = ARRAY_SIZE(clk_desc_array);
const struct cprman_plat_data *pdata;
size_t i;
+ u32 clk_id;
int ret;
pdata = of_device_get_match_data(&pdev->dev);
@@ -2291,6 +2323,13 @@ static int bcm2835_clk_probe(struct plat
if (IS_ERR(cprman->regs))
return PTR_ERR(cprman->regs);
+ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
+ for (i = 0;
+ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
+ i, &clk_id);
+ i++)
+ bcm2835_clk_claimed[clk_id]= true;
+
memcpy(cprman->real_parent_names, cprman_parent_names,
sizeof(cprman_parent_names));
of_clk_parent_fill(dev->of_node, cprman->real_parent_names,

View File

@ -0,0 +1,122 @@
From 1c0f5f04c143e5543d498fb05c1ec50c5aa7e3e8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 6 Mar 2017 09:06:18 +0000
Subject: [PATCH 027/697] clk-bcm2835: Read max core clock from firmware
The VPU is responsible for managing the core clock, usually under
direction from the bcm2835-cpufreq driver but not via the clk-bcm2835
driver. Since the core frequency can change without warning, it is
safer to report the maximum clock rate to users of the core clock -
I2C, SPI and the mini UART - to err on the safe side when calculating
clock divisors.
If the DT node for the clock driver includes a reference to the
firmware node, use the firmware API to query the maximum core clock
instead of reading the divider registers.
Prior to this patch, a "100KHz" I2C bus was sometimes clocked at about
160KHz. In particular, switching to the 4.9 kernel was likely to break
SenseHAT usage on a Pi3.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
clk: bcm2835: Pass DT node to rpi_firmware_get
The fw_node pointer has already been retrieved, and using it allows
us to remove a downstream patch to the firmware driver.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/clk/bcm/clk-bcm2835.c | 39 ++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -36,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/bcm2835.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
#define CM_PASSWORD 0x5a000000
@@ -296,6 +297,8 @@
#define SOC_BCM2711 BIT(1)
#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
+#define VCMSG_ID_CORE_CLOCK 4
+
/*
* Names of clocks used within the driver that need to be replaced
* with an external parent's name. This array is in the order that
@@ -314,6 +317,7 @@ static const char *const cprman_parent_n
struct bcm2835_cprman {
struct device *dev;
void __iomem *regs;
+ struct rpi_firmware *fw;
spinlock_t regs_lock; /* spinlock for all clocks */
unsigned int soc;
@@ -1039,6 +1043,30 @@ static unsigned long bcm2835_clock_get_r
return rate;
}
+static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct bcm2835_cprman *cprman = clock->cprman;
+
+ if (cprman->fw) {
+ struct {
+ u32 id;
+ u32 val;
+ } packet;
+
+ packet.id = VCMSG_ID_CORE_CLOCK;
+ packet.val = 0;
+
+ if (!rpi_firmware_property(cprman->fw,
+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
+ &packet, sizeof(packet)))
+ return packet.val;
+ }
+
+ return bcm2835_clock_get_rate(hw, parent_rate);
+}
+
static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
{
struct bcm2835_cprman *cprman = clock->cprman;
@@ -1327,7 +1355,7 @@ static int bcm2835_vpu_clock_is_on(struc
*/
static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
- .recalc_rate = bcm2835_clock_get_rate,
+ .recalc_rate = bcm2835_clock_get_rate_vpu,
.set_rate = bcm2835_clock_set_rate,
.determine_rate = bcm2835_clock_determine_rate,
.set_parent = bcm2835_clock_set_parent,
@@ -2303,6 +2331,7 @@ static int bcm2835_clk_probe(struct plat
const struct bcm2835_clk_desc *desc;
const size_t asize = ARRAY_SIZE(clk_desc_array);
const struct cprman_plat_data *pdata;
+ struct device_node *fw_node;
size_t i;
u32 clk_id;
int ret;
@@ -2323,6 +2352,14 @@ static int bcm2835_clk_probe(struct plat
if (IS_ERR(cprman->regs))
return PTR_ERR(cprman->regs);
+ fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
+ if (fw_node) {
+ struct rpi_firmware *fw = rpi_firmware_get(fw_node);
+ if (!fw)
+ return -EPROBE_DEFER;
+ cprman->fw = fw;
+ }
+
memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
for (i = 0;
!of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",

View File

@ -0,0 +1,38 @@
From b8607274cb63f5367763bd0aa958c7341e295989 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 23 Jan 2019 16:11:50 +0000
Subject: [PATCH 028/697] 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
@@ -647,15 +647,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,

View File

@ -0,0 +1,53 @@
From d47e5b29dc19e4a5b1984e109c0541a19ba28d3a Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 2 May 2019 15:11:05 -0700
Subject: [PATCH 029/697] 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
@@ -1138,15 +1138,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);
@@ -1522,7 +1526,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.

View File

@ -0,0 +1,71 @@
From bf79500a8deff78a1b1c8ef906d3eda1b742b449 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 2 May 2019 15:24:04 -0700
Subject: [PATCH 030/697] 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
@@ -1127,8 +1127,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;
@@ -1150,6 +1152,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);
@@ -1161,6 +1168,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)
{
@@ -1344,6 +1357,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,
@@ -1526,7 +1540,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.

View File

@ -0,0 +1,29 @@
From 5be3ac68ad03a16a5039ebdbbc2361b7972c870e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 6 Aug 2019 15:23:14 +0100
Subject: [PATCH 031/697] 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
@@ -2334,9 +2334,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;

View File

@ -0,0 +1,84 @@
From 93d180421ece351c0f36d43106def3e82c8e3e2b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 3 Sep 2019 20:28:00 +0100
Subject: [PATCH 032/697] clk-bcm2835: Disable v3d clock
This is controlled by firmware, see clk-raspberrypi.c
Signed-off-by: popcornmix <popcornmix@gmail.com>
clk-bcm2835: Remove VEC clock support
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
drivers/clk/bcm/clk-bcm2835.c | 45 ++++++++++-------------------------
1 file changed, 12 insertions(+), 33 deletions(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1764,16 +1764,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",
@@ -2074,14 +2070,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
@@ -2244,21 +2238,6 @@ static const struct bcm2835_clk_desc clk
.tcnt_mux = 28,
.round_up = true),
- /* TV encoder clock. Only operating frequency is 108Mhz. */
- [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK(
- SOC_ALL,
- .name = "vec",
- .ctl_reg = CM_VECCTL,
- .div_reg = CM_VECDIV,
- .int_bits = 4,
- .frac_bits = 0,
- /*
- * Allow rate change propagation only on PLLH_AUX which is
- * assigned index 7 in the parent array.
- */
- .set_rate_parent = BIT(7),
- .tcnt_mux = 29),
-
/* dsi clocks */
[BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK(
SOC_ALL,

View File

@ -0,0 +1,35 @@
From 5688f668827f7afed32950b89b8763f23810adf6 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 26 Apr 2024 17:05:39 +0100
Subject: [PATCH 033/697] clk-bcm2835: Use PLLD for DSI0 HS clock
DSI0 can take the clock from either PLLA or PLLD. PLLA is
the default muxing, but PLLD is considered the more stable.
Switch to using PLLD.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/clk/bcm/clk-bcm2835.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -107,6 +107,7 @@
#define CM_UARTDIV 0x0f4
#define CM_VECCTL 0x0f8
#define CM_VECDIV 0x0fc
+#define CM_DSI0HSCK 0x120
#define CM_PULSECTL 0x190
#define CM_PULSEDIV 0x194
#define CM_SDCCTL 0x1a8
@@ -2352,6 +2353,9 @@ static int bcm2835_clk_probe(struct plat
if (IS_ERR(cprman->regs))
return PTR_ERR(cprman->regs);
+ /* Mux DSI0 clock to PLLD */
+ cprman_write(cprman, CM_DSI0HSCK, 1);
+
fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
if (fw_node) {
struct rpi_firmware *fw = rpi_firmware_get(fw_node);

View File

@ -0,0 +1,53 @@
From a90210e2da00901e65ac5a3147338f3b2421fca4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 25 Aug 2017 19:18:13 +0100
Subject: [PATCH 034/697] cache: export clean and invalidate
hack: cache: Fix linker error
---
arch/arm/mm/cache-v6.S | 4 ++--
arch/arm/mm/cache-v7.S | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -206,7 +206,7 @@ SYM_FUNC_END(v6_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_inv_range:
+ENTRY(v6_dma_inv_range)
tst r0, #D_CACHE_LINE_SIZE - 1
bic r0, r0, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
@@ -239,7 +239,7 @@ v6_dma_inv_range:
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_clean_range:
+ENTRY(v6_dma_clean_range)
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef HARVARD_CACHE
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -364,7 +364,8 @@ SYM_FUNC_END(v7_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_inv_range:
+ENTRY(b15_dma_inv_range)
+ENTRY(v7_dma_inv_range)
dcache_line_size r2, r3
sub r3, r2, #1
tst r0, r3
@@ -394,7 +395,8 @@ ENDPROC(v7_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_clean_range:
+ENTRY(b15_dma_clean_range)
+ENTRY(v7_dma_clean_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3

View File

@ -0,0 +1,43 @@
From fab8fa9116af0c5fe24df66ab0adbb9900a25c80 Mon Sep 17 00:00:00 2001
From: Sam Nazarko <email@samnazarko.co.uk>
Date: Fri, 1 Apr 2016 17:27:21 +0100
Subject: [PATCH 035/697] smsc95xx: Experimental: Enable turbo_mode and
packetsize=2560 by default
See: http://forum.kodi.tv/showthread.php?tid=285288
---
drivers/net/usb/smsc95xx.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -79,6 +79,10 @@ static bool turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+static int packetsize = 2560;
+module_param(packetsize, int, 0644);
+MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
+
static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
u32 *data)
{
@@ -932,13 +936,13 @@ static int smsc95xx_reset(struct usbnet
if (!turbo_mode) {
burst_cap = 0;
- dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+ dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE;
} else if (dev->udev->speed == USB_SPEED_HIGH) {
- burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
- dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE;
+ burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE;
} else {
- burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
- dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE;
+ burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE;
}
netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",

View File

@ -0,0 +1,72 @@
From 263f694f2ea62ab6222689edcc1f3657892889e0 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 17:26:38 +0000
Subject: [PATCH 036/697] Allow mac address to be set in smsc95xx
Signed-off-by: popcornmix <popcornmix@gmail.com>
SQUASH: smsc95xx: Use dev_mod_addr to set MAC addr
Since adeef3e32146 ("net: constify netdev->dev_addr") it has been
illegal to write to the dev_addr MAC address field. Later commits
have added explicit checks that it hasn't been modified by nefarious
means. The dev_addr_mod helper function is the accepted way to change
the dev_addr field, so use it.
Squash with 96c1def63ee1 ("Allow mac address to be set in smsc95xx").
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/net/usb/smsc95xx.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -83,6 +83,10 @@ static int packetsize = 2560;
module_param(packetsize, int, 0644);
MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
+static char *macaddr = ":";
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
u32 *data)
{
@@ -805,6 +809,21 @@ static int smsc95xx_ioctl(struct net_dev
return phy_mii_ioctl(netdev->phydev, rq, cmd);
}
+/* Check the macaddr module parameter for a MAC address */
+static int smsc95xx_macaddr_param(struct usbnet *dev, struct net_device *nd)
+{
+ u8 mtbl[ETH_ALEN];
+
+ if (mac_pton(macaddr, mtbl)) {
+ netif_dbg(dev, ifup, dev->net,
+ "Overriding MAC address with: %pM\n", mtbl);
+ dev_addr_mod(nd, 0, mtbl, ETH_ALEN);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
static void smsc95xx_init_mac_address(struct usbnet *dev)
{
u8 addr[ETH_ALEN];
@@ -827,6 +846,14 @@ static void smsc95xx_init_mac_address(st
return;
}
}
+
+ /* Check module parameters */
+ if (smsc95xx_macaddr_param(dev, dev->net) == 0) {
+ if (is_valid_ether_addr(dev->net->dev_addr)) {
+ netif_dbg(dev, ifup, dev->net, "MAC address read from module parameter\n");
+ return;
+ }
+ }
/* no useful static MAC address found. generate a random one */
eth_hw_addr_random(dev->net);

View File

@ -0,0 +1,28 @@
From 9b1bb38bb5a638b1d0c21e8b7828d9f71d326ece Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 13 Mar 2015 12:43:36 +0000
Subject: [PATCH 037/697] Protect __release_resource against resources without
parents
Without this patch, removing a device tree overlay can crash here.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
kernel/resource.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -192,6 +192,12 @@ static int __release_resource(struct res
{
struct resource *tmp, **p, *chd;
+ if (!old->parent) {
+ WARN(old->sibling, "sibling but no parent");
+ if (old->sibling)
+ return -EINVAL;
+ return 0;
+ }
p = &old->parent->child;
for (;;) {
tmp = *p;

View File

@ -0,0 +1,24 @@
From ed8471410d1f18d25507b68f81333bb45ed45ccd Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 9 Feb 2017 14:33:30 +0000
Subject: [PATCH 038/697] irq-bcm2836: Avoid "Invalid trigger warning"
Initialise the level for each IRQ to avoid a warning from the
arm arch timer code.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/irqchip/irq-bcm2836.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -128,7 +128,7 @@ static int bcm2836_map(struct irq_domain
irq_set_percpu_devid(irq);
irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
+ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW);
return 0;
}

View File

@ -0,0 +1,127 @@
From 413429d8367d139cc4198cd69e8c66ad2c07aff3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 12 Jun 2015 19:01:05 +0200
Subject: [PATCH 039/697] irqchip: bcm2835: Add FIQ support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add a duplicate irq range with an offset on the hwirq's so the
driver can detect that enable_fiq() is used.
Tested with downstream dwc_otg USB controller driver.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
---
arch/arm/mach-bcm/Kconfig | 1 +
drivers/irqchip/irq-bcm2835.c | 51 +++++++++++++++++++++++++++++++----
2 files changed, 47 insertions(+), 5 deletions(-)
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -158,6 +158,7 @@ config ARCH_BCM2835
select ARM_TIMER_SP804
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select BCM2835_TIMER
+ select FIQ
select PINCTRL
select PINCTRL_BCM2835
select MFD_CORE
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -45,7 +45,7 @@
#include <asm/exception.h>
/* Put the bank and irq (32 bits) into the hwirq */
-#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
+#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
#define HWIRQ_BANK(i) (i >> 5)
#define HWIRQ_BIT(i) BIT(i & 0x1f)
@@ -62,9 +62,13 @@
#define REG_FIQ_CONTROL 0x0c
#define FIQ_CONTROL_ENABLE BIT(7)
+#define REG_FIQ_ENABLE FIQ_CONTROL_ENABLE
+#define REG_FIQ_DISABLE 0
#define NR_BANKS 3
#define IRQS_PER_BANK 32
+#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
+#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
@@ -89,14 +93,38 @@ static void __exception_irq_entry bcm283
struct pt_regs *regs);
static void bcm2836_chained_handle_irq(struct irq_desc *desc);
+static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
+{
+ hwirq -= NUMBER_IRQS;
+ /*
+ * The hwirq numbering used in this driver is:
+ * BASE (0-7) GPU1 (32-63) GPU2 (64-95).
+ * This differ from the one used in the FIQ register:
+ * GPU1 (0-31) GPU2 (32-63) BASE (64-71)
+ */
+ if (hwirq >= 32)
+ return hwirq - 32;
+
+ return hwirq + 64;
+}
+
static void armctrl_mask_irq(struct irq_data *d)
{
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
+ if (d->hwirq >= NUMBER_IRQS)
+ writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
+ else
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
+ intc.disable[HWIRQ_BANK(d->hwirq)]);
}
static void armctrl_unmask_irq(struct irq_data *d)
{
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
+ if (d->hwirq >= NUMBER_IRQS)
+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+ intc.base + REG_FIQ_CONTROL);
+ else
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
+ intc.enable[HWIRQ_BANK(d->hwirq)]);
}
static struct irq_chip armctrl_chip = {
@@ -144,8 +172,9 @@ static int __init armctrl_of_init(struct
if (!base)
panic("%pOF: unable to map IC registers\n", node);
- intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
- &armctrl_ops, NULL);
+ intc.base = base;
+ intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
+ &armctrl_ops, NULL);
if (!intc.domain)
panic("%pOF: unable to create IRQ domain\n", node);
@@ -188,6 +217,18 @@ static int __init armctrl_of_init(struct
set_handle_irq(bcm2835_handle_irq);
}
+ /* Make a duplicate irq range which is used to enable FIQ */
+ for (b = 0; b < NR_BANKS; b++) {
+ for (i = 0; i < bank_irqs[b]; i++) {
+ irq = irq_create_mapping(intc.domain,
+ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
+ BUG_ON(irq <= 0);
+ irq_set_chip(irq, &armctrl_chip);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ }
+ init_FIQ(FIQ_START);
+
return 0;
}

View File

@ -0,0 +1,99 @@
From 37d40a56c903c47aef2d15c3d73e6a5d00dbffb3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 23 Oct 2015 16:26:55 +0200
Subject: [PATCH 040/697] irqchip: irq-bcm2835: Add 2836 FIQ support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/irqchip/irq-bcm2835.c | 43 +++++++++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -41,8 +41,11 @@
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <asm/exception.h>
+#include <asm/mach/irq.h>
/* Put the bank and irq (32 bits) into the hwirq */
#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
@@ -60,6 +63,9 @@
#define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
| SHORTCUT1_MASK | SHORTCUT2_MASK)
+#undef ARM_LOCAL_GPU_INT_ROUTING
+#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
+
#define REG_FIQ_CONTROL 0x0c
#define FIQ_CONTROL_ENABLE BIT(7)
#define REG_FIQ_ENABLE FIQ_CONTROL_ENABLE
@@ -86,6 +92,7 @@ struct armctrl_ic {
void __iomem *enable[NR_BANKS];
void __iomem *disable[NR_BANKS];
struct irq_domain *domain;
+ struct regmap *local_regmap;
};
static struct armctrl_ic intc __read_mostly;
@@ -119,12 +126,35 @@ static void armctrl_mask_irq(struct irq_
static void armctrl_unmask_irq(struct irq_data *d)
{
- if (d->hwirq >= NUMBER_IRQS)
+ if (d->hwirq >= NUMBER_IRQS) {
+ if (num_online_cpus() > 1) {
+ unsigned int data;
+ int ret;
+
+ if (!intc.local_regmap) {
+ pr_err("FIQ is disabled due to missing regmap\n");
+ return;
+ }
+
+ ret = regmap_read(intc.local_regmap,
+ ARM_LOCAL_GPU_INT_ROUTING, &data);
+ if (ret) {
+ pr_err("Failed to read int routing %d\n", ret);
+ return;
+ }
+
+ data &= ~0xc;
+ data |= (1 << 2);
+ regmap_write(intc.local_regmap,
+ ARM_LOCAL_GPU_INT_ROUTING, data);
+ }
+
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
intc.base + REG_FIQ_CONTROL);
- else
+ } else {
writel_relaxed(HWIRQ_BIT(d->hwirq),
intc.enable[HWIRQ_BANK(d->hwirq)]);
+ }
}
static struct irq_chip armctrl_chip = {
@@ -217,6 +247,15 @@ static int __init armctrl_of_init(struct
set_handle_irq(bcm2835_handle_irq);
}
+ if (is_2836) {
+ intc.local_regmap =
+ syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
+ if (IS_ERR(intc.local_regmap)) {
+ pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
+ intc.local_regmap = NULL;
+ }
+ }
+
/* Make a duplicate irq range which is used to enable FIQ */
for (b = 0; b < NR_BANKS; b++) {
for (i = 0; i < bank_irqs[b]; i++) {

View File

@ -0,0 +1,24 @@
From e7b3aedf8b24fcb4a0fc27965098f291f7d3c23b Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Mon, 24 Jan 2022 13:41:16 +0000
Subject: [PATCH 041/697] spi: spidev: Completely disable the spidev warning
An alternative strategy would be to use "rpi,spidev" instead, but that
would require many Raspberry Pi Device Tree changes.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/spi/spidev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -721,7 +721,7 @@ MODULE_DEVICE_TABLE(spi, spidev_spi_ids)
*/
static int spidev_of_check(struct device *dev)
{
- if (device_property_match_string(dev, "compatible", "spidev") < 0)
+ if (1 || device_property_match_string(dev, "compatible", "spidev") < 0)
return 0;
dev_err(dev, "spidev listed directly in DT is not supported\n");

View File

@ -0,0 +1,20 @@
From ee79ef68ef6caa1a2ec4d47819b09c24f17315fc Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 15 Jun 2016 16:48:41 +0100
Subject: [PATCH 043/697] rtc: Add SPI alias for pcf2123 driver
Without this alias, Device Tree won't cause the driver
to be loaded.
See: https://github.com/raspberrypi/linux/pull/1510
---
drivers/rtc/rtc-pcf2123.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -479,3 +479,4 @@ module_spi_driver(pcf2123_driver);
MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:rtc-pcf2123");

View File

@ -0,0 +1,102 @@
From 23bd9095c0e8842e3b2d0fb377a5b16b22a53103 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 7 Oct 2016 16:50:59 +0200
Subject: [PATCH 044/697] watchdog: bcm2835: Support setting reboot partition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The Raspberry Pi firmware looks at the RSTS register to know which
partition to boot from. The reboot syscall command
LINUX_REBOOT_CMD_RESTART2 supports passing in a string argument.
Add support for passing in a partition number 0..63 to boot from.
Partition 63 is a special partiton indicating halt.
If the partition doesn't exist, the firmware falls back to partition 0.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/watchdog/bcm2835_wdt.c | 49 +++++++++++++++++++---------------
1 file changed, 27 insertions(+), 22 deletions(-)
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -32,13 +32,7 @@
#define PM_RSTC_WRCFG_SET 0x00000030
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
#define PM_RSTC_RESET 0x00000102
-
-/*
- * The Raspberry Pi firmware uses the RSTS register to know which partition
- * to boot from. The partition value is spread into bits 0, 2, 4, 6, 8, 10.
- * Partition 63 is a special partition used by the firmware to indicate halt.
- */
-#define PM_RSTS_RASPBERRYPI_HALT 0x555
+#define PM_RSTS_PARTITION_CLR 0xfffffaaa
#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
@@ -98,9 +92,24 @@ static unsigned int bcm2835_wdt_get_time
return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
}
-static void __bcm2835_restart(struct bcm2835_wdt *wdt)
+/*
+ * The Raspberry Pi firmware uses the RSTS register to know which partiton
+ * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10.
+ * Partiton 63 is a special partition used by the firmware to indicate halt.
+ */
+
+static void __bcm2835_restart(struct bcm2835_wdt *wdt, u8 partition)
{
- u32 val;
+ u32 val, rsts;
+
+ rsts = (partition & BIT(0)) | ((partition & BIT(1)) << 1) |
+ ((partition & BIT(2)) << 2) | ((partition & BIT(3)) << 3) |
+ ((partition & BIT(4)) << 4) | ((partition & BIT(5)) << 5);
+
+ val = readl_relaxed(wdt->base + PM_RSTS);
+ val &= PM_RSTS_PARTITION_CLR;
+ val |= PM_PASSWORD | rsts;
+ writel_relaxed(val, wdt->base + PM_RSTS);
/* use a timeout of 10 ticks (~150us) */
writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
@@ -118,7 +127,13 @@ static int bcm2835_restart(struct watchd
{
struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
- __bcm2835_restart(wdt);
+ unsigned long long val;
+ u8 partition = 0;
+
+ if (data && !kstrtoull(data, 0, &val) && val <= 63)
+ partition = val;
+
+ __bcm2835_restart(wdt, partition);
return 0;
}
@@ -153,19 +168,9 @@ static struct watchdog_device bcm2835_wd
static void bcm2835_power_off(void)
{
struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
- u32 val;
-
- /*
- * We set the watchdog hard reset bit here to distinguish this reset
- * from the normal (full) reset. bootcode.bin will not reboot after a
- * hard reset.
- */
- val = readl_relaxed(wdt->base + PM_RSTS);
- val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT;
- writel_relaxed(val, wdt->base + PM_RSTS);
- /* Continue with normal reset mechanism */
- __bcm2835_restart(wdt);
+ /* Partition 63 tells the firmware that this is a halt */
+ __bcm2835_restart(wdt, 63);
}
static int bcm2835_wdt_probe(struct platform_device *pdev)

View File

@ -0,0 +1,49 @@
From 76f6475c036de43457c980bb61560f4f0d2e8210 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 5 Apr 2016 19:40:12 +0100
Subject: [PATCH 045/697] reboot: Use power off rather than busy spinning when
halt is requested
reboot: Use power off rather than busy spinning when halt is requested
Busy spinning after halt is dumb
We've previously applied this patch to arch/arm
but it is currenltly missing in arch/arm64
Pi4 after "sudo halt" uses 520mA
Pi4 after "sudo shutdown now" uses 310mA
Make them both use the lower powered option
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
arch/arm/kernel/reboot.c | 4 +---
arch/arm64/kernel/process.c | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -102,9 +102,7 @@ void machine_shutdown(void)
*/
void machine_halt(void)
{
- local_irq_disable();
- smp_send_stop();
- while (1);
+ machine_power_off();
}
/*
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -97,9 +97,7 @@ void machine_shutdown(void)
*/
void machine_halt(void)
{
- local_irq_disable();
- smp_send_stop();
- while (1);
+ machine_power_off();
}
/*

View File

@ -0,0 +1,25 @@
From 66bea8024da1f06fc766b32f2be284040481d651 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 6 Dec 2016 17:05:39 +0000
Subject: [PATCH 046/697] bcm2835-rng: Avoid initialising if already enabled
Avoids the 0x40000 cycles of warmup again if firmware has already used it
---
drivers/char/hw_random/bcm2835-rng.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -107,8 +107,10 @@ static int bcm2835_rng_init(struct hwrng
}
/* set warm-up count & enable */
- rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
- rng_writel(priv, RNG_RBGEN, RNG_CTRL);
+ if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) {
+ rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
+ rng_writel(priv, RNG_RBGEN, RNG_CTRL);
+ }
return ret;
}

View File

@ -0,0 +1,137 @@
From 1f82489c12ee1f104649498bc6b67d9d217602e1 Mon Sep 17 00:00:00 2001
From: Claggy3 <stephen.maclagan@hotmail.com>
Date: Sat, 11 Feb 2017 14:00:30 +0000
Subject: [PATCH 047/697] Update vfpmodule.c
Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m.
This patch fixes a problem with VFP state save and restore related
to exception handling (panic with message "BUG: unsupported FP
instruction in kernel mode") present on VFP11 floating point units
(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry
Pi boards). This patch was developed and discussed on
https://github.com/raspberrypi/linux/issues/859
A precondition to see the crashes is that floating point exception
traps are enabled. In this case, the VFP11 might determine that a FPU
operation needs to trap at a point in time when it is not possible to
signal this to the ARM11 core any more. The VFP11 will then set the
FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases,
a second opcode might have been accepted by the VFP11 before the
exception was detected and could be reported to the ARM11 - in this
case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in
FPINST2.)
If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued
by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode
trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits
to decide what actions to take, i.e., whether to emulate the opcodes
found in FPINST and FPINST2, and whether to retry the bounced instruction.
If a user space application has left the VFP11 in this "pending trap"
state, the next FPU opcode issued to the VFP11 might actually be the
VSTMIA operation vfp_save_state() uses to store the FPU registers
to memory (in our test cases, when building the signal stack frame).
In this case, the kernel crashes as described above.
This patch fixes the problem by making sure that vfp_save_state() is
always entered with FPEXC.EX cleared. (The current value of FPEXC has
already been saved, so this does not corrupt the context. Clearing
FPEXC.EX has no effects on FPINST or FPINST2. Also note that many
callers already modify FPEXC by setting FPEXC.EN before invoking
vfp_save_state().)
This patch also addresses a second problem related to FPEXC.EX: After
returning from signal handling, the kernel reloads the VFP context
from the user mode stack. However, the current code explicitly clears
both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these
bits to be preserved, this patch disables clearing them for VFP
implementations belonging to architecture 1. There should be no
negative side effects: the user can set both bits by executing FPU
opcodes anyway, and while user code may now place arbitrary values
into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support
code knows which instructions can be emulated, and rejects other
opcodes with "unhandled bounce" messages, so there should be no
security impact from allowing reloading FPEXC.EX and FPEXC.FP2V.
Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net>
---
arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -176,8 +176,11 @@ static int vfp_notifier(struct notifier_
* case the thread migrates to a different CPU. The
* restoring is done lazily.
*/
- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
+ /* vfp_save_state oopses on VFP11 if EX bit set */
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
+ }
#endif
/*
@@ -451,13 +454,16 @@ static int vfp_pm_suspend(void)
/* if vfp is on, then save state for resumption */
if (fpexc & FPEXC_EN) {
pr_debug("%s: saving vfp state\n", __func__);
+ /* vfp_save_state oopses on VFP11 if EX bit set */
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
vfp_save_state(&ti->vfpstate, fpexc);
/* disable, just in case */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
} else if (vfp_current_hw_state[ti->cpu]) {
#ifndef CONFIG_SMP
- fmxr(FPEXC, fpexc | FPEXC_EN);
+ /* vfp_save_state oopses on VFP11 if EX bit set */
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
fmxr(FPEXC, fpexc);
#endif
@@ -522,7 +528,8 @@ void vfp_sync_hwstate(struct thread_info
/*
* Save the last VFP state on this CPU.
*/
- fmxr(FPEXC, fpexc | FPEXC_EN);
+ /* vfp_save_state oopses on VFP11 if EX bit set */
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
fmxr(FPEXC, fpexc);
}
@@ -589,6 +596,7 @@ int vfp_restore_user_hwstate(struct user
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
unsigned long fpexc;
+ u32 fpsid = fmrx(FPSID);
/* Disable VFP to avoid corrupting the new thread state. */
vfp_flush_hwstate(thread);
@@ -611,8 +619,12 @@ int vfp_restore_user_hwstate(struct user
/* Ensure the VFP is enabled. */
fpexc |= FPEXC_EN;
- /* Ensure FPINST2 is invalid and the exception flag is cleared. */
- fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
+ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
+ /* Ensure FPINST2 is invalid and the exception flag is cleared. */
+ fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+ }
+
hwstate->fpexc = fpexc;
hwstate->fpinst = ufp_exc->fpinst;
@@ -848,7 +860,8 @@ void kernel_neon_begin(void)
cpu = __smp_processor_id();
fpexc = fmrx(FPEXC) | FPEXC_EN;
- fmxr(FPEXC, fpexc);
+ /* vfp_save_state oopses on VFP11 if EX bit set */
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
/*
* Save the userland NEON/VFP state. Under UP,

View File

@ -0,0 +1,189 @@
From f85e49f1da2b674f63d9ac5ce9e2331e5e93ebd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Tue, 1 Nov 2016 15:15:41 +0100
Subject: [PATCH 048/697] i2c: bcm2835: Add debug support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This adds a debug module parameter to aid in debugging transfer issues
by printing info to the kernel log. When enabled, status values are
collected in the interrupt routine and msg info in
bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid
affecting timing. Having printk in the isr can mask issues.
debug values (additive):
1: Print info on error
2: Print info on all transfers
3: Print messages before transfer is started
The value can be changed at runtime:
/sys/module/i2c_bcm2835/parameters/debug
Example output, debug=3:
[ 747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
[ 747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
[ 747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
[ 747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE [i2c1]
[ 747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
[ 747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD [i2c1]
[ 747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD [i2c1]
[ 747.117870] isr: remain=8, status=0x32 : DONE TXD RXD [i2c1]
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/i2c/busses/i2c-bcm2835.c | 99 +++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -56,6 +56,18 @@
#define BCM2835_I2C_CDIV_MIN 0x0002
#define BCM2835_I2C_CDIV_MAX 0xFFFE
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer");
+
+#define BCM2835_DEBUG_MAX 512
+struct bcm2835_debug {
+ struct i2c_msg *msg;
+ int msg_idx;
+ size_t remain;
+ u32 status;
+};
+
struct bcm2835_i2c_dev {
struct device *dev;
void __iomem *regs;
@@ -68,8 +80,78 @@ struct bcm2835_i2c_dev {
u32 msg_err;
u8 *msg_buf;
size_t msg_buf_remaining;
+ struct bcm2835_debug debug[BCM2835_DEBUG_MAX];
+ unsigned int debug_num;
+ unsigned int debug_num_msgs;
};
+static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s)
+{
+ if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
+ return;
+
+ i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg;
+ i2c_dev->debug[i2c_dev->debug_num].msg_idx =
+ i2c_dev->debug_num_msgs - i2c_dev->num_msgs;
+ i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining;
+ i2c_dev->debug[i2c_dev->debug_num].status = s;
+ i2c_dev->debug_num++;
+}
+
+static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev,
+ struct bcm2835_debug *d)
+{
+ u32 s = d->status;
+
+ pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n",
+ d->remain, s,
+ s & BCM2835_I2C_S_TA ? "TA " : "",
+ s & BCM2835_I2C_S_DONE ? "DONE " : "",
+ s & BCM2835_I2C_S_TXW ? "TXW " : "",
+ s & BCM2835_I2C_S_RXR ? "RXR " : "",
+ s & BCM2835_I2C_S_TXD ? "TXD " : "",
+ s & BCM2835_I2C_S_RXD ? "RXD " : "",
+ s & BCM2835_I2C_S_TXE ? "TXE " : "",
+ s & BCM2835_I2C_S_RXF ? "RXF " : "",
+ s & BCM2835_I2C_S_ERR ? "ERR " : "",
+ s & BCM2835_I2C_S_CLKT ? "CLKT " : "",
+ i2c_dev->adapter.nr);
+}
+
+static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, int i, int total,
+ const char *fname)
+{
+ pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n",
+ fname, i, total,
+ msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len,
+ msg->flags & I2C_M_TEN ? "TEN" : "",
+ msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "",
+ msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "",
+ msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "",
+ msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "",
+ msg->flags & I2C_M_NOSTART ? "NOSTART" : "",
+ msg->flags & I2C_M_STOP ? "STOP" : "",
+ i2c_dev->adapter.nr);
+}
+
+static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev)
+{
+ struct bcm2835_debug *d;
+ unsigned int i;
+
+ for (i = 0; i < i2c_dev->debug_num; i++) {
+ d = &i2c_dev->debug[i];
+ if (d->status == ~0)
+ bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx,
+ i2c_dev->debug_num_msgs, "start_transfer");
+ else
+ bcm2835_debug_print_status(i2c_dev, d);
+ }
+ if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
+ pr_info("BCM2835_DEBUG_MAX reached\n");
+}
+
static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
u32 reg, u32 val)
{
@@ -257,6 +339,7 @@ static void bcm2835_i2c_start_transfer(s
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
+ bcm2835_debug_add(i2c_dev, ~0);
}
static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev)
@@ -283,6 +366,7 @@ static irqreturn_t bcm2835_i2c_isr(int t
u32 val, err;
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+ bcm2835_debug_add(i2c_dev, val);
err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
if (err) {
@@ -349,6 +433,13 @@ static int bcm2835_i2c_xfer(struct i2c_a
unsigned long time_left;
int i;
+ if (debug)
+ i2c_dev->debug_num_msgs = num;
+
+ if (debug > 2)
+ for (i = 0; i < num; i++)
+ bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__);
+
for (i = 0; i < (num - 1); i++)
if (msgs[i].flags & I2C_M_RD) {
dev_warn_once(i2c_dev->dev,
@@ -367,6 +458,10 @@ static int bcm2835_i2c_xfer(struct i2c_a
bcm2835_i2c_finish_transfer(i2c_dev);
+ if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err)))
+ bcm2835_debug_print(i2c_dev);
+ i2c_dev->debug_num_msgs = 0;
+ i2c_dev->debug_num = 0;
if (!time_left) {
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
BCM2835_I2C_C_CLEAR);
@@ -376,7 +471,9 @@ static int bcm2835_i2c_xfer(struct i2c_a
if (!i2c_dev->msg_err)
return num;
- dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
+ if (debug)
+ dev_err(i2c_dev->dev, "i2c transfer failed: %x\n",
+ i2c_dev->msg_err);
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
return -EREMOTEIO;

View File

@ -0,0 +1,112 @@
From d60db5d76824afbb83f65ff24cfebba74f4ba4d6 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 23 Jan 2018 16:52:45 +0000
Subject: [PATCH 049/697] irqchip: irq-bcm2836: Remove regmap and syscon use
The syscon node defines a register range that duplicates that used by
the local_intc node on bcm2836/7. Since irq-bcm2835 and irq-bcm2836 are
built in and always present together (both drivers are enabled by
CONFIG_ARCH_BCM2835), it is possible to replace the syscon usage with a
global variable that simplifies the code. Doing so does lose the
locking provided by regmap, but as only one side is using the regmap
interface (irq-bcm2835 uses readl and write) there is no loss of
atomicity.
See: https://github.com/raspberrypi/firmware/issues/926
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/irqchip/irq-bcm2835.c | 32 ++++++++++++--------------------
drivers/irqchip/irq-bcm2836.c | 5 +++++
2 files changed, 17 insertions(+), 20 deletions(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -41,8 +41,6 @@
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
@@ -92,7 +90,7 @@ struct armctrl_ic {
void __iomem *enable[NR_BANKS];
void __iomem *disable[NR_BANKS];
struct irq_domain *domain;
- struct regmap *local_regmap;
+ void __iomem *local_base;
};
static struct armctrl_ic intc __read_mostly;
@@ -129,24 +127,20 @@ static void armctrl_unmask_irq(struct ir
if (d->hwirq >= NUMBER_IRQS) {
if (num_online_cpus() > 1) {
unsigned int data;
- int ret;
- if (!intc.local_regmap) {
- pr_err("FIQ is disabled due to missing regmap\n");
+ if (!intc.local_base) {
+ pr_err("FIQ is disabled due to missing arm_local_intc\n");
return;
}
- ret = regmap_read(intc.local_regmap,
- ARM_LOCAL_GPU_INT_ROUTING, &data);
- if (ret) {
- pr_err("Failed to read int routing %d\n", ret);
- return;
- }
+ data = readl_relaxed(intc.local_base +
+ ARM_LOCAL_GPU_INT_ROUTING);
data &= ~0xc;
data |= (1 << 2);
- regmap_write(intc.local_regmap,
- ARM_LOCAL_GPU_INT_ROUTING, data);
+ writel_relaxed(data,
+ intc.local_base +
+ ARM_LOCAL_GPU_INT_ROUTING);
}
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
@@ -248,12 +242,10 @@ static int __init armctrl_of_init(struct
}
if (is_2836) {
- intc.local_regmap =
- syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
- if (IS_ERR(intc.local_regmap)) {
- pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
- intc.local_regmap = NULL;
- }
+ extern void __iomem * __attribute__((weak)) arm_local_intc;
+ intc.local_base = arm_local_intc;
+ if (!intc.local_base)
+ pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n");
}
/* Make a duplicate irq range which is used to enable FIQ */
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -22,6 +22,9 @@ struct bcm2836_arm_irqchip_intc {
static struct bcm2836_arm_irqchip_intc intc __read_mostly;
+void __iomem *arm_local_intc;
+EXPORT_SYMBOL_GPL(arm_local_intc);
+
static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
unsigned int bit,
int cpu)
@@ -320,6 +323,8 @@ static int __init bcm2836_arm_irqchip_l1
panic("%pOF: unable to map local interrupt registers\n", node);
}
+ arm_local_intc = intc.base;
+
bcm2835_init_local_timer_frequency();
intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,

View File

@ -0,0 +1,27 @@
From 0f1e8b96198b74dcb95a10e139c66ee5ae36e6b2 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 29 Sep 2017 10:32:19 +0100
Subject: [PATCH 050/697] amba_pl011: Insert mb() for correct FIFO handling
The pl011 register accessor functions use the _relaxed versions of the
standard readl() and writel() functions, meaning that there are no
automatic memory barriers. When polling a FIFO status register to check
for fullness, it is necessary to ensure that any outstanding writes have
completed; otherwise the flags are effectively stale, making it possible
that the next write is to a full FIFO.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/tty/serial/amba-pl011.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1433,6 +1433,7 @@ static bool pl011_tx_char(struct uart_am
return false; /* unable to transmit character */
pl011_write(c, uap, REG_DR);
+ mb();
uap->port.icount.tx++;
return true;

View File

@ -0,0 +1,50 @@
From 2d203a775b47a3bc0f1aa50b6d67fb7d7a627218 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 29 Sep 2017 10:32:19 +0100
Subject: [PATCH 051/697] amba_pl011: Add cts-event-workaround DT property
The BCM2835 PL011 implementation seems to have a bug that can lead to a
transmission lockup if CTS changes frequently. A workaround was added to
the driver with a vendor-specific flag to enable it, but this flag is
currently not set for ARM implementations.
Add a "cts-event-workaround" property to Pi DTBs and use the presence
of that property to force the flag to be enabled in the driver.
See: https://github.com/raspberrypi/linux/issues/1280
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
Documentation/devicetree/bindings/serial/pl011.yaml | 6 ++++++
drivers/tty/serial/amba-pl011.c | 5 +++++
2 files changed, 11 insertions(+)
--- a/Documentation/devicetree/bindings/serial/pl011.yaml
+++ b/Documentation/devicetree/bindings/serial/pl011.yaml
@@ -101,6 +101,12 @@ properties:
on the device.
enum: [1, 4]
+ cts-event-workaround:
+ description:
+ Enables the (otherwise vendor-specific) workaround for the
+ CTS-induced TX lockup.
+ type: boolean
+
required:
- compatible
- reg
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2783,6 +2783,11 @@ static int pl011_probe(struct amba_devic
if (IS_ERR(uap->clk))
return PTR_ERR(uap->clk);
+ if (of_property_read_bool(dev->dev.of_node, "cts-event-workaround")) {
+ vendor->cts_event_workaround = true;
+ dev_info(&dev->dev, "cts_event_workaround enabled\n");
+ }
+
uap->reg_offset = vendor->reg_offset;
uap->vendor = vendor;
uap->fifosize = vendor->get_fifosize(dev);

View File

@ -0,0 +1,42 @@
From 492c6b7b05bdb4daaa8889e5f80d6d651e4b131a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 29 Jan 2020 09:35:19 +0000
Subject: [PATCH 052/697] 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
@@ -1466,6 +1466,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 (!kfifo_peek(&tport->xmit_fifo, &c))
break;

View File

@ -0,0 +1,150 @@
From bf3174d438a6244ac733e236f3ceb4726d427944 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 12 May 2013 12:24:19 +0100
Subject: [PATCH 053/697] Main bcm2708/bcm2709 linux port
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: popcornmix <popcornmix@gmail.com>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
bcm2709: Drop platform smp and timer init code
irq-bcm2836 handles this through these functions:
bcm2835_init_local_timer_frequency()
bcm2836_arm_irqchip_smp_init()
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
bcm270x: Use watchdog for reboot/poweroff
The watchdog driver already has support for reboot/poweroff.
Make use of this and remove the code from the platform files.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
board_bcm2835: Remove coherent dma pool increase - API has gone
---
arch/arm/mach-bcm/Kconfig | 1 +
arch/arm/mm/proc-v6.S | 15 ++++++++++++---
drivers/irqchip/irq-bcm2835.c | 7 ++++++-
drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
4 files changed, 35 insertions(+), 6 deletions(-)
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -162,6 +162,7 @@ config ARCH_BCM2835
select PINCTRL
select PINCTRL_BCM2835
select MFD_CORE
+ select MFD_SYSCON if ARCH_MULTI_V7
help
This enables support for the Broadcom BCM2711 and BCM283x SoCs.
This SoC is used in the Raspberry Pi and Roku 2 devices.
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -75,10 +75,19 @@ SYM_FUNC_END(cpu_v6_reset)
*
* IRQs are already disabled.
*/
+
+/* See jira SW-5991 for details of this workaround */
SYM_TYPED_FUNC_START(cpu_v6_do_idle)
- mov r1, #0
- mcr p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
- mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
+ .align 5
+ mov r1, #2
+1: subs r1, #1
+ nop
+ mcreq p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
+ mcreq p15, 0, r1, c7, c0, 4 @ wait for interrupt
+ nop
+ nop
+ nop
+ bne 1b
ret lr
SYM_FUNC_END(cpu_v6_do_idle)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -43,7 +43,9 @@
#include <linux/irqdomain.h>
#include <asm/exception.h>
+#ifndef CONFIG_ARM64
#include <asm/mach/irq.h>
+#endif
/* Put the bank and irq (32 bits) into the hwirq */
#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
@@ -72,6 +74,7 @@
#define NR_BANKS 3
#define IRQS_PER_BANK 32
#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
+#undef FIQ_START
#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
@@ -255,10 +258,12 @@ static int __init armctrl_of_init(struct
MAKE_HWIRQ(b, i) + NUMBER_IRQS);
BUG_ON(irq <= 0);
irq_set_chip(irq, &armctrl_chip);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_probe(irq);
}
}
+#ifndef CONFIG_ARM64
init_FIQ(FIQ_START);
+#endif
return 0;
}
--- a/drivers/mailbox/bcm2835-mailbox.c
+++ b/drivers/mailbox/bcm2835-mailbox.c
@@ -45,12 +45,15 @@
#define MAIL1_WRT (ARM_0_MAIL1 + 0x00)
#define MAIL1_STA (ARM_0_MAIL1 + 0x18)
+/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
+#ifndef ARM_MS_FULL
/* Status register: FIFO state. */
#define ARM_MS_FULL BIT(31)
#define ARM_MS_EMPTY BIT(30)
/* Configuration register: Enable interrupts. */
#define ARM_MC_IHAVEDATAIRQEN BIT(0)
+#endif
struct bcm2835_mbox {
void __iomem *regs;
@@ -144,7 +147,7 @@ static int bcm2835_mbox_probe(struct pla
return -ENOMEM;
spin_lock_init(&mbox->lock);
- ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
bcm2835_mbox_irq, IRQF_NO_SUSPEND, dev_name(dev),
mbox);
if (ret) {
@@ -193,7 +196,18 @@ static struct platform_driver bcm2835_mb
},
.probe = bcm2835_mbox_probe,
};
-module_platform_driver(bcm2835_mbox_driver);
+
+static int __init bcm2835_mbox_init(void)
+{
+ return platform_driver_register(&bcm2835_mbox_driver);
+}
+arch_initcall(bcm2835_mbox_init);
+
+static void __init bcm2835_mbox_exit(void)
+{
+ platform_driver_unregister(&bcm2835_mbox_driver);
+}
+module_exit(bcm2835_mbox_exit);
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,652 @@
From 5a1882f4e4544a866f1b07a12bf352bac5a6f90f Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 14:22:53 +0100
Subject: [PATCH 056/697] dmaengine: Add support for BCM2708
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add support for DMA controller of BCM2708 as used in the Raspberry Pi.
Currently it only supports cyclic DMA.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
dmaengine: expand functionality by supporting scatter/gather transfers sdhci-bcm2708 and dma.c: fix for LITE channels
DMA: fix cyclic LITE length overflow bug
dmaengine: bcm2708: Remove chancnt affectations
Mirror bcm2835-dma.c commit 9eba5536a7434c69d8c185d4bd1c70734d92287d:
chancnt is already filled by dma_async_device_register, which uses the channel
list to know how much channels there is.
Since it's already filled, we can safely remove it from the drivers' probe
function.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: overwrite dreq only if it is not set
dreq is set when the DMA channel is fetched from Device Tree.
slave_id is set using dmaengine_slave_config().
Only overwrite dreq with slave_id if it is not set.
dreq/slave_id in the cyclic DMA case is not touched, because I don't
have hardware to test with.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: do device registration in the board file
Don't register the device in the driver. Do it in the board file.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: don't restrict DT support to ARCH_BCM2835
Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now.
Add Device Tree support to the non ARCH_BCM2835 case.
Use the same driver name regardless of architecture.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
BCM270x_DT: add bcm2835-dma entry
Add Device Tree entry for bcm2835-dma.
The entry doesn't contain any resources since they are handled
by the arch/arm/mach-bcm270x/dma.c driver.
In non-DT mode, don't add the device in the board file.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
bcm2708-dmaengine: Add debug options
BCM270x: Add memory and irq resources to dmaengine device and DT
Prepare for merging of the legacy DMA API arch driver dma.c
with bcm2708-dmaengine by adding memory and irq resources both
to platform file device and Device Tree node.
Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: Merge with arch dma.c driver and disable dma.c
Merge the legacy DMA API driver with bcm2708-dmaengine.
This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox
driver is also needed).
Changes to the dma.c code:
- Use BIT() macro.
- Cutdown some comments to one line.
- Add mutex to vc_dmaman and use this, since the dev lock is locked
during probing of the engine part.
- Add global g_dmaman variable since drvdata is used by the engine part.
- Restructure for readability:
vc_dmaman_chan_alloc()
vc_dmaman_chan_free()
bcm_dma_chan_free()
- Restructure bcm_dma_chan_alloc() to simplify error handling.
- Use device irq resources instead of hardcoded bcm_dma_irqs table.
- Remove dev_dmaman_register() and code it directly.
- Remove dev_dmaman_deregister() and code it directly.
- Simplify bcm_dmaman_probe() using devm_* functions.
- Get dmachans from DT if available.
- Keep 'dma.dmachans' module argument name for backwards compatibility.
Make it available on ARCH_BCM2835 as well.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: set residue_granularity field
bcm2708-dmaengine supports residue reporting at burst level
but didn't report this via the residue_granularity field.
Without this field set properly we get playback issues with I2S cards.
dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer
bcm2708-dmaengine: Use more DMA channels (but not 12)
1) Only the bcm2708_fb drivers uses the legacy DMA API, and
it requires a BULK-capable channel, so all other types
(FAST, NORMAL and LITE) can be made available to the regular
DMA API.
2) DMA channels 11-14 share an interrupt. The driver can't
handle this, so don't use channels 12-14 (12 was used, probably
because it appears to have an interrupt, but in reality that
interrupt is for activity on ANY channel). This may explain
a lockup encountered when running out of DMA channels.
The combined effect of this patch is to leave 7 DMA channels
available + channel 0 for bcm2708_fb via the legacy API.
See: https://github.com/raspberrypi/linux/issues/1110
https://github.com/raspberrypi/linux/issues/1108
dmaengine: bcm2708: Make legacy API available for bcm2835-dma
bcm2708_fb uses the legacy DMA API, so in order to start using
bcm2835-dma, bcm2835-dma has to support the legacy API. Make this
possible by exporting bcm_dmaman_probe() and bcm_dmaman_remove().
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: Change DT compatible string
Both bcm2835-dma and bcm2708-dmaengine have the same compatible string.
So change compatible to "brcm,bcm2708-dma".
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
dmaengine: bcm2708: Remove driver but keep legacy API
Dropping non-DT support means we don't need this driver,
but we still need the legacy DMA API.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
bcm2708-dmaengine - Fix arm64 portability/build issues
dma-bcm2708: Fix module compilation of CONFIG_DMA_BCM2708
bcm2708-dmaengine.c defines functions like bcm_dma_start which are
defined as well in dma-bcm2708.h as inline versions when
CONFIG_DMA_BCM2708 is not defined. This works fine when
CONFIG_DMA_BCM2708 is built in, but when it is selected as module build
fails with redefinition errors because in the build system when
CONFIG_DMA_BCM2708 is selected as module, the macro becomes
CONFIG_DMA_BCM2708_MODULE.
This patch makes the header use CONFIG_DMA_BCM2708_MODULE too when
available.
Fixes https://github.com/raspberrypi/linux/issues/2056
Signed-off-by: Andrei Gherzan <andrei@gherzan.com>
bcm2708-dmaengine: Use platform_get_irq
The platform driver framework no longer creates IRQ resources for
platform devices because they are expected to use platform_get_irq.
This causes the bcm2808_fb acceleration to fail.
Fix the problem by calling platform_get_irq as intended.
See: https://github.com/raspberrypi/linux/issues/5131
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/dma/Kconfig | 6 +-
drivers/dma/Makefile | 1 +
drivers/dma/bcm2708-dmaengine.c | 281 ++++++++++++++++++++++
include/linux/platform_data/dma-bcm2708.h | 143 +++++++++++
4 files changed, 430 insertions(+), 1 deletion(-)
create mode 100644 drivers/dma/bcm2708-dmaengine.c
create mode 100644 include/linux/platform_data/dma-bcm2708.h
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -136,7 +136,7 @@ config BCM_SBA_RAID
config DMA_BCM2835
tristate "BCM2835 DMA engine support"
- depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ depends on ARCH_BCM2835
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
@@ -669,6 +669,10 @@ config UNIPHIER_XDMAC
UniPhier platform. This DMA controller can transfer data from
memory to memory, memory to peripheral and peripheral to memory.
+config DMA_BCM2708
+ tristate "BCM2708 DMA legacy API support"
+ depends on DMA_BCM2835
+
config XGENE_DMA
tristate "APM X-Gene DMA support"
depends on ARCH_XGENE || COMPILE_TEST
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o
obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o
+obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
--- /dev/null
+++ b/drivers/dma/bcm2708-dmaengine.c
@@ -0,0 +1,281 @@
+/*
+ * BCM2708 legacy DMA API
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_data/dma-bcm2708.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include "virt-dma.h"
+
+#define CACHE_LINE_MASK 31
+#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */
+
+/* valid only for channels 0 - 14, 15 has its own base address */
+#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */
+#define BCM2708_DMA_CHANIO(dma_base, n) \
+ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n)))
+
+struct vc_dmaman {
+ void __iomem *dma_base;
+ u32 chan_available; /* bitmap of available channels */
+ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
+ struct mutex lock;
+};
+
+static struct device *dmaman_dev; /* we assume there's only one! */
+static struct vc_dmaman *g_dmaman; /* DMA manager */
+
+/* DMA Auxiliary Functions */
+
+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
+ section inside the DMA buffer and another section outside it.
+ Even if we flush DMA buffers from the cache there is always the chance that
+ during a DMA someone will access the part of a cache line that is outside
+ the DMA buffer - which will then bring in unwelcome data.
+ Without being able to dictate our own buffer pools we must insist that
+ DMA buffers consist of a whole number of cache lines.
+*/
+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
+{
+ int i;
+
+ for (i = 0; i < sg_len; i++) {
+ if (sg_ptr[i].offset & CACHE_LINE_MASK ||
+ sg_ptr[i].length & CACHE_LINE_MASK)
+ return 0;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
+
+extern void bcm_dma_start(void __iomem *dma_chan_base,
+ dma_addr_t control_block)
+{
+ dsb(sy); /* ARM data synchronization (push) operation */
+
+ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
+ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
+}
+EXPORT_SYMBOL_GPL(bcm_dma_start);
+
+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
+{
+ dsb(sy);
+
+ /* ugly busy wait only option for now */
+ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
+ cpu_relax();
+}
+EXPORT_SYMBOL_GPL(bcm_dma_wait_idle);
+
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base)
+{
+ dsb(sy);
+
+ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_is_busy);
+
+/* Complete an ongoing DMA (assuming its results are to be ignored)
+ Does nothing if there is no DMA in progress.
+ This routine waits for the current AXI transfer to complete before
+ terminating the current DMA. If the current transfer is hung on a DREQ used
+ by an uncooperative peripheral the AXI transfer may never complete. In this
+ case the routine times out and return a non-zero error code.
+ Use of this routine doesn't guarantee that the ongoing or aborted DMA
+ does not produce an interrupt.
+*/
+extern int bcm_dma_abort(void __iomem *dma_chan_base)
+{
+ unsigned long int cs;
+ int rc = 0;
+
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+ if (BCM2708_DMA_ACTIVE & cs) {
+ long int timeout = 10000;
+
+ /* write 0 to the active bit - pause the DMA */
+ writel(0, dma_chan_base + BCM2708_DMA_CS);
+
+ /* wait for any current AXI transfer to complete */
+ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+ if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
+ /* we'll un-pause when we set of our next DMA */
+ rc = -ETIMEDOUT;
+
+ } else if (BCM2708_DMA_ACTIVE & cs) {
+ /* terminate the control block chain */
+ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
+
+ /* abort the whole DMA */
+ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
+ dma_chan_base + BCM2708_DMA_CS);
+ }
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_abort);
+
+ /* DMA Manager Device Methods */
+
+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
+ u32 chans_available)
+{
+ dmaman->dma_base = dma_base;
+ dmaman->chan_available = chans_available;
+ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */
+ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */
+ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */
+ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */
+}
+
+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
+ unsigned required_feature_set)
+{
+ u32 chans;
+ int chan = 0;
+ int feature;
+
+ chans = dmaman->chan_available;
+ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
+ /* select the subset of available channels with the desired
+ features */
+ if (required_feature_set & (1 << feature))
+ chans &= dmaman->has_feature[feature];
+
+ if (!chans)
+ return -ENOENT;
+
+ /* return the ordinal of the first channel in the bitmap */
+ while (chans != 0 && (chans & 1) == 0) {
+ chans >>= 1;
+ chan++;
+ }
+ /* claim the channel */
+ dmaman->chan_available &= ~(1 << chan);
+
+ return chan;
+}
+
+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
+{
+ if (chan < 0)
+ return -EINVAL;
+
+ if ((1 << chan) & dmaman->chan_available)
+ return -EIDRM;
+
+ dmaman->chan_available |= (1 << chan);
+
+ return 0;
+}
+
+/* DMA Manager Monitor */
+
+extern int bcm_dma_chan_alloc(unsigned required_feature_set,
+ void __iomem **out_dma_base, int *out_dma_irq)
+{
+ struct vc_dmaman *dmaman = g_dmaman;
+ struct platform_device *pdev = to_platform_device(dmaman_dev);
+ int chan;
+ int irq;
+
+ if (!dmaman_dev)
+ return -ENODEV;
+
+ mutex_lock(&dmaman->lock);
+ chan = vc_dmaman_chan_alloc(dmaman, required_feature_set);
+ if (chan < 0)
+ goto out;
+
+ irq = platform_get_irq(pdev, (unsigned int)chan);
+ if (irq < 0) {
+ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n",
+ chan);
+ vc_dmaman_chan_free(dmaman, chan);
+ chan = -ENOENT;
+ goto out;
+ }
+
+ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan);
+ *out_dma_irq = irq;
+ dev_dbg(dmaman_dev,
+ "Legacy API allocated channel=%d, base=%p, irq=%i\n",
+ chan, *out_dma_base, *out_dma_irq);
+
+out:
+ mutex_unlock(&dmaman->lock);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
+
+extern int bcm_dma_chan_free(int channel)
+{
+ struct vc_dmaman *dmaman = g_dmaman;
+ int rc;
+
+ if (!dmaman_dev)
+ return -ENODEV;
+
+ mutex_lock(&dmaman->lock);
+ rc = vc_dmaman_chan_free(dmaman, channel);
+ mutex_unlock(&dmaman->lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
+
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
+ u32 chans_available)
+{
+ struct device *dev = &pdev->dev;
+ struct vc_dmaman *dmaman;
+
+ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL);
+ if (!dmaman)
+ return -ENOMEM;
+
+ mutex_init(&dmaman->lock);
+ vc_dmaman_init(dmaman, base, chans_available);
+ g_dmaman = dmaman;
+ dmaman_dev = dev;
+
+ dev_info(dev, "DMA legacy API manager, dmachans=0x%x\n",
+ chans_available);
+
+ return 0;
+}
+EXPORT_SYMBOL(bcm_dmaman_probe);
+
+int bcm_dmaman_remove(struct platform_device *pdev)
+{
+ dmaman_dev = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(bcm_dmaman_remove);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/include/linux/platform_data/dma-bcm2708.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * 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.
+ */
+
+#ifndef _PLAT_BCM2708_DMA_H
+#define _PLAT_BCM2708_DMA_H
+
+/* DMA CS Control and Status bits */
+#define BCM2708_DMA_ACTIVE BIT(0)
+#define BCM2708_DMA_INT BIT(2)
+#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */
+#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */
+#define BCM2708_DMA_ERR BIT(8)
+#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */
+#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */
+
+/* DMA control block "info" field bits */
+#define BCM2708_DMA_INT_EN BIT(0)
+#define BCM2708_DMA_TDMODE BIT(1)
+#define BCM2708_DMA_WAIT_RESP BIT(3)
+#define BCM2708_DMA_D_INC BIT(4)
+#define BCM2708_DMA_D_WIDTH BIT(5)
+#define BCM2708_DMA_D_DREQ BIT(6)
+#define BCM2708_DMA_S_INC BIT(8)
+#define BCM2708_DMA_S_WIDTH BIT(9)
+#define BCM2708_DMA_S_DREQ BIT(10)
+
+#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12)
+#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
+#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21)
+
+#define BCM2708_DMA_DREQ_EMMC 11
+#define BCM2708_DMA_DREQ_SDHOST 13
+
+#define BCM2708_DMA_CS 0x00 /* Control and Status */
+#define BCM2708_DMA_ADDR 0x04
+/* the current control block appears in the following registers - read only */
+#define BCM2708_DMA_INFO 0x08
+#define BCM2708_DMA_SOURCE_AD 0x0c
+#define BCM2708_DMA_DEST_AD 0x10
+#define BCM2708_DMA_NEXTCB 0x1C
+#define BCM2708_DMA_DEBUG 0x20
+
+#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS)
+#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR)
+
+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
+
+/* When listing features we can ask for when allocating DMA channels give
+ those with higher priority smaller ordinal numbers */
+#define BCM_DMA_FEATURE_FAST_ORD 0
+#define BCM_DMA_FEATURE_BULK_ORD 1
+#define BCM_DMA_FEATURE_NORMAL_ORD 2
+#define BCM_DMA_FEATURE_LITE_ORD 3
+#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD)
+#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD)
+#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD)
+#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD)
+#define BCM_DMA_FEATURE_COUNT 4
+
+struct bcm2708_dma_cb {
+ u32 info;
+ u32 src;
+ u32 dst;
+ u32 length;
+ u32 stride;
+ u32 next;
+ u32 pad[2];
+};
+
+struct scatterlist;
+struct platform_device;
+
+#if defined(CONFIG_DMA_BCM2708) || defined(CONFIG_DMA_BCM2708_MODULE)
+
+int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
+void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block);
+void bcm_dma_wait_idle(void __iomem *dma_chan_base);
+bool bcm_dma_is_busy(void __iomem *dma_chan_base);
+int bcm_dma_abort(void __iomem *dma_chan_base);
+
+/* return channel no or -ve error */
+int bcm_dma_chan_alloc(unsigned preferred_feature_set,
+ void __iomem **out_dma_base, int *out_dma_irq);
+int bcm_dma_chan_free(int channel);
+
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
+ u32 chans_available);
+int bcm_dmaman_remove(struct platform_device *pdev);
+
+#else /* CONFIG_DMA_BCM2708 */
+
+static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr,
+ int sg_len)
+{
+ return 0;
+}
+
+static inline void bcm_dma_start(void __iomem *dma_chan_base,
+ dma_addr_t control_block) { }
+
+static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { }
+
+static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base)
+{
+ return false;
+}
+
+static inline int bcm_dma_abort(void __iomem *dma_chan_base)
+{
+ return -EINVAL;
+}
+
+static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set,
+ void __iomem **out_dma_base,
+ int *out_dma_irq)
+{
+ return -EINVAL;
+}
+
+static inline int bcm_dma_chan_free(int channel)
+{
+ return -EINVAL;
+}
+
+static inline int bcm_dmaman_probe(struct platform_device *pdev,
+ void __iomem *base, u32 chans_available)
+{
+ return 0;
+}
+
+static inline int bcm_dmaman_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#endif /* CONFIG_DMA_BCM2708 || CONFIG_DMA_BCM2708_MODULE */
+
+#endif /* _PLAT_BCM2708_DMA_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
From 1d93086aea536ea7025cae7fa370c9c95faafe2e Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 16 May 2022 10:28:27 +0100
Subject: [PATCH 058/697] mmc: block: Don't do single-sector reads during
recovery
See https://github.com/raspberrypi/linux/issues/5019
If an SD card has degraded performance such that IO operations time out
then the MMC block layer will leak SG DMA mappings in the swiotlb during
recovery. It retries the same SG and this causes the leak, as it is
mapped twice - once in sdhci_pre_req() and again during single-block
reads in sdhci_prepare_data().
Resetting the card (including power-cycling if a regulator for vmmc is
present) ought to be enough to recover a stuck state, so for now don't
try single-block reads in the recovery path.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/block.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2011,7 +2011,7 @@ static void mmc_blk_mq_rw_recovery(struc
return;
}
- if (rq_data_dir(req) == READ && brq->data.blocks >
+ if (0 && rq_data_dir(req) == READ && brq->data.blocks >
queue_physical_block_size(mq->queue) >> 9) {
/* Read one (native) sector at a time */
mmc_blk_read_single(mq, req);

View File

@ -0,0 +1,771 @@
From 29d4966c087ed60cf8423ae91b2055b954a8ec42 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 28 Oct 2016 15:36:43 +0100
Subject: [PATCH 060/697] vc_mem: Add vc_mem driver for querying firmware
memory addresses
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: popcornmix <popcornmix@gmail.com>
BCM270x: Move vc_mem
Make the vc_mem module available for ARCH_BCM2835 by moving it.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
char: vc_mem: Fix up compat ioctls for 64bit kernel
compat_ioctl wasn't defined, so 32bit user/64bit kernel
always failed.
VC_MEM_IOC_MEM_PHYS_ADDR was defined with parameter size
unsigned long, so the ioctl cmd changes between sizes.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
char: vc_mem: Fix all coding style issues.
Cleans up all checkpatch errors in vc_mem.c and vc_mem.h
No functional change to the code.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
char: vc_mem: Delete dead code
There are no error exists once device_create has succeeded, and
therefore no need to call device_destroy from vc_mem_init.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
char: broadcom: vc_mem: Fix preprocessor conditional
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
vc_mem: Add the DMA memcpy support from bcm2708_fb
bcm2708_fb is disabled by the vc4-kms-v3d overlay, which means that the
DMA memcpy support it provides is not available to allow vclog to read
the VC logs from the top 16MB on Pi 2 and Pi 3. Add the code to the
vc_mem driver, which will still be enabled.
It ought to be possible to do a proper DMA_MEM_TO_MEM copy via the
generic DMA customer API, but that can be a later step.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/char/broadcom/Kconfig | 18 +
drivers/char/broadcom/Makefile | 1 +
drivers/char/broadcom/vc_mem.c | 635 ++++++++++++++++++++++++++++++++
include/linux/broadcom/vc_mem.h | 39 ++
4 files changed, 693 insertions(+)
create mode 100644 drivers/char/broadcom/Kconfig
create mode 100644 drivers/char/broadcom/Makefile
create mode 100644 drivers/char/broadcom/vc_mem.c
create mode 100644 include/linux/broadcom/vc_mem.h
--- /dev/null
+++ b/drivers/char/broadcom/Kconfig
@@ -0,0 +1,18 @@
+#
+# Broadcom char driver config
+#
+
+menuconfig BRCM_CHAR_DRIVERS
+ bool "Broadcom Char Drivers"
+ help
+ Broadcom's char drivers
+
+if BRCM_CHAR_DRIVERS
+
+config BCM2708_VCMEM
+ bool "Videocore Memory"
+ default y
+ help
+ Helper for videocore memory access and total size allocation.
+
+endif
--- /dev/null
+++ b/drivers/char/broadcom/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
--- /dev/null
+++ b/drivers/char/broadcom/vc_mem.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/broadcom/vc_mem.h>
+#include <linux/compat.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dma-bcm2708.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define DRIVER_NAME "vc-mem"
+
+/* N.B. These use a different magic value for compatibility with bmc7208_fb */
+#define VC_MEM_IOC_DMACOPY _IOW('z', 0x22, struct vc_mem_dmacopy)
+#define VC_MEM_IOC_DMACOPY32 _IOW('z', 0x22, struct vc_mem_dmacopy32)
+
+/* address with no aliases */
+#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000)
+/* cache coherent but non-allocating in L1 and L2 */
+#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000)
+
+/* Device (/dev) related variables */
+static dev_t vc_mem_devnum;
+static struct class *vc_mem_class;
+static struct cdev vc_mem_cdev;
+static int vc_mem_inited;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *vc_mem_debugfs_entry;
+#endif
+
+struct vc_mem_dmacopy {
+ void *dst;
+ __u32 src;
+ __u32 length;
+};
+
+#ifdef CONFIG_COMPAT
+struct vc_mem_dmacopy32 {
+ compat_uptr_t dst;
+ __u32 src;
+ __u32 length;
+};
+#endif
+
+/*
+ * Videocore memory addresses and size
+ *
+ * Drivers that wish to know the videocore memory addresses and sizes should
+ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
+ * headers. This allows the other drivers to not be tied down to a a certain
+ * address/size at compile time.
+ *
+ * In the future, the goal is to have the videocore memory virtual address and
+ * size be calculated at boot time rather than at compile time. The decision of
+ * where the videocore memory resides and its size would be in the hands of the
+ * bootloader (and/or kernel). When that happens, the values of these variables
+ * would be calculated and assigned in the init function.
+ */
+/* In the 2835 VC in mapped above ARM, but ARM has full access to VC space */
+unsigned long mm_vc_mem_phys_addr;
+EXPORT_SYMBOL(mm_vc_mem_phys_addr);
+unsigned int mm_vc_mem_size;
+EXPORT_SYMBOL(mm_vc_mem_size);
+unsigned int mm_vc_mem_base;
+EXPORT_SYMBOL(mm_vc_mem_base);
+
+static uint phys_addr;
+static uint mem_size;
+static uint mem_base;
+
+struct vc_mem_dma {
+ struct device *dev;
+ int dma_chan;
+ int dma_irq;
+ void __iomem *dma_chan_base;
+ wait_queue_head_t dma_waitq;
+ void *cb_base; /* DMA control blocks */
+ dma_addr_t cb_handle;
+};
+
+struct { u32 base, length; } gpu_mem;
+static struct mutex dma_mutex;
+static struct vc_mem_dma vc_mem_dma;
+
+static int
+vc_mem_open(struct inode *inode, struct file *file)
+{
+ (void)inode;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+}
+
+static int
+vc_mem_release(struct inode *inode, struct file *file)
+{
+ (void)inode;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+}
+
+static void
+vc_mem_get_size(void)
+{
+}
+
+static void
+vc_mem_get_base(void)
+{
+}
+
+int
+vc_mem_get_current_size(void)
+{
+ return mm_vc_mem_size;
+}
+EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
+
+static int
+vc_mem_dma_init(void)
+{
+ struct vc_mem_dma *vcdma = &vc_mem_dma;
+ struct platform_device *pdev;
+ struct device_node *fwnode;
+ struct rpi_firmware *fw;
+ struct device *dev;
+ u32 revision;
+ int rc;
+
+ if (vcdma->dev)
+ return 0;
+
+ fwnode = of_find_node_by_path("/system");
+ rc = of_property_read_u32(fwnode, "linux,revision", &revision);
+ revision = (revision >> 12) & 0xf;
+ if (revision != 1 && revision != 2) {
+ /* Only BCM2709 and BCM2710 may have logs where the ARMs
+ * can't see them.
+ */
+ return -ENXIO;
+ }
+
+ fwnode = rpi_firmware_find_node();
+ if (!fwnode)
+ return -ENXIO;
+
+ pdev = of_find_device_by_node(fwnode);
+ dev = &pdev->dev;
+
+ rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+
+ fw = rpi_firmware_get(fwnode);
+ if (!fw)
+ return -ENXIO;
+ rc = rpi_firmware_property(fw, RPI_FIRMWARE_GET_VC_MEMORY,
+ &gpu_mem, sizeof(gpu_mem));
+ if (rc)
+ return rc;
+
+ gpu_mem.base = INTALIAS_NORMAL(gpu_mem.base);
+
+ if (!gpu_mem.base || !gpu_mem.length) {
+ dev_err(dev, "%s: unable to determine gpu memory (%x,%x)\n",
+ __func__, gpu_mem.base, gpu_mem.length);
+ return -EFAULT;
+ }
+
+ vcdma->cb_base = dma_alloc_wc(dev, SZ_4K, &vcdma->cb_handle, GFP_KERNEL);
+ if (!vcdma->cb_base) {
+ dev_err(dev, "failed to allocate DMA CBs\n");
+ return -ENOMEM;
+ }
+
+ rc = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
+ &vcdma->dma_chan_base,
+ &vcdma->dma_irq);
+ if (rc < 0) {
+ dev_err(dev, "failed to allocate a DMA channel\n");
+ goto free_cb;
+ }
+
+ vcdma->dma_chan = rc;
+
+ init_waitqueue_head(&vcdma->dma_waitq);
+
+ vcdma->dev = dev;
+
+ return 0;
+
+free_cb:
+ dma_free_wc(dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle);
+
+ return rc;
+}
+
+static void
+vc_mem_dma_uninit(void)
+{
+ struct vc_mem_dma *vcdma = &vc_mem_dma;
+
+ if (vcdma->dev) {
+ bcm_dma_chan_free(vcdma->dma_chan);
+ dma_free_wc(vcdma->dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle);
+ vcdma->dev = NULL;
+ }
+}
+
+static int dma_memcpy(struct vc_mem_dma *vcdma, dma_addr_t dst, dma_addr_t src,
+ int size)
+{
+ struct bcm2708_dma_cb *cb = vcdma->cb_base;
+ int burst_size = (vcdma->dma_chan == 0) ? 8 : 2;
+
+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
+ BCM2708_DMA_D_INC;
+ cb->dst = dst;
+ cb->src = src;
+ cb->length = size;
+ cb->stride = 0;
+ cb->pad[0] = 0;
+ cb->pad[1] = 0;
+ cb->next = 0;
+
+ bcm_dma_start(vcdma->dma_chan_base, vcdma->cb_handle);
+ bcm_dma_wait_idle(vcdma->dma_chan_base);
+
+ return 0;
+}
+
+static long vc_mem_copy(struct vc_mem_dmacopy *ioparam)
+{
+ struct vc_mem_dma *vcdma = &vc_mem_dma;
+ size_t size = PAGE_SIZE;
+ const u32 dma_xfer_chunk = 256;
+ u32 *buf = NULL;
+ dma_addr_t bus_addr;
+ long rc = 0;
+ size_t offset;
+
+ /* restrict this to root user */
+ if (!uid_eq(current_euid(), GLOBAL_ROOT_UID))
+ return -EFAULT;
+
+ if (mutex_lock_interruptible(&dma_mutex))
+ return -EINTR;
+
+ rc = vc_mem_dma_init();
+ if (rc)
+ goto out;
+
+ vcdma = &vc_mem_dma;
+
+ if (INTALIAS_NORMAL(ioparam->src) < gpu_mem.base ||
+ INTALIAS_NORMAL(ioparam->src) >= gpu_mem.base + gpu_mem.length) {
+ pr_err("%s: invalid memory access %x (%x-%x)", __func__,
+ INTALIAS_NORMAL(ioparam->src), gpu_mem.base,
+ gpu_mem.base + gpu_mem.length);
+ rc = -EFAULT;
+ goto out;
+ }
+
+ buf = dma_alloc_coherent(vcdma->dev, PAGE_ALIGN(size), &bus_addr,
+ GFP_ATOMIC);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ for (offset = 0; offset < ioparam->length; offset += size) {
+ size_t remaining = ioparam->length - offset;
+ size_t s = min(size, remaining);
+ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset);
+ u8 *q = (u8 *)ioparam->dst + offset;
+
+ rc = dma_memcpy(vcdma, bus_addr,
+ INTALIAS_L1L2_NONALLOCATING((u32)(uintptr_t)p),
+ (s + dma_xfer_chunk - 1) & ~(dma_xfer_chunk - 1));
+ if (rc) {
+ dev_err(vcdma->dev, "dma_memcpy failed\n");
+ break;
+ }
+ if (copy_to_user(q, buf, s) != 0) {
+ pr_err("%s: copy_to_user failed\n", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ }
+
+out:
+ if (buf)
+ dma_free_coherent(vcdma->dev, PAGE_ALIGN(size), buf,
+ bus_addr);
+
+ mutex_unlock(&dma_mutex);
+
+ return rc;
+}
+
+static long
+vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+
+ (void) cmd;
+ (void) arg;
+
+ pr_debug("%s: called file = 0x%p, cmd %08x\n", __func__, file, cmd);
+
+ switch (cmd) {
+ case VC_MEM_IOC_MEM_PHYS_ADDR:
+ {
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
+ __func__, (void *)mm_vc_mem_phys_addr);
+
+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
+ sizeof(mm_vc_mem_phys_addr))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_SIZE:
+ {
+ /* Get the videocore memory size first */
+ vc_mem_get_size();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
+ mm_vc_mem_size);
+
+ if (copy_to_user((void *)arg, &mm_vc_mem_size,
+ sizeof(mm_vc_mem_size))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_BASE:
+ {
+ /* Get the videocore memory base */
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
+ sizeof(mm_vc_mem_base))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_LOAD:
+ {
+ /* Get the videocore memory base */
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
+ sizeof(mm_vc_mem_base))) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_DMACOPY:
+ {
+ struct vc_mem_dmacopy ioparam;
+ /* Get the parameter data.
+ */
+ if (copy_from_user
+ (&ioparam, (void *)arg, sizeof(ioparam))) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = vc_mem_copy(&ioparam);
+ break;
+ }
+ default:
+ {
+ return -ENOTTY;
+ }
+ }
+ pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
+
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+static long
+vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+
+ switch (cmd) {
+ case VC_MEM_IOC_MEM_PHYS_ADDR32:
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR32=0x%p\n",
+ __func__, (void *)mm_vc_mem_phys_addr);
+
+ /* This isn't correct, but will cover us for now as
+ * VideoCore is 32bit only.
+ */
+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
+ sizeof(compat_ulong_t)))
+ rc = -EFAULT;
+
+ break;
+
+ case VC_MEM_IOC_DMACOPY32:
+ {
+ struct vc_mem_dmacopy32 param32;
+ struct vc_mem_dmacopy param;
+ /* Get the parameter data.
+ */
+ if (copy_from_user(&param32, (void *)arg, sizeof(param32))) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ param.dst = compat_ptr(param32.dst);
+ param.src = param32.src;
+ param.length = param32.length;
+ rc = vc_mem_copy(&param);
+ break;
+ }
+
+ default:
+ rc = vc_mem_ioctl(file, cmd, arg);
+ break;
+ }
+
+ return rc;
+}
+#endif
+
+static int
+vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ int rc = 0;
+ unsigned long length = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
+ __func__, (long)vma->vm_start, (long)vma->vm_end,
+ (long)vma->vm_pgoff);
+
+ if (offset + length > mm_vc_mem_size) {
+ pr_err("%s: length %ld is too big\n", __func__, length);
+ return -EINVAL;
+ }
+ /* Do not cache the memory map */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ rc = remap_pfn_range(vma, vma->vm_start,
+ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
+ vma->vm_pgoff, length, vma->vm_page_prot);
+ if (rc)
+ pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
+
+ return rc;
+}
+
+/* File Operations for the driver. */
+static const struct file_operations vc_mem_fops = {
+ .owner = THIS_MODULE,
+ .open = vc_mem_open,
+ .release = vc_mem_release,
+ .unlocked_ioctl = vc_mem_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vc_mem_compat_ioctl,
+#endif
+ .mmap = vc_mem_mmap,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void vc_mem_debugfs_deinit(void)
+{
+ debugfs_remove_recursive(vc_mem_debugfs_entry);
+ vc_mem_debugfs_entry = NULL;
+}
+
+
+static int vc_mem_debugfs_init(
+ struct device *dev)
+{
+ vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
+ if (!vc_mem_debugfs_entry) {
+ dev_warn(dev, "could not create debugfs entry\n");
+ return -EFAULT;
+ }
+
+ debugfs_create_x32("vc_mem_phys_addr",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_phys_addr);
+ debugfs_create_x32("vc_mem_size",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_size);
+ debugfs_create_x32("vc_mem_base",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_base);
+
+ return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+/* Module load/unload functions */
+
+static int __init
+vc_mem_init(void)
+{
+ int rc = -EFAULT;
+ struct device *dev;
+
+ pr_debug("%s: called\n", __func__);
+
+ mm_vc_mem_phys_addr = phys_addr;
+ mm_vc_mem_size = mem_size;
+ mm_vc_mem_base = mem_base;
+
+ vc_mem_get_size();
+
+ pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
+ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size,
+ mm_vc_mem_size / (1024 * 1024));
+
+ rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME);
+ if (rc < 0) {
+ pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
+ __func__, rc);
+ goto out_err;
+ }
+
+ cdev_init(&vc_mem_cdev, &vc_mem_fops);
+ rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1);
+ if (rc) {
+ pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
+ goto out_unregister;
+ }
+
+ vc_mem_class = class_create(DRIVER_NAME);
+ if (IS_ERR(vc_mem_class)) {
+ rc = PTR_ERR(vc_mem_class);
+ pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
+ goto out_cdev_del;
+ }
+
+ dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
+ DRIVER_NAME);
+ if (IS_ERR(dev)) {
+ rc = PTR_ERR(dev);
+ pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
+ goto out_class_destroy;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ /* don't fail if the debug entries cannot be created */
+ vc_mem_debugfs_init(dev);
+#endif
+
+ mutex_init(&dma_mutex);
+ vc_mem_inited = 1;
+ return 0;
+
+out_class_destroy:
+ class_destroy(vc_mem_class);
+ vc_mem_class = NULL;
+
+out_cdev_del:
+ cdev_del(&vc_mem_cdev);
+
+out_unregister:
+ unregister_chrdev_region(vc_mem_devnum, 1);
+
+out_err:
+ return -1;
+}
+
+static void __exit
+vc_mem_exit(void)
+{
+ pr_debug("%s: called\n", __func__);
+
+ vc_mem_dma_uninit();
+ if (vc_mem_inited) {
+#ifdef CONFIG_DEBUG_FS
+ vc_mem_debugfs_deinit();
+#endif
+ device_destroy(vc_mem_class, vc_mem_devnum);
+ class_destroy(vc_mem_class);
+ cdev_del(&vc_mem_cdev);
+ unregister_chrdev_region(vc_mem_devnum, 1);
+ vc_mem_inited = 0;
+ }
+}
+
+module_init(vc_mem_init);
+module_exit(vc_mem_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom Corporation");
+
+module_param(phys_addr, uint, 0644);
+module_param(mem_size, uint, 0644);
+module_param(mem_base, uint, 0644);
--- /dev/null
+++ b/include/linux/broadcom/vc_mem.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ */
+
+#ifndef _VC_MEM_H
+#define _VC_MEM_H
+
+#include <linux/ioctl.h>
+
+#define VC_MEM_IOC_MAGIC 'v'
+
+#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR(VC_MEM_IOC_MAGIC, 0, unsigned long)
+#define VC_MEM_IOC_MEM_SIZE _IOR(VC_MEM_IOC_MAGIC, 1, unsigned int)
+#define VC_MEM_IOC_MEM_BASE _IOR(VC_MEM_IOC_MAGIC, 2, unsigned int)
+#define VC_MEM_IOC_MEM_LOAD _IOR(VC_MEM_IOC_MAGIC, 3, unsigned int)
+
+#ifdef __KERNEL__
+#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
+
+extern unsigned long mm_vc_mem_phys_addr;
+extern unsigned int mm_vc_mem_size;
+extern int vc_mem_get_current_size(void);
+#endif
+
+#ifdef CONFIG_COMPAT
+#define VC_MEM_IOC_MEM_PHYS_ADDR32 _IOR(VC_MEM_IOC_MAGIC, 0, compat_ulong_t)
+#endif
+
+#endif /* _VC_MEM_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,658 @@
From c75556e9fd6f131f405726babfff4cc97ac0cfb9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 15:44:08 +0100
Subject: [PATCH 062/697] Add Chris Boot's i2c driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
i2c-bcm2708: fixed baudrate
Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock).
In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits.
This resulted in incorrect setting of CDIV and higher baudrate than intended.
Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz
After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz
The correct baudrate is shown in the log after the cdiv > 0xffff correction.
Perform I2C combined transactions when possible
Perform I2C combined transactions whenever possible, within the
restrictions of the Broadcomm Serial Controller.
Disable DONE interrupt during TA poll
Prevent interrupt from being triggered if poll is missed and transfer
starts and finishes.
i2c: Make combined transactions optional and disabled by default
i2c: bcm2708: add device tree support
Add DT support to driver and add to .dtsi file.
Setup pins in .dts file.
i2c is disabled by default.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
bcm2708: don't register i2c controllers when using DT
The devices for the i2c controllers are in the Device Tree.
Only register devices when not using DT.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
I2C: Only register the I2C device for the current board revision
i2c_bcm2708: Fix clock reference counting
Fix grabbing lock from atomic context in i2c driver
2 main changes:
- check for timeouts in the bcm2708_bsc_setup function as indicated by this comment:
/* poll for transfer start bit (should only take 1-20 polls) */
This implies that the setup function can now fail so account for this everywhere it's called
- Removed the clk_get_rate call from inside the setup function as it locks a mutex and that's not ok since we call it from under a spin lock.
i2c-bcm2708: When using DT, leave the GPIO setup to pinctrl
i2c-bcm2708: Increase timeouts to allow larger transfers
Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting
for completion. The default timeout is 1 second.
See: https://github.com/raspberrypi/linux/issues/260
i2c-bcm2708/BCM270X_DT: Add support for I2C2
The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
use of this bus can break an attached display - use with caution.
It is recommended to disable accesses by VideoCore by setting
hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
The interface is disabled by default - enable using the
i2c2_iknowwhatimdoing DT parameter.
bcm2708-spi: Don't use static pin configuration with DT
Also remove superfluous error checking - the SPI framework ensures the
validity of the chip_select value.
i2c-bcm2708: Remove non-DT support
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.
Fixes i2c_bcm2708: Write to FIFO correctly - v2 (#1574)
* i2c: fix i2c_bcm2708: Clear FIFO before sending data
Make sure FIFO gets cleared before trying to send
data in case of a repeated start (COMBINED=Y).
* i2c: fix i2c_bcm2708: Only write to FIFO when not full
Check if FIFO can accept data before writing.
To avoid a peripheral read on the last iteration of a loop,
both bcm2708_bsc_fifo_fill and ~drain are changed as well.
---
drivers/i2c/busses/Kconfig | 19 ++
drivers/i2c/busses/Makefile | 2 +
drivers/i2c/busses/i2c-bcm2708.c | 510 +++++++++++++++++++++++++++++++
3 files changed, 531 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -16,6 +16,25 @@ config I2C_CCGX_UCSI
for Cypress CCGx Type-C controller. Individual bus drivers
need to select this one on demand.
+config I2C_BCM2708
+ tristate "BCM2708 BSC"
+ depends on ARCH_BCM2835
+ help
+ Enabling this option will add BSC (Broadcom Serial Controller)
+ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
+ with I2C/TWI/SMBus.
+
+config I2C_BCM2708_BAUDRATE
+ prompt "BCM2708 I2C baudrate"
+ depends on I2C_BCM2708
+ int
+ default 100000
+ help
+ Set the I2C baudrate. This will alter the default value. A
+ different baudrate can be set by using a module parameter as well. If
+ no parameter is provided when loading, this is the value that will be
+ used.
+
config I2C_ALI1535
tristate "ALI 1535"
depends on PCI && HAS_IOPORT
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -3,6 +3,8 @@
# Makefile for the i2c bus drivers.
#
+obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
+
# ACPI drivers
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -0,0 +1,510 @@
+/*
+ * Driver for Broadcom BCM2708 BSC Controllers
+ *
+ * Copyright (C) 2012 Chris Boot & Frank Buss
+ *
+ * This driver is inspired by:
+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+/* BSC register offsets */
+#define BSC_C 0x00
+#define BSC_S 0x04
+#define BSC_DLEN 0x08
+#define BSC_A 0x0c
+#define BSC_FIFO 0x10
+#define BSC_DIV 0x14
+#define BSC_DEL 0x18
+#define BSC_CLKT 0x1c
+
+/* Bitfields in BSC_C */
+#define BSC_C_I2CEN 0x00008000
+#define BSC_C_INTR 0x00000400
+#define BSC_C_INTT 0x00000200
+#define BSC_C_INTD 0x00000100
+#define BSC_C_ST 0x00000080
+#define BSC_C_CLEAR_1 0x00000020
+#define BSC_C_CLEAR_2 0x00000010
+#define BSC_C_READ 0x00000001
+
+/* Bitfields in BSC_S */
+#define BSC_S_CLKT 0x00000200
+#define BSC_S_ERR 0x00000100
+#define BSC_S_RXF 0x00000080
+#define BSC_S_TXE 0x00000040
+#define BSC_S_RXD 0x00000020
+#define BSC_S_TXD 0x00000010
+#define BSC_S_RXR 0x00000008
+#define BSC_S_TXW 0x00000004
+#define BSC_S_DONE 0x00000002
+#define BSC_S_TA 0x00000001
+
+#define I2C_WAIT_LOOP_COUNT 200
+
+#define DRV_NAME "bcm2708_i2c"
+
+static unsigned int baudrate;
+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
+
+static bool combined = false;
+module_param(combined, bool, 0644);
+MODULE_PARM_DESC(combined, "Use combined transactions");
+
+struct bcm2708_i2c {
+ struct i2c_adapter adapter;
+
+ spinlock_t lock;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ u32 cdiv;
+ u32 clk_tout;
+
+ struct completion done;
+
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ bool error;
+};
+
+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
+{
+ return readl(bi->base + reg);
+}
+
+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
+{
+ writel(val, bi->base + reg);
+}
+
+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
+{
+ bcm2708_wr(bi, BSC_C, 0);
+ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
+}
+
+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
+{
+ while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_RXD))
+ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
+}
+
+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
+{
+ while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_TXD))
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+}
+
+static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
+{
+ u32 cdiv, s, clk_tout;
+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
+ int wait_loops = I2C_WAIT_LOOP_COUNT;
+
+ /* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
+ * Use the value that we cached in the probe.
+ */
+ cdiv = bi->cdiv;
+ clk_tout = bi->clk_tout;
+
+ if (bi->msg->flags & I2C_M_RD)
+ c |= BSC_C_INTR | BSC_C_READ;
+ else
+ c |= BSC_C_INTT;
+
+ bcm2708_wr(bi, BSC_CLKT, clk_tout);
+ bcm2708_wr(bi, BSC_DIV, cdiv);
+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+ if (combined)
+ {
+ /* Do the next two messages meet combined transaction criteria?
+ - Current message is a write, next message is a read
+ - Both messages to same slave address
+ - Write message can fit inside FIFO (16 bytes or less) */
+ if ( (bi->nmsgs > 1) &&
+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
+
+ /* Clear FIFO */
+ bcm2708_wr(bi, BSC_C, BSC_C_CLEAR_1);
+
+ /* Fill FIFO with entire write message (16 byte FIFO) */
+ while (bi->pos < bi->msg->len) {
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+ }
+ /* Start write transfer (no interrupts, don't clear FIFO) */
+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
+
+ /* poll for transfer start bit (should only take 1-20 polls) */
+ do {
+ s = bcm2708_rd(bi, BSC_S);
+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
+
+ /* did we time out or some error occured? */
+ if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
+ return -1;
+ }
+
+ /* Send next read message before the write transfer finishes. */
+ bi->nmsgs--;
+ bi->msg++;
+ bi->pos = 0;
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
+ }
+ }
+ bcm2708_wr(bi, BSC_C, c);
+
+ return 0;
+}
+
+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
+{
+ struct bcm2708_i2c *bi = dev_id;
+ bool handled = true;
+ u32 s;
+ int ret;
+
+ spin_lock(&bi->lock);
+
+ /* we may see camera interrupts on the "other" I2C channel
+ Just return if we've not sent anything */
+ if (!bi->nmsgs || !bi->msg) {
+ goto early_exit;
+ }
+
+ s = bcm2708_rd(bi, BSC_S);
+
+ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
+ bcm2708_bsc_reset(bi);
+ bi->error = true;
+
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ } else if (s & BSC_S_DONE) {
+ bi->nmsgs--;
+
+ if (bi->msg->flags & I2C_M_RD) {
+ bcm2708_bsc_fifo_drain(bi);
+ }
+
+ bcm2708_bsc_reset(bi);
+
+ if (bi->nmsgs) {
+ /* advance to next message */
+ bi->msg++;
+ bi->pos = 0;
+ ret = bcm2708_bsc_setup(bi);
+ if (ret < 0) {
+ bcm2708_bsc_reset(bi);
+ bi->error = true;
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ goto early_exit;
+ }
+ } else {
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ }
+ } else if (s & BSC_S_TXW) {
+ bcm2708_bsc_fifo_fill(bi);
+ } else if (s & BSC_S_RXR) {
+ bcm2708_bsc_fifo_drain(bi);
+ } else {
+ handled = false;
+ }
+
+early_exit:
+ spin_unlock(&bi->lock);
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bcm2708_i2c *bi = adap->algo_data;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&bi->lock, flags);
+
+ reinit_completion(&bi->done);
+ bi->msg = msgs;
+ bi->pos = 0;
+ bi->nmsgs = num;
+ bi->error = false;
+
+ ret = bcm2708_bsc_setup(bi);
+
+ spin_unlock_irqrestore(&bi->lock, flags);
+
+ /* check the result of the setup */
+ if (ret < 0)
+ {
+ dev_err(&adap->dev, "transfer setup timed out\n");
+ goto error_timeout;
+ }
+
+ ret = wait_for_completion_timeout(&bi->done, adap->timeout);
+ if (ret == 0) {
+ dev_err(&adap->dev, "transfer timed out\n");
+ goto error_timeout;
+ }
+
+ ret = bi->error ? -EIO : num;
+ return ret;
+
+error_timeout:
+ spin_lock_irqsave(&bi->lock, flags);
+ bcm2708_bsc_reset(bi);
+ bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
+ bi->nmsgs = 0;
+ spin_unlock_irqrestore(&bi->lock, flags);
+ return -ETIMEDOUT;
+}
+
+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm bcm2708_i2c_algorithm = {
+ .master_xfer = bcm2708_i2c_master_xfer,
+ .functionality = bcm2708_i2c_functionality,
+};
+
+static int bcm2708_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ int irq, err = -ENOMEM;
+ struct clk *clk;
+ struct bcm2708_i2c *bi;
+ struct i2c_adapter *adap;
+ unsigned long bus_hz;
+ u32 cdiv, clk_tout;
+ u32 baud;
+
+ baud = CONFIG_I2C_BCM2708_BAUDRATE;
+
+ if (pdev->dev.of_node) {
+ u32 bus_clk_rate;
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
+ if (pdev->id < 0) {
+ dev_err(&pdev->dev, "alias is missing\n");
+ return -EINVAL;
+ }
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &bus_clk_rate))
+ baud = bus_clk_rate;
+ else
+ dev_warn(&pdev->dev,
+ "Could not read clock-frequency property\n");
+ }
+
+ if (baudrate)
+ baud = baudrate;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "could not get IO memory\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "could not get IRQ\n");
+ return irq;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ err = clk_prepare_enable(clk);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable clk: %d\n", err);
+ goto out_clk_put;
+ }
+
+ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
+ if (!bi)
+ goto out_clk_disable;
+
+ platform_set_drvdata(pdev, bi);
+
+ adap = &bi->adapter;
+ adap->class = I2C_CLASS_HWMON;
+ adap->algo = &bcm2708_i2c_algorithm;
+ adap->algo_data = bi;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+ strscpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+ adap->dev.of_node = pdev->dev.of_node;
+
+ switch (pdev->id) {
+ case 0:
+ adap->class = I2C_CLASS_HWMON;
+ break;
+ case 1:
+ adap->class = I2C_CLASS_HWMON;
+ break;
+ case 2:
+ adap->class = I2C_CLASS_HWMON;
+ break;
+ default:
+ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
+ err = -ENXIO;
+ goto out_free_bi;
+ }
+
+ spin_lock_init(&bi->lock);
+ init_completion(&bi->done);
+
+ bi->base = ioremap(regs->start, resource_size(regs));
+ if (!bi->base) {
+ dev_err(&pdev->dev, "could not remap memory\n");
+ goto out_free_bi;
+ }
+
+ bi->irq = irq;
+ bi->clk = clk;
+
+ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
+ dev_name(&pdev->dev), bi);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+ goto out_iounmap;
+ }
+
+ bcm2708_bsc_reset(bi);
+
+ err = i2c_add_numbered_adapter(adap);
+ if (err < 0) {
+ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
+ goto out_free_irq;
+ }
+
+ bus_hz = clk_get_rate(bi->clk);
+ cdiv = bus_hz / baud;
+ if (cdiv > 0xffff) {
+ cdiv = 0xffff;
+ baud = bus_hz / cdiv;
+ }
+
+ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs.
+ if (clk_tout > 0xffff)
+ clk_tout = 0xffff;
+
+ bi->cdiv = cdiv;
+ bi->clk_tout = clk_tout;
+
+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
+ pdev->id, (unsigned long)regs->start, irq, baud);
+
+ return 0;
+
+out_free_irq:
+ free_irq(bi->irq, bi);
+out_iounmap:
+ iounmap(bi->base);
+out_free_bi:
+ kfree(bi);
+out_clk_disable:
+ clk_disable_unprepare(clk);
+out_clk_put:
+ clk_put(clk);
+ return err;
+}
+
+static void bcm2708_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&bi->adapter);
+ free_irq(bi->irq, bi);
+ iounmap(bi->base);
+ clk_disable_unprepare(bi->clk);
+ clk_put(bi->clk);
+ kfree(bi);
+}
+
+static const struct of_device_id bcm2708_i2c_of_match[] = {
+ { .compatible = "brcm,bcm2708-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
+
+static struct platform_driver bcm2708_i2c_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2708_i2c_of_match,
+ },
+ .probe = bcm2708_i2c_probe,
+ .remove = bcm2708_i2c_remove,
+};
+
+// module_platform_driver(bcm2708_i2c_driver);
+
+
+static int __init bcm2708_i2c_init(void)
+{
+ return platform_driver_register(&bcm2708_i2c_driver);
+}
+
+static void __exit bcm2708_i2c_exit(void)
+{
+ platform_driver_unregister(&bcm2708_i2c_driver);
+}
+
+module_init(bcm2708_i2c_init);
+module_exit(bcm2708_i2c_exit);
+
+
+
+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -0,0 +1,30 @@
From b9a2234c9a117aff21f85436d11d49ed42bdf285 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 28 Sep 2020 20:23:30 +0100
Subject: [PATCH 063/697] char: Add broadcom char drivers back to build files
See: https://github.com/raspberrypi/linux/issues/3875
Signed-off-by: popcornmix <popcornmix@gmail.com>
---
drivers/char/Kconfig | 2 ++
drivers/char/Makefile | 1 +
2 files changed, 3 insertions(+)
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -5,6 +5,8 @@
menu "Character devices"
+source "drivers/char/broadcom/Kconfig"
+
source "drivers/tty/Kconfig"
config TTY_PRINTK
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
obj-$(CONFIG_ADI) += adi.o
+obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/

View File

@ -0,0 +1,273 @@
From f2158870e6bcba478fef6d8b84ed6a814d2d8374 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 26 Jun 2015 14:27:06 +0200
Subject: [PATCH 064/697] char: broadcom: Add vcio module
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add module for accessing the mailbox property channel through
/dev/vcio. Was previously in bcm2708-vcio.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
char: vcio: Add compat ioctl handling
There was no compat ioctl handler, so 32 bit userspace on a
64 bit kernel failed as IOCTL_MBOX_PROPERTY used the size
of char*.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
char: vcio: Fail probe if rpi_firmware is not found.
Device Tree is now the only supported config mechanism, therefore
uncomment the block of code that fails the probe if the
firmware node can't be found.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
drivers: char: vcio: Use common compat header
The definition of compat_ptr is now common for most platforms, but
requires the inclusion of <linux/compat.h>.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
char: vcio: Rewrite as a firmware node child
The old vcio driver is a simple character device that manually locates
the firmware driver. Initialising it before the firmware driver causes
a failure, and no retries are attempted.
Rewrite vcio as a platform driver that depends on a DT node for its
instantiation and the location of the firmware driver, making use of
the miscdevice framework to reduce the code size.
N.B. Using miscdevice changes the udev SUBSYSTEM string, so a change
to the companion udev rule is required in order to continue to set
the correct device permissions, e.g.:
KERNEL="vcio", GROUP="video", MODE="0660"
See: https://github.com/raspberrypi/linux/issues/4620
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/char/broadcom/Kconfig | 6 ++
drivers/char/broadcom/Makefile | 1 +
drivers/char/broadcom/vcio.c | 187 +++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+)
create mode 100644 drivers/char/broadcom/vcio.c
--- a/drivers/char/broadcom/Kconfig
+++ b/drivers/char/broadcom/Kconfig
@@ -15,6 +15,12 @@ config BCM2708_VCMEM
help
Helper for videocore memory access and total size allocation.
+config BCM_VCIO
+ tristate "Mailbox userspace access"
+ depends on BCM2835_MBOX
+ help
+ Gives access to the mailbox property channel from userspace.
+
endif
config BCM2835_SMI_DEV
--- a/drivers/char/broadcom/Makefile
+++ b/drivers/char/broadcom/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
+obj-$(CONFIG_BCM_VCIO) += vcio.o
obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
--- /dev/null
+++ b/drivers/char/broadcom/vcio.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 2015 Noralf Trønnes
+ * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/miscdevice.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MODULE_NAME "vcio"
+#define VCIO_IOC_MAGIC 100
+#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
+#ifdef CONFIG_COMPAT
+#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
+#endif
+
+struct vcio_data {
+ struct rpi_firmware *fw;
+ struct miscdevice misc_dev;
+};
+
+static int vcio_user_property_list(struct vcio_data *vcio, void *user)
+{
+ u32 *buf, size;
+ int ret;
+
+ /* The first 32-bit is the size of the buffer */
+ if (copy_from_user(&size, user, sizeof(size)))
+ return -EFAULT;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user, size)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ /* Strip off protocol encapsulation */
+ ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
+ if (ret) {
+ kfree(buf);
+ return ret;
+ }
+
+ buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
+ if (copy_to_user(user, buf, size))
+ ret = -EFAULT;
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int vcio_device_open(struct inode *inode, struct file *file)
+{
+ try_module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static int vcio_device_release(struct inode *inode, struct file *file)
+{
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ struct vcio_data *vcio = container_of(file->private_data,
+ struct vcio_data, misc_dev);
+
+ switch (ioctl_num) {
+ case IOCTL_MBOX_PROPERTY:
+ return vcio_user_property_list(vcio, (void *)ioctl_param);
+ default:
+ pr_err("unknown ioctl: %x\n", ioctl_num);
+ return -EINVAL;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ struct vcio_data *vcio = container_of(file->private_data,
+ struct vcio_data, misc_dev);
+
+ switch (ioctl_num) {
+ case IOCTL_MBOX_PROPERTY32:
+ return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
+ default:
+ pr_err("unknown ioctl: %x\n", ioctl_num);
+ return -EINVAL;
+ }
+}
+#endif
+
+const struct file_operations vcio_fops = {
+ .unlocked_ioctl = vcio_device_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vcio_device_compat_ioctl,
+#endif
+ .open = vcio_device_open,
+ .release = vcio_device_release,
+};
+
+static int vcio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *fw_node;
+ struct rpi_firmware *fw;
+ struct vcio_data *vcio;
+
+ fw_node = of_get_parent(np);
+ if (!fw_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ fw = rpi_firmware_get(fw_node);
+ of_node_put(fw_node);
+ if (!fw)
+ return -EPROBE_DEFER;
+
+ vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
+ if (!vcio)
+ return -ENOMEM;
+
+ vcio->fw = fw;
+ vcio->misc_dev.fops = &vcio_fops;
+ vcio->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ vcio->misc_dev.name = "vcio";
+ vcio->misc_dev.parent = dev;
+
+ return misc_register(&vcio->misc_dev);
+}
+
+static void vcio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ misc_deregister(dev_get_drvdata(dev));
+}
+
+static const struct of_device_id vcio_ids[] = {
+ { .compatible = "raspberrypi,vcio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, vcio_ids);
+
+static struct platform_driver vcio_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .of_match_table = of_match_ptr(vcio_ids),
+ },
+ .probe = vcio_probe,
+ .remove = vcio_remove,
+};
+
+module_platform_driver(vcio_driver);
+
+MODULE_AUTHOR("Gray Girling");
+MODULE_AUTHOR("Noralf Trønnes");
+MODULE_DESCRIPTION("Mailbox userspace access");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rpi-vcio");

View File

@ -0,0 +1,327 @@
From 6ff3acf627170d870d90cc555520876103af0292 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Tue, 25 Apr 2023 15:52:13 +0100
Subject: [PATCH 065/697] drivers: char: add generic gpiomem driver
Based on bcm2835-gpiomem.
We allow export of the "GPIO registers" to userspace via a chardev as
this allows for finer access control (e.g. users must be group gpio, root
not required).
This driver allows access to either rp1-gpiomem or gpiomem, depending on
which nodes are populated in devicetree.
RP1 has a different look-and-feel to BCM283x SoCs as it has split ranges
for IO controls and the parallel registered OE/IN/OUT access. To handle
this, the driver concatenates the ranges for an IO bank and the
corresponding RIO instance into a contiguous buffer.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/char/Kconfig | 8 +
drivers/char/Makefile | 1 +
drivers/char/raspberrypi-gpiomem.c | 275 +++++++++++++++++++++++++++++
3 files changed, 284 insertions(+)
create mode 100644 drivers/char/raspberrypi-gpiomem.c
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -424,4 +424,12 @@ config ADI
and SSM (Silicon Secured Memory). Intended consumers of this
driver include crash and makedumpfile.
+config RASPBERRYPI_GPIOMEM
+ tristate "Rootless GPIO access via mmap() on Raspberry Pi boards"
+ default n
+ help
+ Provides users with root-free access to the GPIO registers
+ on the board. Calling mmap(/dev/gpiomem) will map the GPIO
+ register page to the user's pointer.
+
endmenu
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_XILLYBUS_CLASS) += xillybus
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
obj-$(CONFIG_ADI) += adi.o
obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
+obj-$(CONFIG_RASPBERRYPI_GPIOMEM) += raspberrypi-gpiomem.o
--- /dev/null
+++ b/drivers/char/raspberrypi-gpiomem.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/**
+ * raspberrypi-gpiomem.c
+ *
+ * Provides MMIO access to discontiguous section of Device memory as a linear
+ * user mapping. Successor to bcm2835-gpiomem.c.
+ *
+ * Copyright (c) 2023, Raspberry Pi Ltd.
+ */
+
+#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 "rpi-gpiomem"
+#define DEVICE_MINOR 0
+
+/*
+ * Sensible max for a hypothetical "gpio" controller that splits pads,
+ * IO controls, GPIO in/out/enable, and function selection into different
+ * ranges. Most use only one or two.
+ */
+#define MAX_RANGES 4
+
+struct io_windows {
+ unsigned long phys_base;
+ unsigned long len;
+};
+
+struct rpi_gpiomem_priv {
+ dev_t devid;
+ struct class *class;
+ struct cdev rpi_gpiomem_cdev;
+ struct device *dev;
+ const char *name;
+ unsigned int nr_wins;
+ struct io_windows iowins[4];
+};
+
+static int rpi_gpiomem_open(struct inode *inode, struct file *file)
+{
+ int dev = iminor(inode);
+ int ret = 0;
+ struct rpi_gpiomem_priv *priv;
+
+ if (dev != DEVICE_MINOR)
+ ret = -ENXIO;
+
+ priv = container_of(inode->i_cdev, struct rpi_gpiomem_priv,
+ rpi_gpiomem_cdev);
+ if (!priv)
+ return -EINVAL;
+ file->private_data = priv;
+ return ret;
+}
+
+static int rpi_gpiomem_release(struct inode *inode, struct file *file)
+{
+ int dev = iminor(inode);
+ int ret = 0;
+
+ if (dev != DEVICE_MINOR)
+ ret = -ENXIO;
+
+ return ret;
+}
+
+static const struct vm_operations_struct rpi_gpiomem_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys
+#endif
+};
+
+static int rpi_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int i;
+ struct rpi_gpiomem_priv *priv;
+ unsigned long base;
+ unsigned long len = 0;
+ unsigned long offset;
+
+ priv = file->private_data;
+ /*
+ * Userspace must provide a virtual address space at least
+ * the size of the concatenated ranges.
+ */
+ for (i = 0; i < priv->nr_wins; i++)
+ len += priv->iowins[i].len;
+ if (len > vma->vm_end - vma->vm_start + 1)
+ return -EINVAL;
+
+ vma->vm_ops = &rpi_gpiomem_vm_ops;
+ offset = vma->vm_start;
+ for (i = 0; i < priv->nr_wins; i++) {
+ base = priv->iowins[i].phys_base >> PAGE_SHIFT;
+ len = priv->iowins[i].len;
+ vma->vm_page_prot = phys_mem_access_prot(file, base, len,
+ vma->vm_page_prot);
+ if (remap_pfn_range(vma, offset,
+ base, len,
+ vma->vm_page_prot))
+ break;
+ offset += len;
+ }
+
+ if (i < priv->nr_wins)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static const struct file_operations rpi_gpiomem_fops = {
+ .owner = THIS_MODULE,
+ .open = rpi_gpiomem_open,
+ .release = rpi_gpiomem_release,
+ .mmap = rpi_gpiomem_mmap,
+};
+
+static const struct of_device_id rpi_gpiomem_of_match[];
+
+static int rpi_gpiomem_probe(struct platform_device *pdev)
+{
+ int err, i;
+ const struct of_device_id *id;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct resource *ioresource;
+ struct rpi_gpiomem_priv *priv;
+
+ /* Allocate buffers and instance data */
+
+ priv = kzalloc(sizeof(struct rpi_gpiomem_priv), GFP_KERNEL);
+
+ if (!priv) {
+ err = -ENOMEM;
+ goto failed_inst_alloc;
+ }
+ platform_set_drvdata(pdev, priv);
+
+ priv->dev = dev;
+ id = of_match_device(rpi_gpiomem_of_match, dev);
+ if (!id)
+ return -EINVAL;
+
+ /*
+ * Device node naming - for legacy (bcm2835) DT bindings, the driver
+ * created the node based on a hardcoded name - for new bindings,
+ * take the node name from DT.
+ */
+ if (id == &rpi_gpiomem_of_match[0]) {
+ priv->name = "gpiomem";
+ } else {
+ err = of_property_read_string(node, "chardev-name", &priv->name);
+ if (err)
+ return -EINVAL;
+ }
+
+ /*
+ * Go find the register ranges associated with this instance
+ */
+ for (i = 0; i < MAX_RANGES; i++) {
+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!ioresource && i == 0) {
+ dev_err(priv->dev, "failed to get IO resource - no ranges available\n");
+ err = -ENOENT;
+ goto failed_get_resource;
+ }
+ if (!ioresource)
+ break;
+
+ priv->iowins[i].phys_base = ioresource->start;
+ priv->iowins[i].len = (ioresource->end + 1) - ioresource->start;
+ dev_info(&pdev->dev, "window base 0x%08lx size 0x%08lx\n",
+ priv->iowins[i].phys_base, priv->iowins[i].len);
+ priv->nr_wins++;
+ }
+
+ /* Create character device entries */
+
+ err = alloc_chrdev_region(&priv->devid,
+ DEVICE_MINOR, 1, priv->name);
+ if (err != 0) {
+ dev_err(priv->dev, "unable to allocate device number");
+ goto failed_alloc_chrdev;
+ }
+ cdev_init(&priv->rpi_gpiomem_cdev, &rpi_gpiomem_fops);
+ priv->rpi_gpiomem_cdev.owner = THIS_MODULE;
+ err = cdev_add(&priv->rpi_gpiomem_cdev, priv->devid, 1);
+ if (err != 0) {
+ dev_err(priv->dev, "unable to register device");
+ goto failed_cdev_add;
+ }
+
+ /* Create sysfs entries */
+
+ priv->class = class_create(priv->name);
+ if (IS_ERR(priv->class)) {
+ err = PTR_ERR(priv->class);
+ goto failed_class_create;
+ }
+
+ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name);
+ if (IS_ERR(dev)) {
+ err = PTR_ERR(dev);
+ goto failed_device_create;
+ }
+
+ dev_info(priv->dev, "initialised %u regions as /dev/%s\n",
+ priv->nr_wins, priv->name);
+
+ return 0;
+
+failed_device_create:
+ class_destroy(priv->class);
+failed_class_create:
+ cdev_del(&priv->rpi_gpiomem_cdev);
+failed_cdev_add:
+ unregister_chrdev_region(priv->devid, 1);
+failed_alloc_chrdev:
+failed_get_resource:
+ kfree(priv);
+failed_inst_alloc:
+ dev_err(&pdev->dev, "could not load rpi_gpiomem");
+ return err;
+}
+
+static void rpi_gpiomem_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpi_gpiomem_priv *priv = platform_get_drvdata(pdev);
+
+ device_destroy(priv->class, priv->devid);
+ class_destroy(priv->class);
+ cdev_del(&priv->rpi_gpiomem_cdev);
+ unregister_chrdev_region(priv->devid, 1);
+ kfree(priv);
+
+ dev_info(dev, "%s driver removed - OK", priv->name);
+}
+
+static const struct of_device_id rpi_gpiomem_of_match[] = {
+ {
+ .compatible = "brcm,bcm2835-gpiomem",
+ },
+ {
+ .compatible = "raspberrypi,gpiomem",
+ },
+ { /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, rpi_gpiomem_of_match);
+
+static struct platform_driver rpi_gpiomem_driver = {
+ .probe = rpi_gpiomem_probe,
+ .remove = rpi_gpiomem_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = rpi_gpiomem_of_match,
+ },
+};
+
+module_platform_driver(rpi_gpiomem_driver);
+
+MODULE_ALIAS("platform:rpi-gpiomem");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Driver for accessing GPIOs from userspace");
+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>");

View File

@ -0,0 +1,74 @@
From ec076200dd0eed1df5aa179babfa8b2723de88c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 26 Jun 2015 14:25:01 +0200
Subject: [PATCH 066/697] firmware: bcm2835: Support ARCH_BCM270x
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Support booting without Device Tree.
Turn on USB power.
Load driver early because of lacking support for deferred probing
in many drivers.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
firmware: bcm2835: Don't turn on USB power
The raspberrypi-power driver is now used to turn on USB power.
This partly reverts commit:
firmware: bcm2835: Support ARCH_BCM270x
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/firmware/raspberrypi.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -34,6 +34,8 @@ struct rpi_firmware {
struct kref consumers;
};
+static struct platform_device *g_pdev;
+
static DEFINE_MUTEX(transaction_lock);
static void response_callback(struct mbox_client *cl, void *msg)
@@ -301,6 +303,7 @@ static int rpi_firmware_probe(struct pla
kref_init(&fw->consumers);
platform_set_drvdata(pdev, fw);
+ g_pdev = pdev;
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
@@ -329,6 +332,7 @@ static void rpi_firmware_remove(struct p
rpi_clk = NULL;
rpi_firmware_put(fw);
+ g_pdev = NULL;
}
static const struct of_device_id rpi_firmware_of_match[] = {
@@ -408,7 +412,18 @@ static struct platform_driver rpi_firmwa
.shutdown = rpi_firmware_shutdown,
.remove_new = rpi_firmware_remove,
};
-module_platform_driver(rpi_firmware_driver);
+
+static int __init rpi_firmware_init(void)
+{
+ return platform_driver_register(&rpi_firmware_driver);
+}
+core_initcall(rpi_firmware_init);
+
+static void __init rpi_firmware_exit(void)
+{
+ platform_driver_unregister(&rpi_firmware_driver);
+}
+module_exit(rpi_firmware_exit);
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("Raspberry Pi firmware driver");

View File

@ -0,0 +1,168 @@
From 09656b6be61c38b287446ac2aade80fdf71636c9 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 6 Feb 2015 13:50:57 +0000
Subject: [PATCH 067/697] leds: Add the "input" trigger, for pwr_led
The "input" trigger makes the associated GPIO an input. This is to support
the Raspberry Pi PWR LED, which is driven by external hardware in normal use.
N.B. pwr_led is not available on Model A or B boards.
leds-gpio: Implement the brightness_get method
The power LED uses some clever logic that means it is driven
by a voltage measuring circuit when configured as input, otherwise
it is driven by the GPIO output value. This patch wires up the
brightness_get method for leds-gpio so that user-space can monitor
the LED value via /sys/class/gpio/led1/brightness. Using the input
trigger this returns an indication of the system power health,
otherwise it is just whatever value the trigger has written most
recently.
See: https://github.com/raspberrypi/linux/issues/1064
---
drivers/leds/leds-gpio.c | 17 ++++++++-
drivers/leds/trigger/Kconfig | 7 ++++
drivers/leds/trigger/Makefile | 1 +
drivers/leds/trigger/ledtrig-input.c | 55 ++++++++++++++++++++++++++++
include/linux/leds.h | 3 ++
5 files changed, 82 insertions(+), 1 deletion(-)
create mode 100644 drivers/leds/trigger/ledtrig-input.c
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -52,8 +52,15 @@ static void gpio_led_set(struct led_clas
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
+ } else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
+ gpiod_direction_input(led_dat->gpiod);
+ led_dat->cdev.flags &= ~SET_GPIO_INPUT;
+ } else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
+ gpiod_direction_output(led_dat->gpiod, level);
+ led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
} else {
- if (led_dat->can_sleep)
+ if (led_dat->can_sleep ||
+ (led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) ))
gpiod_set_value_cansleep(led_dat->gpiod, level);
else
gpiod_set_value(led_dat->gpiod, level);
@@ -67,6 +74,13 @@ static int gpio_led_set_blocking(struct
return 0;
}
+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+ return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
+}
+
static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
@@ -96,6 +110,7 @@ static int create_gpio_led(const struct
led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
+ led_dat->cdev.brightness_get = gpio_led_get;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) {
state = gpiod_get_value_cansleep(led_dat->gpiod);
if (state < 0)
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -113,6 +113,13 @@ config LEDS_TRIGGER_CAMERA
This enables direct flash/torch on/off by the driver, kernel space.
If unsure, say Y.
+config LEDS_TRIGGER_INPUT
+ tristate "LED Input Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows the GPIOs assigned to be LEDs to be initialised to inputs.
+ If unsure, say Y.
+
config LEDS_TRIGGER_PANIC
bool "LED Panic Trigger"
help
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += l
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
+obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-input.c
@@ -0,0 +1,55 @@
+/*
+ * Set LED GPIO to Input "Trigger"
+ *
+ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
+ *
+ * Based on Nick Forbes's ledtrig-default-on.c.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include "../leds.h"
+
+static int input_trig_activate(struct led_classdev *led_cdev)
+{
+ led_cdev->flags |= SET_GPIO_INPUT;
+ led_set_brightness(led_cdev, 0);
+ return 0;
+}
+
+static void input_trig_deactivate(struct led_classdev *led_cdev)
+{
+ led_cdev->flags |= SET_GPIO_OUTPUT;
+ led_set_brightness(led_cdev, 0);
+}
+
+static struct led_trigger input_led_trigger = {
+ .name = "input",
+ .activate = input_trig_activate,
+ .deactivate = input_trig_deactivate,
+};
+
+static int __init input_trig_init(void)
+{
+ return led_trigger_register(&input_led_trigger);
+}
+
+static void __exit input_trig_exit(void)
+{
+ led_trigger_unregister(&input_led_trigger);
+}
+
+module_init(input_trig_init);
+module_exit(input_trig_exit);
+
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
+MODULE_LICENSE("GPL");
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -109,6 +109,9 @@ struct led_classdev {
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
#define LED_REJECT_NAME_CONFLICT BIT(24)
#define LED_MULTI_COLOR BIT(25)
+ /* Additions for Raspberry Pi PWR LED */
+#define SET_GPIO_INPUT BIT(30)
+#define SET_GPIO_OUTPUT BIT(31)
/* set_brightness_work / blink_timer flags, atomic, private. */
unsigned long work_flags;

View File

@ -0,0 +1,22 @@
From ac6c60609e5a8f1fc1e5aad48eea1340ed0fce98 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:54:08 +0100
Subject: [PATCH 068/697] Added Device IDs for August DVB-T 205
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1964,6 +1964,10 @@ static const struct usb_device_id rtl28x
&rtl28xxu_props, "Compro VideoMate U650F", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
&rtl28xxu_props, "MaxMedia HU394-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
&rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,

View File

@ -0,0 +1,408 @@
From 82aebddad0ceb9b44158f0cb87f5b34c2a647c42 Mon Sep 17 00:00:00 2001
From: Phil Elwell <pelwell@users.noreply.github.com>
Date: Tue, 14 Jul 2015 14:32:47 +0100
Subject: [PATCH 070/697] mfd: Add Raspberry Pi Sense HAT core driver
mfd: Add rpi_sense_core of compatible string
rpisense-fb: Set pseudo_pallete to prevent crash on fbcon takeover
Signed-off-by: Serge Schneider <serge@raspberrypi.com>
rpisense-fb: Add explicit fb_deferred_io_mmap hook
As of commit [1], introduced in 5.18, fbdev drivers that use
deferred IO and need mmap support must include an explicit fb_mmap
pointer to the fb_deferred_io_mmap.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
[1] 590558510327 ("fbdev: Put mmap for deferred I/O into drivers")
drivers: Remove downstream SenseHAT core and joystick drivers
Parts of a SenseHAT driver have been submitted upstream using the
simple-i2c-mfd framework. The joystick driver has been merged.
It's been noted that there are several issues with the downstream
joystick and core drivers, so remove these in favour of the upstream
approach, and fix up the FB driver to match.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/video/fbdev/Kconfig | 13 +
drivers/video/fbdev/Makefile | 1 +
drivers/video/fbdev/rpisense-fb.c | 295 +++++++++++++++++++++++
include/linux/mfd/rpisense/framebuffer.h | 35 +++
4 files changed, 344 insertions(+)
create mode 100644 drivers/video/fbdev/rpisense-fb.c
create mode 100644 include/linux/mfd/rpisense/framebuffer.h
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1826,6 +1826,19 @@ config FB_SM712
called sm712fb. If you want to compile it as a module, say M
here and read <file:Documentation/kbuild/modules.rst>.
+config FB_RPISENSE
+ tristate "Raspberry Pi Sense HAT framebuffer"
+ depends on FB && I2C
+ select MFD_SIMPLE_MFD_I2C
+ select FB_SYS_FOPS
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_DEFERRED_IO
+
+ help
+ This is the framebuffer driver for the Raspberry Pi Sense HAT
+
source "drivers/video/fbdev/omap/Kconfig"
source "drivers/video/fbdev/omap2/Kconfig"
source "drivers/video/fbdev/mmp/Kconfig"
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_VGA16) += vga
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
+obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
--- /dev/null
+++ b/drivers/video/fbdev/rpisense-fb.c
@@ -0,0 +1,295 @@
+/*
+ * Raspberry Pi Sense HAT framebuffer driver
+ * http://raspberrypi.org
+ *
+ * Copyright (C) 2015 Raspberry Pi
+ *
+ * Author: Serge Schneider
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/rpisense/framebuffer.h>
+
+static bool lowlight;
+module_param(lowlight, bool, 0);
+MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
+
+struct rpisense_fb_param {
+ char __iomem *vmem;
+ u8 *vmem_work;
+ u32 vmemsize;
+ u8 *gamma;
+};
+
+static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
+ 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
+
+static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
+
+static u8 gamma_user[32];
+
+static u32 pseudo_palette[16];
+
+static struct rpisense_fb_param rpisense_fb_param = {
+ .vmem = NULL,
+ .vmemsize = 128,
+ .gamma = gamma_default,
+};
+
+static struct fb_deferred_io rpisense_fb_defio;
+
+static struct fb_fix_screeninfo rpisense_fb_fix = {
+ .id = "RPi-Sense FB",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+ .line_length = 16,
+};
+
+static struct fb_var_screeninfo rpisense_fb_var = {
+ .xres = 8,
+ .yres = 8,
+ .xres_virtual = 8,
+ .yres_virtual = 8,
+ .bits_per_pixel = 16,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+};
+
+static ssize_t rpisense_fb_write(struct fb_info *info,
+ const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ ssize_t res = fb_sys_write(info, buf, count, ppos);
+
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
+ return res;
+}
+
+static void rpisense_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ sys_fillrect(info, rect);
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
+}
+
+static void rpisense_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ sys_copyarea(info, area);
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
+}
+
+static void rpisense_fb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ sys_imageblit(info, image);
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
+}
+
+static void rpisense_fb_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ int i;
+ int j;
+ u8 *vmem_work = rpisense_fb_param.vmem_work;
+ u16 *mem = (u16 *)rpisense_fb_param.vmem;
+ u8 *gamma = rpisense_fb_param.gamma;
+ struct rpisense_fb *rpisense_fb = info->par;
+
+ for (j = 0; j < 8; j++) {
+ for (i = 0; i < 8; i++) {
+ vmem_work[(j * 24) + i] =
+ gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
+ vmem_work[(j * 24) + (i + 8)] =
+ gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
+ vmem_work[(j * 24) + (i + 16)] =
+ gamma[(mem[(j * 8) + i]) & 0x1F];
+ }
+ }
+ regmap_bulk_write(rpisense_fb->regmap, 0, vmem_work, 192);
+}
+
+static struct fb_deferred_io rpisense_fb_defio = {
+ .delay = HZ/100,
+ .deferred_io = rpisense_fb_deferred_io,
+};
+
+static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case SENSEFB_FBIOGET_GAMMA:
+ if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
+ sizeof(u8[32])))
+ return -EFAULT;
+ return 0;
+ case SENSEFB_FBIOSET_GAMMA:
+ if (copy_from_user(gamma_user, (void __user *)arg,
+ sizeof(u8[32])))
+ return -EFAULT;
+ rpisense_fb_param.gamma = gamma_user;
+ schedule_delayed_work(&info->deferred_work,
+ rpisense_fb_defio.delay);
+ return 0;
+ case SENSEFB_FBIORESET_GAMMA:
+ switch (arg) {
+ case 0:
+ rpisense_fb_param.gamma = gamma_default;
+ break;
+ case 1:
+ rpisense_fb_param.gamma = gamma_low;
+ break;
+ case 2:
+ rpisense_fb_param.gamma = gamma_user;
+ break;
+ default:
+ return -EINVAL;
+ }
+ schedule_delayed_work(&info->deferred_work,
+ rpisense_fb_defio.delay);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct fb_ops rpisense_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = rpisense_fb_write,
+ .fb_fillrect = rpisense_fb_fillrect,
+ .fb_copyarea = rpisense_fb_copyarea,
+ .fb_imageblit = rpisense_fb_imageblit,
+ .fb_ioctl = rpisense_fb_ioctl,
+ .fb_mmap = fb_deferred_io_mmap,
+};
+
+static int rpisense_fb_probe(struct platform_device *pdev)
+{
+ struct fb_info *info;
+ int ret = -ENOMEM;
+ struct rpisense_fb *rpisense_fb;
+
+ info = framebuffer_alloc(sizeof(*rpisense_fb), &pdev->dev);
+ if (!info) {
+ dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
+ goto err_malloc;
+ }
+
+ rpisense_fb = info->par;
+ platform_set_drvdata(pdev, rpisense_fb);
+
+ rpisense_fb->pdev = pdev;
+ rpisense_fb->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!rpisense_fb->regmap) {
+ dev_err(&pdev->dev,
+ "unable to get sensehat regmap");
+ return -ENODEV;
+ }
+
+ rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
+ if (!rpisense_fb_param.vmem)
+ return ret;
+
+ rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
+ if (!rpisense_fb_param.vmem_work)
+ goto err_malloc;
+
+
+ rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
+ rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
+
+ info->fbops = &rpisense_fb_ops;
+ info->fix = rpisense_fb_fix;
+ info->var = rpisense_fb_var;
+ info->fbdefio = &rpisense_fb_defio;
+ info->flags = FBINFO_VIRTFB;
+ info->screen_base = rpisense_fb_param.vmem;
+ info->screen_size = rpisense_fb_param.vmemsize;
+ info->pseudo_palette = pseudo_palette;
+
+ if (lowlight)
+ rpisense_fb_param.gamma = gamma_low;
+
+ fb_deferred_io_init(info);
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register framebuffer.\n");
+ goto err_fballoc;
+ }
+
+ fb_info(info, "%s frame buffer device\n", info->fix.id);
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
+ return 0;
+err_fballoc:
+ framebuffer_release(info);
+err_malloc:
+ vfree(rpisense_fb_param.vmem);
+ return ret;
+}
+
+static void rpisense_fb_remove(struct platform_device *pdev)
+{
+ struct rpisense_fb *rpisense_fb = platform_get_drvdata(pdev);
+ struct fb_info *info = rpisense_fb->info;
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_deferred_io_cleanup(info);
+ framebuffer_release(info);
+ vfree(rpisense_fb_param.vmem);
+ }
+}
+
+static const struct of_device_id rpisense_fb_id[] = {
+ { .compatible = "raspberrypi,rpi-sense-fb" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rpisense_fb_id);
+
+static struct platform_driver rpisense_fb_driver = {
+ .probe = rpisense_fb_probe,
+ .remove = rpisense_fb_remove,
+ .driver = {
+ .name = "rpi-sense-fb",
+ .owner = THIS_MODULE,
+ .of_match_table = rpisense_fb_id,
+ },
+};
+
+module_platform_driver(rpisense_fb_driver);
+
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+++ b/include/linux/mfd/rpisense/framebuffer.h
@@ -0,0 +1,35 @@
+/*
+ * Raspberry Pi Sense HAT framebuffer driver
+ * http://raspberrypi.org
+ *
+ * Copyright (C) 2015 Raspberry Pi
+ *
+ * Author: Serge Schneider
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __LINUX_RPISENSE_FB_H_
+#define __LINUX_RPISENSE_FB_H_
+
+#include <linux/regmap.h>
+
+#define SENSEFB_FBIO_IOC_MAGIC 0xF1
+
+#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
+#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
+#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
+
+struct rpisense;
+
+struct rpisense_fb {
+ struct fb_info *info;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+};
+
+#endif

View File

@ -0,0 +1,29 @@
From 80ce6b7c548b4073c700b61e5b3a2171dbfd6b4b Mon Sep 17 00:00:00 2001
From: Charles Mirabile <cmirabil@redhat.com>
Date: Tue, 19 Apr 2022 16:51:53 -0400
Subject: [PATCH 071/697] drivers/mfd: sensehat: Add Raspberry Pi Sense HAT to
simple_mfd_i2c
This patch adds the compatible string for the Sense HAT device to
the list of compatible strings in the simple_mfd_i2c driver so that
it can match against the device and load its children and their drivers
Co-developed-by: Mwesigwa Guma <mguma@redhat.com>
Signed-off-by: Mwesigwa Guma <mguma@redhat.com>
Co-developed-by: Joel Savitz <jsavitz@redhat.com>
Signed-off-by: Joel Savitz <jsavitz@redhat.com>
Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
---
drivers/mfd/simple-mfd-i2c.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -88,6 +88,7 @@ static const struct of_device_id simple_
{ .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
{ .compatible = "maxim,max5970", .data = &maxim_max5970},
{ .compatible = "maxim,max5978", .data = &maxim_max5970},
+ { .compatible = "raspberrypi,sensehat" },
{}
};
MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);

View File

@ -0,0 +1,28 @@
From dceb771df6eabca41880cdc721b8b55a0bab226e Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 20 Sep 2024 16:16:02 +0100
Subject: [PATCH 072/697] Input: sensehat-joystick : Revert to downstream
keymap
Upstream chose to use BTN_DPAD_* and BTN_SELECT, whilst downstream
had used KEY_*.
Revert to the downstream map to avoid any regressions.
(Ideally this would be read from DT)
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/input/joystick/sensehat-joystick.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/input/joystick/sensehat-joystick.c
+++ b/drivers/input/joystick/sensehat-joystick.c
@@ -28,7 +28,7 @@ struct sensehat_joystick {
};
static const unsigned int keymap[] = {
- BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT,
+ KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT
};
static irqreturn_t sensehat_joystick_report(int irq, void *cookie)

View File

@ -0,0 +1,171 @@
From ebc0dcfb01af90c5fb64b6bd13d8cd8ff53b67fa Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Wed, 21 Oct 2015 14:55:21 +0100
Subject: [PATCH 074/697] rpi_display: add backlight driver and overlay
Add a mailbox-driven backlight controller for the Raspberry Pi DSI
touchscreen display. Requires updated GPU firmware to recognise the
mailbox request.
Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
Add Raspberry Pi firmware driver to the dependencies of backlight driver
Otherwise the backlight driver fails to build if the firmware
loading driver is not in the kernel
Signed-off-by: Alex Riesen <alexander.riesen@cetitec.com>
---
drivers/video/backlight/Kconfig | 7 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/rpi_backlight.c | 118 ++++++++++++++++++++++++
3 files changed, 126 insertions(+)
create mode 100644 drivers/video/backlight/rpi_backlight.c
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -249,6 +249,13 @@ config BACKLIGHT_PWM
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
+config BACKLIGHT_RPI
+ tristate "Raspberry Pi display firmware driven backlight"
+ depends on RASPBERRYPI_FIRMWARE
+ help
+ If you have the Raspberry Pi DSI touchscreen display, say Y to
+ enable the mailbox-controlled backlight driver.
+
config BACKLIGHT_DA903X
tristate "Backlight Driver for DA9030/DA9034 using WLED"
depends on PMIC_DA903X
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
+obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o
obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
--- /dev/null
+++ b/drivers/video/backlight/rpi_backlight.c
@@ -0,0 +1,118 @@
+/*
+ * rpi_bl.c - Backlight controller through VPU
+ *
+ * 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/backlight.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+struct rpi_backlight {
+ struct device *dev;
+ struct device *fbdev;
+ struct rpi_firmware *fw;
+};
+
+static int rpi_backlight_update_status(struct backlight_device *bl)
+{
+ struct rpi_backlight *gbl = bl_get_data(bl);
+ int brightness = bl->props.brightness;
+ int ret;
+
+ if (bl->props.power != FB_BLANK_UNBLANK ||
+ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+ brightness = 0;
+
+ ret = rpi_firmware_property(gbl->fw,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
+ &brightness, sizeof(brightness));
+ if (ret) {
+ dev_err(gbl->dev, "Failed to set brightness\n");
+ return ret;
+ }
+
+ if (brightness < 0) {
+ dev_err(gbl->dev, "Backlight change failed\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops rpi_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = rpi_backlight_update_status,
+};
+
+static int rpi_backlight_probe(struct platform_device *pdev)
+{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+ struct rpi_backlight *gbl;
+ struct device_node *fw_node;
+
+ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
+ if (gbl == NULL)
+ return -ENOMEM;
+
+ gbl->dev = &pdev->dev;
+
+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+ if (!fw_node) {
+ dev_err(&pdev->dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ gbl->fw = rpi_firmware_get(fw_node);
+ if (!gbl->fw)
+ return -EPROBE_DEFER;
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = 255;
+ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
+ &pdev->dev, gbl, &rpi_backlight_ops,
+ &props);
+ if (IS_ERR(bl)) {
+ dev_err(&pdev->dev, "failed to register backlight\n");
+ return PTR_ERR(bl);
+ }
+
+ bl->props.brightness = 255;
+ backlight_update_status(bl);
+
+ platform_set_drvdata(pdev, bl);
+ return 0;
+}
+
+static const struct of_device_id rpi_backlight_of_match[] = {
+ { .compatible = "raspberrypi,rpi-backlight" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
+
+static struct platform_driver rpi_backlight_driver = {
+ .driver = {
+ .name = "rpi-backlight",
+ .of_match_table = of_match_ptr(rpi_backlight_of_match),
+ },
+ .probe = rpi_backlight_probe,
+};
+
+module_platform_driver(rpi_backlight_driver);
+
+MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
+MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,275 @@
From bca457f76477ff2de37e830cf6590617d694a10c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 23 Feb 2016 19:56:04 +0000
Subject: [PATCH 075/697] bcm2835-virtgpio: Virtual GPIO driver
Add a virtual GPIO driver that uses the firmware mailbox interface to
request that the VPU toggles LEDs.
gpio: bcm-virt: Fix the get() method
The get() method does not understand the on-the-wire encoding of the
remote GPIO states, thinking they are simple on/off bits when they are
really pairs of 16-bit counts. Rewrite the get() handler to return the
value last written, which will eventually match the actual GPIO state
if there are no other changes.
See: https://github.com/raspberrypi/linux/issues/4638
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
bcm2835-virtgpio: Update for Linux 6.6
The gpio subsystem is happier if the gpiochip is given a parent, and
if it doesn't have a fixed base gpio number. While we're in here,
use the fact that the firmware node is the parent to locate it,
and use the devm_ version of rpi_firmware_get.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-bcm-virt.c | 212 +++++++++++++++++++++++++++++++++++
3 files changed, 219 insertions(+)
create mode 100644 drivers/gpio/gpio-bcm-virt.c
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -216,6 +216,12 @@ config GPIO_BCM_XGS_IPROC
help
Say yes here to enable GPIO support for Broadcom XGS iProc SoCs.
+config GPIO_BCM_VIRT
+ bool "Broadcom Virt GPIO"
+ depends on OF_GPIO && RASPBERRYPI_FIRMWARE && (ARCH_BCM2835 || COMPILE_TEST)
+ help
+ Turn on virtual GPIO support for Broadcom BCM283X chips.
+
config GPIO_BRCMSTB
tristate "BRCMSTB GPIO support"
default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
+obj-$(CONFIG_GPIO_BCM_VIRT) += gpio-bcm-virt.o
obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
--- /dev/null
+++ b/drivers/gpio/gpio-bcm-virt.c
@@ -0,0 +1,212 @@
+/*
+ * brcmvirt GPIO driver
+ *
+ * Copyright (C) 2012,2013 Dom Cobley <popcornmix@gmail.com>
+ * Based on gpio-clps711x.c by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MODULE_NAME "brcmvirt-gpio"
+#define NUM_GPIO 2
+
+struct brcmvirt_gpio {
+ struct gpio_chip gc;
+ u32 __iomem *ts_base;
+ /* two packed 16-bit counts of enabled and disables
+ Allows host to detect a brief enable that was missed */
+ u32 enables_disables[NUM_GPIO];
+ dma_addr_t bus_addr;
+};
+
+static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
+{
+ struct brcmvirt_gpio *gpio;
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
+ return -EINVAL;
+}
+
+static int brcmvirt_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
+{
+ struct brcmvirt_gpio *gpio;
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
+ return 0;
+}
+
+static int brcmvirt_gpio_get(struct gpio_chip *gc, unsigned off)
+{
+ struct brcmvirt_gpio *gpio;
+ unsigned v;
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
+ v = readl(gpio->ts_base + off);
+ return (s16)((v >> 16) - v) > 0;
+}
+
+static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
+{
+ struct brcmvirt_gpio *gpio;
+ u16 enables, disables;
+ s16 diff;
+ bool lit;
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
+ enables = gpio->enables_disables[off] >> 16;
+ disables = gpio->enables_disables[off] >> 0;
+ diff = (s16)(enables - disables);
+ lit = diff > 0;
+ if ((val && lit) || (!val && !lit))
+ return;
+ if (val)
+ enables++;
+ else
+ disables++;
+ diff = (s16)(enables - disables);
+ BUG_ON(diff != 0 && diff != 1);
+ gpio->enables_disables[off] = (enables << 16) | (disables << 0);
+ writel(gpio->enables_disables[off], gpio->ts_base + off);
+}
+
+static int brcmvirt_gpio_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev_of_node(dev);
+ struct device_node *fw_node;
+ struct rpi_firmware *fw;
+ struct brcmvirt_gpio *ucb;
+ u32 gpiovirtbuf;
+
+ fw_node = of_get_parent(np);
+ if (!fw_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
+ of_node_put(fw_node);
+ if (!fw)
+ return -EPROBE_DEFER;
+
+ ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
+ if (!ucb) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ ucb->ts_base = dma_alloc_coherent(dev, PAGE_SIZE, &ucb->bus_addr, GFP_KERNEL);
+ if (!ucb->ts_base) {
+ pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
+ __func__, PAGE_SIZE);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ gpiovirtbuf = (u32)ucb->bus_addr;
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF,
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+ if (err || gpiovirtbuf != 0) {
+ dev_warn(dev, "Failed to set gpiovirtbuf, trying to get err:%x\n", err);
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ ucb->ts_base = 0;
+ ucb->bus_addr = 0;
+ }
+
+ if (!ucb->ts_base) {
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
+
+ if (err) {
+ dev_err(dev, "Failed to get gpiovirtbuf\n");
+ goto out;
+ }
+
+ if (!gpiovirtbuf) {
+ dev_err(dev, "No virtgpio buffer\n");
+ err = -ENOENT;
+ goto out;
+ }
+
+ // mmap the physical memory
+ gpiovirtbuf &= ~0xc0000000;
+ ucb->ts_base = ioremap(gpiovirtbuf, 4096);
+ if (ucb->ts_base == NULL) {
+ dev_err(dev, "Failed to map physical address\n");
+ err = -ENOENT;
+ goto out;
+ }
+ ucb->bus_addr = 0;
+ }
+ ucb->gc.parent = dev;
+ ucb->gc.label = MODULE_NAME;
+ ucb->gc.owner = THIS_MODULE;
+ ucb->gc.base = -1;
+ ucb->gc.ngpio = NUM_GPIO;
+
+ ucb->gc.direction_input = brcmvirt_gpio_dir_in;
+ ucb->gc.direction_output = brcmvirt_gpio_dir_out;
+ ucb->gc.get = brcmvirt_gpio_get;
+ ucb->gc.set = brcmvirt_gpio_set;
+ ucb->gc.can_sleep = true;
+
+ err = gpiochip_add_data(&ucb->gc, NULL);
+ if (err)
+ goto out;
+
+ platform_set_drvdata(pdev, ucb);
+
+ return 0;
+out:
+ if (ucb->bus_addr) {
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ ucb->bus_addr = 0;
+ ucb->ts_base = NULL;
+ } else if (ucb->ts_base) {
+ iounmap(ucb->ts_base);
+ ucb->ts_base = NULL;
+ }
+ return err;
+}
+
+static void brcmvirt_gpio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&ucb->gc);
+ if (ucb->bus_addr)
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
+ else if (ucb->ts_base)
+ iounmap(ucb->ts_base);
+}
+
+static const struct of_device_id __maybe_unused brcmvirt_gpio_ids[] = {
+ { .compatible = "brcm,bcm2835-virtgpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, brcmvirt_gpio_ids);
+
+static struct platform_driver brcmvirt_gpio_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(brcmvirt_gpio_ids),
+ },
+ .probe = brcmvirt_gpio_probe,
+ .remove = brcmvirt_gpio_remove,
+};
+module_platform_driver(brcmvirt_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>");
+MODULE_DESCRIPTION("brcmvirt GPIO driver");
+MODULE_ALIAS("platform:brcmvirt-gpio");

View File

@ -0,0 +1,408 @@
From ee77b24e7973982d4ad0a768fa281ee3a1dbac3f Mon Sep 17 00:00:00 2001
From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
Date: Wed, 3 Dec 2014 13:23:28 +0200
Subject: [PATCH 076/697] OF: DT-Overlay configfs interface
This is a port of Pantelis Antoniou's v3 port that makes use of the
new upstreamed configfs support for binary attributes.
Original commit message:
Add a runtime interface to using configfs for generic device tree overlay
usage. With it its possible to use device tree overlays without having
to use a per-platform overlay manager.
Please see Documentation/devicetree/configfs-overlays.txt for more info.
Changes since v2:
- Removed ifdef CONFIG_OF_OVERLAY (since for now it's required)
- Created a documentation entry
- Slight rewording in Kconfig
Changes since v1:
- of_resolve() -> of_resolve_phandles().
Originally-signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
DT configfs: Fix build errors on other platforms
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
DT configfs: fix build error
There is an error when compiling rpi-4.6.y branch:
CC drivers/of/configfs.o
drivers/of/configfs.c:291:21: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.default_groups = of_cfs_def_groups,
^
drivers/of/configfs.c:291:21: note: (near initialization for 'of_cfs_subsys.su_group.default_groups.next')
The .default_groups is linked list since commit
1ae1602de028acaa42a0f6ff18d19756f8e825c6.
This commit uses configfs_add_default_group to fix this problem.
Signed-off-by: Slawomir Stepien <sst@poczta.fm>
configfs: New of_overlay API
of: configfs: Use of_overlay_fdt_apply API call
The published API to the dynamic overlay application mechanism now
takes a Flattened Device Tree blob as input so that it can manage the
lifetime of the unflattened tree. Conveniently, the new API call -
of_overlay_fdt_apply - is virtually a drop-in replacement for
create_overlay, which can now be deleted.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
.../devicetree/configfs-overlays.txt | 31 ++
drivers/of/Kconfig | 11 +
drivers/of/Makefile | 1 +
drivers/of/configfs.c | 277 ++++++++++++++++++
4 files changed, 320 insertions(+)
create mode 100644 Documentation/devicetree/configfs-overlays.txt
create mode 100644 drivers/of/configfs.c
--- /dev/null
+++ b/Documentation/devicetree/configfs-overlays.txt
@@ -0,0 +1,31 @@
+Howto use the configfs overlay interface.
+
+A device-tree configfs entry is created in /config/device-tree/overlays
+and and it is manipulated using standard file system I/O.
+Note that this is a debug level interface, for use by developers and
+not necessarily something accessed by normal users due to the
+security implications of having direct access to the kernel's device tree.
+
+* To create an overlay you mkdir the directory:
+
+ # mkdir /config/device-tree/overlays/foo
+
+* Either you echo the overlay firmware file to the path property file.
+
+ # echo foo.dtbo >/config/device-tree/overlays/foo/path
+
+* Or you cat the contents of the overlay to the dtbo file
+
+ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
+
+The overlay file will be applied, and devices will be created/destroyed
+as required.
+
+To remove it simply rmdir the directory.
+
+ # rmdir /config/device-tree/overlays/foo
+
+The rationalle of the dual interface (firmware & direct copy) is that each is
+better suited to different use patterns. The firmware interface is what's
+intended to be used by hardware managers in the kernel, while the copy interface
+make sense for developers (since it avoids problems with namespaces).
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -120,4 +120,15 @@ config OF_OVERLAY_KUNIT_TEST
config OF_NUMA
bool
+config OF_DMA_DEFAULT_COHERENT
+ # arches should select this if DMA is coherent by default for OF devices
+ bool
+
+config OF_CONFIGFS
+ bool "Device Tree Overlay ConfigFS interface"
+ select CONFIGFS_FS
+ select OF_OVERLAY
+ help
+ Enable a simple user-space driven DT overlay interface.
+
endif # OF
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-y = base.o cpu.o device.o module.o platform.o property.o
obj-$(CONFIG_OF_KOBJ) += kobj.o
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o empty_root.dtb.o
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
--- /dev/null
+++ b/drivers/of/configfs.c
@@ -0,0 +1,277 @@
+/*
+ * Configfs entries for device-tree
+ *
+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/ctype.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/configfs.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/limits.h>
+#include <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/sizes.h>
+
+#include "of_private.h"
+
+struct cfs_overlay_item {
+ struct config_item item;
+
+ char path[PATH_MAX];
+
+ const struct firmware *fw;
+ struct device_node *overlay;
+ int ov_id;
+
+ void *dtbo;
+ int dtbo_size;
+};
+
+static inline struct cfs_overlay_item *to_cfs_overlay_item(
+ struct config_item *item)
+{
+ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
+}
+
+static ssize_t cfs_overlay_item_path_show(struct config_item *item,
+ char *page)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+ return sprintf(page, "%s\n", overlay->path);
+}
+
+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+ const char *p = page;
+ char *s;
+ int err;
+
+ /* if it's set do not allow changes */
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+ return -EPERM;
+
+ /* copy to path buffer (and make sure it's always zero terminated */
+ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
+ overlay->path[sizeof(overlay->path) - 1] = '\0';
+
+ /* strip trailing newlines */
+ s = overlay->path + strlen(overlay->path);
+ while (s > overlay->path && *--s == '\n')
+ *s = '\0';
+
+ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
+
+ err = request_firmware(&overlay->fw, overlay->path, NULL);
+ if (err != 0)
+ goto out_err;
+
+ err = of_overlay_fdt_apply((void *)overlay->fw->data,
+ (u32)overlay->fw->size, &overlay->ov_id, NULL);
+ if (err != 0)
+ goto out_err;
+
+ return count;
+
+out_err:
+
+ release_firmware(overlay->fw);
+ overlay->fw = NULL;
+
+ overlay->path[0] = '\0';
+ return err;
+}
+
+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
+ char *page)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+ return sprintf(page, "%s\n",
+ overlay->ov_id > 0 ? "applied" : "unapplied");
+}
+
+CONFIGFS_ATTR(cfs_overlay_item_, path);
+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
+
+static struct configfs_attribute *cfs_overlay_attrs[] = {
+ &cfs_overlay_item_attr_path,
+ &cfs_overlay_item_attr_status,
+ NULL,
+};
+
+static ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
+ void *buf, size_t max_count)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+ pr_debug("%s: buf=%p max_count=%zu\n", __func__,
+ buf, max_count);
+
+ if (overlay->dtbo == NULL)
+ return 0;
+
+ /* copy if buffer provided */
+ if (buf != NULL) {
+ /* the buffer must be large enough */
+ if (overlay->dtbo_size > max_count)
+ return -ENOSPC;
+
+ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
+ }
+
+ return overlay->dtbo_size;
+}
+
+static ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
+ const void *buf, size_t count)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+ int err;
+
+ /* if it's set do not allow changes */
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+ return -EPERM;
+
+ /* copy the contents */
+ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
+ if (overlay->dtbo == NULL)
+ return -ENOMEM;
+
+ overlay->dtbo_size = count;
+
+ err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size,
+ &overlay->ov_id, NULL);
+ if (err != 0)
+ goto out_err;
+
+ return count;
+
+out_err:
+ kfree(overlay->dtbo);
+ overlay->dtbo = NULL;
+ overlay->dtbo_size = 0;
+ overlay->ov_id = 0;
+
+ return err;
+}
+
+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
+
+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
+ &cfs_overlay_item_attr_dtbo,
+ NULL,
+};
+
+static void cfs_overlay_release(struct config_item *item)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+ if (overlay->ov_id > 0)
+ of_overlay_remove(&overlay->ov_id);
+ if (overlay->fw)
+ release_firmware(overlay->fw);
+ /* kfree with NULL is safe */
+ kfree(overlay->dtbo);
+ kfree(overlay);
+}
+
+static struct configfs_item_operations cfs_overlay_item_ops = {
+ .release = cfs_overlay_release,
+};
+
+static struct config_item_type cfs_overlay_type = {
+ .ct_item_ops = &cfs_overlay_item_ops,
+ .ct_attrs = cfs_overlay_attrs,
+ .ct_bin_attrs = cfs_overlay_bin_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *cfs_overlay_group_make_item(
+ struct config_group *group, const char *name)
+{
+ struct cfs_overlay_item *overlay;
+
+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
+ if (!overlay)
+ return ERR_PTR(-ENOMEM);
+
+ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
+ return &overlay->item;
+}
+
+static void cfs_overlay_group_drop_item(struct config_group *group,
+ struct config_item *item)
+{
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+ config_item_put(&overlay->item);
+}
+
+static struct configfs_group_operations overlays_ops = {
+ .make_item = cfs_overlay_group_make_item,
+ .drop_item = cfs_overlay_group_drop_item,
+};
+
+static struct config_item_type overlays_type = {
+ .ct_group_ops = &overlays_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_group_operations of_cfs_ops = {
+ /* empty - we don't allow anything to be created */
+};
+
+static struct config_item_type of_cfs_type = {
+ .ct_group_ops = &of_cfs_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+struct config_group of_cfs_overlay_group;
+
+static struct configfs_subsystem of_cfs_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "device-tree",
+ .ci_type = &of_cfs_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
+};
+
+static int __init of_cfs_init(void)
+{
+ int ret;
+
+ pr_info("%s\n", __func__);
+
+ config_group_init(&of_cfs_subsys.su_group);
+ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
+ &overlays_type);
+ configfs_add_default_group(&of_cfs_overlay_group,
+ &of_cfs_subsys.su_group);
+
+ ret = configfs_register_subsystem(&of_cfs_subsys);
+ if (ret != 0) {
+ pr_err("%s: failed to register subsys\n", __func__);
+ goto out;
+ }
+ pr_info("%s: OK\n", __func__);
+out:
+ return ret;
+}
+late_initcall(of_cfs_init);

View File

@ -0,0 +1,102 @@
From 111148df28ac59821f28f19727fe41d3b54ebb1a Mon Sep 17 00:00:00 2001
From: Cheong2K <cheong@redbear.cc>
Date: Fri, 26 Feb 2016 18:20:10 +0800
Subject: [PATCH 077/697] brcm: adds support for BCM43341 wifi
brcmfmac: Disable power management
Disable wireless power saving in the brcmfmac WLAN driver. This is a
temporary measure until the connectivity loss resulting from power
saving is resolved.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
brcmfmac: Use original country code as a fallback
Commit 73345fd212980d2e28a5c6d83801c903bd773680:
brcmfmac: Configure country code using device specific settings
prevents region codes from working on devices that lack a region code
translation table. In the event of an absent table, preserve the old
behaviour of using the provided code as-is.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
brcmfmac: Plug memory leak in brcmf_fill_bss_param
See: https://github.com/raspberrypi/linux/issues/1471
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
brcmfmac: do not use internal roaming engine by default
Some evidence of curing disconnects with this disabled, so make it a default.
Can be overridden with module parameter roamoff=0
See: http://projectable.me/optimize-my-pi-wi-fi/
brcmfmac: Change stop_ap sequence
Patch from Broadcom/Cypress to resolve a customer error
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
Revert "brcmfmac: Disable power management"
Shortly after the release of the Pi 3B, a loss of SSH connectivity
over WiFi was traced to the power management handling, so power
management was disabled. And so it has remained ever since.
Enabling power management saves 55mA (~270mW) on a Pi 4B, so is very
much worth the minimal effort of reverting this patch, which was
squashed and rebased many times since then to the commit hash is
meaningless.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +-
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +-
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++-
3 files changed, 4 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -3299,7 +3299,7 @@ brcmf_cfg80211_set_power_mgmt(struct wip
brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
pm = PM_OFF;
}
- brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
+ brcmf_err("power save %s\n", (pm ? "enabled" : "disabled"));
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
if (err) {
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -59,7 +59,7 @@ static int brcmf_fcmode;
module_param_named(fcmode, brcmf_fcmode, int, 0);
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
-static int brcmf_roamoff;
+static int brcmf_roamoff = 1;
module_param_named(roamoff, brcmf_roamoff, int, 0400);
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -609,6 +609,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio");
BRCMF_FW_DEF(4330, "brcmfmac4330-sdio");
BRCMF_FW_DEF(4334, "brcmfmac4334-sdio");
BRCMF_FW_DEF(43340, "brcmfmac43340-sdio");
+BRCMF_FW_DEF(43341, "brcmfmac43341-sdio");
BRCMF_FW_DEF(4335, "brcmfmac4335-sdio");
BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
@@ -641,7 +642,7 @@ static const struct brcmf_firmware_mappi
BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
- BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
+ BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43341),
BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),

View File

@ -0,0 +1,23 @@
From 556ef1576e1a0353e94ab2a28ceb37e5887e96eb Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 17 Dec 2015 13:37:07 +0000
Subject: [PATCH 078/697] hci_h5: Don't send conf_req when ACTIVE
Without this patch, a modem and kernel can continuously bombard each
other with conf_req and conf_rsp messages, in a demented game of tag.
---
drivers/bluetooth/hci_h5.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -358,7 +358,8 @@ static void h5_handle_internal_rx(struct
h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_req, 2) == 0) {
h5_link_control(hu, conf_rsp, 2);
- h5_link_control(hu, conf_req, 3);
+ if (h5->state != H5_ACTIVE)
+ h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_rsp, 2) == 0) {
if (H5_HDR_LEN(hdr) > 2)
h5->tx_win = (data[2] & 0x07);

View File

@ -0,0 +1,138 @@
From 9d49c9632feb3e9037ccd7cfe629b4c65e1c2c1c Mon Sep 17 00:00:00 2001
From: Michael Zoran <mzoran@crowfest.net>
Date: Sat, 14 Jan 2017 21:43:57 -0800
Subject: [PATCH 079/697] ARM64: Round-Robin dispatch IRQs between CPUs.
IRQ-CPU mapping is round robined on ARM64 to increase
concurrency and allow multiple interrupts to be serviced
at a time. This reduces the need for FIQ.
Signed-off-by: Michael Zoran <mzoran@crowfest.net>
drivers: irqchip: irq-bcm2835: Concurrency fix
The commit shown in Fixes: aims to improve interrupt throughput by
getting the handlers invoked on different CPU cores. It does so (*) by
using an irq_ack hook to change the interrupt routing.
Unfortunately, the IRQ status bits must be cleared at source, which only
happens once the interrupt handler has run - there is no easy way for
one core to claim one of the IRQs before sending the remainder to the
next core on the list, so waking another core immediately results in a
race with a chance of both cores handling the same IRQ. It is probably
for this reason that the routing change is deferred to irq_ack, but that
doesn't guarantee no clashes - after irq_ack is called, control returns
to bcm2836_chained_handler_irq which proceeds to check for other pending
IRQs at a time when the next core is probably doing the same thing.
Since the whole point of the original commit is to distribute the IRQ
handling, there is no reason to attempt to handle multiple IRQs in one
interrupt callback, so the problem can be solved (or at least made much
harder to reproduce) by changing a "while" into an "if", so that each
invocation only handles one IRQ.
(*) I'm not convinced it's as effective as claimed since irq_ack is
called _after_ the interrupt handler, but the author thought it made a
difference.
See: https://github.com/raspberrypi/linux/issues/5214
https://github.com/raspberrypi/linux/pull/1794
Fixes: fd4c9785bde8 ("ARM64: Round-Robin dispatch IRQs between CPUs.")
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
irqchip: irq-bcm2836: Avoid prototype warning
Declare bcm2836_arm_irqchip_spin_gpu_irq in irq-bcm2836.h to avoid a
compiler warning about a missing prototype.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/irqchip/irq-bcm2835.c | 16 +++++++++++++++-
drivers/irqchip/irq-bcm2836.c | 21 +++++++++++++++++++++
include/linux/irqchip/irq-bcm2836.h | 2 ++
3 files changed, 38 insertions(+), 1 deletion(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -40,6 +40,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/irq-bcm2836.h>
#include <linux/irqdomain.h>
#include <asm/exception.h>
@@ -154,12 +155,24 @@ static void armctrl_unmask_irq(struct ir
}
}
+#ifdef CONFIG_ARM64
+
+static void armctrl_ack_irq(struct irq_data *d)
+{
+ bcm2836_arm_irqchip_spin_gpu_irq();
+}
+
+#endif
+
static struct irq_chip armctrl_chip = {
.name = "ARMCTRL-level",
.irq_mask = armctrl_mask_irq,
.irq_unmask = armctrl_unmask_irq,
.flags = IRQCHIP_MASK_ON_SUSPEND |
IRQCHIP_SKIP_SET_WAKE,
+#ifdef CONFIG_ARM64
+ .irq_ack = armctrl_ack_irq
+#endif
};
static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
@@ -332,7 +345,8 @@ static void bcm2836_chained_handle_irq(s
{
u32 hwirq;
- while ((hwirq = get_next_armctrl_hwirq()) != ~0)
+ hwirq = get_next_armctrl_hwirq();
+ if (hwirq != ~0)
generic_handle_domain_irq(intc.domain, hwirq);
}
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -87,6 +87,27 @@ static void bcm2836_arm_irqchip_unmask_g
{
}
+#ifdef CONFIG_ARM64
+
+void bcm2836_arm_irqchip_spin_gpu_irq(void)
+{
+ u32 i;
+ void __iomem *gpurouting = (intc.base + LOCAL_GPU_ROUTING);
+ u32 routing_val = readl(gpurouting);
+
+ for (i = 1; i <= 3; i++) {
+ u32 new_routing_val = (routing_val + i) & 3;
+
+ if (cpu_active(new_routing_val)) {
+ writel(new_routing_val, gpurouting);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL(bcm2836_arm_irqchip_spin_gpu_irq);
+
+#endif
+
static struct irq_chip bcm2836_arm_irqchip_gpu = {
.name = "bcm2836-gpu",
.irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,
--- a/include/linux/irqchip/irq-bcm2836.h
+++ b/include/linux/irqchip/irq-bcm2836.h
@@ -59,3 +59,5 @@
#define LOCAL_IRQ_GPU_FAST 8
#define LOCAL_IRQ_PMU_FAST 9
#define LAST_IRQ LOCAL_IRQ_PMU_FAST
+
+void bcm2836_arm_irqchip_spin_gpu_irq(void);

View File

@ -0,0 +1,27 @@
From c4d6ab27980e6ca023af27d9de3fba173276a922 Mon Sep 17 00:00:00 2001
From: Michael Zoran <mzoran@crowfest.net>
Date: Sat, 11 Feb 2017 01:18:31 -0800
Subject: [PATCH 080/697] ARM64: Force hardware emulation of deprecated
instructions.
---
arch/arm64/kernel/armv8_deprecated.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -540,9 +540,14 @@ static void __init register_insn_emulati
switch (insn->status) {
case INSN_DEPRECATED:
+#if 0
insn->current_mode = INSN_EMULATE;
/* Disable the HW mode if it was turned on at early boot time */
run_all_cpu_set_hw_mode(insn, false);
+#else
+ insn->current_mode = INSN_HW;
+ run_all_cpu_set_hw_mode(insn, true);
+#endif
insn->max = INSN_HW;
break;
case INSN_OBSOLETE:

View File

@ -0,0 +1,887 @@
From 5a907fe6189e15007f7c56203cae757ca09c18b8 Mon Sep 17 00:00:00 2001
From: James Hughes <JamesH65@users.noreply.github.com>
Date: Tue, 14 Nov 2017 15:13:15 +0000
Subject: [PATCH 081/697] AXI performance monitor driver (#2222)
Uses the debugfs I/F to provide access to the AXI
bus performance monitors.
Requires the new mailbox peripheral access for access
to the VPU performance registers, system bus access
is done using direct register reads.
Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
raspberrypi_axi_monitor: suppress warning
Suppress the following warning by casting the pointer to and uintptr_t
before to u32:
Signed-off-by: Matteo Croce <mcroce@redhat.com>
perf/raspberry: Add support for 2712 axi performance monitors
Also handle 2711 correctly which has a different configuration
from 2835.
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
---
drivers/perf/Kconfig | 8 +
drivers/perf/Makefile | 1 +
drivers/perf/raspberrypi_axi_monitor.c | 826 +++++++++++++++++++++++++
3 files changed, 835 insertions(+)
create mode 100644 drivers/perf/raspberrypi_axi_monitor.c
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -251,6 +251,14 @@ config ALIBABA_UNCORE_DRW_PMU
Support for Driveway PMU events monitoring on Yitian 710 DDR
Sub-system.
+config RPI_AXIPERF
+ depends on ARCH_BCM2835
+ tristate "RaspberryPi AXI Performance monitors"
+ default n
+ help
+ Say y if you want to use Raspberry Pi AXI performance monitors, m if
+ you want to build it as a module.
+
source "drivers/perf/hisilicon/Kconfig"
config MARVELL_CN10K_DDR_PMU
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_DWC_PCIE_PMU) += dwc_pcie_p
obj-$(CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU) += arm_cspmu/
obj-$(CONFIG_MESON_DDR_PMU) += amlogic/
obj-$(CONFIG_CXL_PMU) += cxl_pmu.o
+obj-$(CONFIG_RPI_AXIPERF) += raspberrypi_axi_monitor.o
--- /dev/null
+++ b/drivers/perf/raspberrypi_axi_monitor.c
@@ -0,0 +1,826 @@
+/*
+ * raspberrypi_axi_monitor.c
+ *
+ * Author: james.hughes@raspberrypi.org
+ *
+ * Raspberry Pi AXI performance counters.
+ *
+ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/devcoredump.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define NUM_MONITORS 2
+#define NUM_BUS_WATCHERS_PER_MONITOR 3
+
+#define SYSTEM_MONITOR 0
+#define VPU_MONITOR 1
+
+#define MAX_BUSES 16
+#define DEFAULT_SAMPLE_TIME 100
+
+#define NUM_BUS_WATCHER_RESULTS 11
+
+struct bus_watcher_data {
+ union {
+ u32 results[NUM_BUS_WATCHER_RESULTS];
+ struct {
+ u32 atrans;
+ u32 atwait;
+ u32 amax;
+ u32 wtrans;
+ u32 wtwait;
+ u32 wmax;
+ u32 rtrans;
+ u32 rtwait;
+ u32 rmax;
+ u32 rpend;
+ u32 ratrans;
+ };
+ };
+};
+
+
+struct rpi_axiperf {
+ struct platform_device *dev;
+ struct dentry *root_folder;
+
+ struct task_struct *monitor_thread;
+ struct mutex lock;
+
+ struct rpi_firmware *firmware;
+
+ /* Sample time spent on for each bus */
+ int sample_time;
+
+ /* chip specific bus config */
+ const struct bwconfig_config *config;
+
+ /* Now storage for the per monitor settings and the resulting
+ * performance figures
+ */
+ struct {
+ /* Bit field of buses we want to monitor */
+ int bus_enabled;
+ /* Bit field of buses to filter by */
+ int bus_filter;
+ /* The current buses being monitored on this monitor */
+ int current_bus[NUM_BUS_WATCHERS_PER_MONITOR];
+ /* The last bus monitored on this monitor */
+ int last_monitored;
+
+ /* Set true if this mailbox must use the mailbox interface
+ * rather than access registers directly.
+ */
+ int use_mailbox_interface;
+
+ /* Current result values */
+ struct bus_watcher_data results[MAX_BUSES];
+
+ struct dentry *debugfs_entry;
+ void __iomem *base_address;
+
+ } monitor[NUM_MONITORS];
+
+};
+
+static struct rpi_axiperf *state;
+
+/* Two monitors, System and VPU, each with the following register sets.
+ * Each monitor can only monitor one bus at a time, so we time share them,
+ * giving each bus 100ms (default, settable via debugfs) of time on its
+ * associated monitor
+ * Record results from the three Bus watchers per monitor and push to the sysfs
+ */
+
+/* general registers */
+const int GEN_CTRL;
+
+const int GEN_CTL_ENABLE_BIT = BIT(0);
+const int GEN_CTL_RESET_BIT = BIT(1);
+const int GEN_CTL_WATCH_BIT = BIT(2);
+
+/* Bus watcher registers */
+const int BW_PITCH = 0x40;
+
+const int BW0_CTRL = 0x40;
+const int BW1_CTRL = 0x80;
+const int BW2_CTRL = 0xc0;
+
+const int BW_ATRANS_OFFSET = 0x04;
+const int BW_ATWAIT_OFFSET = 0x08;
+const int BW_AMAX_OFFSET = 0x0c;
+const int BW_WTRANS_OFFSET = 0x10;
+const int BW_WTWAIT_OFFSET = 0x14;
+const int BW_WMAX_OFFSET = 0x18;
+const int BW_RTRANS_OFFSET = 0x1c;
+const int BW_RTWAIT_OFFSET = 0x20;
+const int BW_RMAX_OFFSET = 0x24;
+
+const int BW_CTRL_RESET_BIT = BIT(31);
+const int BW_CTRL_ENABLE_BIT = BIT(30);
+const int BW_CTRL_ENABLE_ID_FILTER_BIT = BIT(29);
+const int BW_CTRL_LIMIT_HALT_BIT = BIT(28);
+
+const int BW_CTRL_SOURCE_SHIFT = 8;
+const int BW_CTRL_SOURCE_MASK = GENMASK(12, 8); // 5 bits
+const int BW_CTRL_BUS_WATCH_SHIFT;
+const int BW_CTRL_BUS_WATCH_MASK = GENMASK(5, 0); // 6 bits
+const int BW_CTRL_BUS_FILTER_SHIFT = 8;
+
+static const char *bus_filter_strings[] = {
+ "",
+ "CORE0_V",
+ "ICACHE0",
+ "DCACHE0",
+ "CORE1_V",
+ "ICACHE1",
+ "DCACHE1",
+ "L2_MAIN",
+ "HOST_PORT",
+ "HOST_PORT2",
+ "HVS",
+ "ISP",
+ "VIDEO_DCT",
+ "VIDEO_SD2AXI",
+ "CAM0",
+ "CAM1",
+ "DMA0",
+ "DMA1",
+ "DMA2_VPU",
+ "JPEG",
+ "VIDEO_CME",
+ "TRANSPOSER",
+ "VIDEO_FME",
+ "CCP2TX",
+ "USB",
+ "V3D0",
+ "V3D1",
+ "V3D2",
+ "AVE",
+ "DEBUG",
+ "CPU",
+ "M30"
+};
+
+static const char * const bus_filter_strings_2711[] = {
+ "AIO",
+ "CORE0_V",
+ "ICACHE0",
+ "DCACHE0",
+ "CORE1_V",
+ "ICACHE1",
+ "DCACHE1",
+ "L2_MAIN",
+ "ARGON",
+ "PCIE",
+ "HVS",
+ "ISP",
+ "VIDEO_DCT",
+ "VIDEO_SD2AXI",
+ "CAM0",
+ "CAM1",
+ "DMA0",
+ "DMA1",
+ "DMA2",
+ "JPEG",
+ "VIDEO_CME",
+ "TRANSPOSER",
+ "VIDEO_FME",
+ "GIGE",
+ "USB",
+ "V3D0",
+ "V3D1",
+ "V3D2",
+ "GISB_AXI",
+ "DEBUG",
+ "ARM",
+ "EMMCSTB",
+};
+
+static const char * const bus_filter_strings_2712[] = {
+ "",
+ "VPU_UC0",
+ "VPU_IC0",
+ "VPU_DC0",
+ "VPU_UC1",
+ "VPU_IC1",
+ "VPU_DC1",
+ "VPU_L2",
+ "DMA2",
+ "VPU_DEBUG",
+ "ARM",
+ "DMA0",
+ "DMA1",
+ "RAAGA",
+ "BBSI",
+ "PCIE0",
+ "PCIE1",
+ "PCIE2",
+ "UMR",
+ "SAGE",
+ "HVDP",
+ "BSP",
+ "HVS",
+ "HVS_WMK",
+ "MOP0",
+ "MOP1",
+ "MBVN",
+ "DSI",
+ "XPT",
+ "EMMC0",
+ "GENET",
+ "USB",
+ "ARGON",
+ "UNICAM",
+ "PISP",
+ "PISPFE",
+ "JPEG",
+ "EMMC1",
+ "EMMC2",
+ "TRC",
+ "BSTM0",
+ "BSTM1",
+ "BSTM0_SEC",
+ "BSTM1_SEC",
+ "AIO",
+ "MAP",
+ "SYS_DMA",
+ "MMUCACHE0",
+ "MMUCACHE1",
+ "MPUCACHE0",
+ "MPUCACHE1",
+};
+
+static const char *system_bus_string[] = {
+ "DMA_L2",
+ "TRANS",
+ "JPEG",
+ "SYSTEM_UC",
+ "DMA_UC",
+ "SYSTEM_L2",
+ "CCP2TX",
+ "MPHI_RX",
+ "MPHI_TX",
+ "HVS",
+ "H264",
+ "ISP",
+ "V3D",
+ "PERIPHERAL",
+ "CPU_UC",
+ "CPU_L2"
+};
+
+static const char * const system_bus_string_2711[] = {
+ "DMA_L2",
+ "TRANS",
+ "JPEG",
+ "VPU_UC",
+ "DMA_UC",
+ "SYSTEM_L2",
+ "HVS",
+ "ARGON",
+ "H264",
+ "PERIPHERAL",
+ "ARM_UC",
+ "ARM_L2",
+};
+
+static const char * const system_bus_string_2712[] = {
+ "VPU_UC",
+ "DISPLAY_TOP",
+ "V3D",
+ "ARM",
+ "XPT",
+ "BSTM_TOP",
+ "PCIE_01",
+ "ARGON_TOP",
+ "ARB3",
+ "SRC",
+ "HVDP",
+ "PER",
+ "SYSTEM_L2",
+};
+
+static const char *vpu_bus_string[] = {
+ "VPU1_D_L2",
+ "VPU0_D_L2",
+ "VPU1_I_L2",
+ "VPU0_I_L2",
+ "SYSTEM_L2",
+ "L2_FLUSH",
+ "DMA_L2",
+ "VPU1_D_UC",
+ "VPU0_D_UC",
+ "VPU1_I_UC",
+ "VPU0_I_UC",
+ "SYSTEM_UC",
+ "L2_OUT",
+ "DMA_UC",
+ "SDRAM",
+ "L2_IN"
+};
+
+static const char * const vpu_bus_string_2711[] = {
+ "VPU1_D_L2",
+ "VPU0_D_L2",
+ "VPU1_I_L2",
+ "VPU0_I_L2",
+ "SYSTEM_L2",
+ "DMA_L2",
+ "VPU1_D_UC",
+ "VPU0_D_UC",
+ "VPU1_I_UC",
+ "VPU0_I_UC",
+ "VPU_UC",
+ "L2_OUT",
+ "DMA_UC",
+ "L2_IN"
+};
+
+static const char * const vpu_bus_string_2712[] = {
+ "VPU1_D_L2",
+ "VPU0_D_L2",
+ "VPU1_I_L2",
+ "VPU0_I_L2",
+ "SYSTEM_L2",
+ "DMA_L2",
+ "VPU1_D_UC",
+ "VPU0_D_UC",
+ "VPU1_I_UC",
+ "VPU0_I_UC",
+ "VPU_UC",
+ "L2_OUT",
+ "DMA_UC",
+ "L2_IN"
+};
+
+struct bwconfig_config {
+ const char * const *bus_filter_strings;
+ const int num_bus_filters;
+ const char * const *system_bus_string;
+ const int num_system_buses;
+ const char * const *vpu_bus_string;
+ const int num_vpu_buses;
+};
+
+static const struct bwconfig_config config_2835 = {
+ bus_filter_strings, ARRAY_SIZE(bus_filter_strings),
+ system_bus_string, ARRAY_SIZE(system_bus_string),
+ vpu_bus_string, ARRAY_SIZE(vpu_bus_string),
+};
+
+static const struct bwconfig_config config_2711 = {
+ bus_filter_strings_2711, ARRAY_SIZE(bus_filter_strings_2711),
+ system_bus_string_2711, ARRAY_SIZE(system_bus_string_2711),
+ vpu_bus_string_2711, ARRAY_SIZE(vpu_bus_string_2711),
+};
+
+static const struct bwconfig_config config_2712 = {
+ bus_filter_strings_2712, ARRAY_SIZE(bus_filter_strings_2712),
+ system_bus_string_2712, ARRAY_SIZE(system_bus_string_2712),
+ vpu_bus_string_2712, ARRAY_SIZE(vpu_bus_string_2712),
+};
+
+static const char *monitor_name[] = {
+ "System",
+ "VPU"
+};
+
+static inline void write_reg(int monitor, int reg, u32 value)
+{
+ writel(value, state->monitor[monitor].base_address + reg);
+}
+
+static inline u32 read_reg(int monitor, u32 reg)
+{
+ return readl(state->monitor[monitor].base_address + reg);
+}
+
+static void read_bus_watcher(int monitor, int watcher, u32 *results)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ /* We have NUM_BUS_WATCHER_RESULTS results, plus the overheads
+ * of start address and length
+ */
+ u32 tmp[NUM_BUS_WATCHER_RESULTS+2];
+ int err;
+
+ tmp[0] = (u32)(uintptr_t)(state->monitor[monitor].base_address + watcher
+ + BW_ATRANS_OFFSET);
+ tmp[1] = NUM_BUS_WATCHER_RESULTS;
+
+ err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_GET_PERIPH_REG,
+ tmp, sizeof(tmp));
+
+ if (err < 0 || tmp[1] != NUM_BUS_WATCHER_RESULTS)
+ dev_err_once(&state->dev->dev,
+ "Failed to read bus watcher");
+ else
+ memcpy(results, &tmp[2],
+ NUM_BUS_WATCHER_RESULTS * sizeof(u32));
+ } else {
+ int i;
+ void __iomem *addr = state->monitor[monitor].base_address
+ + watcher + BW_ATRANS_OFFSET;
+ for (i = 0; i < NUM_BUS_WATCHER_RESULTS; i++, addr += 4)
+ *results++ = readl(addr);
+ }
+}
+
+static void set_monitor_control(int monitor, u32 set)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+ GEN_CTRL), 1, set};
+ int err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_SET_PERIPH_REG,
+ tmp, sizeof(tmp));
+
+ if (err < 0 || tmp[1] != 1)
+ dev_err_once(&state->dev->dev,
+ "Failed to set monitor control");
+ } else
+ write_reg(monitor, GEN_CTRL, set);
+}
+
+static void set_bus_watcher_control(int monitor, int watcher, u32 set)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+ watcher), 1, set};
+ int err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_SET_PERIPH_REG,
+ tmp, sizeof(tmp));
+ if (err < 0 || tmp[1] != 1)
+ dev_err_once(&state->dev->dev,
+ "Failed to set bus watcher control");
+ } else
+ write_reg(monitor, watcher, set);
+}
+
+static void monitor(struct rpi_axiperf *state)
+{
+ int monitor, num_buses[NUM_MONITORS];
+
+ mutex_lock(&state->lock);
+
+ for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+ typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+ /* Anything enabled? */
+ if (mon->bus_enabled == 0) {
+ /* No, disable all monitoring for this monitor */
+ set_monitor_control(monitor, GEN_CTL_RESET_BIT);
+ } else {
+ int i;
+
+ /* Find out how many busses we want to monitor, and
+ * spread our 3 actual monitors over them
+ */
+ num_buses[monitor] = hweight32(mon->bus_enabled);
+ num_buses[monitor] = min(num_buses[monitor],
+ NUM_BUS_WATCHERS_PER_MONITOR);
+
+ for (i = 0; i < num_buses[monitor]; i++) {
+ int bus_control;
+
+ do {
+ mon->last_monitored++;
+ mon->last_monitored &= 0xf;
+ } while ((mon->bus_enabled &
+ (1 << mon->last_monitored)) == 0);
+
+ mon->current_bus[i] = mon->last_monitored;
+
+ /* Reset the counters */
+ set_bus_watcher_control(monitor,
+ BW0_CTRL +
+ i*BW_PITCH,
+ BW_CTRL_RESET_BIT);
+
+ bus_control = BW_CTRL_ENABLE_BIT |
+ mon->current_bus[i];
+
+ if (mon->bus_filter) {
+ bus_control |=
+ BW_CTRL_ENABLE_ID_FILTER_BIT;
+ bus_control |=
+ ((mon->bus_filter & 0x1f)
+ << BW_CTRL_BUS_FILTER_SHIFT);
+ }
+
+ // Start capture
+ set_bus_watcher_control(monitor,
+ BW0_CTRL + i*BW_PITCH,
+ bus_control);
+ }
+ }
+
+ /* start monitoring */
+ set_monitor_control(monitor, GEN_CTL_ENABLE_BIT | GEN_CTL_WATCH_BIT);
+ }
+
+ mutex_unlock(&state->lock);
+
+ msleep(state->sample_time);
+
+ /* Now read the results */
+
+ mutex_lock(&state->lock);
+ for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+ typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+ /* Anything enabled? */
+ if (mon->bus_enabled == 0) {
+ /* No, disable all monitoring for this monitor */
+ set_monitor_control(monitor, 0);
+ } else {
+ int i;
+
+ for (i = 0; i < num_buses[monitor]; i++) {
+ int bus = mon->current_bus[i];
+
+ read_bus_watcher(monitor,
+ BW0_CTRL + i*BW_PITCH,
+ (u32 *)&mon->results[bus].results);
+ }
+ }
+ }
+ mutex_unlock(&state->lock);
+}
+
+static int monitor_thread(void *data)
+{
+ struct rpi_axiperf *state = data;
+
+ while (1) {
+ monitor(state);
+
+ if (kthread_should_stop())
+ return 0;
+ }
+ return 0;
+}
+
+static ssize_t myreader(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+#define INIT_BUFF_SIZE 2048
+
+ int i;
+ int idx = (int)(uintptr_t)(fp->private_data);
+ int num_buses, cnt;
+ char *string_buffer;
+ int buff_size = INIT_BUFF_SIZE;
+ char *p;
+ typeof(state->monitor[0]) *mon = &(state->monitor[idx]);
+ const struct bwconfig_config *config = state->config;
+
+ if (idx < 0 || idx > NUM_MONITORS)
+ idx = 0;
+
+ num_buses = idx == SYSTEM_MONITOR ? config->num_system_buses : config->num_vpu_buses;
+
+ string_buffer = kmalloc(buff_size, GFP_KERNEL);
+
+ if (!string_buffer) {
+ dev_err(&state->dev->dev,
+ "Failed temporary string allocation\n");
+ return 0;
+ }
+
+ p = string_buffer;
+
+ mutex_lock(&state->lock);
+
+ if (mon->bus_filter) {
+ int filt = min(mon->bus_filter & 0x1f, config->num_bus_filters);
+
+ cnt = snprintf(p, buff_size,
+ "\nMonitoring transactions from %s only\n",
+ config->bus_filter_strings[filt]);
+ p += cnt;
+ buff_size -= cnt;
+ }
+
+ cnt = snprintf(p, buff_size, " Bus | Atrans Atwait AMax Wtrans Wtwait WMax Rtrans Rtwait RMax RPend RAtrans\n"
+ "===========================================================================================================================\n");
+
+ if (cnt >= buff_size)
+ goto done;
+
+ p += cnt;
+ buff_size -= cnt;
+
+#define M(x) ((x) >= 1000000000 ? (x)/1000000 : (x) >= 1000 ? (x)/1000 : (x))
+#define N(x) ((x) >= 1000000000 ? 'M' : (x) >= 1000 ? 'K' : ' ')
+
+ for (i = 0; i < num_buses; i++) {
+ if (mon->bus_enabled & (1 << i)) {
+ typeof(mon->results[0]) *res = &(mon->results[i]);
+
+ cnt = snprintf(p, buff_size,
+ "%11s | %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c %8u%c\n",
+ idx == SYSTEM_MONITOR ?
+ config->system_bus_string[i] :
+ config->vpu_bus_string[i],
+ M(res->atrans), N(res->atrans),
+ M(res->atwait), N(res->atwait),
+ M(res->amax), N(res->amax),
+ M(res->wtrans), N(res->wtrans),
+ M(res->wtwait), N(res->wtwait),
+ M(res->wmax), N(res->wmax),
+ M(res->rtrans), N(res->rtrans),
+ M(res->rtwait), N(res->rtwait),
+ M(res->rmax), N(res->rmax),
+ M(res->rpend), N(res->rpend),
+ M(res->ratrans), N(res->ratrans)
+ );
+ if (cnt >= buff_size)
+ goto done;
+
+ p += cnt;
+ buff_size -= cnt;
+ }
+ }
+
+ mutex_unlock(&state->lock);
+
+done:
+
+ /* did the last string entry exceeed our buffer size? ie out of string
+ * buffer space. Null terminate, use what we have.
+ */
+ if (cnt >= buff_size) {
+ buff_size = 0;
+ string_buffer[INIT_BUFF_SIZE] = 0;
+ }
+
+ cnt = simple_read_from_buffer(user_buffer, count, position,
+ string_buffer,
+ INIT_BUFF_SIZE - buff_size);
+
+ kfree(string_buffer);
+
+ return cnt;
+}
+
+static ssize_t mywriter(struct file *fp, const char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+ int idx = (int)(uintptr_t)(fp->private_data);
+
+ if (idx < 0 || idx > NUM_MONITORS)
+ idx = 0;
+
+ /* At the moment, this does nothing, but in the future it could be
+ * used to reset counters etc
+ */
+ return count;
+}
+
+static const struct file_operations fops_debug = {
+ .read = myreader,
+ .write = mywriter,
+ .open = simple_open
+};
+
+static int rpi_axiperf_probe(struct platform_device *pdev)
+{
+ int ret = 0, i;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *fw_node;
+
+ state = kzalloc(sizeof(struct rpi_axiperf), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ state->config = of_device_get_match_data(dev);
+ if (!state->config)
+ return -EINVAL;
+
+ /* Get the firmware handle for future rpi-firmware-xxx calls */
+ fw_node = of_parse_phandle(np, "firmware", 0);
+ if (!fw_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ state->firmware = rpi_firmware_get(fw_node);
+ if (!state->firmware)
+ return -EPROBE_DEFER;
+
+ /* Special case for the VPU monitor, we must use the mailbox interface
+ * as it is not accessible from the ARM address space.
+ */
+ state->monitor[VPU_MONITOR].use_mailbox_interface = 1;
+ state->monitor[SYSTEM_MONITOR].use_mailbox_interface = 0;
+
+ for (i = 0; i < NUM_MONITORS; i++) {
+ if (state->monitor[i].use_mailbox_interface) {
+ of_property_read_u32_index(np, "reg", i*2,
+ (u32 *)(&state->monitor[i].base_address));
+ } else {
+ struct resource *resource =
+ platform_get_resource(pdev, IORESOURCE_MEM, i);
+
+ state->monitor[i].base_address =
+ devm_ioremap_resource(&pdev->dev, resource);
+ }
+
+ if (IS_ERR(state->monitor[i].base_address))
+ return PTR_ERR(state->monitor[i].base_address);
+
+ /* Enable all buses by default */
+ state->monitor[i].bus_enabled = 0xffff;
+ }
+
+ state->dev = pdev;
+ platform_set_drvdata(pdev, state);
+
+ state->sample_time = DEFAULT_SAMPLE_TIME;
+
+ /* Set up all the debugfs stuff */
+ state->root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+ for (i = 0; i < NUM_MONITORS; i++) {
+ state->monitor[i].debugfs_entry =
+ debugfs_create_dir(monitor_name[i], state->root_folder);
+ if (IS_ERR(state->monitor[i].debugfs_entry))
+ state->monitor[i].debugfs_entry = NULL;
+
+ debugfs_create_file("data", 0444,
+ state->monitor[i].debugfs_entry,
+ (void *)(uintptr_t)i, &fops_debug);
+ debugfs_create_u32("enable", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->monitor[i].bus_enabled);
+ debugfs_create_u32("filter", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->monitor[i].bus_filter);
+ debugfs_create_u32("sample_time", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->sample_time);
+ }
+
+ mutex_init(&state->lock);
+
+ state->monitor_thread = kthread_run(monitor_thread, state,
+ "rpi-axiperfmon");
+
+ return ret;
+
+}
+
+static void rpi_axiperf_remove(struct platform_device *dev)
+{
+ kthread_stop(state->monitor_thread);
+
+ debugfs_remove_recursive(state->root_folder);
+ state->root_folder = NULL;
+}
+
+static const struct of_device_id rpi_axiperf_match[] = {
+ { .compatible = "brcm,bcm2835-axiperf",
+ .data = &config_2835 },
+ { .compatible = "brcm,bcm2711-axiperf",
+ .data = &config_2711 },
+ { .compatible = "brcm,bcm2712-axiperf",
+ .data = &config_2712 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_axiperf_match);
+
+static struct platform_driver rpi_axiperf_driver = {
+ .probe = rpi_axiperf_probe,
+ .remove = rpi_axiperf_remove,
+ .driver = {
+ .name = "rpi-bcm2835-axiperf",
+ .of_match_table = of_match_ptr(rpi_axiperf_match),
+ },
+};
+
+module_platform_driver(rpi_axiperf_driver);
+
+/* Module information */
+MODULE_AUTHOR("James Hughes <james.hughes@raspberrypi.org>");
+MODULE_DESCRIPTION("RPI AXI Performance monitor driver");
+MODULE_LICENSE("GPL");
+

View File

@ -0,0 +1,63 @@
From 503201eacd4f72aa986cc167909410c48f91025a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Wed, 3 Jun 2015 12:26:13 +0200
Subject: [PATCH 082/697] ARM: bcm2835: Set Serial number and Revision
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The VideoCore bootloader passes in Serial number and
Revision number through Device Tree. Make these available to
userspace through /proc/cpuinfo.
Mainline status:
There is a commit in linux-next that standardize passing the serial
number through Device Tree (string: /serial-number):
ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo
There was an attempt to do the same with the revision number, but it
didn't get in:
[PATCH v2 1/2] arm: devtree: Set system_rev from DT revision
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm/board_bcm2835.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -6,12 +6,25 @@
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
+#include <asm/system_info.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "platsmp.h"
+static void __init bcm2835_init(void)
+{
+ struct device_node *np = of_find_node_by_path("/system");
+ u32 val;
+ u64 val64;
+
+ if (!of_property_read_u32(np, "linux,revision", &val))
+ system_rev = val;
+ if (!of_property_read_u64(np, "linux,serial", &val64))
+ system_serial_low = val64;
+}
+
static const char * const bcm2835_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
@@ -24,6 +37,7 @@ static const char * const bcm2835_compat
};
DT_MACHINE_START(BCM2835, "BCM2835")
+ .init_machine = bcm2835_init,
.dt_compat = bcm2835_compat,
.smp = smp_ops(bcm2836_smp_ops),
MACHINE_END

View File

@ -0,0 +1,116 @@
From 2487ab4d7856ee30d05ec9d78afdabb35db2b70e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 16 Jul 2018 14:40:13 +0100
Subject: [PATCH 083/697] dwc-otg: FIQ: Fix "bad mode in data abort handler"
Create a semi-static mapping for the USB registers early in the boot
process, before additional kernel threads are started, so all threads
will have the mappings from the start. This avoids the need for
data aborts to lazily update them.
See: https://github.com/raspberrypi/linux/issues/2450
Signed-off-by: Floris Bos <bos@je-eigen-domein.nl>
---
arch/arm/mach-bcm/board_bcm2835.c | 69 +++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
+#include <linux/of_fdt.h>
#include <asm/system_info.h>
#include <asm/mach/arch.h>
@@ -13,6 +14,9 @@
#include "platsmp.h"
+#define BCM2835_USB_VIRT_BASE 0xf0980000
+#define BCM2835_USB_VIRT_MPHI 0xf0006000
+
static void __init bcm2835_init(void)
{
struct device_node *np = of_find_node_by_path("/system");
@@ -25,6 +29,70 @@ static void __init bcm2835_init(void)
system_serial_low = val64;
}
+/*
+ * We need to map registers that are going to be accessed by the FIQ
+ * very early, before any kernel threads are spawned. Because if done
+ * later, the mapping tables are not updated instantly but lazily upon
+ * first access through a data abort handler. While that is fine
+ * when executing regular kernel code, if the first access in a specific
+ * thread happens while running FIQ code this will result in a panic.
+ *
+ * For more background see the following old mailing list thread:
+ * https://www.spinics.net/lists/arm-kernel/msg325250.html
+ */
+static int __init bcm2835_map_usb(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct map_desc map[2];
+ const __be32 *reg;
+ int len;
+ unsigned long p2b_offset = *((unsigned long *) data);
+
+ if (!of_flat_dt_is_compatible(node, "brcm,bcm2708-usb"))
+ return 0;
+ reg = of_get_flat_dt_prop(node, "reg", &len);
+ if (!reg || len != (sizeof(unsigned long) * 4))
+ return 0;
+
+ /* Use information about the physical addresses of the
+ * registers from the device tree, but use legacy
+ * iotable_init() static mapping function to map them,
+ * as ioremap() is not functional at this stage in boot.
+ */
+ map[0].virtual = (unsigned long) BCM2835_USB_VIRT_BASE;
+ map[0].pfn = __phys_to_pfn(be32_to_cpu(reg[0]) - p2b_offset);
+ map[0].length = be32_to_cpu(reg[1]);
+ map[0].type = MT_DEVICE;
+ map[1].virtual = (unsigned long) BCM2835_USB_VIRT_MPHI;
+ map[1].pfn = __phys_to_pfn(be32_to_cpu(reg[2]) - p2b_offset);
+ map[1].length = be32_to_cpu(reg[3]);
+ map[1].type = MT_DEVICE;
+ iotable_init(map, 2);
+
+ return 1;
+}
+
+static void __init bcm2835_map_io(void)
+{
+ const __be32 *ranges;
+ int soc, len;
+ unsigned long p2b_offset;
+
+ debug_ll_io_init();
+
+ /* Find out how to map bus to physical address first from soc/ranges */
+ soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc");
+ if (soc < 0)
+ return;
+ ranges = of_get_flat_dt_prop(soc, "ranges", &len);
+ if (!ranges || len < (sizeof(unsigned long) * 3))
+ return;
+ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]);
+
+ /* Now search for bcm2708-usb node in device tree */
+ of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
+}
+
static const char * const bcm2835_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
@@ -37,6 +105,7 @@ static const char * const bcm2835_compat
};
DT_MACHINE_START(BCM2835, "BCM2835")
+ .map_io = bcm2835_map_io,
.init_machine = bcm2835_init,
.dt_compat = bcm2835_compat,
.smp = smp_ops(bcm2836_smp_ops),

View File

@ -0,0 +1,36 @@
From 477c8c6ba92831dfd66b19348b44d95df3da6a5c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 11 Dec 2017 09:18:32 +0000
Subject: [PATCH 084/697] ARM: Activate FIQs to avoid __irq_startup warnings
There is a new test in __irq_startup that the IRQ is activated, which
hasn't been the case for FIQs since they bypass some of the usual setup.
Augment enable_fiq to include a call to irq_activate to avoid the
warning.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/kernel/fiq.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -57,6 +57,8 @@
static unsigned long dfl_fiq_insn;
static struct pt_regs dfl_fiq_regs;
+extern int irq_activate(struct irq_desc *desc);
+
/* Default reacquire function
* - we always relinquish FIQ control
* - we always reacquire FIQ control
@@ -141,6 +143,8 @@ static int fiq_start;
void enable_fiq(int fiq)
{
+ struct irq_desc *desc = irq_to_desc(fiq + fiq_start);
+ irq_activate(desc);
enable_irq(fiq + fiq_start);
}

View File

@ -0,0 +1,35 @@
From bd97ce931bb969e1c375d9d5e1b82d6e697791d8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 20 Feb 2018 10:07:27 +0000
Subject: [PATCH 085/697] i2c-gpio: Also set bus numbers from reg property
I2C busses can be assigned specific bus numbers using aliases in
Device Tree - string properties where the name is the alias and the
value is the path to the node. The current DT parameter mechanism
does not allow property names to be derived from a parameter value
in any way, so it isn't possible to generate unique or matching
aliases for nodes from an overlay that can generate multiple
instances, e.g. i2c-gpio.
Work around this limitation (at least temporarily) by allowing
the i2c adapter number to be initialised from the "reg" property
if present.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/i2c/busses/i2c-gpio.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -428,7 +428,9 @@ static int i2c_gpio_probe(struct platfor
adap->dev.parent = dev;
device_set_node(&adap->dev, fwnode);
- adap->nr = pdev->id;
+ if (pdev->id != PLATFORM_DEVID_NONE || !pdev->dev.of_node ||
+ of_property_read_u32(pdev->dev.of_node, "reg", &adap->nr))
+ adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
return ret;

View File

@ -0,0 +1,22 @@
From 3b24e2cc8ee5b363537f47afe3dc49b0a71d2afa Mon Sep 17 00:00:00 2001
From: hdoverobinson <hdoverobinson@gmail.com>
Date: Tue, 13 Mar 2018 06:58:39 -0400
Subject: [PATCH 086/697] added capture_clear option to pps-gpio via dtoverlay
(#2433)
---
drivers/pps/clients/pps-gpio.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -113,6 +113,9 @@ static int pps_gpio_setup(struct device
data->assert_falling_edge =
device_property_read_bool(dev, "assert-falling-edge");
+ data->capture_clear =
+ device_property_read_bool(dev, "capture-clear");
+
data->echo_pin = devm_gpiod_get_optional(dev, "echo", GPIOD_OUT_LOW);
if (IS_ERR(data->echo_pin))
return dev_err_probe(dev, PTR_ERR(data->echo_pin),

View File

@ -0,0 +1,46 @@
From e0fa936ac8cd90ae9f8b2b7e2f849390a907329f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 14 Jul 2014 22:02:09 +0100
Subject: [PATCH 087/697] hid: Reduce default mouse polling interval to 60Hz
Reduces overhead when using X
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 | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -46,7 +46,7 @@
* Module parameters.
*/
-static unsigned int hid_mousepoll_interval;
+static unsigned int hid_mousepoll_interval = ~0;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
@@ -1113,7 +1113,9 @@ static int usbhid_start(struct hid_devic
*/
switch (hid->collection->usage) {
case HID_GD_MOUSE:
- if (hid_mousepoll_interval > 0)
+ if (hid_mousepoll_interval == ~0 && interval < 16)
+ interval = 16;
+ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
interval = hid_mousepoll_interval;
break;
case HID_GD_JOYSTICK:
@@ -1125,6 +1127,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)) {

View File

@ -0,0 +1,84 @@
From ae63a39b401e76766b95b706e815660def7c6dcd Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Sat, 12 May 2018 21:35:43 +0100
Subject: [PATCH 088/697] firmware/raspberrypi: Notify firmware of a reboot
Register for reboot notifications, sending RPI_FIRMWARE_NOTIFY_REBOOT
over the mailbox interface on reception.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/firmware/raspberrypi.c | 40 +++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -14,6 +14,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
@@ -182,6 +183,26 @@ int rpi_firmware_property(struct rpi_fir
}
EXPORT_SYMBOL_GPL(rpi_firmware_property);
+static int rpi_firmware_notify_reboot(struct notifier_block *nb,
+ unsigned long action,
+ void *data)
+{
+ struct rpi_firmware *fw;
+ struct platform_device *pdev = g_pdev;
+
+ if (!pdev)
+ return 0;
+
+ fw = platform_get_drvdata(pdev);
+ if (!fw)
+ return 0;
+
+ (void)rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT,
+ 0, 0);
+
+ return 0;
+}
+
static void
rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
{
@@ -413,15 +434,32 @@ static struct platform_driver rpi_firmwa
.remove_new = rpi_firmware_remove,
};
+static struct notifier_block rpi_firmware_reboot_notifier = {
+ .notifier_call = rpi_firmware_notify_reboot,
+};
+
static int __init rpi_firmware_init(void)
{
- return platform_driver_register(&rpi_firmware_driver);
+ int ret = register_reboot_notifier(&rpi_firmware_reboot_notifier);
+ if (ret)
+ goto out1;
+ ret = platform_driver_register(&rpi_firmware_driver);
+ if (ret)
+ goto out2;
+
+ return 0;
+
+out2:
+ unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
+out1:
+ return ret;
}
core_initcall(rpi_firmware_init);
static void __init rpi_firmware_exit(void)
{
platform_driver_unregister(&rpi_firmware_driver);
+ unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
}
module_exit(rpi_firmware_exit);

View File

@ -0,0 +1,66 @@
From 590d329717464417244843f07141551927ba6dac Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 14 Jun 2018 11:21:04 +0100
Subject: [PATCH 089/697] irqchip: irq-bcm2835: Calc. FIQ_START at boot-time
ad83c7cb2f37 ("irqchip/irq-bcm2836: Add support for DT interrupt polarity")
changed the way that the BCM2836/7 local interrupts are mapped; instead
of being pre-mapped they are now mapped on-demand. A side effect of this
change is that the call to irq_of_parse_and_map from armctrl_of_init
creates a new mapping, forming a gap between the IRQs and the FIQs. This
gap breaks the FIQ<->IRQ mapping which up to now has been done by assuming:
1) that the value of FIQ_START is the same as the number of normal IRQs
that will be mapped (still true), and
2) that this value is also the offset between an IRQ and its equivalent
FIQ (which is no longer the case).
Remove both assumptions by measuring the interval between the last IRQ
and the last FIQ, passing it as the parameter to init_FIQ().
Fixes: https://github.com/raspberrypi/linux/issues/2432
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/irqchip/irq-bcm2835.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -75,8 +75,6 @@
#define NR_BANKS 3
#define IRQS_PER_BANK 32
#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
-#undef FIQ_START
-#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
@@ -205,7 +203,7 @@ static int __init armctrl_of_init(struct
bool is_2836)
{
void __iomem *base;
- int irq, b, i;
+ int irq = 0, last_irq, b, i;
u32 reg;
base = of_iomap(node, 0);
@@ -245,6 +243,8 @@ static int __init armctrl_of_init(struct
pr_err(FW_BUG "Bootloader left fiq enabled\n");
}
+ last_irq = irq;
+
if (is_2836) {
int parent_irq = irq_of_parse_and_map(node, 0);
@@ -275,7 +275,7 @@ static int __init armctrl_of_init(struct
}
}
#ifndef CONFIG_ARM64
- init_FIQ(FIQ_START);
+ init_FIQ(irq - last_irq);
#endif
return 0;

View File

@ -0,0 +1,29 @@
From 9677dfed46ff080ea6fb5049149b5fc2e2511093 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 20 Jun 2018 12:20:01 +0100
Subject: [PATCH 090/697] brcmfmac: Re-enable firmware roaming support
As of 4.18, a firmware that implements the update_connect_params
method but doesn't claim to support roaming causes an error. We
disabled firmware roaming in 4.4 [1] because it appeared to
prevent disconnects, but let's try with the current firmware to see
if things have improved.
[1] https://github.com/raspberrypi/linux/commit/dd9188011786fb62a7960922f31e8e086fb2009b
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -59,7 +59,7 @@ static int brcmf_fcmode;
module_param_named(fcmode, brcmf_fcmode, int, 0);
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
-static int brcmf_roamoff = 1;
+static int brcmf_roamoff;
module_param_named(roamoff, brcmf_roamoff, int, 0400);
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");

View File

@ -0,0 +1,20 @@
From 01680d48f35a23b6cb565d80d9e984c5e3c1388a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 17 Sep 2018 17:31:18 +0100
Subject: [PATCH 091/697] cxd2880: CXD2880_SPI_DRV should select DVB_CXD2880
with MEDIA_SUBDRV_AUTOSELECT
---
drivers/media/spi/Kconfig | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -9,6 +9,7 @@ menu "Media SPI Adapters"
config CXD2880_SPI_DRV
tristate "Sony CXD2880 SPI support"
depends on DVB_CORE && SPI
+ select DVB_CXD2880 if MEDIA_SUBDRV_AUTOSELECT
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Choose if you would like to have SPI interface support for Sony CXD2880.

View File

@ -0,0 +1,79 @@
From c032deca20b5517d082cb71f13c870d638d1ff3b Mon Sep 17 00:00:00 2001
From: Stefan Wahren <stefan.wahren@i2se.com>
Date: Sat, 13 Oct 2018 13:31:21 +0200
Subject: [PATCH 092/697] firmware: raspberrypi: Add backward compatible
get_throttled
Avoid a hard userspace ABI change by adding a compatible get_throttled
sysfs entry. Its value is now feed by the GET_THROTTLED requests of the
new hwmon driver. The first access to get_throttled will generate
a warning.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/firmware/raspberrypi.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -33,6 +33,7 @@ struct rpi_firmware {
u32 enabled;
struct kref consumers;
+ u32 get_throttled;
};
static struct platform_device *g_pdev;
@@ -179,6 +180,12 @@ int rpi_firmware_property(struct rpi_fir
kfree(data);
+ if ((tag == RPI_FIRMWARE_GET_THROTTLED) &&
+ memcmp(&fw->get_throttled, tag_data, sizeof(fw->get_throttled))) {
+ memcpy(&fw->get_throttled, tag_data, sizeof(fw->get_throttled));
+ sysfs_notify(&fw->cl.dev->kobj, NULL, "get_throttled");
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(rpi_firmware_property);
@@ -203,6 +210,27 @@ static int rpi_firmware_notify_reboot(st
return 0;
}
+static ssize_t get_throttled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpi_firmware *fw = dev_get_drvdata(dev);
+
+ WARN_ONCE(1, "deprecated, use hwmon sysfs instead\n");
+
+ return sprintf(buf, "%x\n", fw->get_throttled);
+}
+
+static DEVICE_ATTR_RO(get_throttled);
+
+static struct attribute *rpi_firmware_dev_attrs[] = {
+ &dev_attr_get_throttled.attr,
+ NULL,
+};
+
+static const struct attribute_group rpi_firmware_dev_group = {
+ .attrs = rpi_firmware_dev_attrs,
+};
+
static void
rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
{
@@ -232,6 +260,11 @@ rpi_register_hwmon_driver(struct device
rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon",
-1, NULL, 0);
+
+ if (!IS_ERR_OR_NULL(rpi_hwmon)) {
+ if (devm_device_add_group(dev, &rpi_firmware_dev_group))
+ dev_err(dev, "Failed to create get_trottled attr\n");
+ }
}
static void rpi_register_clk_driver(struct device *dev)

View File

@ -0,0 +1,89 @@
From c87dbd4dd422e0b4fb150492aeb75e796d79d2e6 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 10 Jan 2019 17:58:06 +0000
Subject: [PATCH 093/697] firmware: raspberrypi: Report the fw variant during
probe
The driver already reported the firmware build date during probe.
The mailbox calls have been extended to also report the variant
1 = standard start.elf
2 = start_x.elf (includes camera stack)
3 = start_db.elf (includes assert logging)
4 = start_cd.elf (cutdown version for smallest memory footprint).
Log the variant during probe.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
firmware: raspberrypi: Report the fw git hash during probe
The firmware can now report the git hash from which it was built
via the mailbox, so report it during probe.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/firmware/raspberrypi.c | 40 +++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -236,6 +236,15 @@ rpi_firmware_print_firmware_revision(str
{
time64_t date_and_time;
u32 packet;
+ static const char * const variant_strs[] = {
+ "unknown",
+ "start",
+ "start_x",
+ "start_db",
+ "start_cd",
+ };
+ const char *variant_str = "cmd unsupported";
+ u32 variant;
int ret = rpi_firmware_property(fw,
RPI_FIRMWARE_GET_FIRMWARE_REVISION,
&packet, sizeof(packet));
@@ -245,7 +254,35 @@ rpi_firmware_print_firmware_revision(str
/* This is not compatible with y2038 */
date_and_time = packet;
- dev_info(fw->cl.dev, "Attached to firmware from %ptT\n", &date_and_time);
+
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT,
+ &variant, sizeof(variant));
+
+ if (!ret) {
+ if (variant >= ARRAY_SIZE(variant_strs))
+ variant = 0;
+ variant_str = variant_strs[variant];
+ }
+
+ dev_info(fw->cl.dev,
+ "Attached to firmware from %ptT, variant %s\n",
+ &date_and_time, variant_str);
+}
+
+static void
+rpi_firmware_print_firmware_hash(struct rpi_firmware *fw)
+{
+ u32 hash[5];
+ int ret = rpi_firmware_property(fw,
+ RPI_FIRMWARE_GET_FIRMWARE_HASH,
+ hash, sizeof(hash));
+
+ if (ret)
+ return;
+
+ dev_info(fw->cl.dev,
+ "Firmware hash is %08x%08x%08x%08x%08x\n",
+ hash[0], hash[1], hash[2], hash[3], hash[4]);
}
static void
@@ -360,6 +397,7 @@ static int rpi_firmware_probe(struct pla
g_pdev = pdev;
rpi_firmware_print_firmware_revision(fw);
+ rpi_firmware_print_firmware_hash(fw);
rpi_register_hwmon_driver(dev, fw);
rpi_register_clk_driver(dev);

View File

@ -0,0 +1,56 @@
From 25db57002e41c9258d08a6ee818a8dcfe97d44f3 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 13 Jun 2018 15:21:10 +0100
Subject: [PATCH 094/697] net: lan78xx: Disable TCP Segmentation Offload (TSO)
TSO seems to be having issues when packets are dropped and the
remote end uses Selective Acknowledge (SACK) to denote that
data is missing. The missing data is never resent, so the
connection eventually stalls.
There is a module parameter of enable_tso added to allow
further debugging without forcing a rebuild of the kernel.
https://github.com/raspberrypi/linux/issues/2449
https://github.com/raspberrypi/linux/issues/2482
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/net/usb/lan78xx.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -604,6 +604,15 @@ static int lan78xx_alloc_tx_resources(st
dev->n_tx_urbs, dev->tx_urb_size, dev);
}
+/* TSO seems to be having some issue with Selective Acknowledge (SACK) that
+ * results in lost data never being retransmitted.
+ * Disable it by default now, but adds a module parameter to enable it for
+ * debug purposes (the full cause is not currently understood).
+ */
+static bool enable_tso;
+module_param(enable_tso, bool, 0644);
+MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+
static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
{
u32 *buf;
@@ -3444,8 +3453,14 @@ static int lan78xx_bind(struct lan78xx_n
if (DEFAULT_RX_CSUM_ENABLE)
dev->net->features |= NETIF_F_RXCSUM;
- if (DEFAULT_TSO_CSUM_ENABLE)
- dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG;
+ if (DEFAULT_TSO_CSUM_ENABLE) {
+ dev->net->features |= NETIF_F_SG;
+ /* Use module parameter to control TCP segmentation offload as
+ * it appears to cause issues.
+ */
+ if (enable_tso)
+ dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ }
if (DEFAULT_VLAN_RX_OFFLOAD)
dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX;

View File

@ -0,0 +1,91 @@
From 019f4fcddce3981bf1496670da91c8c7e6845eec Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 26 Nov 2018 19:46:58 +0000
Subject: [PATCH 095/697] net: lan78xx: Support auto-downshift to 100Mb/s
Ethernet cables with faulty or missing pairs (specifically pairs C and
D) allow auto-negotiation to 1000Mbs, but do not support the successful
establishment of a link. Add a DT property, "microchip,downshift-after",
to configure the number of auto-negotiation failures after which it
falls back to 100Mbs. Valid values are 2, 3, 4, 5 and 0, where 0 means
never downshift.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
.../bindings/net/microchip,lan78xx.txt | 3 +++
drivers/net/phy/microchip.c | 27 +++++++++++++++++++
include/linux/microchipphy.h | 8 ++++++
3 files changed, 38 insertions(+)
--- a/Documentation/devicetree/bindings/net/microchip,lan78xx.txt
+++ b/Documentation/devicetree/bindings/net/microchip,lan78xx.txt
@@ -14,6 +14,9 @@ Optional properties of the embedded PHY:
- microchip,led-modes: a 0..4 element vector, with each element configuring
the operating mode of an LED. Omitted LEDs are turned off. Allowed values
are defined in "include/dt-bindings/net/microchip-lan78xx.h".
+- microchip,downshift-after: sets the number of failed auto-negotiation
+ attempts after which the link is downgraded from 1000BASE-T. Should be one of
+ 2, 3, 4, 5 or 0, where 0 means never downshift.
Example:
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -239,6 +239,7 @@ static int lan88xx_probe(struct phy_devi
struct device *dev = &phydev->mdio.dev;
struct lan88xx_priv *priv;
u32 led_modes[4];
+ u32 downshift_after = 0;
int len;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -268,6 +269,32 @@ static int lan88xx_probe(struct phy_devi
return -EINVAL;
}
+ if (!of_property_read_u32(dev->of_node,
+ "microchip,downshift-after",
+ &downshift_after)) {
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK;
+ u32 val= LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+ switch (downshift_after) {
+ case 2: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+ break;
+ case 3: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+ break;
+ case 4: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+ break;
+ case 5: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+ break;
+ case 0: // Disable completely
+ mask = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ (void)phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ mask, val);
+ }
+
/* these values can be used to identify internal PHY */
priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,14 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT (0x0010)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK (0x000c)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0x0000)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (0x0004)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (0x0008)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (0x000c)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)

View File

@ -0,0 +1,45 @@
From 411c8c532bf720664c5dfda033491cd5153cee85 Mon Sep 17 00:00:00 2001
From: Joshua Emele <jemele@acm.org>
Date: Wed, 7 Nov 2018 16:07:40 -0800
Subject: [PATCH 096/697] lan78xx: Debounce link events to minimize poll storm
The bInterval is set to 4 (i.e. 8 microframes => 1ms) and the only bit
that the driver pays attention to is "link was reset". If there's a
flapping status bit in that endpoint data, (such as if PHY negotiation
needs a few tries to get a stable link) then polling at a slower rate
would act as a de-bounce.
See: https://github.com/raspberrypi/linux/issues/2447
---
drivers/net/usb/lan78xx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -613,6 +613,11 @@ static bool enable_tso;
module_param(enable_tso, bool, 0644);
MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+#define INT_URB_MICROFRAMES_PER_MS 8
+static int int_urb_interval_ms = 8;
+module_param(int_urb_interval_ms, int, 0);
+MODULE_PARM_DESC(int_urb_interval_ms, "Override usb interrupt urb interval");
+
static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
{
u32 *buf;
@@ -4430,7 +4435,13 @@ static int lan78xx_probe(struct usb_inte
if (ret < 0)
goto out4;
- period = ep_intr->desc.bInterval;
+ if (int_urb_interval_ms <= 0)
+ period = ep_intr->desc.bInterval;
+ else
+ period = int_urb_interval_ms * INT_URB_MICROFRAMES_PER_MS;
+
+ netif_notice(dev, probe, netdev, "int urb period %d\n", period);
+
maxp = usb_maxpacket(dev->udev, dev->pipe_intr);
dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL);

View File

@ -0,0 +1,32 @@
From 36daab2dfb621c983dd7d9c62fbfb86bbda7e131 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 15 Dec 2020 16:38:37 +0000
Subject: [PATCH 097/697] net: lan78xx: Ack pending PHY ints when resetting
lan78xx_link_reset explicitly clears the MAC's view of the PHY's IRQ
status. In doing so it potentially leaves the PHY with a pending
interrupt that will never be acknowledged, at which point no further
interrupts will be generated.
Avoid the problem by acknowledging any pending PHY interrupt after
clearing the MAC's status bit.
See: https://github.com/raspberrypi/linux/issues/2937
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/net/usb/lan78xx.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -1435,6 +1435,9 @@ static int lan78xx_link_reset(struct lan
if (unlikely(ret < 0))
return ret;
+ /* Acknowledge any pending PHY interrupt, lest it be the last */
+ phy_read(phydev, LAN88XX_INT_STS);
+
mutex_lock(&phydev->lock);
phy_read_status(phydev);
link = phydev->link;

View File

@ -0,0 +1,20 @@
From 5bb9dff1dfb80acb9caac699e56832b776d0af47 Mon Sep 17 00:00:00 2001
From: tiagofreire-pt <41837236+tiagofreire-pt@users.noreply.github.com>
Date: Sat, 29 Jan 2022 10:01:36 +0000
Subject: [PATCH 098/697] Patching lan78xx for SOF_TIMESTAMPING_TX_SOFTWARE
support
---
drivers/net/usb/lan78xx.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -1935,6 +1935,7 @@ static const struct ethtool_ops lan78xx_
.set_link_ksettings = lan78xx_set_link_ksettings,
.get_regs_len = lan78xx_get_regs_len,
.get_regs = lan78xx_get_regs,
+ .get_ts_info = ethtool_op_get_ts_info,
};
static void lan78xx_init_mac_address(struct lan78xx_net *dev)

View File

@ -0,0 +1,49 @@
From 360bfdf87620dd2d5504877e2da07704ef349932 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 17 Oct 2017 15:04:29 +0100
Subject: [PATCH 099/697] lan78xx: Enable LEDs and auto-negotiation
For applications of the LAN78xx that don't have valid programmed
EEPROMs or OTPs, enabling both LEDs and auto-negotiation by default
seems reasonable.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/usb/lan78xx.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2897,6 +2897,11 @@ static int lan78xx_reset(struct lan78xx_
int ret;
u32 buf;
u8 sig;
+ bool has_eeprom;
+ bool has_otp;
+
+ has_eeprom = !lan78xx_read_eeprom(dev, 0, 0, NULL);
+ has_otp = !lan78xx_read_otp(dev, 0, 0, NULL);
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
if (ret < 0)
@@ -2963,6 +2968,10 @@ static int lan78xx_reset(struct lan78xx_
buf |= HW_CFG_CLK125_EN_;
buf |= HW_CFG_REFCLK25_EN_;
+ /* If no valid EEPROM and no valid OTP, enable the LEDs by default */
+ if (!has_eeprom && !has_otp)
+ buf |= HW_CFG_LED0_EN_ | HW_CFG_LED1_EN_;
+
ret = lan78xx_write_reg(dev, HW_CFG, buf);
if (ret < 0)
return ret;
@@ -3065,6 +3074,9 @@ static int lan78xx_reset(struct lan78xx_
buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
}
}
+ /* If no valid EEPROM and no valid OTP, enable AUTO negotiation */
+ if (!has_eeprom && !has_otp)
+ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
ret = lan78xx_write_reg(dev, MAC_CR, buf);
if (ret < 0)
return ret;

View File

@ -0,0 +1,31 @@
From 63b70709d87f1afa05a4d90413abde19ee137af5 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:56:59 +0000
Subject: [PATCH 100/697] media: tc358743: Increase FIFO level to 374.
The existing fixed value of 16 worked for UYVY 720P60 over
2 lanes at 594MHz, or UYVY 1080P60 over 4 lanes. (RGB888
1080P60 needs 6 lanes at 594MHz).
It doesn't allow for lower resolutions to work as the FIFO
underflows.
374 is required for 1080P24-30 UYVY over 2 lanes @ 972Mbit/s, but
>374 means that the FIFO underflows on 1080P50 UYVY over 2 lanes
@ 972Mbit/s.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/tc358743.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1942,7 +1942,7 @@ static int tc358743_probe_of(struct tc35
state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
state->pdata.enable_hdcp = false;
/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
- state->pdata.fifo_level = 16;
+ state->pdata.fifo_level = 374;
/*
* The PLL input clock is obtained by dividing refclk by pll_prd.
* It must be between 6 MHz and 40 MHz, lower frequency is better.

View File

@ -0,0 +1,91 @@
From 6bdc682efda1798faad0b32ea9a92778e5ce8c87 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:57:21 +0000
Subject: [PATCH 101/697] media: tc358743: Add support for 972Mbit/s link freq.
Adds register setups for running the CSI lanes at 972Mbit/s,
which allows 1080P50 UYVY down 2 lanes.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
media: tc358743: Add support for 972Mbit/s link freq.
Adds register setups for running the CSI lanes at 972Mbit/s,
which allows 1080P50 UYVY down 2 lanes.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
media: i2c: tc358743: Fix fallthrough warning
Signed-off-by: Jacko Dirks <jdirks.linuxdev@gmail.com>
---
drivers/media/i2c/tc358743.c | 48 +++++++++++++++++++++++++-----------
1 file changed, 34 insertions(+), 14 deletions(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1962,6 +1962,7 @@ static int tc358743_probe_of(struct tc35
/*
* The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
* The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
+ * 972 Mbps allows 1080P50 UYVY over 2-lane.
*/
bps_pr_lane = 2 * endpoint.link_frequencies[0];
if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
@@ -1975,23 +1976,42 @@ static int tc358743_probe_of(struct tc35
state->pdata.refclk_hz * state->pdata.pll_prd;
/*
- * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz
- * link frequency). In principle it should be possible to calculate
+ * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane
+ * (297 MHz or 486 MHz link frequency).
+ * In principle it should be possible to calculate
* them based on link frequency and resolution.
*/
- if (bps_pr_lane != 594000000U)
+ switch (bps_pr_lane) {
+ default:
dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane);
- state->pdata.lineinitcnt = 0xe80;
- state->pdata.lptxtimecnt = 0x003;
- /* tclk-preparecnt: 3, tclk-zerocnt: 20 */
- state->pdata.tclk_headercnt = 0x1403;
- state->pdata.tclk_trailcnt = 0x00;
- /* ths-preparecnt: 3, ths-zerocnt: 1 */
- state->pdata.ths_headercnt = 0x0103;
- state->pdata.twakeup = 0x4882;
- state->pdata.tclk_postcnt = 0x008;
- state->pdata.ths_trailcnt = 0x2;
- state->pdata.hstxvregcnt = 0;
+ fallthrough;
+ case 594000000U:
+ state->pdata.lineinitcnt = 0xe80;
+ state->pdata.lptxtimecnt = 0x003;
+ /* tclk-preparecnt: 3, tclk-zerocnt: 20 */
+ state->pdata.tclk_headercnt = 0x1403;
+ state->pdata.tclk_trailcnt = 0x00;
+ /* ths-preparecnt: 3, ths-zerocnt: 1 */
+ state->pdata.ths_headercnt = 0x0103;
+ state->pdata.twakeup = 0x4882;
+ state->pdata.tclk_postcnt = 0x008;
+ state->pdata.ths_trailcnt = 0x2;
+ state->pdata.hstxvregcnt = 0;
+ break;
+ case 972000000U:
+ state->pdata.lineinitcnt = 0x1b58;
+ state->pdata.lptxtimecnt = 0x007;
+ /* tclk-preparecnt: 6, tclk-zerocnt: 40 */
+ state->pdata.tclk_headercnt = 0x2806;
+ state->pdata.tclk_trailcnt = 0x00;
+ /* ths-preparecnt: 6, ths-zerocnt: 8 */
+ state->pdata.ths_headercnt = 0x0806;
+ state->pdata.twakeup = 0x4268;
+ state->pdata.tclk_postcnt = 0x008;
+ state->pdata.ths_trailcnt = 0x5;
+ state->pdata.hstxvregcnt = 0;
+ break;
+ }
state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);

View File

@ -0,0 +1,98 @@
From ffe6b9c74a772bbecf6ea09c3dd097901c2048ef Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:57:34 +0000
Subject: [PATCH 102/697] media: tc358743: Check I2C succeeded during probe.
The probe for the TC358743 reads the CHIPID register from
the device and compares it to the expected value of 0.
If the I2C request fails then that also returns 0, so
the driver loads thinking that the device is there.
Generally I2C communications are reliable so there is
limited need to check the return value on every transfer,
therefore only amend the one read during probe to check
for I2C errors.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/tc358743.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -110,7 +110,7 @@ static inline struct tc358743_state *to_
/* --------------- I2C --------------- */
-static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
+static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
{
struct tc358743_state *state = to_state(sd);
struct i2c_client *client = state->i2c_client;
@@ -136,6 +136,7 @@ static void i2c_rd(struct v4l2_subdev *s
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n",
__func__, reg, client->addr, err);
}
+ return err != ARRAY_SIZE(msgs);
}
static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
@@ -192,15 +193,24 @@ static void i2c_wr(struct v4l2_subdev *s
}
}
-static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n,
+ int *err)
{
+ int error;
__le32 val = 0;
- i2c_rd(sd, reg, (u8 __force *)&val, n);
+ error = i2c_rd(sd, reg, (u8 __force *)&val, n);
+ if (err)
+ *err = error;
return le32_to_cpu(val);
}
+static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
+{
+ return i2c_rdreg_err(sd, reg, n, NULL);
+}
+
static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
{
__le32 raw = cpu_to_le32(val);
@@ -229,6 +239,13 @@ static u16 i2c_rd16(struct v4l2_subdev *
return i2c_rdreg(sd, reg, 2);
}
+static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value)
+{
+ int err;
+ *value = i2c_rdreg_err(sd, reg, 2, &err);
+ return err;
+}
+
static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
{
i2c_wrreg(sd, reg, val, 2);
@@ -2050,6 +2067,7 @@ static int tc358743_probe(struct i2c_cli
struct tc358743_platform_data *pdata = client->dev.platform_data;
struct v4l2_subdev *sd;
u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK;
+ u16 chipid;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -2081,7 +2099,8 @@ static int tc358743_probe(struct i2c_cli
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
/* i2c access */
- if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) {
+ if (i2c_rd16_err(sd, CHIPID, &chipid) ||
+ (chipid & MASK_CHIPID) != 0) {
v4l2_info(sd, "not a TC358743 on address 0x%x\n",
client->addr << 1);
return -ENODEV;

View File

@ -0,0 +1,45 @@
From 2904284caace567741621bf4d1f1edb7685ce9ac Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:57:46 +0000
Subject: [PATCH 103/697] media: adv7180: Default to the first valid input
The hardware default is differential CVBS on AIN1 & 2, which
isn't very useful.
Select the first input that is defined as valid for the
chip variant (typically CVBS_AIN1).
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/adv7180.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1352,6 +1352,7 @@ static const struct adv7180_chip_info ad
static int init_device(struct adv7180_state *state)
{
int ret;
+ int i;
mutex_lock(&state->mutex);
@@ -1399,6 +1400,18 @@ static int init_device(struct adv7180_st
goto out_unlock;
}
+ /* Select first valid input */
+ for (i = 0; i < 32; i++) {
+ if (BIT(i) & state->chip_info->valid_input_mask) {
+ ret = state->chip_info->select_input(state, i);
+
+ if (ret == 0) {
+ state->input = i;
+ break;
+ }
+ }
+ }
+
out_unlock:
mutex_unlock(&state->mutex);

View File

@ -0,0 +1,24 @@
From 574a32c1fa8e3c8bba75f90a2d0a8db25eca983f Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 31 Oct 2018 14:57:56 +0000
Subject: [PATCH 104/697] media: adv7180: Add YPrPb support for ADV7282M
The ADV7282M can support YPbPr on AIN1-3, but this was
not selectable from the driver. Add it to the list of
supported input modes.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/media/i2c/adv7180.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1341,6 +1341,7 @@ static const struct adv7180_chip_info ad
BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),

Some files were not shown because too many files have changed in this diff Show More