mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-24 07:46:48 +00:00
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:
parent
3bb0365112
commit
f59f26ed47
@ -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;
|
@ -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 */
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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>,
|
@ -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";
|
@ -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
|
@ -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.
|
@ -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;
|
||||
|
@ -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)
|
@ -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;
|
@ -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)
|
@ -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:
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/*
|
@ -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,
|
||||
};
|
||||
|
@ -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");
|
@ -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;
|
||||
|
@ -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,
|
@ -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",
|
@ -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,
|
@ -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.
|
@ -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.
|
@ -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;
|
@ -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,
|
@ -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);
|
@ -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
|
@ -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",
|
@ -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);
|
@ -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;
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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++) {
|
@ -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");
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
@ -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)
|
@ -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();
|
||||
}
|
||||
|
||||
/*
|
@ -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;
|
||||
}
|
@ -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,
|
@ -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;
|
@ -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,
|
@ -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;
|
@ -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);
|
@ -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;
|
||||
|
@ -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");
|
61017
target/linux/bcm27xx/patches-6.12/950-0054-Add-dwc_otg-driver.patch
Normal file
61017
target/linux/bcm27xx/patches-6.12/950-0054-Add-dwc_otg-driver.patch
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
@ -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);
|
File diff suppressed because it is too large
Load Diff
@ -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(¶m32, (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(¶m);
|
||||
+ 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 */
|
1970
target/linux/bcm27xx/patches-6.12/950-0061-Add-SMI-driver.patch
Normal file
1970
target/linux/bcm27xx/patches-6.12/950-0061-Add-SMI-driver.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
@ -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/
|
@ -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");
|
@ -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>");
|
@ -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");
|
@ -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;
|
@ -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,
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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);
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
@ -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");
|
@ -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);
|
@ -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),
|
@ -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);
|
@ -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);
|
@ -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:
|
@ -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");
|
||||
+
|
@ -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
|
@ -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),
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -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),
|
@ -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)) {
|
@ -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);
|
||||
|
@ -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;
|
@ -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");
|
||||
|
@ -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.
|
@ -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)
|
@ -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);
|
||||
|
@ -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;
|
@ -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)
|
@ -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);
|
@ -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;
|
@ -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)
|
@ -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;
|
@ -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.
|
@ -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);
|
@ -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;
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user